|
@@ -101,16 +101,29 @@ void del_ipv4_address ( struct net_device *netdev ) {
|
101
|
101
|
}
|
102
|
102
|
|
103
|
103
|
/**
|
104
|
|
- * Dump IPv4 packet header
|
|
104
|
+ * Perform IPv4 routing
|
105
|
105
|
*
|
106
|
|
- * @v iphdr IPv4 header
|
|
106
|
+ * @v dest Final destination address
|
|
107
|
+ * @ret dest Next hop destination address
|
|
108
|
+ * @ret miniroute Routing table entry to use, or NULL if no route
|
107
|
109
|
*/
|
108
|
|
-static void ipv4_dump ( struct iphdr *iphdr __unused ) {
|
|
110
|
+static struct ipv4_miniroute * ipv4_route ( struct in_addr *dest ) {
|
|
111
|
+ struct ipv4_miniroute *miniroute;
|
|
112
|
+ int local;
|
|
113
|
+ int has_gw;
|
109
|
114
|
|
110
|
|
- DBG ( "IP4 %p transmitting %p+%d ident %d protocol %d header-csum %x\n",
|
111
|
|
- &ipv4_protocol, iphdr, ntohs ( iphdr->len ), ntohs ( iphdr->ident ),
|
112
|
|
- iphdr->protocol, ntohs ( iphdr->chksum ) );
|
113
|
|
- DBG ( "src %s, dest %s\n", inet_ntoa ( iphdr->src ), inet_ntoa ( iphdr->dest ) );
|
|
115
|
+ list_for_each_entry ( miniroute, &miniroutes, list ) {
|
|
116
|
+ local = ( ( ( dest->s_addr ^ miniroute->address.s_addr )
|
|
117
|
+ & miniroute->netmask.s_addr ) == 0 );
|
|
118
|
+ has_gw = ( miniroute->gateway.s_addr != INADDR_NONE );
|
|
119
|
+ if ( local || has_gw ) {
|
|
120
|
+ if ( ! local )
|
|
121
|
+ *dest = miniroute->gateway;
|
|
122
|
+ return miniroute;
|
|
123
|
+ }
|
|
124
|
+ }
|
|
125
|
+
|
|
126
|
+ return NULL;
|
114
|
127
|
}
|
115
|
128
|
|
116
|
129
|
/**
|
|
@@ -280,59 +293,39 @@ static int ipv4_tx ( struct pk_buff *pkb,
|
280
|
293
|
int rc;
|
281
|
294
|
|
282
|
295
|
/* Fill up the IP header, except source address */
|
283
|
|
- iphdr->verhdrlen = ( IP_VER << 4 ) | ( sizeof ( *iphdr ) / 4 );
|
|
296
|
+ iphdr->verhdrlen = ( ( IP_VER << 4 ) | ( sizeof ( *iphdr ) / 4 ) );
|
284
|
297
|
iphdr->service = IP_TOS;
|
285
|
298
|
iphdr->len = htons ( pkb_len ( pkb ) );
|
286
|
|
- iphdr->ident = htons ( next_ident++ );
|
|
299
|
+ iphdr->ident = htons ( ++next_ident );
|
287
|
300
|
iphdr->frags = 0;
|
288
|
301
|
iphdr->ttl = IP_TTL;
|
289
|
302
|
iphdr->protocol = tcpip_protocol->tcpip_proto;
|
290
|
|
-
|
291
|
|
- /* Copy destination address */
|
|
303
|
+ iphdr->chksum = 0;
|
292
|
304
|
iphdr->dest = sin_dest->sin_addr;
|
293
|
305
|
|
294
|
|
- /**
|
295
|
|
- * All fields in the IP header filled in except the source network
|
296
|
|
- * address (which requires routing) and the header checksum (which
|
297
|
|
- * requires the source network address). As the pseudo header requires
|
298
|
|
- * the source address as well and the transport-layer checksum is
|
299
|
|
- * updated after routing.
|
300
|
|
- */
|
301
|
|
-
|
302
|
306
|
/* Use routing table to identify next hop and transmitting netdev */
|
303
|
307
|
next_hop = iphdr->dest;
|
304
|
|
- list_for_each_entry ( miniroute, &miniroutes, list ) {
|
305
|
|
- int local, has_gw;
|
306
|
|
-
|
307
|
|
- local = ( ( ( iphdr->dest.s_addr ^ miniroute->address.s_addr )
|
308
|
|
- & miniroute->netmask.s_addr ) == 0 );
|
309
|
|
- has_gw = ( miniroute->gateway.s_addr != INADDR_NONE );
|
310
|
|
- if ( local || has_gw ) {
|
311
|
|
- netdev = miniroute->netdev;
|
312
|
|
- iphdr->src = miniroute->address;
|
313
|
|
- if ( ! local )
|
314
|
|
- next_hop = miniroute->gateway;
|
315
|
|
- break;
|
316
|
|
- }
|
317
|
|
- }
|
318
|
|
- /* Abort if no network device identified */
|
319
|
|
- if ( ! netdev ) {
|
|
308
|
+ miniroute = ipv4_route ( &next_hop );
|
|
309
|
+ if ( ! miniroute ) {
|
320
|
310
|
DBG ( "No route to %s\n", inet_ntoa ( iphdr->dest ) );
|
321
|
311
|
rc = -EHOSTUNREACH;
|
322
|
312
|
goto err;
|
323
|
313
|
}
|
|
314
|
+ iphdr->src = miniroute->address;
|
|
315
|
+ netdev = miniroute->netdev;
|
324
|
316
|
|
325
|
317
|
/* Calculate the transport layer checksum */
|
326
|
|
- if ( tcpip_protocol->csum_offset > 0 ) {
|
|
318
|
+ if ( tcpip_protocol->csum_offset > 0 )
|
327
|
319
|
ipv4_tx_csum ( pkb, tcpip_protocol );
|
328
|
|
- }
|
329
|
320
|
|
330
|
321
|
/* Calculate header checksum, in network byte order */
|
331
|
|
- iphdr->chksum = 0;
|
332
|
322
|
iphdr->chksum = tcpip_chksum ( iphdr, sizeof ( *iphdr ) );
|
333
|
323
|
|
334
|
324
|
/* Print IP4 header for debugging */
|
335
|
|
- ipv4_dump ( iphdr );
|
|
325
|
+ DBG ( "IPv4 TX %s->", inet_ntoa ( iphdr->src ) );
|
|
326
|
+ DBG ( "%s len %d proto %d id %04x csum %04x\n",
|
|
327
|
+ inet_ntoa ( iphdr->dest ), ntohs ( iphdr->len ), iphdr->protocol,
|
|
328
|
+ ntohs ( iphdr->ident ), ntohs ( iphdr->chksum ) );
|
336
|
329
|
|
337
|
330
|
/* Determine link-layer destination address */
|
338
|
331
|
if ( next_hop.s_addr == INADDR_BROADCAST ) {
|
|
@@ -394,7 +387,10 @@ static int ipv4_rx ( struct pk_buff *pkb, struct net_device *netdev __unused,
|
394
|
387
|
}
|
395
|
388
|
|
396
|
389
|
/* Print IP4 header for debugging */
|
397
|
|
- ipv4_dump ( iphdr );
|
|
390
|
+ DBG ( "IPv4 RX %s<-", inet_ntoa ( iphdr->dest ) );
|
|
391
|
+ DBG ( "%s len %d proto %d id %04x csum %04x\n",
|
|
392
|
+ inet_ntoa ( iphdr->src ), ntohs ( iphdr->len ), iphdr->protocol,
|
|
393
|
+ ntohs ( iphdr->ident ), ntohs ( iphdr->chksum ) );
|
398
|
394
|
|
399
|
395
|
/* Validate version and header length */
|
400
|
396
|
if ( iphdr->verhdrlen != 0x45 ) {
|
|
@@ -414,8 +410,8 @@ static int ipv4_rx ( struct pk_buff *pkb, struct net_device *netdev __unused,
|
414
|
410
|
DBG ( "Bad checksum %x\n", chksum );
|
415
|
411
|
}
|
416
|
412
|
/* Fragment reassembly */
|
417
|
|
- if ( ( iphdr->frags & IP_MASK_MOREFRAGS ) ||
|
418
|
|
- ( ( iphdr->frags & IP_MASK_OFFSET ) != 0 ) ) {
|
|
413
|
+ if ( ( iphdr->frags & htons ( IP_MASK_MOREFRAGS ) ) ||
|
|
414
|
+ ( ( iphdr->frags & htons ( IP_MASK_OFFSET ) ) != 0 ) ) {
|
419
|
415
|
/* Pass the fragment to the reassembler ipv4_ressable() which
|
420
|
416
|
* either returns a fully reassembled packet buffer or NULL.
|
421
|
417
|
*/
|