Fixed whitespaces; updated UDP code
authorNikhil Chandru Rao <nikhilcrao@users.sourceforge.net>
Wed, 28 Jun 2006 07:46:28 +0000 (07:46 +0000)
committerNikhil Chandru Rao <nikhilcrao@users.sourceforge.net>
Wed, 28 Jun 2006 07:46:28 +0000 (07:46 +0000)
src/include/gpxe/udp.h
src/net/udp.c

index ed45c18..faad6c2 100644 (file)
@@ -18,7 +18,6 @@
  * UDP constants
  */
 
-#define UDP_HLEN       8
 #define UDP_MAX_HLEN   72
 #define UDP_MAX_TXPKB  ETH_MAX_MTU
 #define UDP_MIN_TXPKB  ETH_ZLEN
@@ -29,10 +28,10 @@ typedef uint16_t port_t;
  * A UDP header
  */
 struct udp_header {
-        port_t source_port;
-        port_t dest_port;
-        uint16_t len;
-        uint16_t chksum;
+       port_t source_port;
+       port_t dest_port;
+       uint16_t len;
+       uint16_t chksum;
 };
 
 struct udp_connection;
@@ -59,15 +58,15 @@ struct udp_operations {
  */
 struct udp_connection {
        /** Address of the remote end of the connection */
-        struct sockaddr sin;
-        /** Local port on which the connection receives packets */
-        port_t local_port;
-        /** Transmit buffer */
-        struct pk_buff *tx_pkb;
-        /** List of registered connections */
-        struct list_head list;
-        /** Operations table for this connection */
-        struct udp_operations *udp_op;
+       struct sockaddr sin;
+       /** Local port on which the connection receives packets */
+       port_t local_port;
+       /** Transmit buffer */
+       struct pk_buff *tx_pkb;
+       /** List of registered connections */
+       struct list_head list;
+       /** Operations table for this connection */
+       struct udp_operations *udp_op;
 };
 
 /**
index 9a6898d..abfa759 100644 (file)
  * UDP protocol
  */
 
-void copy_sockaddr ( struct sockaddr *source, struct sockaddr *dest );
+static inline void copy_sockaddr ( struct sockaddr *source, struct sockaddr *dest ) {
+       memcpy ( dest, source, sizeof ( *dest ) );
+}
+
+static inline uint16_t dest_port ( struct sockaddr *sock, uint16_t *dest ) {
+       switch ( sock->sa_family ) {
+       case AF_INET:
+               dest = &sock->sin.sin_port;
+               break;
+       case AF_INET6:
+               dest = &sock->sin6.sin6_port;
+               break;
+       default:
+               DBG ( "Network family %d not supported\n", sock->sa_family );
+               return -EAFNOSUPPORT;
+       }
+       return 0;
+}
+
+/**
+ * Dump the UDP header
+ *
+ * @v udphdr   UDP header
+ */
+void udp_dump ( struct udp_header *udphdr ) {
+
+       /* Print UDP header for debugging */
+       DBG ( "UDP header at %#x + %d\n", udphdr, sizeof ( *udphdr ) );
+       DBG ( "\tSource Port = %d\n", ntohs ( udphdr->source_port ) );
+       DBG ( "\tDestination Port = %d\n", ntohs ( udphdr->dest_port ) );
+       DBG ( "\tLength = %d\n", ntohs ( udphdr->len ) );
+       DBG ( "\tChecksum = %d\n", ntohs ( udphdr->chksum ) );
+       DBG ( "\tChecksum located at %#x\n", &udphdr->chksum );
+}
 
 /**
  * Open a UDP connection
@@ -28,10 +61,11 @@ void copy_sockaddr ( struct sockaddr *source, struct sockaddr *dest );
  * This function stores the socket address within the connection
  */
 void udp_connect ( struct udp_connection *conn, struct sockaddr *peer ) {
-        copy_sockaddr ( peer, &conn->sin );
-        /**
-         * Not sure if this should add the connection to udp_conns; If it does, uncomment the following code
-         */
+       copy_sockaddr ( peer, &conn->sin );
+
+       /* Not sure if this should add the connection to udp_conns; If it does,
+        * uncomment the following code
+        */
 //     list_add ( &conn->list, &udp_conns );
 }
 
@@ -42,11 +76,11 @@ void udp_connect ( struct udp_connection *conn, struct sockaddr *peer ) {
  * @v udp_op   UDP operations
  */
 void udp_init ( struct udp_connection *conn, struct udp_operations *udp_op ) {
-        conn->local_port = 0;
-        conn->tx_pkb = NULL;
-        if ( udp_op != NULL ) {
-                conn->udp_op = udp_op;
-        }
+       conn->local_port = 0;
+       conn->tx_pkb = NULL;
+       if ( udp_op != NULL ) {
+               conn->udp_op = udp_op;
+       }
 }
 
 /**
@@ -59,12 +93,12 @@ void udp_init ( struct udp_connection *conn, struct udp_operations *udp_op ) {
  * Allocate "len" amount of space in the transmit buffer
  */
 int udp_buf_alloc ( struct udp_connection *conn, size_t len ) {
-        if ( conn->tx_pkb != NULL ) {
-                free_pkb ( conn->tx_pkb );
-                conn->tx_pkb = NULL;
-        }
-        conn->tx_pkb = alloc_pkb ( len < UDP_MIN_TXPKB ? UDP_MIN_TXPKB : len );
-        return !conn ? -ENOMEM : 0;
+       if ( conn->tx_pkb != NULL ) {
+               free_pkb ( conn->tx_pkb );
+               conn->tx_pkb = NULL;
+       }
+       conn->tx_pkb = alloc_pkb ( len < UDP_MIN_TXPKB ? UDP_MIN_TXPKB : len );
+       return !conn ? -ENOMEM : 0;
 }
 
 /**
@@ -74,45 +108,47 @@ int udp_buf_alloc ( struct udp_connection *conn, size_t len ) {
  * @v data      Data to send
  * @v len       Length of data
  *
- * This function fills up the UDP headers and sends the data. Discover the network protocol to
- * use through the sa_family field in the destination socket address.
+ * This function fills up the UDP headers and sends the data. Discover the
+ * network protocol through the sa_family field in the destination socket
+ * address.
  */
 int udp_send ( struct udp_connection *conn, const void *data, size_t len ) {
-               struct udp_header *udphdr;              /* UDP header */
-        struct sockaddr *sock = &conn->sin;     /* Destination sockaddr */
-        int rc;
-
-        /* Copy data into packet buffer if necessary */
-        if ( data != conn->tx_pkb->data ) {
-                /* Allocate a buffer */
-                if ( ( rc = udp_buf_alloc ( conn, len + UDP_MAX_HLEN ) ) != 0 ) {
-                        DBG ( "Error allocating buffer" );
-                        return rc;
-                }
-
-                /* Reserve space for the headers and copy contents */
-                pkb_reserve ( conn->tx_pkb, UDP_MAX_HLEN );
-                memcpy ( pkb_put ( conn->tx_pkb, len ), data, len );
-        }
-
-        /* Add the UDP header */
-        udphdr = pkb_push ( conn->tx_pkb, UDP_HLEN );
-        if ( sock->sa_family == AF_INET )
-                udphdr->dest_port = sock->sin.sin_port;
-        else
-                udphdr->dest_port = sock->sin6.sin6_port;
-        udphdr->source_port = conn->local_port;
-        udphdr->len = htons ( pkb_len ( conn->tx_pkb ) );
-        udphdr->chksum = calc_chksum ( udphdr, UDP_HLEN );
-
-        /* Print UDP header for debugging */
-        DBG ( "UDP header at %#x + %d\n", udphdr, UDP_HDR_LEN  );
-        DBG ( "\tSource Port = %d\n", udphdr->source_port );
-        DBG ( "\tDestination Port = %d\n", udphdr->dest_port );
-        DBG ( "\tLength = %d\n", udphdr->len );
-        DBG ( "\tChecksum = %d\n", udphdr->chksum );
-        DBG ( "\tChecksum located at %#x\n", &udphdr->chksum );
+               struct udp_header *udphdr;              /* UDP header */
+       struct sockaddr *sock = &conn->sin;     /* Destination sockaddr */
+       uint16_t *dest;
+       int rc;
+
+       /* Copy data into packet buffer, if necessary */
+       if ( data != conn->tx_pkb->data ) {
+               /* Allocate space for data and lower layer headers */
+               if ( ( rc = udp_buf_alloc ( conn, len + UDP_MAX_HLEN ) ) != 0 ) {
+                       DBG ( "Error allocating buffer" );
+                       return rc;
+               }
+
+               /* Reserve space for the headers and copy contents */
+               pkb_reserve ( conn->tx_pkb, UDP_MAX_HLEN );
+               memcpy ( pkb_put ( conn->tx_pkb, len ), data, len );
+       }
 
+       /*
+        * Add the UDP header
+        *
+        * Covert all 16- and 32- bit integers into network btye order before
+        * sending it over the network
+        */
+       udphdr = pkb_push ( conn->tx_pkb, sizeof ( *udphdr ) );
+       if ( (rc = dest_port ( sock, dest ) ) != 0 ) {
+               return rc;
+       }
+       udphdr->dest_port = htons ( *dest );
+       udphdr->source_port = htons ( conn->local_port );
+       udphdr->len = htons ( pkb_len ( conn->tx_pkb ) );
+       udphdr->chksum = htons ( calc_chksum ( udphdr, sizeof ( *udphdr ) ) );
+
+       udp_dump ( udphdr );
+
+       /* Send it to the next layer for processing */
        return trans_tx ( conn->tx_pkb, IP_UDP, sock );
 }
 
@@ -125,13 +161,13 @@ int udp_send ( struct udp_connection *conn, const void *data, size_t len ) {
  * @v len       Length of data
  */
 int udp_sendto ( struct udp_connection *conn, struct sockaddr *peer,
-                        const void *data, size_t len ) {
-        struct sockaddr tempsock;
-        copy_sockaddr ( &conn->sin, &tempsock );
-        copy_sockaddr ( peer, &conn->sin );
-        int rc = udp_send ( conn, data, len );
-        copy_sockaddr ( &tempsock, &conn->sin );
-        return rc;
+                const void *data, size_t len ) {
+       struct sockaddr tempsock;
+       copy_sockaddr ( &conn->sin, &tempsock );
+       copy_sockaddr ( peer, &conn->sin );
+       int rc = udp_send ( conn, data, len );
+       copy_sockaddr ( &tempsock, &conn->sin );
+       return rc;
 }
 
 /**
@@ -140,7 +176,7 @@ int udp_sendto ( struct udp_connection *conn, struct sockaddr *peer,
  * @v conn      UDP connection
  */
 void udp_close ( struct udp_connection *conn ) {
-        list_del ( &conn->list );
+       list_del ( &conn->list );
 }
 
 /**
@@ -152,74 +188,90 @@ void udp_close ( struct udp_connection *conn ) {
  * This does not support the 0 port option correctly yet
  */
 int udp_open ( struct udp_connection *conn, uint16_t local_port ) {
-        struct udp_connection *connr;
-        uint16_t min_port = 0xffff;
-        list_for_each_entry ( connr, &udp_conns, list ) {
-                if ( connr->local_port == local_port ) {
-                        return -EISCONN; /* CHECK THE ERROR NUMBER */
-                }
-                if ( min_port > connr->local_port ) {
-                        min_port = connr->local_port;
-                }
-        }
-        conn->local_port = local_port == 0 ? min_port > 1024 ? 1024 : min_port + 1 : local_port; // FAULTY!!!
-        list_add ( &conn->list, &udp_conns );
-        return 0;
+       struct udp_connection *connr;
+       uint16_t min_port = 0xffff;
+
+       /* Iterate through udp_conns to see if local_port is available */
+       list_for_each_entry ( connr, &udp_conns, list ) {
+               if ( connr->local_port == local_port ) {
+                       return -EISCONN;
+               }
+               if ( min_port > connr->local_port ) {
+                       min_port = connr->local_port;
+               }
+       }
+       /* This code is buggy. I will update it soon :) */
+       conn->local_port = local_port == 0 ? min_port > 1024 ? 1024 :
+                                               min_port + 1 : local_port;
+
+       /* Add the connection to the list of listening connections */
+       list_add ( &conn->list, &udp_conns );
+       return 0;
 }
 
 /**
  * Process a received packet
  *
- * @v pkb               Packet buffer
+ * @v pkb             Packet buffer
  * @v src_net_addr      Source network address
  * @v dest_net_addr     Destination network address
  */
 void udp_rx ( struct pk_buff *pkb, struct in_addr *src_net_addr __unused,
-                        struct in_addr *dest_net_addr __unused ) {
-        struct udp_header *udphdr = pkb->data;
-        struct udp_connection *conn;
-
-        /* todo: Compute and verify checksum */
-
-        /* Print UDP header for debugging */
-        DBG ( "UDP header at %#x + %d\n", udphdr, UDP_HDR_LEN  );
-        DBG ( "\tSource Port = %d\n", udphdr->source_port );
-        DBG ( "\tDestination Port = %d\n", udphdr->dest_port );
-        DBG ( "\tLength = %d\n", udphdr->len );
-        DBG ( "\tChecksum = %d\n", udphdr->chksum );
-        DBG ( "\tChecksum located at %#x\n", &udphdr->chksum );
-
-        /* Demux the connection */
-        list_for_each_entry ( conn, &udp_conns, list ) {
-                if ( conn->local_port == udphdr->dest_port ) {
-                        goto conn;
-                }
-        }
-        return;
-
-        conn:
-        /** Strip off the UDP header */
-        pkb_pull ( pkb, UDP_HLEN );
-
-        /** Allocate max possible buffer space to the tx buffer */
-        conn->tx_pkb = alloc_pkb ( UDP_MAX_TXPKB );
-        pkb_reserve ( conn->tx_pkb, UDP_MAX_HLEN );
-
-        /** Call the application's callback */
-        conn->udp_op->newdata ( conn, pkb->data, ntohs ( udphdr->len ) - UDP_HLEN  );
+                       struct in_addr *dest_net_addr __unused ) {
+       struct udp_header *udphdr = pkb->data;
+       struct udp_connection *conn;
+       uint16_t ulen;
+       uint16_t chksum;
+
+       udp_dump ( udphdr );
+
+       /* Validate the packet and the UDP length */
+       if ( pkb_len ( pkb ) < sizeof ( *udphdr ) ) {
+               DBG ( "UDP packet too short (%d bytes)\n",
+                     pkb_len ( pkb ) );
+               return;
+       }
+
+       ulen = ntohs ( udphdr->len );
+       if ( ulen != pkb_len ( pkb ) ) {
+               DBG ( "Inconsistent UDP packet length (%d bytes)\n",
+                     pkb_len ( pkb ) );
+               return;
+       }
+
+       /* Verify the checksum */
+       chksum = calc_chksum ( pkb->data, pkb_len ( pkb ) );
+       if ( chksum != 0xffff ) {
+               DBG ( "Bad checksum %d\n", chksum );
+               return;
+       }
+
+       /* Todo: Check if it is a broadcast or multicast address */
+
+       /* Demux the connection */
+       list_for_each_entry ( conn, &udp_conns, list ) {
+               if ( conn->local_port == ntohs ( udphdr->dest_port ) ) {
+                       goto conn;
+               }
+       }
+       return;
+
+       conn:
+       /** Strip off the UDP header */
+       pkb_pull ( pkb, sizeof ( *udphdr ) );
+
+       /** Allocate max possible buffer space to the tx buffer */
+       conn->tx_pkb = alloc_pkb ( UDP_MAX_TXPKB );
+       pkb_reserve ( conn->tx_pkb, UDP_MAX_HLEN );
+
+       /** Call the application's callback */
+       conn->udp_op->newdata ( conn, pkb->data, ulen - sizeof ( *udphdr ) );
 }
 
 struct trans_protocol udp_protocol  = {
-        .name = "UDP",
-        .rx = udp_rx,
-        .trans_proto = IP_UDP,
+       .name = "UDP",
+       .rx = udp_rx,
+       .trans_proto = IP_UDP,
 };
 
 TRANS_PROTOCOL ( udp_protocol );
-
-/**
- * Internal functions
- */
-void copy_sockaddr ( struct sockaddr *source, struct sockaddr *dest ) {
-        memcpy ( dest, source, sizeof ( struct sockaddr ) );
-}