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
 	 *
83
 	 *
84
 	 * This method should prepend in the link-layer header
84
 	 * This method should prepend in the link-layer header
85
 	 * (e.g. the Ethernet DIX header) and transmit the packet.
85
 	 * (e.g. the Ethernet DIX header) and transmit the packet.
86
+	 * This method takes ownership of the packet buffer.
86
 	 */
87
 	 */
87
 	int ( * tx ) ( struct pk_buff *pkb, struct net_device *netdev,
88
 	int ( * tx ) ( struct pk_buff *pkb, struct net_device *netdev,
88
 		       struct net_protocol *net_protocol,
89
 		       struct net_protocol *net_protocol,
95
 	 *
96
 	 *
96
 	 * This method should strip off the link-layer header
97
 	 * This method should strip off the link-layer header
97
 	 * (e.g. the Ethernet DIX header) and pass the packet to
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
 	 * Transcribe link-layer address
104
 	 * Transcribe link-layer address
103
 	 *
105
 	 *
206
 extern void netdev_rx ( struct net_device *netdev, struct pk_buff *pkb );
208
 extern void netdev_rx ( struct net_device *netdev, struct pk_buff *pkb );
207
 extern int net_tx ( struct pk_buff *pkb, struct net_device *netdev,
209
 extern int net_tx ( struct pk_buff *pkb, struct net_device *netdev,
208
 		    struct net_protocol *net_protocol, const void *ll_dest );
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
 extern int netdev_poll ( struct net_device *netdev );
213
 extern int netdev_poll ( struct net_device *netdev );
212
 extern struct pk_buff * netdev_rx_dequeue ( struct net_device *netdev );
214
 extern struct pk_buff * netdev_rx_dequeue ( struct net_device *netdev );
213
 extern struct net_device * alloc_netdev ( size_t priv_size );
215
 extern struct net_device * alloc_netdev ( size_t priv_size );

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

19
 #include <stdint.h>
19
 #include <stdint.h>
20
 #include <string.h>
20
 #include <string.h>
21
 #include <byteswap.h>
21
 #include <byteswap.h>
22
+#include <errno.h>
22
 #include <assert.h>
23
 #include <assert.h>
23
 #include <vsprintf.h>
24
 #include <vsprintf.h>
24
 #include <gpxe/if_arp.h>
25
 #include <gpxe/if_arp.h>
68
  * Strips off the Ethernet link-layer header and passes up to the
69
  * Strips off the Ethernet link-layer header and passes up to the
69
  * network-layer protocol.
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
 	struct ethhdr *ethhdr = pkb->data;
73
 	struct ethhdr *ethhdr = pkb->data;
73
 
74
 
74
 	/* Sanity check */
75
 	/* Sanity check */
75
 	if ( pkb_len ( pkb ) < sizeof ( *ethhdr ) ) {
76
 	if ( pkb_len ( pkb ) < sizeof ( *ethhdr ) ) {
76
 		DBG ( "Ethernet packet too short (%d bytes)\n",
77
 		DBG ( "Ethernet packet too short (%d bytes)\n",
77
 		      pkb_len ( pkb ) );
78
 		      pkb_len ( pkb ) );
78
-		return;
79
+		free_pkb ( pkb );
80
+		return -EINVAL;
79
 	}
81
 	}
80
 
82
 
81
 	/* Strip off Ethernet header */
83
 	/* Strip off Ethernet header */
82
 	pkb_pull ( pkb, sizeof ( *ethhdr ) );
84
 	pkb_pull ( pkb, sizeof ( *ethhdr ) );
83
 
85
 
84
 	/* Hand off to network-layer protocol */
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
 
389
 
390
 	/* Sanity check */
390
 	/* Sanity check */
391
 	if ( pkb_len ( pkb ) < sizeof ( *iphdr ) ) {
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
 	/* Print IP4 header for debugging */
396
 	/* Print IP4 header for debugging */
400
 	/* Validate version and header length */
399
 	/* Validate version and header length */
401
 	if ( iphdr->verhdrlen != 0x45 ) {
400
 	if ( iphdr->verhdrlen != 0x45 ) {
402
 		DBG ( "Bad version and header length %x\n", iphdr->verhdrlen );
401
 		DBG ( "Bad version and header length %x\n", iphdr->verhdrlen );
403
-		return -EINVAL;
402
+		goto err;
404
 	}
403
 	}
405
 
404
 
406
 	/* Validate length of IP packet */
405
 	/* Validate length of IP packet */
407
 	if ( ntohs ( iphdr->len ) > pkb_len ( pkb ) ) {
406
 	if ( ntohs ( iphdr->len ) > pkb_len ( pkb ) ) {
408
 		DBG ( "Inconsistent packet length %d\n",
407
 		DBG ( "Inconsistent packet length %d\n",
409
 		      ntohs ( iphdr->len ) );
408
 		      ntohs ( iphdr->len ) );
410
-		return -EINVAL;
409
+		goto err;
411
 	}
410
 	}
412
 
411
 
413
 	/* Verify the checksum */
412
 	/* Verify the checksum */
447
 
446
 
448
 	/* Send it to the transport layer */
447
 	/* Send it to the transport layer */
449
 	return tcpip_rx ( pkb, iphdr->protocol, &src.st, &dest.st );
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
  * @v netdev		Network device
97
  * @v netdev		Network device
98
  * @v net_proto		Network-layer protocol, in network-byte order
98
  * @v net_proto		Network-layer protocol, in network-byte order
99
  * @v ll_source		Source link-layer address
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
 	      uint16_t net_proto, const void *ll_source ) {
103
 	      uint16_t net_proto, const void *ll_source ) {
103
 	struct net_protocol *net_protocol;
104
 	struct net_protocol *net_protocol;
104
 
105
 
106
 	for ( net_protocol = net_protocols ; net_protocol < net_protocols_end ;
107
 	for ( net_protocol = net_protocols ; net_protocol < net_protocols_end ;
107
 	      net_protocol++ ) {
108
 	      net_protocol++ ) {
108
 		if ( net_protocol->net_proto == net_proto ) {
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
 	}
54
 	}
55
 
55
 
56
 	DBG ( "Unrecognised TCP/IP protocol %d\n", tcpip_proto );
56
 	DBG ( "Unrecognised TCP/IP protocol %d\n", tcpip_proto );
57
+	free_pkb ( pkb );
57
 	return -EPROTONOSUPPORT;
58
 	return -EPROTONOSUPPORT;
58
 }
59
 }
59
 
60
 
78
 	}
79
 	}
79
 	
80
 	
80
 	DBG ( "Unrecognised TCP/IP address family %d\n", st_dest->st_family );
81
 	DBG ( "Unrecognised TCP/IP address family %d\n", st_dest->st_family );
82
+	free_pkb ( pkb );
81
 	return -EAFNOSUPPORT;
83
 	return -EAFNOSUPPORT;
82
 }
84
 }
83
 
85
 

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

93
  * callback. The callback may use the buffer space
93
  * callback. The callback may use the buffer space
94
  */
94
  */
95
 int udp_senddata ( struct udp_connection *conn ) {
95
 int udp_senddata ( struct udp_connection *conn ) {
96
+	int rc;
97
+
96
 	conn->tx_pkb = alloc_pkb ( UDP_MAX_TXPKB );
98
 	conn->tx_pkb = alloc_pkb ( UDP_MAX_TXPKB );
97
 	if ( conn->tx_pkb == NULL ) {
99
 	if ( conn->tx_pkb == NULL ) {
98
 		DBG ( "UDP %p cannot allocate packet buffer of length %d\n",
100
 		DBG ( "UDP %p cannot allocate packet buffer of length %d\n",
100
 		return -ENOMEM;
102
 		return -ENOMEM;
101
 	}
103
 	}
102
 	pkb_reserve ( conn->tx_pkb, UDP_MAX_HLEN );
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
 int udp_sendto ( struct udp_connection *conn, struct sockaddr_tcpip *peer,
127
 int udp_sendto ( struct udp_connection *conn, struct sockaddr_tcpip *peer,
123
 		 const void *data, size_t len ) {
128
 		 const void *data, size_t len ) {
124
        	struct udp_header *udphdr;
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
 	/* Avoid overflowing TX buffer */
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
 	/* Copy payload */
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
 	 * Add the UDP header
146
 	 * Add the UDP header
136
 	 * Covert all 16- and 32- bit integers into network btye order before
148
 	 * Covert all 16- and 32- bit integers into network btye order before
137
 	 * sending it over the network
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
 	udphdr->dest_port = peer->st_port;
152
 	udphdr->dest_port = peer->st_port;
141
 	udphdr->source_port = conn->local_port;
153
 	udphdr->source_port = conn->local_port;
142
-	udphdr->len = htons ( pkb_len ( conn->tx_pkb ) );
154
+	udphdr->len = htons ( pkb_len ( pkb ) );
143
 	udphdr->chksum = 0;
155
 	udphdr->chksum = 0;
144
 	udphdr->chksum = tcpip_chksum ( udphdr, sizeof ( *udphdr ) + len );
156
 	udphdr->chksum = tcpip_chksum ( udphdr, sizeof ( *udphdr ) + len );
145
 
157
 
146
 	/* Dump debugging information */
158
 	/* Dump debugging information */
147
 	DBG ( "UDP %p transmitting %p+%#zx len %#x src %d dest %d "
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
 	      ntohs ( udphdr->source_port ), ntohs ( udphdr->dest_port ),
162
 	      ntohs ( udphdr->source_port ), ntohs ( udphdr->dest_port ),
151
 	      ntohs ( udphdr->chksum ) );
163
 	      ntohs ( udphdr->chksum ) );
152
 
164
 
153
 	/* Send it to the next layer for processing */
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
 	struct udp_connection *conn;
198
 	struct udp_connection *conn;
187
 	unsigned int ulen;
199
 	unsigned int ulen;
188
 	uint16_t chksum;
200
 	uint16_t chksum;
201
+	int rc;
189
 
202
 
190
 	/* Sanity check */
203
 	/* Sanity check */
191
 	if ( pkb_len ( pkb ) < sizeof ( *udphdr ) ) {
204
 	if ( pkb_len ( pkb ) < sizeof ( *udphdr ) ) {
192
 		DBG ( "UDP received underlength packet %p+%#zx\n",
205
 		DBG ( "UDP received underlength packet %p+%#zx\n",
193
 		      pkb->data, pkb_len ( pkb ) );
206
 		      pkb->data, pkb_len ( pkb ) );
194
-		return -EINVAL;
207
+		rc = -EINVAL;
208
+		goto done;
195
 	}
209
 	}
196
 
210
 
197
 	/* Dump debugging information */
211
 	/* Dump debugging information */
205
 	if ( ulen > pkb_len ( pkb ) ) {
219
 	if ( ulen > pkb_len ( pkb ) ) {
206
 		DBG ( "UDP received truncated packet %p+%#zx\n",
220
 		DBG ( "UDP received truncated packet %p+%#zx\n",
207
 		      pkb->data, pkb_len ( pkb ) );
221
 		      pkb->data, pkb_len ( pkb ) );
208
-		return -EINVAL;
222
+		rc = -EINVAL;
223
+		goto done;
209
 	}
224
 	}
210
 	pkb_unput ( pkb, ( pkb_len ( pkb ) - ulen ) );
225
 	pkb_unput ( pkb, ( pkb_len ( pkb ) - ulen ) );
211
 
226
 
215
 	chksum = tcpip_chksum ( pkb->data, pkb_len ( pkb ) );
230
 	chksum = tcpip_chksum ( pkb->data, pkb_len ( pkb ) );
216
 	if ( chksum != 0xffff ) {
231
 	if ( chksum != 0xffff ) {
217
 		DBG ( "Bad checksum %#x\n", chksum );
232
 		DBG ( "Bad checksum %#x\n", chksum );
218
-		return -EINVAL;
233
+		rc = -EINVAL;
234
+		goto done;
219
 	}
235
 	}
220
 #endif
236
 #endif
221
 
237
 
237
 		DBG ( "UDP delivering to %p\n", conn );
253
 		DBG ( "UDP delivering to %p\n", conn );
238
 		
254
 		
239
 		/* Call the application's callback */
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
 	DBG ( "No UDP connection listening on port %d\n",
261
 	DBG ( "No UDP connection listening on port %d\n",
245
 	      ntohs ( udphdr->dest_port ) );
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
 struct tcpip_protocol udp_protocol  = {
270
 struct tcpip_protocol udp_protocol  = {

Loading…
Cancel
Save