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
  */
8
  */
9
 
9
 
10
 #include <ip.h>
10
 #include <ip.h>
11
+#include <gpxe/retry.h>
11
 
12
 
12
 /* IP constants */
13
 /* IP constants */
13
 
14
 
14
 #define IP_VER		4
15
 #define IP_VER		4
15
 #define IP_MASK_VER	0xf0
16
 #define IP_MASK_VER	0xf0
16
 #define IP_MASK_HLEN 	0x0f
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
 #define IP_PSHLEN 	12
21
 #define IP_PSHLEN 	12
18
 
22
 
19
 /* IP header defaults */
23
 /* IP header defaults */
20
 #define IP_TOS		0
24
 #define IP_TOS		0
21
 #define IP_TTL		64
25
 #define IP_TTL		64
22
 
26
 
27
+#define IP_FRAG_PKB_SIZE	1500
28
+#define IP_FRAG_TIMEOUT		50
29
+
23
 /* IP4 pseudo header */
30
 /* IP4 pseudo header */
24
 struct ipv4_pseudo_header {
31
 struct ipv4_pseudo_header {
25
 	struct in_addr src;
32
 	struct in_addr src;
29
 	uint16_t len;
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
 struct pk_buff;
55
 struct pk_buff;
33
 struct net_device;
56
 struct net_device;
34
 struct net_protocol;
57
 struct net_protocol;

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

47
 /** List of IPv4 miniroutes */
47
 /** List of IPv4 miniroutes */
48
 static LIST_HEAD ( miniroutes );
48
 static LIST_HEAD ( miniroutes );
49
 
49
 
50
+/** List of fragment reassembly buffers */
51
+static LIST_HEAD ( frag_buffers );
52
+
50
 /**
53
 /**
51
  * Add IPv4 interface
54
  * Add IPv4 interface
52
  *
55
  *
119
 	DBG ( "\tDestination = %s\n", inet_ntoa ( iphdr->dest ) );
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
  * Complete the transport-layer checksum
230
  * Complete the transport-layer checksum
124
  *
231
  *
294
 	}
401
 	}
295
 
402
 
296
 	/* Calculate the transport layer checksum */
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
 	/* Calculate header checksum, in network byte order */
408
 	/* Calculate header checksum, in network byte order */
300
 	iphdr->chksum = 0;
409
 	iphdr->chksum = 0;
416
 	if ( ( chksum = ipv4_rx_csum ( pkb, iphdr->protocol ) )	!= 0xffff ) {
525
 	if ( ( chksum = ipv4_rx_csum ( pkb, iphdr->protocol ) )	!= 0xffff ) {
417
 		DBG ( "Bad checksum %x\n", chksum );
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
 	/* To reduce code size, the following functions are not implemented:
541
 	/* To reduce code size, the following functions are not implemented:
421
 	 * 1. Check the destination address
542
 	 * 1. Check the destination address

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

22
 	memcpy ( dest, source, sizeof ( *dest ) );
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
 	switch ( sock->sa_family ) {
26
 	switch ( sock->sa_family ) {
27
 	case AF_INET:
27
 	case AF_INET:
28
-		dest = &sock->sin.sin_port;
29
-		break;
28
+		return &sock->sin.sin_port;
30
 	case AF_INET6:
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
 	DBG ( "\tSource Port = %d\n", ntohs ( udphdr->source_port ) );
44
 	DBG ( "\tSource Port = %d\n", ntohs ( udphdr->source_port ) );
50
 	DBG ( "\tDestination Port = %d\n", ntohs ( udphdr->dest_port ) );
45
 	DBG ( "\tDestination Port = %d\n", ntohs ( udphdr->dest_port ) );
51
 	DBG ( "\tLength = %d\n", ntohs ( udphdr->len ) );
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
 	DBG ( "\tChecksum located at %#x\n", &udphdr->chksum );
48
 	DBG ( "\tChecksum located at %#x\n", &udphdr->chksum );
54
 }
49
 }
55
 
50
 
139
 	 * sending it over the network
134
 	 * sending it over the network
140
 	 */
135
 	 */
141
 	udphdr = pkb_push ( conn->tx_pkb, sizeof ( *udphdr ) );
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
 	udphdr->len = htons ( pkb_len ( conn->tx_pkb ) );
143
 	udphdr->len = htons ( pkb_len ( conn->tx_pkb ) );
148
 	udphdr->chksum = htons ( calc_chksum ( udphdr, sizeof ( *udphdr ) ) );
144
 	udphdr->chksum = htons ( calc_chksum ( udphdr, sizeof ( *udphdr ) ) );
149
 
145
 

Loading…
Cancel
Save