Browse Source

Clarified packet ownership transfer between a few functions.

Added a large number of missing calls to free_pkb().  In the case of UDP,
no received packets were ever freed, which lead to memory exhaustion
remarkably quickly once pxelinux started up.

In general, any function with _rx() in its name which accepts a pk_buff
*must* either call free_pkb() or pass the pkb to another _rx() function
(e.g. the next layer up the stack).  Since the UDP (and TCP) layers don't
pass packet buffers up to the higher-layer protocols (the
"applications"), they must free the packet buffer after calling the
application's newdata() method.
tags/v0.9.3
Michael Brown 18 years ago
parent
commit
a3d508b648
6 changed files with 63 additions and 31 deletions
  1. 6
    4
      src/include/gpxe/netdevice.h
  2. 5
    3
      src/net/ethernet.c
  3. 8
    5
      src/net/ipv4.c
  4. 5
    3
      src/net/netdevice.c
  5. 2
    0
      src/net/tcpip.c
  6. 37
    16
      src/net/udp.c

+ 6
- 4
src/include/gpxe/netdevice.h View File

@@ -83,6 +83,7 @@ struct ll_protocol {
83 83
 	 *
84 84
 	 * This method should prepend in the link-layer header
85 85
 	 * (e.g. the Ethernet DIX header) and transmit the packet.
86
+	 * This method takes ownership of the packet buffer.
86 87
 	 */
87 88
 	int ( * tx ) ( struct pk_buff *pkb, struct net_device *netdev,
88 89
 		       struct net_protocol *net_protocol,
@@ -95,9 +96,10 @@ struct ll_protocol {
95 96
 	 *
96 97
 	 * This method should strip off the link-layer header
97 98
 	 * (e.g. the Ethernet DIX header) and pass the packet to
98
-	 * net_rx().
99
+	 * net_rx().  This method takes ownership of the packet
100
+	 * buffer.
99 101
 	 */
100
-	void ( * rx ) ( struct pk_buff *pkb, struct net_device *netdev );
102
+	int ( * rx ) ( struct pk_buff *pkb, struct net_device *netdev );
101 103
 	/**
102 104
 	 * Transcribe link-layer address
103 105
 	 *
@@ -206,8 +208,8 @@ extern int netdev_tx ( struct net_device *netdev, struct pk_buff *pkb );
206 208
 extern void netdev_rx ( struct net_device *netdev, struct pk_buff *pkb );
207 209
 extern int net_tx ( struct pk_buff *pkb, struct net_device *netdev,
208 210
 		    struct net_protocol *net_protocol, const void *ll_dest );
209
-extern void net_rx ( struct pk_buff *pkb, struct net_device *netdev,
210
-		     uint16_t net_proto, const void *ll_source );
211
+extern int net_rx ( struct pk_buff *pkb, struct net_device *netdev,
212
+		    uint16_t net_proto, const void *ll_source );
211 213
 extern int netdev_poll ( struct net_device *netdev );
212 214
 extern struct pk_buff * netdev_rx_dequeue ( struct net_device *netdev );
213 215
 extern struct net_device * alloc_netdev ( size_t priv_size );

+ 5
- 3
src/net/ethernet.c View File

@@ -19,6 +19,7 @@
19 19
 #include <stdint.h>
20 20
 #include <string.h>
21 21
 #include <byteswap.h>
22
+#include <errno.h>
22 23
 #include <assert.h>
23 24
 #include <vsprintf.h>
24 25
 #include <gpxe/if_arp.h>
@@ -68,21 +69,22 @@ static int eth_tx ( struct pk_buff *pkb, struct net_device *netdev,
68 69
  * Strips off the Ethernet link-layer header and passes up to the
69 70
  * network-layer protocol.
70 71
  */
71
-static void eth_rx ( struct pk_buff *pkb, struct net_device *netdev ) {
72
+static int eth_rx ( struct pk_buff *pkb, struct net_device *netdev ) {
72 73
 	struct ethhdr *ethhdr = pkb->data;
73 74
 
74 75
 	/* Sanity check */
75 76
 	if ( pkb_len ( pkb ) < sizeof ( *ethhdr ) ) {
76 77
 		DBG ( "Ethernet packet too short (%d bytes)\n",
77 78
 		      pkb_len ( pkb ) );
78
-		return;
79
+		free_pkb ( pkb );
80
+		return -EINVAL;
79 81
 	}
80 82
 
81 83
 	/* Strip off Ethernet header */
82 84
 	pkb_pull ( pkb, sizeof ( *ethhdr ) );
83 85
 
84 86
 	/* Hand off to network-layer protocol */
85
-	net_rx ( pkb, netdev, ethhdr->h_protocol, ethhdr->h_source );
87
+	return net_rx ( pkb, netdev, ethhdr->h_protocol, ethhdr->h_source );
86 88
 }
87 89
 
88 90
 /**

+ 8
- 5
src/net/ipv4.c View File

@@ -389,9 +389,8 @@ static int ipv4_rx ( struct pk_buff *pkb, struct net_device *netdev __unused,
389 389
 
390 390
 	/* Sanity check */
391 391
 	if ( pkb_len ( pkb ) < sizeof ( *iphdr ) ) {
392
-		DBG ( "IP datagram too short (%d bytes)\n",
393
-			pkb_len ( pkb ) );
394
-		return -EINVAL;
392
+		DBG ( "IP datagram too short (%d bytes)\n", pkb_len ( pkb ) );
393
+		goto err;
395 394
 	}
396 395
 
397 396
 	/* Print IP4 header for debugging */
@@ -400,14 +399,14 @@ static int ipv4_rx ( struct pk_buff *pkb, struct net_device *netdev __unused,
400 399
 	/* Validate version and header length */
401 400
 	if ( iphdr->verhdrlen != 0x45 ) {
402 401
 		DBG ( "Bad version and header length %x\n", iphdr->verhdrlen );
403
-		return -EINVAL;
402
+		goto err;
404 403
 	}
405 404
 
406 405
 	/* Validate length of IP packet */
407 406
 	if ( ntohs ( iphdr->len ) > pkb_len ( pkb ) ) {
408 407
 		DBG ( "Inconsistent packet length %d\n",
409 408
 		      ntohs ( iphdr->len ) );
410
-		return -EINVAL;
409
+		goto err;
411 410
 	}
412 411
 
413 412
 	/* Verify the checksum */
@@ -447,6 +446,10 @@ static int ipv4_rx ( struct pk_buff *pkb, struct net_device *netdev __unused,
447 446
 
448 447
 	/* Send it to the transport layer */
449 448
 	return tcpip_rx ( pkb, iphdr->protocol, &src.st, &dest.st );
449
+
450
+ err:
451
+	free_pkb ( pkb );
452
+	return -EINVAL;
450 453
 }
451 454
 
452 455
 /** 

+ 5
- 3
src/net/netdevice.c View File

@@ -97,8 +97,9 @@ int net_tx ( struct pk_buff *pkb, struct net_device *netdev,
97 97
  * @v netdev		Network device
98 98
  * @v net_proto		Network-layer protocol, in network-byte order
99 99
  * @v ll_source		Source link-layer address
100
+ * @ret rc		Return status code
100 101
  */
101
-void net_rx ( struct pk_buff *pkb, struct net_device *netdev,
102
+int net_rx ( struct pk_buff *pkb, struct net_device *netdev,
102 103
 	      uint16_t net_proto, const void *ll_source ) {
103 104
 	struct net_protocol *net_protocol;
104 105
 
@@ -106,10 +107,11 @@ void net_rx ( struct pk_buff *pkb, struct net_device *netdev,
106 107
 	for ( net_protocol = net_protocols ; net_protocol < net_protocols_end ;
107 108
 	      net_protocol++ ) {
108 109
 		if ( net_protocol->net_proto == net_proto ) {
109
-			net_protocol->rx ( pkb, netdev, ll_source );
110
-			break;
110
+			return net_protocol->rx ( pkb, netdev, ll_source );
111 111
 		}
112 112
 	}
113
+	free_pkb ( pkb );
114
+	return 0;
113 115
 }
114 116
 
115 117
 /**

+ 2
- 0
src/net/tcpip.c View File

@@ -54,6 +54,7 @@ int tcpip_rx ( struct pk_buff *pkb, uint8_t tcpip_proto,
54 54
 	}
55 55
 
56 56
 	DBG ( "Unrecognised TCP/IP protocol %d\n", tcpip_proto );
57
+	free_pkb ( pkb );
57 58
 	return -EPROTONOSUPPORT;
58 59
 }
59 60
 
@@ -78,6 +79,7 @@ int tcpip_tx ( struct pk_buff *pkb, struct tcpip_protocol *tcpip_protocol,
78 79
 	}
79 80
 	
80 81
 	DBG ( "Unrecognised TCP/IP address family %d\n", st_dest->st_family );
82
+	free_pkb ( pkb );
81 83
 	return -EAFNOSUPPORT;
82 84
 }
83 85
 

+ 37
- 16
src/net/udp.c View File

@@ -93,6 +93,8 @@ void udp_close ( struct udp_connection *conn ) {
93 93
  * callback. The callback may use the buffer space
94 94
  */
95 95
 int udp_senddata ( struct udp_connection *conn ) {
96
+	int rc;
97
+
96 98
 	conn->tx_pkb = alloc_pkb ( UDP_MAX_TXPKB );
97 99
 	if ( conn->tx_pkb == NULL ) {
98 100
 		DBG ( "UDP %p cannot allocate packet buffer of length %d\n",
@@ -100,8 +102,11 @@ int udp_senddata ( struct udp_connection *conn ) {
100 102
 		return -ENOMEM;
101 103
 	}
102 104
 	pkb_reserve ( conn->tx_pkb, UDP_MAX_HLEN );
103
-	return conn->udp_op->senddata ( conn, conn->tx_pkb->data, 
104
-					pkb_available ( conn->tx_pkb ) );
105
+	rc = conn->udp_op->senddata ( conn, conn->tx_pkb->data, 
106
+				      pkb_available ( conn->tx_pkb ) );
107
+	if ( conn->tx_pkb )
108
+		free_pkb ( conn->tx_pkb );
109
+	return rc;
105 110
 }
106 111
 		
107 112
 /**
@@ -122,13 +127,20 @@ int udp_senddata ( struct udp_connection *conn ) {
122 127
 int udp_sendto ( struct udp_connection *conn, struct sockaddr_tcpip *peer,
123 128
 		 const void *data, size_t len ) {
124 129
        	struct udp_header *udphdr;
130
+	struct pk_buff *pkb;
131
+
132
+	/* Take ownership of packet buffer back from the
133
+	 * udp_connection structure.
134
+	 */
135
+	pkb = conn->tx_pkb;
136
+	conn->tx_pkb = NULL;
125 137
 
126 138
 	/* Avoid overflowing TX buffer */
127
-	if ( len > pkb_available ( conn->tx_pkb ) )
128
-		len = pkb_available ( conn->tx_pkb );
139
+	if ( len > pkb_available ( pkb ) )
140
+		len = pkb_available ( pkb );
129 141
 
130 142
 	/* Copy payload */
131
-	memmove ( pkb_put ( conn->tx_pkb, len ), data, len );
143
+	memmove ( pkb_put ( pkb, len ), data, len );
132 144
 
133 145
 	/*
134 146
 	 * Add the UDP header
@@ -136,22 +148,22 @@ int udp_sendto ( struct udp_connection *conn, struct sockaddr_tcpip *peer,
136 148
 	 * Covert all 16- and 32- bit integers into network btye order before
137 149
 	 * sending it over the network
138 150
 	 */
139
-	udphdr = pkb_push ( conn->tx_pkb, sizeof ( *udphdr ) );
151
+	udphdr = pkb_push ( pkb, sizeof ( *udphdr ) );
140 152
 	udphdr->dest_port = peer->st_port;
141 153
 	udphdr->source_port = conn->local_port;
142
-	udphdr->len = htons ( pkb_len ( conn->tx_pkb ) );
154
+	udphdr->len = htons ( pkb_len ( pkb ) );
143 155
 	udphdr->chksum = 0;
144 156
 	udphdr->chksum = tcpip_chksum ( udphdr, sizeof ( *udphdr ) + len );
145 157
 
146 158
 	/* Dump debugging information */
147 159
 	DBG ( "UDP %p transmitting %p+%#zx len %#x src %d dest %d "
148
-	      "chksum %#04x\n", conn, conn->tx_pkb->data,
149
-	      pkb_len ( conn->tx_pkb ), ntohs ( udphdr->len ),
160
+	      "chksum %#04x\n", conn, pkb->data,
161
+	      pkb_len ( pkb ), ntohs ( udphdr->len ),
150 162
 	      ntohs ( udphdr->source_port ), ntohs ( udphdr->dest_port ),
151 163
 	      ntohs ( udphdr->chksum ) );
152 164
 
153 165
 	/* Send it to the next layer for processing */
154
-	return tcpip_tx ( conn->tx_pkb, &udp_protocol, peer );
166
+	return tcpip_tx ( pkb, &udp_protocol, peer );
155 167
 }
156 168
 
157 169
 /**
@@ -186,12 +198,14 @@ static int udp_rx ( struct pk_buff *pkb, struct sockaddr_tcpip *st_src,
186 198
 	struct udp_connection *conn;
187 199
 	unsigned int ulen;
188 200
 	uint16_t chksum;
201
+	int rc;
189 202
 
190 203
 	/* Sanity check */
191 204
 	if ( pkb_len ( pkb ) < sizeof ( *udphdr ) ) {
192 205
 		DBG ( "UDP received underlength packet %p+%#zx\n",
193 206
 		      pkb->data, pkb_len ( pkb ) );
194
-		return -EINVAL;
207
+		rc = -EINVAL;
208
+		goto done;
195 209
 	}
196 210
 
197 211
 	/* Dump debugging information */
@@ -205,7 +219,8 @@ static int udp_rx ( struct pk_buff *pkb, struct sockaddr_tcpip *st_src,
205 219
 	if ( ulen > pkb_len ( pkb ) ) {
206 220
 		DBG ( "UDP received truncated packet %p+%#zx\n",
207 221
 		      pkb->data, pkb_len ( pkb ) );
208
-		return -EINVAL;
222
+		rc = -EINVAL;
223
+		goto done;
209 224
 	}
210 225
 	pkb_unput ( pkb, ( pkb_len ( pkb ) - ulen ) );
211 226
 
@@ -215,7 +230,8 @@ static int udp_rx ( struct pk_buff *pkb, struct sockaddr_tcpip *st_src,
215 230
 	chksum = tcpip_chksum ( pkb->data, pkb_len ( pkb ) );
216 231
 	if ( chksum != 0xffff ) {
217 232
 		DBG ( "Bad checksum %#x\n", chksum );
218
-		return -EINVAL;
233
+		rc = -EINVAL;
234
+		goto done;
219 235
 	}
220 236
 #endif
221 237
 
@@ -237,13 +253,18 @@ static int udp_rx ( struct pk_buff *pkb, struct sockaddr_tcpip *st_src,
237 253
 		DBG ( "UDP delivering to %p\n", conn );
238 254
 		
239 255
 		/* Call the application's callback */
240
-		return conn->udp_op->newdata ( conn, pkb->data, pkb_len( pkb ),
241
-					       st_src, st_dest );
256
+		rc = conn->udp_op->newdata ( conn, pkb->data, pkb_len( pkb ),
257
+					     st_src, st_dest );
258
+		goto done;
242 259
 	}
243 260
 
244 261
 	DBG ( "No UDP connection listening on port %d\n",
245 262
 	      ntohs ( udphdr->dest_port ) );
246
-	return 0;
263
+	rc = 0;
264
+
265
+ done:
266
+	free_pkb ( pkb );
267
+	return rc;
247 268
 }
248 269
 
249 270
 struct tcpip_protocol udp_protocol  = {

Loading…
Cancel
Save