6 #include <gpxe/tcpip.h>
7 #include <gpxe/pkbuff.h>
8 #include <gpxe/netdevice.h>
16 struct tcpip_protocol udp_protocol;
19 * List of registered UDP connections
21 static LIST_HEAD ( udp_conns );
24 * Bind UDP connection to local port
26 * @v conn UDP connection
27 * @v local_port Local port, in network byte order
28 * @ret rc Return status code
30 int udp_bind ( struct udp_connection *conn, uint16_t local_port ) {
31 struct udp_connection *existing;
33 list_for_each_entry ( existing, &udp_conns, list ) {
34 if ( existing->local_port == local_port )
37 conn->local_port = local_port;
44 * @v conn UDP connection
45 * @v local_port Local port, in network byte order, or zero
46 * @ret rc Return status code
48 * Opens the UDP connection and binds to a local port. If no local
49 * port is specified, the first available port will be used.
51 int udp_open ( struct udp_connection *conn, uint16_t local_port ) {
52 static uint16_t try_port = 1024;
55 /* If no port specified, find the first available port */
57 for ( ; try_port ; try_port++ ) {
58 if ( try_port < 1024 )
60 if ( udp_open ( conn, htons ( try_port ) ) == 0 )
66 /* Attempt bind to local port */
67 if ( ( rc = udp_bind ( conn, local_port ) ) != 0 ) {
68 DBGC ( conn, "UDP %p could not bind to local port %d: %s\n",
69 conn, local_port, strerror ( rc ) );
73 /* Add to UDP connection list */
74 list_add ( &conn->list, &udp_conns );
75 DBGC ( conn, "UDP %p opened on port %d\n", conn,
76 ntohs ( local_port ) );
82 * Close a UDP connection
84 * @v conn UDP connection
86 void udp_close ( struct udp_connection *conn ) {
87 list_del ( &conn->list );
88 DBGC ( conn, "UDP %p closed\n", conn );
92 * Allocate packet buffer for UDP
94 * @v conn UDP connection
95 * @ret pkb Packet buffer, or NULL
97 static struct pk_buff * udp_alloc_pkb ( struct udp_connection *conn ) {
100 pkb = alloc_pkb ( UDP_MAX_TXPKB );
102 DBGC ( conn, "UDP %p cannot allocate buffer of length %d\n",
103 conn, UDP_MAX_TXPKB );
106 pkb_reserve ( pkb, UDP_MAX_HLEN );
111 * User request to send data via a UDP connection
113 * @v conn UDP connection
115 * This function allocates buffer space and invokes the function's
116 * senddata() callback. The callback may use the buffer space as
117 * temporary storage space.
119 int udp_senddata ( struct udp_connection *conn ) {
122 conn->tx_pkb = udp_alloc_pkb ( conn );
123 if ( ! conn->tx_pkb )
126 rc = conn->udp_op->senddata ( conn, conn->tx_pkb->data,
127 pkb_tailroom ( conn->tx_pkb ) );
129 DBGC ( conn, "UDP %p application could not send packet: %s\n",
130 conn, strerror ( rc ) );
133 if ( conn->tx_pkb ) {
134 free_pkb ( conn->tx_pkb );
142 * Transmit data via a UDP connection to a specified address
144 * @v conn UDP connection
145 * @v peer Destination address
146 * @v netdev Network device to use if no route found, or NULL
147 * @v data Data to send
148 * @v len Length of data
149 * @ret rc Return status code
151 int udp_sendto_via ( struct udp_connection *conn, struct sockaddr_tcpip *peer,
152 struct net_device *netdev, const void *data,
154 struct udp_header *udphdr;
158 /* Use precreated packet buffer if one is available */
159 if ( conn->tx_pkb ) {
163 pkb = udp_alloc_pkb ( conn );
168 /* Avoid overflowing TX buffer */
169 if ( len > pkb_tailroom ( pkb ) )
170 len = pkb_tailroom ( pkb );
173 memmove ( pkb_put ( pkb, len ), data, len );
178 * Covert all 16- and 32- bit integers into network btye order before
179 * sending it over the network
181 udphdr = pkb_push ( pkb, sizeof ( *udphdr ) );
182 udphdr->dest_port = peer->st_port;
183 udphdr->source_port = conn->local_port;
184 udphdr->len = htons ( pkb_len ( pkb ) );
186 udphdr->chksum = tcpip_chksum ( udphdr, sizeof ( *udphdr ) + len );
188 /* Dump debugging information */
189 DBGC ( conn, "UDP %p TX %d->%d len %zd\n", conn,
190 ntohs ( udphdr->source_port ), ntohs ( udphdr->dest_port ),
191 ntohs ( udphdr->len ) );
193 /* Send it to the next layer for processing */
194 if ( ( rc = tcpip_tx ( pkb, &udp_protocol, peer, netdev,
195 &udphdr->chksum ) ) != 0 ) {
196 DBGC ( conn, "UDP %p could not transmit packet: %s\n",
197 conn, strerror ( rc ) );
205 * Transmit data via a UDP connection to a specified address
207 * @v conn UDP connection
208 * @v peer Destination address
209 * @v data Data to send
210 * @v len Length of data
211 * @ret rc Return status code
213 int udp_sendto ( struct udp_connection *conn, struct sockaddr_tcpip *peer,
214 const void *data, size_t len ) {
215 return udp_sendto_via ( conn, peer, NULL, data, len );
219 * Transmit data via a UDP connection
221 * @v conn UDP connection
222 * @v data Data to send
223 * @v len Length of data
224 * @ret rc Return status code
226 int udp_send ( struct udp_connection *conn, const void *data, size_t len ) {
227 return udp_sendto ( conn, &conn->peer, data, len );
231 * Identify UDP connection by local port number
233 * @v local_port Local port (in network-endian order)
234 * @ret conn TCP connection, or NULL
236 static struct udp_connection * udp_demux ( uint16_t local_port ) {
237 struct udp_connection *conn;
239 list_for_each_entry ( conn, &udp_conns, list ) {
240 if ( ( conn->local_port == local_port ) ||
241 ( conn->local_port == 0 ) ) {
249 * Process a received packet
251 * @v pkb Packet buffer
252 * @v st_src Partially-filled source address
253 * @v st_dest Partially-filled destination address
254 * @v pshdr_csum Pseudo-header checksum
255 * @ret rc Return status code
257 static int udp_rx ( struct pk_buff *pkb, struct sockaddr_tcpip *st_src,
258 struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum ) {
259 struct udp_header *udphdr = pkb->data;
260 struct udp_connection *conn;
265 /* Sanity check packet */
266 if ( pkb_len ( pkb ) < sizeof ( *udphdr ) ) {
267 DBG ( "UDP packet too short at %d bytes (min %d bytes)\n",
268 pkb_len ( pkb ), sizeof ( *udphdr ) );
273 ulen = ntohs ( udphdr->len );
274 if ( ulen < sizeof ( *udphdr ) ) {
275 DBG ( "UDP length too short at %d bytes "
276 "(header is %d bytes)\n", ulen, sizeof ( *udphdr ) );
280 if ( ulen > pkb_len ( pkb ) ) {
281 DBG ( "UDP length too long at %d bytes (packet is %d bytes)\n",
282 ulen, pkb_len ( pkb ) );
286 if ( udphdr->chksum ) {
287 csum = tcpip_continue_chksum ( pshdr_csum, pkb->data, ulen );
289 DBG ( "UDP checksum incorrect (is %04x including "
290 "checksum field, should be 0000)\n", csum );
296 /* Parse parameters from header and strip header */
297 st_src->st_port = udphdr->source_port;
298 st_dest->st_port = udphdr->dest_port;
299 conn = udp_demux ( udphdr->dest_port );
300 pkb_unput ( pkb, ( pkb_len ( pkb ) - ulen ) );
301 pkb_pull ( pkb, sizeof ( *udphdr ) );
303 /* Dump debugging information */
304 DBGC ( conn, "UDP %p RX %d<-%d len %zd\n", conn,
305 ntohs ( udphdr->dest_port ), ntohs ( udphdr->source_port ),
308 /* Ignore if no matching connection found */
310 DBG ( "No UDP connection listening on port %d\n",
311 ntohs ( udphdr->dest_port ) );
316 /* Pass data to application */
317 if ( conn->udp_op->newdata ) {
318 rc = conn->udp_op->newdata ( conn, pkb->data, pkb_len ( pkb ),
321 DBGC ( conn, "UDP %p application rejected packet: %s\n",
322 conn, strerror ( rc ) );
325 DBGC ( conn, "UDP %p application has no newdata handler for " \
326 "incoming packet\n", conn );
334 struct tcpip_protocol udp_protocol __tcpip_protocol = {
337 .tcpip_proto = IP_UDP,