|
@@ -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
|