summaryrefslogtreecommitdiffstats
path: root/cfe/cfe/net/net_udp.c
diff options
context:
space:
mode:
Diffstat (limited to 'cfe/cfe/net/net_udp.c')
-rw-r--r--cfe/cfe/net/net_udp.c637
1 files changed, 637 insertions, 0 deletions
diff --git a/cfe/cfe/net/net_udp.c b/cfe/cfe/net/net_udp.c
new file mode 100644
index 0000000..968081a
--- /dev/null
+++ b/cfe/cfe/net/net_udp.c
@@ -0,0 +1,637 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * User Datagram Protocol File: net_udp.c
+ *
+ * This module implements the User Datagram Protocol (RFCxxxx)
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+
+#include "lib_types.h"
+#include "lib_string.h"
+#include "lib_queue.h"
+#include "lib_malloc.h"
+#include "lib_printf.h"
+
+#include "cfe_timer.h"
+
+#include "net_ebuf.h"
+#include "net_ether.h"
+
+#include "net_ip.h"
+
+#include "cfe_error.h"
+
+/* *********************************************************************
+ * Constants
+ ********************************************************************* */
+
+#define UDP_HDR_LENGTH 8
+#define UDP_PORTBASE 1024
+#define UDP_MAX_PORTS 4
+
+/* *********************************************************************
+ * Types
+ ********************************************************************* */
+
+typedef struct udp_port_s udp_port_t;
+
+/*
+ * UDP port structure - describes an open UDP port.
+ */
+
+struct udp_port_s {
+ uint16_t up_destport; /* destination port number */
+ uint16_t up_srcport; /* source port number */
+ queue_t up_rxqueue; /* queue of received packets */
+ int up_maxqueue; /* max # of elements on rx queue */
+ int up_inuse; /* nonzero if port is in use */
+};
+
+
+/*
+ * UDP stack information - describes the entire UDP layer.
+ */
+
+struct udp_info_s {
+ uint16_t ui_portbase;
+ void *ui_ref;
+ ip_info_t *ui_ipinfo;
+ udp_port_t ui_ports[UDP_MAX_PORTS];
+};
+
+/* *********************************************************************
+ * Forward declarations
+ ********************************************************************* */
+
+static int _udp_rx_callback(void *ref,ebuf_t *buf,uint8_t *destaddr,uint8_t *srcaddr);
+
+
+/* *********************************************************************
+ * udp_find_port(info,port)
+ *
+ * Locate an open port. Scan the list of ports looking for one
+ * that is both open and has a matching source port number.
+ *
+ * Input parameters:
+ * info - UDP stack information
+ * port - source port # we're looking for
+ *
+ * Return value:
+ * udp_port_t pointer or NULL if no port was found
+ ********************************************************************* */
+
+static udp_port_t *_udp_find_port(udp_info_t *info,uint16_t port)
+{
+ int idx;
+ udp_port_t *udp = info->ui_ports;
+
+ for (idx = 0; idx < UDP_MAX_PORTS; idx++) {
+ if (udp->up_inuse && (udp->up_srcport == port)) {
+ return udp;
+ }
+ udp++;
+ }
+
+ return NULL;
+}
+
+/* *********************************************************************
+ * _udp_socket(info,port)
+ *
+ * Open a UDP socket. This is an internal function used by
+ * the network API layer.
+ *
+ * Input parameters:
+ * info - UDP stack information
+ * port - port number to open
+ *
+ * Return value:
+ * port number (0 based) or an error code (<0) if an error
+ * occured.
+ ********************************************************************* */
+
+int _udp_socket(udp_info_t *info,uint16_t port)
+{
+ extern int32_t _getticks(void); /* return value of CP0 COUNT */
+ int idx;
+ udp_port_t *udp;
+ uint16_t srcport = UDP_PORTBASE + (_getticks() & 0xFFF);
+
+ while (_udp_find_port(info,srcport)) { /* should always exit */
+ srcport++;
+ if (srcport > (UDP_PORTBASE+4096)) srcport = UDP_PORTBASE;
+ }
+
+ udp = info->ui_ports;
+
+ for (idx = 0; idx < UDP_MAX_PORTS; idx++) {
+ if (!udp->up_inuse) break;
+ udp++;
+ }
+
+ if (idx == UDP_MAX_PORTS) return CFE_ERR_NOHANDLES;
+
+ udp->up_destport = port;
+ udp->up_srcport = srcport;
+ udp->up_maxqueue = 2;
+ udp->up_inuse = TRUE;
+ q_init(&(udp->up_rxqueue));
+
+ return idx;
+}
+
+
+/* *********************************************************************
+ * _udp_close(info,s)
+ *
+ * Internal function to close an open UDP port. This routine is
+ * called by the high-level network API.
+ *
+ * Input parameters:
+ * info - UDP stack information
+ * s - an open UDP socket handle (returned from _udp_open)
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void _udp_close(udp_info_t *info,int s)
+{
+ udp_port_t *udp = &(info->ui_ports[s]);
+ ebuf_t *buf;
+
+ while ((buf = (ebuf_t *) q_deqnext(&(udp->up_rxqueue)))) {
+ _ip_free(info->ui_ipinfo,buf);
+ }
+
+ udp->up_srcport = 0;
+ udp->up_destport = 0;
+ udp->up_maxqueue = 0;
+ udp->up_inuse = FALSE;
+}
+
+/* *********************************************************************
+ * _udp_send(info,s,buf,dest)
+ *
+ * Transmit a UDP datagram. Note that we never send fragmented
+ * datagrams, so all datagrams must be less than the MTU.
+ *
+ * Input parameters:
+ * info - UDP stack information
+ * s - an open UDP socket handle (returned from _udp_open)
+ * buf - an ebuf to send
+ * dest - destination IP address
+ *
+ * Return value:
+ * 0 if packet was sent
+ * else error code
+ ********************************************************************* */
+
+int _udp_send(udp_info_t *info,int s,ebuf_t *buf,uint8_t *dest)
+{
+ udp_port_t *udp = &(info->ui_ports[s]);
+ uint8_t *udphdr;
+ int udplen;
+ uint8_t pseudoheader[12];
+ uint16_t cksum;
+
+ /*
+ * Calculate the length of the IP datagram (includes UDP header)
+ */
+
+ udplen = ebuf_length(buf) + UDP_HDR_LENGTH;
+
+ /*
+ * Build the pseudoheader, which is part of the checksum calculation
+ */
+
+ _ip_getaddr(info->ui_ipinfo,&pseudoheader[0]);
+ memcpy(&pseudoheader[4],dest,IP_ADDR_LEN);
+ pseudoheader[8] = 0;
+ pseudoheader[9] = IPPROTO_UDP;
+ pseudoheader[10] = (udplen >> 8) & 0xFF;
+ pseudoheader[11] = (udplen & 0xFF);
+
+ /*
+ * Back up and build the actual UDP header in the packet
+ */
+
+ ebuf_seek(buf,-UDP_HDR_LENGTH);
+ udphdr = ebuf_ptr(buf);
+
+ ebuf_put_u16_be(buf,udp->up_srcport);
+ ebuf_put_u16_be(buf,udp->up_destport);
+ ebuf_put_u16_be(buf,udplen);
+ ebuf_put_u16_be(buf,0);
+
+ ebuf_prepend(buf,UDP_HDR_LENGTH);
+
+ /*
+ * Checksum the packet and insert the checksum into the header
+ */
+
+ cksum = ip_chksum(0,pseudoheader,sizeof(pseudoheader));
+ cksum = ip_chksum(cksum,udphdr,udplen);
+ cksum = ~cksum;
+ if (cksum == 0) cksum = 0xFFFF;
+ udphdr[6] = (cksum >> 8) & 0xFF;
+ udphdr[7] = (cksum & 0xFF);
+
+ /*
+ * Off it goes!
+ */
+
+ _ip_send(info->ui_ipinfo,buf,dest,IPPROTO_UDP);
+
+ return 0;
+}
+
+/* *********************************************************************
+ * _udp_bind(info,s,port)
+ *
+ * Bind a UDP socket to a particular port number. Basically,
+ * all this means is we set the "source" port number.
+ *
+ * Input parameters:
+ * info - UDP stack information
+ * s - an open UDP socket (from _udp_open)
+ * port - port number to assign to the UDP socket
+ *
+ * Return value:
+ * 0 if ok, else error code
+ ********************************************************************* */
+
+int _udp_bind(udp_info_t *info,int s,uint16_t port)
+{
+ udp_port_t *udp = &(info->ui_ports[s]);
+
+ if (_udp_find_port(info,port)) return CFE_ERR_ALREADYBOUND;
+
+ udp->up_srcport = port;
+
+ return 0;
+}
+
+
+/* *********************************************************************
+ * _udp_connect(info,s,port)
+ *
+ * "connect" a UDP socket to a particular port number. Basically,
+ * this just sets the "destination" port number. It is used for
+ * protocols like TFTP where the destination port number changes
+ * after the port is open.
+ *
+ * Input parameters:
+ * info - UDP stack information
+ * s - an open UDP socket (from _udp_open)
+ * port - port number to assign to the UDP socket
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+int _udp_connect(udp_info_t *info,int s,uint16_t port)
+{
+ udp_port_t *udp = &(info->ui_ports[s]);
+
+ udp->up_destport = port;
+
+ return 0;
+}
+
+/* *********************************************************************
+ * _udp_rx_callback(ref,buf,destaddr,srcaddr)
+ *
+ * Receive callback routine from the IP layer. When an IP
+ * packet of protocol type "UDP" is received, this routine gets
+ * called.
+ *
+ * Input parameters:
+ * ref - reference data (pointer to our UDP stack info)
+ * buf - the ebuf, currently pointing at the UDP header
+ * destaddr - the destination IP address (usually our IP address)
+ * srcaddr - the source IP address
+ *
+ * Return value:
+ * ETH_KEEP to keep (not deallocate) the packet
+ * ETH_DROP to deallocate the packet.
+ ********************************************************************* */
+
+static int _udp_rx_callback(void *ref,ebuf_t *buf,uint8_t *destaddr,uint8_t *srcaddr)
+{
+ uint8_t pseudoheader[12];
+ int udplen;
+ uint16_t calccksum;
+ uint16_t origcksum;
+ uint8_t *udphdr;
+ uint16_t srcport;
+ uint16_t dstport;
+ uint16_t udplen2;
+ udp_port_t *udp;
+ udp_info_t *info = (udp_info_t *) ref;
+
+
+
+ /*
+ * get a pointer to the UDP header
+ */
+
+ udplen = ebuf_length(buf);
+ udphdr = ebuf_ptr(buf);
+
+ /*
+ * see if we are checking checksums (cksum field != 0)
+ */
+
+ if ((udphdr[6] | udphdr[7]) != 0) {
+
+ /*
+ * construct the pseudoheader for the cksum calculation
+ */
+
+ memcpy(&pseudoheader[0],srcaddr,IP_ADDR_LEN);
+ memcpy(&pseudoheader[4],destaddr,IP_ADDR_LEN);
+ pseudoheader[8] = 0;
+ pseudoheader[9] = IPPROTO_UDP;
+ pseudoheader[10] = (udplen >> 8) & 0xFF;
+ pseudoheader[11] = (udplen & 0xFF);
+
+ origcksum = ((uint16_t) udphdr[6] << 8) | (uint16_t) udphdr[7];
+ udphdr[6] = udphdr[7] = 0;
+
+ calccksum = ip_chksum(0,pseudoheader,sizeof(pseudoheader));
+ calccksum = ip_chksum(calccksum,udphdr,udplen);
+ if (calccksum != 0xffff) {
+ calccksum = ~calccksum;
+ }
+
+ if (calccksum != origcksum) {
+ return ETH_DROP;
+ }
+ }
+
+ /* Read the other UDP header fields from the packet */
+
+ ebuf_get_u16_be(buf,srcport);
+ ebuf_get_u16_be(buf,dstport);
+ ebuf_get_u16_be(buf,udplen2);
+ ebuf_skip(buf,2);
+
+ /*
+ * It's no good if the lengths don't match. The length
+ * reported by IP should be the length in the UDP header + 8
+ */
+
+ if (udplen2 != (uint16_t) udplen) {
+ return ETH_DROP;
+ }
+
+ /*
+ * Okay, start looking for a matching port
+ */
+
+ udp = _udp_find_port(info,dstport);
+ if (!udp) {
+ return ETH_DROP; /* drop packet if no matching port */
+ /* XXX should send ICMP message here */
+ }
+
+ buf->eb_usrdata = (int) srcport;
+ buf->eb_usrptr = srcaddr;
+
+ /*
+ * Drop packet if queue is full
+ */
+
+ if (q_count(&(udp->up_rxqueue)) >= udp->up_maxqueue) {
+ return ETH_DROP;
+ }
+
+ /*
+ * Add to receive queue
+ */
+
+ ebuf_setlength(buf,udplen2-UDP_HDR_LENGTH);
+ q_enqueue(&(udp->up_rxqueue),(queue_t *) buf);
+
+ return ETH_KEEP;
+}
+
+
+/* *********************************************************************
+ * _udp_recv(info,s)
+ *
+ * Receive a packet from the specified UDP socket.
+ *
+ * Input parameters:
+ * info - UDP stack information
+ * s - an open UDP socket handle (from _udp_open)
+ *
+ * Return value:
+ * an ebuf, or NULL if no packets have been received.
+ ********************************************************************* */
+
+ebuf_t *_udp_recv(udp_info_t *info,int s)
+{
+ ebuf_t *buf;
+ udp_port_t *udp = &(info->ui_ports[s]);
+
+ buf = (ebuf_t *) q_deqnext(&(udp->up_rxqueue));
+
+ return buf;
+}
+
+
+/* *********************************************************************
+ * _udp_init(ipi,ref)
+ *
+ * Initialize the UDP module. This routine registers our
+ * protocol with the IP layer.
+ *
+ * Input parameters:
+ * ipi - IP information (including our IP address, etc.)
+ * ref - reference data, stored in our UDP stack structure
+ *
+ * Return value:
+ * udp_info_t (allocated) or NULL if something went wrong.
+ ********************************************************************* */
+
+udp_info_t *_udp_init(ip_info_t *ipi,void *ref)
+{
+ udp_info_t *info;
+ udp_port_t *udp;
+ int idx;
+
+ /*
+ * Allocate some memory for our structure
+ */
+
+ info = KMALLOC(sizeof(udp_info_t),0);
+
+ if (info == NULL) return NULL;
+
+ memset(info,0,sizeof(udp_info_t));
+
+ /*
+ * Fill in the fields.
+ */
+
+ info->ui_ref = ref;
+ info->ui_ipinfo = ipi;
+ udp = info->ui_ports;
+ for (idx = 0; idx < UDP_MAX_PORTS; idx++) {
+ udp->up_inuse = FALSE;
+ q_init(&(udp->up_rxqueue));
+ udp++;
+ }
+
+ /*
+ * Register our protocol with IP
+ */
+
+ _ip_register(ipi,IPPROTO_UDP,_udp_rx_callback,info);
+
+ return info;
+}
+
+
+/* *********************************************************************
+ * _udp_uninit(info)
+ *
+ * Uninitialize the UDP module, deregistering ourselves from the
+ * IP layer.
+ *
+ * Input parameters:
+ * info - UDP stack information
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void _udp_uninit(udp_info_t *info)
+{
+ int idx;
+ udp_port_t *udp;
+ ebuf_t *buf;
+
+ /*
+ * Unregister from IP
+ */
+
+ _ip_deregister(info->ui_ipinfo,IPPROTO_UDP);
+
+ /*
+ * Free up any packets that were waiting
+ */
+
+ udp = info->ui_ports;
+ for (idx = 0; idx < UDP_MAX_PORTS; idx++) {
+ if (udp->up_inuse) {
+ while ((buf = (ebuf_t *) q_deqnext(&(udp->up_rxqueue)))) {
+ _ip_free(info->ui_ipinfo,buf);
+ }
+ }
+ udp++;
+ }
+
+ /*
+ * Free the stack info
+ */
+
+ KFREE(info);
+}
+
+/* *********************************************************************
+ * _udp_alloc(info)
+ *
+ * Allocate a buffer for use with UDP. This routine obtains an
+ * ebuf and adjusts its header to include room for the UDP
+ * header.
+ *
+ * Input parameters:
+ * info - UDP stack information
+ *
+ * Return value:
+ * ebuf, or NULL if there are none left
+ ********************************************************************* */
+
+ebuf_t *_udp_alloc(udp_info_t *info)
+{
+ ebuf_t *buf;
+
+ /*
+ * Get an ebuf
+ */
+
+ buf = _ip_alloc(info->ui_ipinfo);
+
+ if (!buf) return NULL;
+
+ /*
+ * make room for the udp header
+ */
+
+ ebuf_seek(buf,UDP_HDR_LENGTH);
+ ebuf_setlength(buf,0);
+
+ return buf;
+}
+
+/* *********************************************************************
+ * _udp_free(info,buf)
+ *
+ * Return an ebuf to the pool.
+ *
+ * Input parameters:
+ * info - UDP stack info
+ * buf - an ebuf
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void _udp_free(udp_info_t *info,ebuf_t *buf)
+{
+ _ip_free(info->ui_ipinfo,buf);
+}