Browse Source

Improve consistency between TCP and UDP RX datapaths

tags/v0.9.3
Michael Brown 18 years ago
parent
commit
94fc68895d
2 changed files with 73 additions and 58 deletions
  1. 17
    12
      src/net/tcp.c
  2. 56
    46
      src/net/udp.c

+ 17
- 12
src/net/tcp.c View File

@@ -600,7 +600,7 @@ static int tcp_rx ( struct pk_buff *pkb,
600 600
 		    struct sockaddr_tcpip *st_src __unused,
601 601
 		    struct sockaddr_tcpip *st_dest __unused,
602 602
 		    uint16_t pshdr_csum ) {
603
-	struct tcp_header *tcphdr;
603
+	struct tcp_header *tcphdr = pkb->data;
604 604
 	struct tcp_connection *conn;
605 605
 	unsigned int hlen;
606 606
 	uint16_t csum;
@@ -611,34 +611,34 @@ static int tcp_rx ( struct pk_buff *pkb,
611 611
 	unsigned int flags;
612 612
 	void *data;
613 613
 	size_t len;
614
-	int rc = 0;
614
+	int rc;
615 615
 
616 616
 	/* Sanity check packet */
617 617
 	if ( pkb_len ( pkb ) < sizeof ( *tcphdr ) ) {
618 618
 		DBG ( "TCP packet too short at %d bytes (min %d bytes)\n",
619 619
 		      pkb_len ( pkb ), sizeof ( *tcphdr ) );
620 620
 		rc = -EINVAL;
621
-		goto err;
621
+		goto done;
622 622
 	}
623
-	tcphdr = pkb->data;
624 623
 	hlen = ( ( tcphdr->hlen & TCP_MASK_HLEN ) / 16 ) * 4;
625 624
 	if ( hlen < sizeof ( *tcphdr ) ) {
626 625
 		DBG ( "TCP header too short at %d bytes (min %d bytes)\n",
627 626
 		      hlen, sizeof ( *tcphdr ) );
628 627
 		rc = -EINVAL;
629
-		goto err;
628
+		goto done;
630 629
 	}
631 630
 	if ( hlen > pkb_len ( pkb ) ) {
632 631
 		DBG ( "TCP header too long at %d bytes (max %d bytes)\n",
633 632
 		      hlen, pkb_len ( pkb ) );
634 633
 		rc = -EINVAL;
635
-		goto err;
634
+		goto done;
636 635
 	}
637 636
 	csum = tcpip_continue_chksum ( pshdr_csum, pkb->data, pkb_len ( pkb ));
638 637
 	if ( csum != 0 ) {
639 638
 		DBG ( "TCP checksum incorrect (is %04x including checksum "
640 639
 		      "field, should be 0000)\n", csum );
641
-		goto err;
640
+		rc = -EINVAL;
641
+		goto done;
642 642
 	}
643 643
 	
644 644
 	/* Parse parameters from header and strip header */
@@ -663,13 +663,17 @@ static int tcp_rx ( struct pk_buff *pkb,
663 663
 	 * sending RST
664 664
 	 */
665 665
 #warning "Handle non-matched connections"
666
-	if ( ! conn )
667
-		goto err;
666
+	if ( ! conn ) {
667
+		rc = -ENOTCONN;
668
+		goto done;
669
+	}
668 670
 
669 671
 	/* Handle RST, if present */
670 672
 #warning "Handle RST"
671
-	if ( flags & TCP_RST )
672
-		goto err;
673
+	if ( flags & TCP_RST ) {
674
+		rc = -ECONNRESET;
675
+		goto done;
676
+	}
673 677
 
674 678
 	/* Handle ACK, if present */
675 679
 	if ( flags & TCP_ACK )
@@ -707,7 +711,8 @@ static int tcp_rx ( struct pk_buff *pkb,
707 711
 		start_timer ( &conn->timer );
708 712
 	}
709 713
 
710
- err:
714
+	rc = 0;
715
+ done:
711 716
 	/* Free received packet */
712 717
 	free_pkb ( pkb );
713 718
 	return rc;

+ 56
- 46
src/net/udp.c View File

@@ -69,7 +69,8 @@ int udp_open ( struct udp_connection *conn, uint16_t local_port ) {
69 69
 
70 70
 	/* Add to UDP connection list */
71 71
 	list_add ( &conn->list, &udp_conns );
72
-	DBG ( "UDP opened %p on port %d\n", conn, ntohs ( local_port ) );
72
+	DBGC ( conn, "UDP %p opened on port %d\n", conn,
73
+	       ntohs ( local_port ) );
73 74
 
74 75
 	return 0;
75 76
 }
@@ -81,7 +82,7 @@ int udp_open ( struct udp_connection *conn, uint16_t local_port ) {
81 82
  */
82 83
 void udp_close ( struct udp_connection *conn ) {
83 84
 	list_del ( &conn->list );
84
-	DBG ( "UDP closed %p\n", conn );
85
+	DBGC ( conn, "UDP %p closed\n", conn );
85 86
 }
86 87
 
87 88
 /**
@@ -97,8 +98,8 @@ int udp_senddata ( struct udp_connection *conn ) {
97 98
 
98 99
 	conn->tx_pkb = alloc_pkb ( UDP_MAX_TXPKB );
99 100
 	if ( conn->tx_pkb == NULL ) {
100
-		DBG ( "UDP %p cannot allocate packet buffer of length %d\n",
101
-		      conn, UDP_MAX_TXPKB );
101
+		DBGC ( conn, "UDP %p cannot allocate buffer of length %d\n",
102
+		       conn, UDP_MAX_TXPKB );
102 103
 		return -ENOMEM;
103 104
 	}
104 105
 	pkb_reserve ( conn->tx_pkb, UDP_MAX_HLEN );
@@ -156,11 +157,9 @@ int udp_sendto ( struct udp_connection *conn, struct sockaddr_tcpip *peer,
156 157
 	udphdr->chksum = tcpip_chksum ( udphdr, sizeof ( *udphdr ) + len );
157 158
 
158 159
 	/* 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 ) );
160
+	DBGC ( conn, "UDP %p TX %d->%d len %zd\n", conn,
161
+	       ntohs ( udphdr->source_port ), ntohs ( udphdr->dest_port ),
162
+	       ntohs ( udphdr->len ) );
164 163
 
165 164
 	/* Send it to the next layer for processing */
166 165
 	return tcpip_tx ( pkb, &udp_protocol, peer, &udphdr->chksum );
@@ -184,6 +183,24 @@ int udp_send ( struct udp_connection *conn, const void *data, size_t len ) {
184 183
 	return udp_sendto ( conn, &conn->peer, data, len );
185 184
 }
186 185
 
186
+/**
187
+ * Identify UDP connection by local port number
188
+ *
189
+ * @v local_port	Local port (in network-endian order)
190
+ * @ret conn		TCP connection, or NULL
191
+ */
192
+static struct udp_connection * udp_demux ( uint16_t local_port ) {
193
+	struct udp_connection *conn;
194
+
195
+	list_for_each_entry ( conn, &udp_conns, list ) {
196
+		if ( ( conn->local_port == local_port ) ||
197
+		     ( conn->local_port == 0 ) ) {
198
+			return conn;
199
+		}
200
+	}
201
+	return NULL;
202
+}
203
+
187 204
 /**
188 205
  * Process a received packet
189 206
  *
@@ -197,36 +214,32 @@ static int udp_rx ( struct pk_buff *pkb, struct sockaddr_tcpip *st_src,
197 214
 		    struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum ) {
198 215
 	struct udp_header *udphdr = pkb->data;
199 216
 	struct udp_connection *conn;
200
-	unsigned int ulen;
217
+	size_t ulen;
201 218
 	uint16_t csum;
202 219
 	int rc;
203 220
 
204
-	/* Sanity check */
221
+	/* Sanity check packet */
205 222
 	if ( pkb_len ( pkb ) < sizeof ( *udphdr ) ) {
206
-		DBG ( "UDP received underlength packet %p+%#zx\n",
207
-		      pkb->data, pkb_len ( pkb ) );
223
+		DBG ( "UDP packet too short at %d bytes (min %d bytes)\n",
224
+		      pkb_len ( pkb ), sizeof ( *udphdr ) );
225
+		
208 226
 		rc = -EINVAL;
209 227
 		goto done;
210 228
 	}
211
-
212
-	/* Dump debugging information */
213
-	DBG ( "UDP received %p+%#zx len %#x src %d dest %d chksum %#04x\n",
214
-	      pkb->data, pkb_len ( pkb ), ntohs ( udphdr->len ),
215
-	      ntohs ( udphdr->source_port ), ntohs ( udphdr->dest_port ),
216
-	      ntohs ( udphdr->chksum ) );
217
-
218
-	/* Check length and trim any excess */
219 229
 	ulen = ntohs ( udphdr->len );
230
+	if ( ulen < sizeof ( *udphdr ) ) {
231
+		DBG ( "UDP length too short at %d bytes "
232
+		      "(header is %d bytes)\n", ulen, sizeof ( *udphdr ) );
233
+		rc = -EINVAL;
234
+		goto done;
235
+	}
220 236
 	if ( ulen > pkb_len ( pkb ) ) {
221
-		DBG ( "UDP received truncated packet %p+%#zx\n",
222
-		      pkb->data, pkb_len ( pkb ) );
237
+		DBG ( "UDP length too long at %d bytes (packet is %d bytes)\n",
238
+		      ulen, pkb_len ( pkb ) );
223 239
 		rc = -EINVAL;
224 240
 		goto done;
225 241
 	}
226
-	pkb_unput ( pkb, ( pkb_len ( pkb ) - ulen ) );
227
-
228
-	/* Verify the checksum */
229
-	csum = tcpip_continue_chksum ( pshdr_csum, pkb->data, pkb_len ( pkb ));
242
+	csum = tcpip_continue_chksum ( pshdr_csum, pkb->data, ulen );
230 243
 	if ( csum != 0 ) {
231 244
 		DBG ( "UDP checksum incorrect (is %04x including checksum "
232 245
 		      "field, should be 0000)\n", csum );
@@ -234,32 +247,29 @@ static int udp_rx ( struct pk_buff *pkb, struct sockaddr_tcpip *st_src,
234 247
 		goto done;
235 248
 	}
236 249
 
237
-	/* Complete the socket addresses */
250
+	/* Parse parameters from header and strip header */
238 251
 	st_src->st_port = udphdr->source_port;
239 252
 	st_dest->st_port = udphdr->dest_port;
253
+	conn = udp_demux ( udphdr->dest_port );
254
+	pkb_unput ( pkb, ( pkb_len ( pkb ) - ulen ) );
255
+	pkb_pull ( pkb, sizeof ( *udphdr ) );
240 256
 
241
-	/* Demux the connection */
242
-	list_for_each_entry ( conn, &udp_conns, list ) {
243
-		if ( conn->local_port &&
244
-		     ( conn->local_port != udphdr->dest_port ) ) {
245
-			/* Bound to local port and local port doesn't match */
246
-			continue;
247
-		}
248
-		
249
-		/* Strip off the UDP header */
250
-		pkb_pull ( pkb, sizeof ( *udphdr ) );
257
+	/* Dump debugging information */
258
+	DBGC ( conn, "UDP %p RX %d<-%d len %zd\n", conn,
259
+	       ntohs ( udphdr->dest_port ), ntohs ( udphdr->source_port ),
260
+	       ulen );
251 261
 
252
-		DBG ( "UDP delivering to %p\n", conn );
253
-		
254
-		/* Call the application's callback */
255
-		rc = conn->udp_op->newdata ( conn, pkb->data, pkb_len( pkb ),
256
-					     st_src, st_dest );
262
+	/* Ignore if no matching connection found */
263
+	if ( ! conn ) {
264
+		DBG ( "No UDP connection listening on port %d\n",
265
+		      ntohs ( udphdr->dest_port ) );
266
+		rc = -ENOTCONN;
257 267
 		goto done;
258 268
 	}
259 269
 
260
-	DBG ( "No UDP connection listening on port %d\n",
261
-	      ntohs ( udphdr->dest_port ) );
262
-	rc = 0;
270
+	/* Pass data to application */
271
+	rc = conn->udp_op->newdata ( conn, pkb->data, pkb_len ( pkb ),
272
+				     st_src, st_dest );
263 273
 
264 274
  done:
265 275
 	free_pkb ( pkb );

Loading…
Cancel
Save