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 )
70 /* Add to UDP connection list */
71 list_add ( &conn
->list
, &udp_conns
);
72 DBG ( "UDP opened %p on port %d\n", conn
, ntohs ( local_port
) );
78 * Close a UDP connection
80 * @v conn UDP connection
82 void udp_close ( struct udp_connection
*conn
) {
83 list_del ( &conn
->list
);
84 DBG ( "UDP closed %p\n", conn
);
88 * User request to send data via a UDP connection
90 * @v conn UDP connection
92 * This function allocates buffer space and invokes the function's senddata()
93 * callback. The callback may use the buffer space
95 int udp_senddata ( struct udp_connection
*conn
) {
98 conn
->tx_pkb
= alloc_pkb ( UDP_MAX_TXPKB
);
99 if ( conn
->tx_pkb
== NULL
) {
100 DBG ( "UDP %p cannot allocate packet buffer of length %d\n",
101 conn
, UDP_MAX_TXPKB
);
104 pkb_reserve ( conn
->tx_pkb
, UDP_MAX_HLEN
);
105 rc
= conn
->udp_op
->senddata ( conn
, conn
->tx_pkb
->data
,
106 pkb_available ( conn
->tx_pkb
) );
108 free_pkb ( conn
->tx_pkb
);
113 * Transmit data via a UDP connection to a specified address
115 * @v conn UDP connection
116 * @v peer Destination address
117 * @v data Data to send
118 * @v len Length of data
119 * @ret rc Return status code
121 * This function fills up the UDP headers and sends the data. It may
122 * be called only from within the context of an application's
123 * senddata() method; if the application wishes to send data it must
124 * call udp_senddata() and wait for its senddata() method to be
127 int udp_sendto ( struct udp_connection
*conn
, struct sockaddr_tcpip
*peer
,
128 const void *data
, size_t len
) {
129 struct udp_header
*udphdr
;
132 /* Take ownership of packet buffer back from the
133 * udp_connection structure.
138 /* Avoid overflowing TX buffer */
139 if ( len
> pkb_available ( pkb
) )
140 len
= pkb_available ( pkb
);
143 memmove ( pkb_put ( pkb
, len
), data
, len
);
148 * Covert all 16- and 32- bit integers into network btye order before
149 * sending it over the network
151 udphdr
= pkb_push ( pkb
, sizeof ( *udphdr
) );
152 udphdr
->dest_port
= peer
->st_port
;
153 udphdr
->source_port
= conn
->local_port
;
154 udphdr
->len
= htons ( pkb_len ( pkb
) );
156 udphdr
->chksum
= tcpip_chksum ( udphdr
, sizeof ( *udphdr
) + len
);
158 /* Dump debugging information */
159 DBG ( "UDP %p transmitting %p+%#zx len %#x src %d dest %d "
160 "chksum %#04x\n", conn
, pkb
->data
,
161 pkb_len ( pkb
), ntohs ( udphdr
->len
),
162 ntohs ( udphdr
->source_port
), ntohs ( udphdr
->dest_port
),
163 ntohs ( udphdr
->chksum
) );
165 /* Send it to the next layer for processing */
166 return tcpip_tx ( pkb
, &udp_protocol
, peer
);
170 * Transmit data via a UDP connection
172 * @v conn UDP connection
173 * @v data Data to send
174 * @v len Length of data
175 * @ret rc Return status code
177 * This function fills up the UDP headers and sends the data. It may
178 * be called only from within the context of an application's
179 * senddata() method; if the application wishes to send data it must
180 * call udp_senddata() and wait for its senddata() method to be
183 int udp_send ( struct udp_connection
*conn
, const void *data
, size_t len
) {
184 return udp_sendto ( conn
, &conn
->peer
, data
, len
);
188 * Process a received packet
190 * @v pkb Packet buffer
191 * @v st_src Partially-filled source address
192 * @v st_dest Partially-filled destination address
193 * @ret rc Return status code
195 static int udp_rx ( struct pk_buff
*pkb
, struct sockaddr_tcpip
*st_src
,
196 struct sockaddr_tcpip
*st_dest
) {
197 struct udp_header
*udphdr
= pkb
->data
;
198 struct udp_connection
*conn
;
204 if ( pkb_len ( pkb
) < sizeof ( *udphdr
) ) {
205 DBG ( "UDP received underlength packet %p+%#zx\n",
206 pkb
->data
, pkb_len ( pkb
) );
211 /* Dump debugging information */
212 DBG ( "UDP received %p+%#zx len %#x src %d dest %d chksum %#04x\n",
213 pkb
->data
, pkb_len ( pkb
), ntohs ( udphdr
->len
),
214 ntohs ( udphdr
->source_port
), ntohs ( udphdr
->dest_port
),
215 ntohs ( udphdr
->chksum
) );
217 /* Check length and trim any excess */
218 ulen
= ntohs ( udphdr
->len
);
219 if ( ulen
> pkb_len ( pkb
) ) {
220 DBG ( "UDP received truncated packet %p+%#zx\n",
221 pkb
->data
, pkb_len ( pkb
) );
225 pkb_unput ( pkb
, ( pkb_len ( pkb
) - ulen
) );
227 /* Verify the checksum */
228 #warning "Don't we need to take the pseudo-header into account here?"
230 chksum
= tcpip_chksum ( pkb
->data
, pkb_len ( pkb
) );
231 if ( chksum
!= 0xffff ) {
232 DBG ( "Bad checksum %#x\n", chksum
);
238 /* Complete the socket addresses */
239 st_src
->st_port
= udphdr
->source_port
;
240 st_dest
->st_port
= udphdr
->dest_port
;
242 /* Demux the connection */
243 list_for_each_entry ( conn
, &udp_conns
, list
) {
244 if ( conn
->local_port
&&
245 ( conn
->local_port
!= udphdr
->dest_port
) ) {
246 /* Bound to local port and local port doesn't match */
250 /* Strip off the UDP header */
251 pkb_pull ( pkb
, sizeof ( *udphdr
) );
253 DBG ( "UDP delivering to %p\n", conn
);
255 /* Call the application's callback */
256 rc
= conn
->udp_op
->newdata ( conn
, pkb
->data
, pkb_len( pkb
),
261 DBG ( "No UDP connection listening on port %d\n",
262 ntohs ( udphdr
->dest_port
) );
270 struct tcpip_protocol udp_protocol __tcpip_protocol
= {
273 .tcpip_proto
= IP_UDP
,