1 /* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
4 * User Datagram Protocol File: net_udp.c
6 * This module implements the User Datagram Protocol (RFCxxxx)
8 * Author: Mitch Lichtenberg (mpl@broadcom.com)
10 *********************************************************************
12 * Copyright 2000,2001,2002,2003
13 * Broadcom Corporation. All rights reserved.
15 * This software is furnished under license and may be used and
16 * copied only in accordance with the following terms and
17 * conditions. Subject to these conditions, you may download,
18 * copy, install, use, modify and distribute modified or unmodified
19 * copies of this software in source and/or binary form. No title
20 * or ownership is transferred hereby.
22 * 1) Any source code used, modified or distributed must reproduce
23 * and retain this copyright notice and list of conditions
24 * as they appear in the source file.
26 * 2) No right is granted to use any trade name, trademark, or
27 * logo of Broadcom Corporation. The "Broadcom Corporation"
28 * name may not be used to endorse or promote products derived
29 * from this software without the prior written permission of
30 * Broadcom Corporation.
32 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
33 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
34 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
35 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
36 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
37 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
38 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
39 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
40 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
41 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
42 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
43 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
44 * THE POSSIBILITY OF SUCH DAMAGE.
45 ********************************************************************* */
49 #include "lib_types.h"
50 #include "lib_string.h"
51 #include "lib_queue.h"
52 #include "lib_malloc.h"
53 #include "lib_printf.h"
55 #include "cfe_timer.h"
58 #include "net_ether.h"
62 #include "cfe_error.h"
64 /* *********************************************************************
66 ********************************************************************* */
68 #define UDP_HDR_LENGTH 8
69 #define UDP_PORTBASE 1024
70 #define UDP_MAX_PORTS 4
72 /* *********************************************************************
74 ********************************************************************* */
76 typedef struct udp_port_s udp_port_t
;
79 * UDP port structure - describes an open UDP port.
83 uint16_t up_destport
; /* destination port number */
84 uint16_t up_srcport
; /* source port number */
85 queue_t up_rxqueue
; /* queue of received packets */
86 int up_maxqueue
; /* max # of elements on rx queue */
87 int up_inuse
; /* nonzero if port is in use */
92 * UDP stack information - describes the entire UDP layer.
99 udp_port_t ui_ports
[UDP_MAX_PORTS
];
102 /* *********************************************************************
103 * Forward declarations
104 ********************************************************************* */
106 static int _udp_rx_callback(void *ref
,ebuf_t
*buf
,uint8_t *destaddr
,uint8_t *srcaddr
);
109 /* *********************************************************************
110 * udp_find_port(info,port)
112 * Locate an open port. Scan the list of ports looking for one
113 * that is both open and has a matching source port number.
116 * info - UDP stack information
117 * port - source port # we're looking for
120 * udp_port_t pointer or NULL if no port was found
121 ********************************************************************* */
123 static udp_port_t
*_udp_find_port(udp_info_t
*info
,uint16_t port
)
126 udp_port_t
*udp
= info
->ui_ports
;
128 for (idx
= 0; idx
< UDP_MAX_PORTS
; idx
++) {
129 if (udp
->up_inuse
&& (udp
->up_srcport
== port
)) {
138 /* *********************************************************************
139 * _udp_socket(info,port)
141 * Open a UDP socket. This is an internal function used by
142 * the network API layer.
145 * info - UDP stack information
146 * port - port number to open
149 * port number (0 based) or an error code (<0) if an error
151 ********************************************************************* */
153 int _udp_socket(udp_info_t
*info
,uint16_t port
)
155 extern int32_t _getticks(void); /* return value of CP0 COUNT */
158 uint16_t srcport
= UDP_PORTBASE
+ (_getticks() & 0xFFF);
160 while (_udp_find_port(info
,srcport
)) { /* should always exit */
162 if (srcport
> (UDP_PORTBASE
+4096)) srcport
= UDP_PORTBASE
;
165 udp
= info
->ui_ports
;
167 for (idx
= 0; idx
< UDP_MAX_PORTS
; idx
++) {
168 if (!udp
->up_inuse
) break;
172 if (idx
== UDP_MAX_PORTS
) return CFE_ERR_NOHANDLES
;
174 udp
->up_destport
= port
;
175 udp
->up_srcport
= srcport
;
176 udp
->up_maxqueue
= 2;
177 udp
->up_inuse
= TRUE
;
178 q_init(&(udp
->up_rxqueue
));
184 /* *********************************************************************
187 * Internal function to close an open UDP port. This routine is
188 * called by the high-level network API.
191 * info - UDP stack information
192 * s - an open UDP socket handle (returned from _udp_open)
196 ********************************************************************* */
198 void _udp_close(udp_info_t
*info
,int s
)
200 udp_port_t
*udp
= &(info
->ui_ports
[s
]);
203 while ((buf
= (ebuf_t
*) q_deqnext(&(udp
->up_rxqueue
)))) {
204 _ip_free(info
->ui_ipinfo
,buf
);
208 udp
->up_destport
= 0;
209 udp
->up_maxqueue
= 0;
210 udp
->up_inuse
= FALSE
;
213 /* *********************************************************************
214 * _udp_send(info,s,buf,dest)
216 * Transmit a UDP datagram. Note that we never send fragmented
217 * datagrams, so all datagrams must be less than the MTU.
220 * info - UDP stack information
221 * s - an open UDP socket handle (returned from _udp_open)
222 * buf - an ebuf to send
223 * dest - destination IP address
226 * 0 if packet was sent
228 ********************************************************************* */
230 int _udp_send(udp_info_t
*info
,int s
,ebuf_t
*buf
,uint8_t *dest
)
232 udp_port_t
*udp
= &(info
->ui_ports
[s
]);
235 uint8_t pseudoheader
[12];
239 * Calculate the length of the IP datagram (includes UDP header)
242 udplen
= ebuf_length(buf
) + UDP_HDR_LENGTH
;
245 * Build the pseudoheader, which is part of the checksum calculation
248 _ip_getaddr(info
->ui_ipinfo
,&pseudoheader
[0]);
249 memcpy(&pseudoheader
[4],dest
,IP_ADDR_LEN
);
251 pseudoheader
[9] = IPPROTO_UDP
;
252 pseudoheader
[10] = (udplen
>> 8) & 0xFF;
253 pseudoheader
[11] = (udplen
& 0xFF);
256 * Back up and build the actual UDP header in the packet
259 ebuf_seek(buf
,-UDP_HDR_LENGTH
);
260 udphdr
= ebuf_ptr(buf
);
262 ebuf_put_u16_be(buf
,udp
->up_srcport
);
263 ebuf_put_u16_be(buf
,udp
->up_destport
);
264 ebuf_put_u16_be(buf
,udplen
);
265 ebuf_put_u16_be(buf
,0);
267 ebuf_prepend(buf
,UDP_HDR_LENGTH
);
270 * Checksum the packet and insert the checksum into the header
273 cksum
= ip_chksum(0,pseudoheader
,sizeof(pseudoheader
));
274 cksum
= ip_chksum(cksum
,udphdr
,udplen
);
276 if (cksum
== 0) cksum
= 0xFFFF;
277 udphdr
[6] = (cksum
>> 8) & 0xFF;
278 udphdr
[7] = (cksum
& 0xFF);
284 _ip_send(info
->ui_ipinfo
,buf
,dest
,IPPROTO_UDP
);
289 /* *********************************************************************
290 * _udp_bind(info,s,port)
292 * Bind a UDP socket to a particular port number. Basically,
293 * all this means is we set the "source" port number.
296 * info - UDP stack information
297 * s - an open UDP socket (from _udp_open)
298 * port - port number to assign to the UDP socket
301 * 0 if ok, else error code
302 ********************************************************************* */
304 int _udp_bind(udp_info_t
*info
,int s
,uint16_t port
)
306 udp_port_t
*udp
= &(info
->ui_ports
[s
]);
308 if (_udp_find_port(info
,port
)) return CFE_ERR_ALREADYBOUND
;
310 udp
->up_srcport
= port
;
316 /* *********************************************************************
317 * _udp_connect(info,s,port)
319 * "connect" a UDP socket to a particular port number. Basically,
320 * this just sets the "destination" port number. It is used for
321 * protocols like TFTP where the destination port number changes
322 * after the port is open.
325 * info - UDP stack information
326 * s - an open UDP socket (from _udp_open)
327 * port - port number to assign to the UDP socket
332 ********************************************************************* */
334 int _udp_connect(udp_info_t
*info
,int s
,uint16_t port
)
336 udp_port_t
*udp
= &(info
->ui_ports
[s
]);
338 udp
->up_destport
= port
;
343 /* *********************************************************************
344 * _udp_rx_callback(ref,buf,destaddr,srcaddr)
346 * Receive callback routine from the IP layer. When an IP
347 * packet of protocol type "UDP" is received, this routine gets
351 * ref - reference data (pointer to our UDP stack info)
352 * buf - the ebuf, currently pointing at the UDP header
353 * destaddr - the destination IP address (usually our IP address)
354 * srcaddr - the source IP address
357 * ETH_KEEP to keep (not deallocate) the packet
358 * ETH_DROP to deallocate the packet.
359 ********************************************************************* */
361 static int _udp_rx_callback(void *ref
,ebuf_t
*buf
,uint8_t *destaddr
,uint8_t *srcaddr
)
363 uint8_t pseudoheader
[12];
372 udp_info_t
*info
= (udp_info_t
*) ref
;
377 * get a pointer to the UDP header
380 udplen
= ebuf_length(buf
);
381 udphdr
= ebuf_ptr(buf
);
384 * see if we are checking checksums (cksum field != 0)
387 if ((udphdr
[6] | udphdr
[7]) != 0) {
390 * construct the pseudoheader for the cksum calculation
393 memcpy(&pseudoheader
[0],srcaddr
,IP_ADDR_LEN
);
394 memcpy(&pseudoheader
[4],destaddr
,IP_ADDR_LEN
);
396 pseudoheader
[9] = IPPROTO_UDP
;
397 pseudoheader
[10] = (udplen
>> 8) & 0xFF;
398 pseudoheader
[11] = (udplen
& 0xFF);
400 origcksum
= ((uint16_t) udphdr
[6] << 8) | (uint16_t) udphdr
[7];
401 udphdr
[6] = udphdr
[7] = 0;
403 calccksum
= ip_chksum(0,pseudoheader
,sizeof(pseudoheader
));
404 calccksum
= ip_chksum(calccksum
,udphdr
,udplen
);
405 if (calccksum
!= 0xffff) {
406 calccksum
= ~calccksum
;
409 if (calccksum
!= origcksum
) {
414 /* Read the other UDP header fields from the packet */
416 ebuf_get_u16_be(buf
,srcport
);
417 ebuf_get_u16_be(buf
,dstport
);
418 ebuf_get_u16_be(buf
,udplen2
);
422 * It's no good if the lengths don't match. The length
423 * reported by IP should be the length in the UDP header + 8
426 if (udplen2
!= (uint16_t) udplen
) {
431 * Okay, start looking for a matching port
434 udp
= _udp_find_port(info
,dstport
);
436 return ETH_DROP
; /* drop packet if no matching port */
439 buf
->eb_usrdata
= (int) srcport
;
440 buf
->eb_usrptr
= srcaddr
;
443 * Drop packet if queue is full
446 if (q_count(&(udp
->up_rxqueue
)) >= udp
->up_maxqueue
) {
451 * Add to receive queue
454 ebuf_setlength(buf
,udplen2
-UDP_HDR_LENGTH
);
455 q_enqueue(&(udp
->up_rxqueue
),(queue_t
*) buf
);
461 /* *********************************************************************
464 * Receive a packet from the specified UDP socket.
467 * info - UDP stack information
468 * s - an open UDP socket handle (from _udp_open)
471 * an ebuf, or NULL if no packets have been received.
472 ********************************************************************* */
474 ebuf_t
*_udp_recv(udp_info_t
*info
,int s
)
477 udp_port_t
*udp
= &(info
->ui_ports
[s
]);
479 buf
= (ebuf_t
*) q_deqnext(&(udp
->up_rxqueue
));
485 /* *********************************************************************
488 * Initialize the UDP module. This routine registers our
489 * protocol with the IP layer.
492 * ipi - IP information (including our IP address, etc.)
493 * ref - reference data, stored in our UDP stack structure
496 * udp_info_t (allocated) or NULL if something went wrong.
497 ********************************************************************* */
499 udp_info_t
*_udp_init(ip_info_t
*ipi
,void *ref
)
506 * Allocate some memory for our structure
509 info
= KMALLOC(sizeof(udp_info_t
),0);
511 if (info
== NULL
) return NULL
;
513 memset(info
,0,sizeof(udp_info_t
));
516 * Fill in the fields.
520 info
->ui_ipinfo
= ipi
;
521 udp
= info
->ui_ports
;
522 for (idx
= 0; idx
< UDP_MAX_PORTS
; idx
++) {
523 udp
->up_inuse
= FALSE
;
524 q_init(&(udp
->up_rxqueue
));
529 * Register our protocol with IP
532 _ip_register(ipi
,IPPROTO_UDP
,_udp_rx_callback
,info
);
538 /* *********************************************************************
541 * Uninitialize the UDP module, deregistering ourselves from the
545 * info - UDP stack information
549 ********************************************************************* */
551 void _udp_uninit(udp_info_t
*info
)
561 _ip_deregister(info
->ui_ipinfo
,IPPROTO_UDP
);
564 * Free up any packets that were waiting
567 udp
= info
->ui_ports
;
568 for (idx
= 0; idx
< UDP_MAX_PORTS
; idx
++) {
570 while ((buf
= (ebuf_t
*) q_deqnext(&(udp
->up_rxqueue
)))) {
571 _ip_free(info
->ui_ipinfo
,buf
);
578 * Free the stack info
584 /* *********************************************************************
587 * Allocate a buffer for use with UDP. This routine obtains an
588 * ebuf and adjusts its header to include room for the UDP
592 * info - UDP stack information
595 * ebuf, or NULL if there are none left
596 ********************************************************************* */
598 ebuf_t
*_udp_alloc(udp_info_t
*info
)
606 buf
= _ip_alloc(info
->ui_ipinfo
);
608 if (!buf
) return NULL
;
611 * make room for the udp header
614 ebuf_seek(buf
,UDP_HDR_LENGTH
);
615 ebuf_setlength(buf
,0);
620 /* *********************************************************************
621 * _udp_free(info,buf)
623 * Return an ebuf to the pool.
626 * info - UDP stack info
631 ********************************************************************* */
633 void _udp_free(udp_info_t
*info
,ebuf_t
*buf
)
635 _ip_free(info
->ui_ipinfo
,buf
);