Browse Source

Added fragment reassembly code

tags/v0.9.3
Nikhil Chandru Rao 18 years ago
parent
commit
5f651f8622
3 changed files with 155 additions and 15 deletions
  1. 23
    0
      src/include/gpxe/ip.h
  2. 122
    1
      src/net/ipv4.c
  3. 10
    14
      src/net/udp.c

+ 23
- 0
src/include/gpxe/ip.h View File

@@ -8,18 +8,25 @@
8 8
  */
9 9
 
10 10
 #include <ip.h>
11
+#include <gpxe/retry.h>
11 12
 
12 13
 /* IP constants */
13 14
 
14 15
 #define IP_VER		4
15 16
 #define IP_MASK_VER	0xf0
16 17
 #define IP_MASK_HLEN 	0x0f
18
+#define IP_MASK_OFFSET	0x1fff
19
+#define IP_MASK_DONOTFRAG	0x4000
20
+#define IP_MASK_MOREFRAGS	0x2000
17 21
 #define IP_PSHLEN 	12
18 22
 
19 23
 /* IP header defaults */
20 24
 #define IP_TOS		0
21 25
 #define IP_TTL		64
22 26
 
27
+#define IP_FRAG_PKB_SIZE	1500
28
+#define IP_FRAG_TIMEOUT		50
29
+
23 30
 /* IP4 pseudo header */
24 31
 struct ipv4_pseudo_header {
25 32
 	struct in_addr src;
@@ -29,6 +36,22 @@ struct ipv4_pseudo_header {
29 36
 	uint16_t len;
30 37
 };
31 38
 
39
+/* Fragment reassembly buffer */
40
+struct frag_buffer {
41
+	/* Identification number */
42
+	uint16_t ident;
43
+	/* Source network address */
44
+	struct in_addr src;
45
+	/* Destination network address */
46
+	struct in_addr dest;
47
+	/* Reassembled packet buffer */
48
+	struct pk_buff *frag_pkb;
49
+	/* Reassembly timer */
50
+	struct retry_timer frag_timer;
51
+	/* List of fragment reassembly buffers */
52
+	struct list_head list;
53
+};
54
+
32 55
 struct pk_buff;
33 56
 struct net_device;
34 57
 struct net_protocol;

+ 122
- 1
src/net/ipv4.c View File

@@ -47,6 +47,9 @@ struct ipv4_miniroute {
47 47
 /** List of IPv4 miniroutes */
48 48
 static LIST_HEAD ( miniroutes );
49 49
 
50
+/** List of fragment reassembly buffers */
51
+static LIST_HEAD ( frag_buffers );
52
+
50 53
 /**
51 54
  * Add IPv4 interface
52 55
  *
@@ -119,6 +122,110 @@ static void ipv4_dump ( struct iphdr *iphdr __unused ) {
119 122
 	DBG ( "\tDestination = %s\n", inet_ntoa ( iphdr->dest ) );
120 123
 }
121 124
 
125
+/**
126
+ * Fragment reassembly counter timeout
127
+ *
128
+ * @v timer	Retry timer
129
+ * @v over	If asserted, the timer is greater than @c MAX_TIMEOUT 
130
+ */
131
+void ipv4_frag_expired ( struct retry_timer *timer __unused , int over ) {
132
+	if ( over ) {
133
+		DBG ( "Fragment reassembly timeout" );
134
+		/* Free the fragment buffer */
135
+	}
136
+}
137
+
138
+/**
139
+ * Free fragment buffer
140
+ *
141
+ * @v fragbug	Fragment buffer
142
+ */
143
+void free_fragbuf ( struct frag_buffer *fragbuf ) {
144
+	if ( fragbuf ) {
145
+		free_dma ( fragbuf, sizeof ( *fragbuf ) );
146
+	}
147
+}
148
+
149
+/**
150
+ * Fragment reassembler
151
+ *
152
+ * @v pkb		Packet buffer, fragment of the datagram
153
+ * @ret frag_pkb	Reassembled packet, or NULL
154
+ */
155
+struct pk_buff * ipv4_reassemble ( struct pk_buff * pkb ) {
156
+	struct iphdr *iphdr = pkb->data;
157
+	struct frag_buffer *fragbuf;
158
+	
159
+	/**
160
+	 * Check if the fragment belongs to any fragment series
161
+	 */
162
+	list_for_each_entry ( fragbuf, &frag_buffers, list ) {
163
+		if ( fragbuf->ident == iphdr->ident &&
164
+		     fragbuf->src.s_addr == iphdr->src.s_addr ) {
165
+			/**
166
+			 * Check if the packet is the expected fragment
167
+			 * 
168
+			 * The offset of the new packet must be equal to the
169
+			 * length of the data accumulated so far (the length of
170
+			 * the reassembled packet buffer
171
+			 */
172
+			if ( pkb_len ( fragbuf->frag_pkb ) == 
173
+			      ( iphdr->frags & IP_MASK_OFFSET ) ) {
174
+				/**
175
+				 * Append the contents of the fragment to the
176
+				 * reassembled packet buffer
177
+				 */
178
+				pkb_pull ( pkb, sizeof ( *iphdr ) );
179
+				memcpy ( pkb_put ( fragbuf->frag_pkb,
180
+							pkb_len ( pkb ) ),
181
+					 pkb->data, pkb_len ( pkb ) );
182
+				free_pkb ( pkb );
183
+
184
+				/** Check if the fragment series is over */
185
+				if ( !iphdr->frags & IP_MASK_MOREFRAGS ) {
186
+					pkb = fragbuf->frag_pkb;
187
+					free_fragbuf ( fragbuf );
188
+					return pkb;
189
+				}
190
+
191
+			} else {
192
+				/* Discard the fragment series */
193
+				free_fragbuf ( fragbuf );
194
+				free_pkb ( pkb );
195
+			}
196
+			return NULL;
197
+		}
198
+	}
199
+	
200
+	/** Check if the fragment is the first in the fragment series */
201
+	if ( iphdr->frags & IP_MASK_MOREFRAGS &&
202
+			( ( iphdr->frags & IP_MASK_OFFSET ) == 0 ) ) {
203
+	
204
+		/** Create a new fragment buffer */
205
+		fragbuf = ( struct frag_buffer* ) malloc ( sizeof( *fragbuf ) );
206
+		fragbuf->ident = iphdr->ident;
207
+		fragbuf->src = iphdr->src;
208
+
209
+		/* Set up the reassembly packet buffer */
210
+		fragbuf->frag_pkb = alloc_pkb ( IP_FRAG_PKB_SIZE );
211
+		pkb_pull ( pkb, sizeof ( *iphdr ) );
212
+		memcpy ( pkb_put ( fragbuf->frag_pkb, pkb_len ( pkb ) ),
213
+			 pkb->data, pkb_len ( pkb ) );
214
+		free_pkb ( pkb );
215
+
216
+		/* Set the reassembly timer */
217
+		fragbuf->frag_timer.timeout = IP_FRAG_TIMEOUT;
218
+		fragbuf->frag_timer.expired = ipv4_frag_expired;
219
+		start_timer ( &fragbuf->frag_timer );
220
+
221
+		/* Add the fragment buffer to the list of fragment buffers */
222
+		list_add ( &fragbuf->list, &frag_buffers );
223
+	}
224
+	
225
+	return NULL;
226
+}
227
+
228
+
122 229
 /**
123 230
  * Complete the transport-layer checksum
124 231
  *
@@ -294,7 +401,9 @@ int ipv4_tx ( struct pk_buff *pkb, struct tcpip_protocol *tcpip,
294 401
 	}
295 402
 
296 403
 	/* Calculate the transport layer checksum */
297
-	ipv4_tx_csum ( pkb, tcpip );
404
+	if ( tcpip->csum_offset > 0 ) {
405
+		ipv4_tx_csum ( pkb, tcpip );
406
+	}
298 407
 
299 408
 	/* Calculate header checksum, in network byte order */
300 409
 	iphdr->chksum = 0;
@@ -416,6 +525,18 @@ void ipv4_rx ( struct pk_buff *pkb, struct net_device *netdev __unused,
416 525
 	if ( ( chksum = ipv4_rx_csum ( pkb, iphdr->protocol ) )	!= 0xffff ) {
417 526
 		DBG ( "Bad checksum %x\n", chksum );
418 527
 	}
528
+	/* Fragment reassembly */
529
+	if ( iphdr->frags & IP_MASK_MOREFRAGS || 
530
+		( !iphdr->frags & IP_MASK_MOREFRAGS &&
531
+			iphdr->frags & IP_MASK_OFFSET != 0 ) ) {
532
+		/* Pass the fragment to the reassembler ipv4_ressable() which
533
+		 * either returns a fully reassembled packet buffer or NULL.
534
+		 */
535
+		pkb = ipv4_reassemble ( pkb );
536
+		if ( !pkb ) {
537
+			return;
538
+		}
539
+	}
419 540
 
420 541
 	/* To reduce code size, the following functions are not implemented:
421 542
 	 * 1. Check the destination address

+ 10
- 14
src/net/udp.c View File

@@ -22,19 +22,14 @@ static inline void copy_sockaddr ( struct sockaddr *source, struct sockaddr *des
22 22
 	memcpy ( dest, source, sizeof ( *dest ) );
23 23
 }
24 24
 
25
-static inline uint16_t dest_port ( struct sockaddr *sock, uint16_t *dest ) {
25
+static inline uint16_t * dest_port ( struct sockaddr *sock ) {
26 26
 	switch ( sock->sa_family ) {
27 27
 	case AF_INET:
28
-		dest = &sock->sin.sin_port;
29
-		break;
28
+		return &sock->sin.sin_port;
30 29
 	case AF_INET6:
31
-		dest = &sock->sin6.sin6_port;
32
-		break;
33
-	default:
34
-		DBG ( "Network family %d not supported\n", sock->sa_family );
35
-		return -EAFNOSUPPORT;
30
+		return &sock->sin6.sin6_port;
36 31
 	}
37
-	return 0;
32
+	return NULL;
38 33
 }
39 34
 
40 35
 /**
@@ -49,7 +44,7 @@ void udp_dump ( struct udp_header *udphdr ) {
49 44
 	DBG ( "\tSource Port = %d\n", ntohs ( udphdr->source_port ) );
50 45
 	DBG ( "\tDestination Port = %d\n", ntohs ( udphdr->dest_port ) );
51 46
 	DBG ( "\tLength = %d\n", ntohs ( udphdr->len ) );
52
-	DBG ( "\tChecksum = %d\n", ntohs ( udphdr->chksum ) );
47
+	DBG ( "\tChecksum = %x\n", ntohs ( udphdr->chksum ) );
53 48
 	DBG ( "\tChecksum located at %#x\n", &udphdr->chksum );
54 49
 }
55 50
 
@@ -139,11 +134,12 @@ int udp_send ( struct udp_connection *conn, const void *data, size_t len ) {
139 134
 	 * sending it over the network
140 135
 	 */
141 136
 	udphdr = pkb_push ( conn->tx_pkb, sizeof ( *udphdr ) );
142
-	if ( (rc = dest_port ( sock, dest ) ) != 0 ) {
143
-		return rc;
137
+	if ( (dest = dest_port ( sock ) ) == NULL ) {
138
+		DBG ( "Network family %d not supported\n", sock->sa_family );
139
+		return -EAFNOSUPPORT;
144 140
 	}
145
-	udphdr->dest_port = htons ( *dest );
146
-	udphdr->source_port = htons ( conn->local_port );
141
+	udphdr->dest_port = *dest;
142
+	udphdr->source_port = conn->local_port;
147 143
 	udphdr->len = htons ( pkb_len ( conn->tx_pkb ) );
148 144
 	udphdr->chksum = htons ( calc_chksum ( udphdr, sizeof ( *udphdr ) ) );
149 145
 

Loading…
Cancel
Save