11 #include <gpxe/init.h>
12 #include <gpxe/pkbuff.h>
13 #include <gpxe/netdevice.h>
14 #include <gpxe/tcpip_if.h>
22 * List of registered UDP connections
24 static LIST_HEAD ( udp_conns );
27 * Some utility functions
29 static inline void copy_sockaddr ( struct sockaddr *source, struct sockaddr *dest ) {
30 memcpy ( dest, source, sizeof ( *dest ) );
33 static inline uint16_t * dest_port ( struct sockaddr *sock ) {
34 switch ( sock->sa_family ) {
36 return &sock->sin.sin_port;
38 return &sock->sin6.sin6_port;
46 * @v udphdr UDP header
48 void udp_dump ( struct udp_header *udphdr ) {
50 /* Print UDP header for debugging */
51 DBG ( "UDP header at %p + %#zx\n", udphdr, sizeof ( *udphdr ) );
52 DBG ( "\tSource Port = %d\n", ntohs ( udphdr->source_port ) );
53 DBG ( "\tDestination Port = %d\n", ntohs ( udphdr->dest_port ) );
54 DBG ( "\tLength = %d\n", ntohs ( udphdr->len ) );
55 DBG ( "\tChecksum = %x\n", ntohs ( udphdr->chksum ) );
56 DBG ( "\tChecksum located at %p\n", &udphdr->chksum );
60 * Open a UDP connection
62 * @v conn UDP connection
63 * @v peer Destination socket address
65 * This function stores the socket address within the connection
67 void udp_connect ( struct udp_connection *conn, struct sockaddr *peer ) {
68 copy_sockaddr ( peer, &conn->sin );
70 /* Not sure if this should add the connection to udp_conns; If it does,
71 * uncomment the following code
73 // list_add ( &conn->list, &udp_conns );
77 * Initialize a UDP connection
79 * @v conn UDP connection
80 * @v udp_op UDP operations
82 void udp_init ( struct udp_connection *conn, struct udp_operations *udp_op ) {
85 if ( udp_op != NULL ) {
86 conn->udp_op = udp_op;
91 * User request to send data via a UDP connection
93 * @v conn UDP connection
95 * This function allocates buffer space and invokes the function's senddata()
96 * callback. The callback may use the buffer space
98 int udp_senddata ( struct udp_connection *conn ) {
99 conn->tx_pkb = alloc_pkb ( UDP_MAX_TXPKB );
100 if ( conn->tx_pkb == NULL ) {
101 DBG ( "Error allocating packet buffer of length %d\n",
105 pkb_reserve ( conn->tx_pkb, UDP_MAX_HLEN );
106 conn->udp_op->senddata ( conn, conn->tx_pkb->data,
107 pkb_available ( conn->tx_pkb ) );
112 * Transmit data via a UDP connection to a specified address
114 * @v conn UDP connection
115 * @v peer Destination address
116 * @v data Data to send
117 * @v len Length of data
119 * This function fills up the UDP headers and sends the data. Discover the
120 * network protocol through the sa_family field in the destination socket
123 int udp_sendto ( struct udp_connection *conn, struct sockaddr *peer,
124 const void *data, size_t len ) {
125 struct udp_header *udphdr; /* UDP header */
129 memmove ( pkb_put ( conn->tx_pkb, len ), data, len );
134 * Covert all 16- and 32- bit integers into network btye order before
135 * sending it over the network
137 udphdr = pkb_push ( conn->tx_pkb, sizeof ( *udphdr ) );
138 if ( (dest = dest_port ( peer ) ) == NULL ) {
139 DBG ( "Network family %d not supported\n", peer->sa_family );
140 return -EAFNOSUPPORT;
142 udphdr->dest_port = *dest;
143 udphdr->source_port = conn->local_port;
144 udphdr->len = htons ( pkb_len ( conn->tx_pkb ) );
145 udphdr->chksum = htons ( calc_chksum ( udphdr, sizeof ( *udphdr ) ) );
149 /* Send it to the next layer for processing */
150 return trans_tx ( conn->tx_pkb, &udp_protocol, peer );
154 * Transmit data via a UDP connection to a specified address
156 * @v conn UDP connection
157 * @v data Data to send
158 * @v len Length of data
160 int udp_send ( struct udp_connection *conn, const void *data, size_t len ) {
161 return udp_sendto ( conn, &conn->sin, data, len );
165 * Close a UDP connection
167 * @v conn UDP connection
169 void udp_close ( struct udp_connection *conn ) {
170 list_del ( &conn->list );
176 * @v conn UDP connection
177 * @v local_port Local port on which to open connection
179 * This does not support the 0 port option correctly yet
181 int udp_open ( struct udp_connection *conn, uint16_t local_port ) {
182 struct udp_connection *connr;
183 uint16_t min_port = 0xffff;
185 /* Iterate through udp_conns to see if local_port is available */
186 list_for_each_entry ( connr, &udp_conns, list ) {
187 if ( connr->local_port == local_port ) {
190 if ( min_port > connr->local_port ) {
191 min_port = connr->local_port;
194 /* This code is buggy. I will update it soon :) */
195 conn->local_port = local_port == 0 ? min_port > 1024 ? 1024 :
196 min_port + 1 : local_port;
198 /* Add the connection to the list of listening connections */
199 list_add ( &conn->list, &udp_conns );
204 * Process a received packet
206 * @v pkb Packet buffer
207 * @v src_net_addr Source network address
208 * @v dest_net_addr Destination network address
210 void udp_rx ( struct pk_buff *pkb, struct in_addr *src_net_addr __unused,
211 struct in_addr *dest_net_addr __unused ) {
212 struct udp_header *udphdr = pkb->data;
213 struct udp_connection *conn;
219 /* Validate the packet and the UDP length */
220 if ( pkb_len ( pkb ) < sizeof ( *udphdr ) ) {
221 DBG ( "UDP packet too short (%d bytes)\n",
226 ulen = ntohs ( udphdr->len );
227 if ( ulen != pkb_len ( pkb ) ) {
228 DBG ( "Inconsistent UDP packet length (%d bytes)\n",
233 /* Verify the checksum */
234 chksum = calc_chksum ( pkb->data, pkb_len ( pkb ) );
235 if ( chksum != 0xffff ) {
236 DBG ( "Bad checksum %d\n", chksum );
240 /* Todo: Check if it is a broadcast or multicast address */
242 /* Demux the connection */
243 list_for_each_entry ( conn, &udp_conns, list ) {
244 if ( conn->local_port == ntohs ( udphdr->dest_port ) ) {
251 /** Strip off the UDP header */
252 pkb_pull ( pkb, sizeof ( *udphdr ) );
254 /** Allocate max possible buffer space to the tx buffer */
255 conn->tx_pkb = alloc_pkb ( UDP_MAX_TXPKB );
256 pkb_reserve ( conn->tx_pkb, UDP_MAX_HLEN );
258 /** Call the application's callback */
259 conn->udp_op->newdata ( conn, pkb->data, ulen - sizeof ( *udphdr ) );
262 struct tcpip_protocol udp_protocol = {
265 .trans_proto = IP_UDP,
269 TCPIP_PROTOCOL ( udp_protocol );