make siit work with 2.6.23
[openwrt/svn-archive/archive.git] / package / siit / src / siit.c
1 /*
2 * siit.c: the Stateless IP/ICMP Translator (SIIT) module for Linux.
3 *
4 *
5 */
6
7 #include <linux/autoconf.h>
8 #include <linux/module.h>
9 #include <linux/version.h>
10 #include <linux/sched.h>
11 #include <linux/kernel.h> /* printk() */
12 #include <linux/slab.h>
13
14 #include <linux/errno.h> /* error codes */
15 #include <linux/types.h> /* size_t */
16 #include <linux/interrupt.h> /* mark_bh */
17 #include <linux/random.h>
18 #include <linux/in.h>
19 #include <linux/netdevice.h> /* struct device, and other headers */
20 #include <linux/etherdevice.h> /* eth_type_trans */
21 #include <net/ip.h> /* struct iphdr */
22 #include <net/icmp.h> /* struct icmphdr */
23 #include <net/ipv6.h>
24 #include <net/udp.h>
25 #include <linux/skbuff.h>
26 #include <linux/in6.h>
27 #include <linux/init.h>
28 #include <asm/uaccess.h>
29 #include <asm/checksum.h>
30
31 #include <linux/in6.h>
32 #include "siit.h"
33
34 MODULE_AUTHOR("Dmitriy Moscalev, Grigory Klyuchnikov, Felix Fietkau");
35
36 /*
37 * If tos_ignore_flag != 0, we don't copy TOS and Traffic Class
38 * from origin paket and set it to 0
39 */
40 int tos_ignore_flag = 0;
41
42 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
43 static struct net_device_stats *
44 siit_get_stats(struct net_device *dev)
45 {
46 return netdev_priv(dev);
47 }
48
49 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
50 static inline void
51 skb_reset_mac_header(struct sk_buff *skb)
52 {
53 skb->mac.raw=skb->data;
54 }
55 #endif
56
57 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
58 static inline void random_ether_addr(u8 *addr)
59 {
60 get_random_bytes (addr, ETH_ALEN);
61 addr [0] &= 0xfe; /* clear multicast bit */
62 addr [0] |= 0x02; /* set local assignment bit (IEEE802) */
63 }
64 #endif
65
66 #define siit_stats(_dev) ((struct net_device_stats *)netdev_priv(_dev))
67 #else
68 #define siit_stats(_dev) (&(_dev)->stats)
69 #endif
70
71 /*
72 * The Utility stuff
73 */
74
75 #ifdef SIIT_DEBUG
76 /* print dump bytes (data point data area sizeof len and message
77 * before dump.
78 */
79 static int siit_print_dump(char *data, int len, char *message)
80 {
81 int i;
82 int j = 0, k = 1;
83
84 len = len > BUFF_SIZE ? BUFF_SIZE : len;
85 printk("%s:\n", message);
86 for (i=0; i < len; i++, k++) {
87 if( i == len-1 || k == 16) {
88 printk("%02x\n", (~(~0 << 8) & *(data+i)));
89 j = 0;
90 k = 0;
91 }
92 else if (j) {
93 printk("%02x ", (~(~0 << 8) & *(data+i)));
94 j--;
95 }
96 else {
97 printk("%02x", (~(~0 << 8) & *(data+i)));
98 j++;
99 }
100 }
101 return 0;
102 }
103 #endif
104
105 /*
106 * Open and close
107 */
108 static int siit_open(struct net_device *dev)
109 {
110 netif_start_queue(dev);
111 return 0;
112 }
113
114
115 static int siit_release(struct net_device *dev)
116 {
117 netif_stop_queue(dev); /* can't transmit any more */
118 return 0;
119 }
120
121 /*
122 * Translation IPv4 to IPv6 stuff
123 *
124 * ip4_ip6 (src, len, dst, include_flag)
125 *
126 * where
127 * src - buffer with original IPv4 packet,
128 * len - size of original packet,
129 * dst - new buffer for IPv6 packet,
130 * include_flag - if = 1, dst point to IPv4 packet that is ICMP error
131 * included IP packet, else = 0
132 */
133
134 static int ip4_ip6(char *src, int len, char *dst, int include_flag)
135 {
136 struct iphdr *ih4 = (struct iphdr *) src; /* point to current IPv4 header struct */
137 struct icmphdr *icmp_hdr; /* point to current ICMPv4 header struct */
138 struct udphdr *udp_hdr; /* point to current IPv4 UDP header struct */
139
140 struct ipv6hdr *ih6 = (struct ipv6hdr *) dst; /* point to current IPv6 header struct */
141 struct frag_hdr *ih6_frag = (struct frag_hdr *)(dst+sizeof(struct ipv6hdr));
142 /* point to current IPv6 fragment header struct */
143 struct icmp6hdr *icmp6_hdr; /* point to current ICMPv6 header */
144
145 int hdr_len = (int)(ih4->ihl * 4); /* IPv4 header length */
146 int icmp_len; /* ICMPv4 packet length */
147 int plen; /* payload length */
148
149 unsigned int csum; /* need to calculate ICMPv6 and UDP checksum */
150 int fl_csum = 0; /* flag to calculate UDP checksum */
151 int icmperr = 1; /* flag to indicate ICMP error message and to need
152 translate ICMP included IP packet */
153 int fr_flag = 0; /* fragment flag, if = 0 - don't add
154 fragment header */
155 __u16 new_tot_len; /* need to calculate IPv6 total length */
156 __u8 new_nexthdr; /* next header code */
157 __u16 icmp_ptr = 0; /* Pointer field in ICMP_PARAMETERPROB */
158
159 #ifdef SIIT_DEBUG /* print IPv4 header dump */
160 siit_print_dump(src, hdr_len, "siit: ip4_ip6() (in) ip4 header dump");
161 #endif
162
163 /* If DF == 1 && MF == 0 && Fragment Offset == 0
164 * or this packet is ICMP included IP packet
165 * we don't need fragment header */
166 if (ntohs(ih4->frag_off) == IP_DF || include_flag ) {
167 /* not fragment and we need not to add Fragment
168 * Header to IPv6 packet. */
169 /* total length = total length from IPv4 packet */
170 new_tot_len = ntohs(ih4->tot_len);
171
172 if (ih4->protocol == IPPROTO_ICMP)
173 new_nexthdr = NEXTHDR_ICMP;
174 else
175 new_nexthdr = ih4->protocol;
176 }
177 else {
178 /* need to add Fragment Header */
179 fr_flag = 1;
180 /* total length = total length from IPv4 packet +
181 length of Fragment Header */
182 new_tot_len = ntohs(ih4->tot_len) + sizeof(struct frag_hdr);
183 /* IPv6 Header NextHeader = NEXTHDR_FRAGMENT */
184 new_nexthdr = NEXTHDR_FRAGMENT;
185 /* Fragment Header NextHeader copy from IPv4 packet */
186 if (ih4->protocol == IPPROTO_ICMP)
187 ih6_frag->nexthdr = NEXTHDR_ICMP;
188 else
189 ih6_frag->nexthdr = ih4->protocol;
190
191 /* copy frag offset from IPv4 packet */
192 ih6_frag->frag_off = htons((ntohs(ih4->frag_off) & IP_OFFSET) << 3);
193 /* copy MF flag from IPv4 packet */
194 ih6_frag->frag_off = htons((ntohs(ih6_frag->frag_off) |
195 ((ntohs(ih4->frag_off) & IP_MF) >> 13)));
196 /* copy Identification field from IPv4 packet */
197 ih6_frag->identification = htonl(ntohs(ih4->id));
198 /* reserved field initialized to zero */
199 ih6_frag->reserved = 0;
200 }
201
202 /* Form rest IPv6 fields */
203
204 /*
205 * At this point we need to add checking of unxpired source
206 * route optin and if it is, send ICMPv4 "destination
207 * unreacheble/source route failes" Type 3/Code 5 and
208 * drop packet. (NOT RELEASED YET)
209 */
210
211 /* IP version = 6 */
212 ih6->version = 6;
213
214 if (tos_ignore_flag) {
215 ih6->priority = 0;
216 ih6->flow_lbl[0] = 0;
217 } else {
218 ih6->priority = (ih4->tos & 0xf0) >> 4;
219 ih6->flow_lbl[0] = (ih4->tos & 0x0f) << 4;
220 }
221 ih6->flow_lbl[1] = 0;
222 ih6->flow_lbl[2] = 0;
223
224 /* Hop Limit = IPv4 TTL */
225 ih6->hop_limit = ih4->ttl;
226
227 /* Translate source destination addresses,
228 for IPv6 host it's IPv4-translated IPv6 address,
229 for IPv4 host it's IPv4-mapped IPv6 address
230
231 !!WARNING!! Instead IPv4-mapped IPv6 addresses we use addreesses
232 with unused prefix ::ffff:ffff:0:0/96, because KAME implementation
233 doesn't support IPv4-mapped addresses in IPv6 packets and discard them.
234
235 */
236
237 if (include_flag) {
238 /*
239 It's ICMP included IP packet and there is a diffirence
240 in src/dst addresses then src/dst in normal direction
241 */
242
243 /*
244 Source address
245 is IPv4-translated IPv6 address because packet traveled
246 from IPv6 to IPv4 area
247 */
248 ih6->saddr.in6_u.u6_addr32[0] = 0;
249 ih6->saddr.in6_u.u6_addr32[1] = 0;
250 ih6->saddr.in6_u.u6_addr32[2] = htonl(TRANSLATED_PREFIX); /* to network order bytes */
251 ih6->saddr.in6_u.u6_addr32[3] = ih4->saddr;
252
253 /*
254 Destination address
255 is IPv4-mapped address (but it's not IPv4- mapped, we use
256 prefix ::ffff:ffff:0:0/96
257 */
258 ih6->daddr.in6_u.u6_addr32[0] = 0;
259 ih6->daddr.in6_u.u6_addr32[1] = 0;
260 ih6->daddr.in6_u.u6_addr32[2] = htonl(MAPPED_PREFIX); /* to network order bytes */
261 ih6->daddr.in6_u.u6_addr32[3] = ih4->daddr;
262 }
263 else {
264
265 /*
266 This is normal case (packet isn't included IP packet)
267
268 Source address
269 is IPv4-mapped address (but it's not IPv4- mapped, we use
270 prefix ::ffff:ffff:0:0/96)
271 */
272 ih6->saddr.in6_u.u6_addr32[0] = 0;
273 ih6->saddr.in6_u.u6_addr32[1] = 0;
274 ih6->saddr.in6_u.u6_addr32[2] = htonl(MAPPED_PREFIX); /* to network order bytes */
275 ih6->saddr.in6_u.u6_addr32[3] = ih4->saddr;
276
277 /* Destination address
278 is is IPv4-translated IPv6 address
279 */
280 ih6->daddr.in6_u.u6_addr32[0] = 0;
281 ih6->daddr.in6_u.u6_addr32[1] = 0;
282 ih6->daddr.in6_u.u6_addr32[2] = htonl(TRANSLATED_PREFIX); /* to network order bytes */
283 ih6->daddr.in6_u.u6_addr32[3] = ih4->daddr;
284 }
285
286 /* Payload Length */
287 plen = new_tot_len - hdr_len; /* Payload length = IPv4 total len - IPv4 header len */
288 ih6->payload_len = htons(plen);
289
290 /* Next Header */
291 ih6->nexthdr = new_nexthdr; /* Next Header */
292
293 /* Process ICMP protocols data */
294
295 switch (ih4->protocol) {
296 case IPPROTO_ICMP:
297 if ( (ntohs(ih4->frag_off) & IP_OFFSET) != 0 || (ntohs(ih4->frag_off) & IP_MF) != 0 ) {
298 PDEBUG("ip4_ip6(): don't translate ICMPv4 fragments - packet dropped.\n");
299 return -1;
300 }
301
302 icmp_hdr = (struct icmphdr *) (src+hdr_len); /* point to ICMPv4 header */
303 csum = 0;
304 icmp_len = ntohs(ih4->tot_len) - hdr_len; /* ICMPv4 packet length */
305 icmp6_hdr = (struct icmp6hdr *)(dst+sizeof(struct ipv6hdr)
306 +fr_flag*sizeof(struct frag_hdr)); /* point to ICMPv6 header */
307
308 if (include_flag) {
309 /* ICMPv4 packet cannot be included in ICMPv4 Error message */
310 /* !!! May be it's WRONG !!! ICMPv4 QUERY packet can be included
311 in ICMPv4 Error message */
312 PDEBUG("ip4_ip6(): It's included ICMPv4 in ICMPv4 Error message - packet dropped.\n");
313 return -1;
314 }
315
316 /* Check ICMPv4 Type field */
317 switch (icmp_hdr->type) {
318 /* ICMP Error messages */
319 /* Destination Unreachable (Type 3) */
320 case ICMP_DEST_UNREACH:
321 icmp6_hdr->icmp6_type = ICMPV6_DEST_UNREACH; /* to Type 1 */
322 icmp6_hdr->icmp6_unused = 0;
323 switch (icmp_hdr->code)
324 {
325 case ICMP_NET_UNREACH: /* Code 0 */
326 case ICMP_HOST_UNREACH: /* Code 1 */
327 case ICMP_SR_FAILED: /* Code 5 */
328 case ICMP_NET_UNKNOWN: /* Code 6 */
329 case ICMP_HOST_UNKNOWN: /* Code 7 */
330 case ICMP_HOST_ISOLATED: /* Code 8 */
331 case ICMP_NET_UNR_TOS: /* Code 11 */
332 case ICMP_HOST_UNR_TOS: /* Code 12 */
333 icmp6_hdr->icmp6_code = ICMPV6_NOROUTE; /* to Code 0 */
334 break;
335 case ICMP_PROT_UNREACH: /* Code 2 */
336 icmp6_hdr->icmp6_type = ICMPV6_PARAMPROB; /* to Type 4 */
337 icmp6_hdr->icmp6_code = ICMPV6_UNK_NEXTHDR; /* to Code 1 */
338 /* Set pointer filed to 6, it's octet offset IPv6 Next Header field */
339 icmp6_hdr->icmp6_pointer = htonl(6);
340 break;
341 case ICMP_PORT_UNREACH: /* Code 3 */
342 icmp6_hdr->icmp6_code = ICMPV6_PORT_UNREACH; /* to Code 4 */
343 break;
344 case ICMP_FRAG_NEEDED: /* Code 4 */
345 icmp6_hdr->icmp6_type = ICMPV6_PKT_TOOBIG; /* to Type 2 */
346 icmp6_hdr->icmp6_code = 0;
347 /* Correct MTU */
348 if (icmp_hdr->un.frag.mtu == 0)
349 /* we use minimum MTU for IPv4 PMTUv4 RFC1191, section 5;
350 IPv6 implementation wouldn't accept Path MTU < 1280,
351 but it records info correctly to always include
352 a fragment header */
353 icmp6_hdr->icmp6_mtu = htonl(576);
354 else
355 /* needs to adjusted for difference between IPv4/IPv6 headers
356 * SIIT RFC2765, section 3.3,
357 * we assume that difference is 20 bytes */
358 icmp6_hdr->icmp6_mtu = htonl(ntohs(icmp_hdr->un.frag.mtu)+IP4_IP6_HDR_DIFF);
359
360 break;
361 case ICMP_NET_ANO: /* Code 9 */
362 case ICMP_HOST_ANO: /* Code 10 */
363 icmp6_hdr->icmp6_code = ICMPV6_ADM_PROHIBITED; /* to Code 1 */
364 break;
365 default: /* discard any other Code */
366 PDEBUG("ip4_ip6(): Unknown ICMPv4 Type %d Code %d - packet dropped.\n",
367 ICMP_DEST_UNREACH, icmp_hdr->code);
368 return -1;
369 }
370 break;
371 /* Time Exceeded (Type 11) */
372 case ICMP_TIME_EXCEEDED:
373 icmp6_hdr->icmp6_type = ICMPV6_TIME_EXCEED;
374 icmp6_hdr->icmp6_code = icmp_hdr->code;
375 break;
376 /* Parameter Problem (Type 12) */
377 case ICMP_PARAMETERPROB:
378 icmp6_hdr->icmp6_type = ICMPV6_PARAMPROB;
379 icmp6_hdr->icmp6_code = icmp_hdr->code;
380
381 icmp_ptr = ntohs(icmp_hdr->un.echo.id) >> 8;
382 switch (icmp_ptr) {
383 case 0:
384 icmp6_hdr->icmp6_pointer = 0; /* IPv4 Version -> IPv6 Version */
385 break;
386 case 2:
387 icmp6_hdr->icmp6_pointer = __constant_htonl(4); /* IPv4 length -> IPv6 Payload Length */
388 break;
389 case 8:
390 icmp6_hdr->icmp6_pointer = __constant_htonl(7); /* IPv4 TTL -> IPv6 Hop Limit */
391 break;
392 case 9:
393 icmp6_hdr->icmp6_pointer = __constant_htonl(6); /* IPv4 Protocol -> IPv6 Next Header */
394 break;
395 case 12:
396 icmp6_hdr->icmp6_pointer = __constant_htonl(8); /* IPv4 Src Addr -> IPv6 Src Addr */
397 break;
398 case 16:
399 icmp6_hdr->icmp6_pointer = __constant_htonl(24); /* IPv4 Dst Addr -> IPv6 Dst Addr */
400 break;
401 default:
402 icmp6_hdr->icmp6_pointer = 0xffffffff; /* set to all ones in any other cases */
403 break;
404 }
405 break;
406 case ICMP_ECHO:
407 icmperr = 0;
408 icmp6_hdr->icmp6_type = ICMPV6_ECHO_REQUEST;
409 icmp6_hdr->icmp6_code = 0;
410 /* Copy rest ICMP data to new IPv6 packet without changing */
411 memcpy(((char *)icmp6_hdr)+4, ((char *)icmp_hdr)+4, len - hdr_len - 4);
412 break;
413
414 case ICMP_ECHOREPLY:
415 icmperr = 0;
416 icmp6_hdr->icmp6_type = ICMPV6_ECHO_REPLY;
417 icmp6_hdr->icmp6_code = 0;
418 /* Copy rest ICMP data to new IPv6 packet without changing */
419 memcpy(((char *)icmp6_hdr)+4, ((char *)icmp_hdr)+4, len - hdr_len - 4);
420 break;
421
422 /* Discard any other ICMP messages */
423 default:
424 PDEBUG("ip4_ip6(): Unknown ICMPv4 packet Type %x - packet dropped.\n", icmp_hdr->type);
425 return -1;
426 }
427
428 /* Now if it's ICMPv4 Error message we must translate included IP packet */
429
430 if (icmperr) {
431 /* Call our ip4_ip6() to translate included IP packet */
432 if (ip4_ip6(src+hdr_len+sizeof(struct icmphdr), len - hdr_len - sizeof(struct icmphdr),
433 dst+sizeof(struct ipv6hdr)+fr_flag*sizeof(struct frag_hdr)
434 +sizeof(struct icmp6hdr), 1) == -1) {
435 PDEBUG("ip4_ip6(): Uncorrect translation of ICMPv4 Error message - packet dropped.\n");
436 return -1;
437 }
438 /* correct ICMPv6 packet length for diffirence between IPv4 and IPv6 headers
439 in included IP packet
440 */
441 icmp_len += 20;
442 /* and correct Payload length for diffirence between IPv4 and IPv6 headers */
443 plen += 20;
444 ih6->payload_len = htons(plen);
445 }
446
447 /* Calculate ICMPv6 checksum */
448
449 icmp6_hdr->icmp6_cksum = 0;
450 csum = 0;
451
452 csum = csum_partial((u_char *)icmp6_hdr, icmp_len, csum);
453 icmp6_hdr->icmp6_cksum = csum_ipv6_magic(&ih6->saddr, &ih6->daddr, icmp_len,
454 IPPROTO_ICMPV6, csum);
455 break;
456
457 /* Process TCP protocols data */
458 case IPPROTO_TCP:
459 /* Copy TCP data to new IPv6 packet without changing */
460 memcpy(dst+sizeof(struct ipv6hdr)+fr_flag*sizeof(struct frag_hdr),
461 src+hdr_len, len - hdr_len);
462 break;
463
464 /* Process UDP protocols data */
465 case IPPROTO_UDP:
466 udp_hdr = (struct udphdr *)(src+hdr_len);
467 if ((ntohs(ih4->frag_off) & IP_OFFSET) == 0) {
468 if ((ntohs(ih4->frag_off) & IP_MF) != 0) {
469 /* It's a first fragment */
470 if (udp_hdr->check == 0) {
471 /* System management event */
472 printk("siit: First fragment of UDP with zero checksum - packet droped\n");
473 printk("siit: addr: %x src port: %d dst port: %d\n",
474 htonl(ih4->saddr), htons(udp_hdr->source), htons(udp_hdr->dest));
475 return -1;
476 }
477 }
478 else if (udp_hdr->check == 0)
479 fl_csum = 1;
480 }
481
482 /* Copy UDP data to new IPv6 packet */
483 udp_hdr = (struct udphdr *)(dst+sizeof(struct ipv6hdr)
484 + fr_flag*sizeof(struct frag_hdr));
485 memcpy((char *)udp_hdr, src+hdr_len, len - hdr_len);
486
487 /* Calculate UDP checksum if UDP checksum in IPv4 packet was ZERO
488 and if it isn't included IP packet
489 */
490 if (fl_csum && (!include_flag)) {
491 udp_hdr->check = 0;
492 csum = 0;
493 csum = csum_partial((unsigned char *)udp_hdr, plen - fr_flag*sizeof(struct frag_hdr), csum);
494 udp_hdr->check = csum_ipv6_magic(&ih6->saddr, &ih6->daddr, plen -
495 fr_flag*sizeof(struct frag_hdr), IPPROTO_UDP, csum);
496 }
497 break;
498
499 /* Discard packets with any other protocol */
500 default:
501 PDEBUG("ip4_ip6(): Unknown upper protocol - packet dropped.\n");
502 return -1;
503 }
504
505 #ifdef SIIT_DEBUG
506 siit_print_dump(dst, sizeof(struct ipv6hdr), "siit: ip4_ip6(): (out) ipv6 header dump");
507 #endif
508
509 return 0;
510 }
511
512 /*
513 * Translation IPv6 to IPv4 stuff
514 *
515 * ip6_ip4(src, len, dst, include_flag)
516 *
517 * where
518 * src - buffer with original IPv6 packet,
519 * len - size of original packet,
520 * dst - new buffer for IPv4 packet,
521 * include_flag - if = 1, dst point to IPv6 packet that is ICMP error
522 * included IP packet, else = 0
523 *
524 */
525
526 static int ip6_ip4(char *src, int len, char *dst, int include_flag)
527 {
528 struct ipv6hdr *ip6_hdr; /* point to current IPv6 header struct */
529 struct iphdr *ip_hdr; /* point to current IPv4 header struct */
530 int opts_len = 0; /* to sum Option Headers length */
531 int icmperr = 1; /* if = 1, indicate that packet is ICMP Error message, else = 0 */
532 int ntot_len = 0; /* to calculate IPv6 Total Length field */
533 int real_len;
534 int len_delta;
535 int ip6_payload_len;
536 int inc_opts_len = 0; /* to sum Option Headers length in ICMP included IP packet */
537 __u8 next_hdr; /* Next Header */
538
539 #ifdef SIIT_DEBUG
540 siit_print_dump(src, sizeof(struct ipv6hdr), "siit: ip6_ip4(): (in) ipv6 header dump");
541 #endif
542
543 if ( (len_delta = len - sizeof(struct ipv6hdr)) >= 0)
544 {
545 ip6_hdr = (struct ipv6hdr *)src;
546 ip_hdr = (struct iphdr *)dst;
547
548 real_len = sizeof(struct iphdr);
549
550 /* Check validation of Saddr & Daddr? is a packet to fall under our translation? */
551 if (include_flag) { /* It's ICMP included IP packet,
552 about process include_flag see comment in ip4_ip6() */
553 if (ip6_hdr->saddr.s6_addr32[2] != htonl(MAPPED_PREFIX)) {
554 PDEBUG("ip6_ip4(): Included IP packet Src addr isn't mapped addr: %x%x%x%x, packet dropped.\n",
555 ip6_hdr->saddr.s6_addr32[0], ip6_hdr->saddr.s6_addr32[1],
556 ip6_hdr->saddr.s6_addr32[2], ip6_hdr->saddr.s6_addr32[3]);
557 return -1;
558 }
559 if ( ip6_hdr->daddr.s6_addr32[2] != htonl(TRANSLATED_PREFIX)) {
560 PDEBUG("ip6_ip4(): Included IP packet Dst addr isn't translated addr: %x%x%x%x, packet dropped.\n",
561 ip6_hdr->daddr.s6_addr32[0], ip6_hdr->daddr.s6_addr32[1],
562 ip6_hdr->daddr.s6_addr32[2], ip6_hdr->daddr.s6_addr32[3]);
563 return -1;
564 }
565 }
566 else { /* It's normal IP packet (not included in ICMP) */
567 if (ip6_hdr->saddr.s6_addr32[2] != htonl(TRANSLATED_PREFIX)) {
568 PDEBUG("ip6_ip4(): Src addr isn't translated addr: %x%x%x%x, packet dropped.\n",
569 ip6_hdr->saddr.s6_addr32[0], ip6_hdr->saddr.s6_addr32[1],
570 ip6_hdr->saddr.s6_addr32[2], ip6_hdr->saddr.s6_addr32[3]);
571 return -1;
572 }
573 if ( ip6_hdr->daddr.s6_addr32[2] != htonl(MAPPED_PREFIX)) {
574 PDEBUG("ip6_ip4(): Dst addr isn't mapped addr: %x%x%x%x, packet dropped.\n",
575 ip6_hdr->daddr.s6_addr32[0], ip6_hdr->daddr.s6_addr32[1],
576 ip6_hdr->daddr.s6_addr32[2], ip6_hdr->daddr.s6_addr32[3]);
577 return -1;
578 }
579 }
580
581 /* Set IPv4 Fragment Offset and ID to 0
582 before process any Option Headers */
583 ip_hdr->frag_off = 0;
584 ip_hdr->id = 0;
585
586 /*
587 * We process only Fragment Header. Any other options headers
588 * are ignored, i.e. there is no attempt to translate them.
589 * However, the Total Length field and the Protocol field would
590 * have to be adjusted to "skip" these extension headers.
591 */
592
593 next_hdr = ip6_hdr->nexthdr;
594
595 /* Hop_by_Hop options header (ip6_hdr->nexthdr = 0). It must
596 * appear only in IPv6 header's Next Header field.
597 */
598 if (next_hdr == NEXTHDR_HOP) {
599 if ( (len_delta - sizeof(struct ipv6_opt_hdr)) >= 0)
600 {
601 struct ipv6_opt_hdr *ip6h =
602 (struct ipv6_opt_hdr *)(src+sizeof(struct ipv6hdr) + opts_len);
603 if ( (len_delta -= ip6h->hdrlen*8 + 8) >= 0)
604 {
605 opts_len += ip6h->hdrlen*8 + 8; /* See RFC 2460 page 11:
606 Hdr Ext Len 8-bit unsigned integer. Length of the Hop-by-
607 Hop Options header in 8-octet units, not
608 including the first 8 octets.
609 */
610 next_hdr = ip6h->nexthdr;
611 }
612 else
613 {
614 PDEBUG("ip6_ip4(): hop_by_hop header error, packet droped");
615 /* Generate ICMP Parameter Problem */
616 return -1;
617 }
618 }
619 }
620
621 if (len_delta > 0)
622 {
623 while(next_hdr != NEXTHDR_ICMP && next_hdr != NEXTHDR_TCP
624 && next_hdr != NEXTHDR_UDP)
625 {
626 /* Destination options header */
627 if (next_hdr == NEXTHDR_DEST)
628 {
629 if ( (len_delta - sizeof(struct ipv6_opt_hdr)) >= 0)
630 {
631 struct ipv6_opt_hdr *ip6d =
632 (struct ipv6_opt_hdr *)(src + sizeof(struct ipv6hdr) + opts_len);
633 if ( (len_delta -= ip6d->hdrlen*8 + 8) >= 0)
634 {
635 opts_len += ip6d->hdrlen*8 + 8;
636 next_hdr = ip6d->nexthdr;
637 }
638 }
639 else
640 {
641 PDEBUG("ip6_ip4(): destination header error, packet droped");
642 /* Generate ICMP Parameter Problem */
643 return -1;
644 }
645 }
646 /* Routing options header */
647 else if (next_hdr == NEXTHDR_ROUTING)
648 {
649 if ( (len_delta - sizeof(struct ipv6_rt_hdr)) >= 0)
650 {
651 struct ipv6_rt_hdr *ip6rt =
652 (struct ipv6_rt_hdr *)(src+sizeof(struct ipv6hdr) + opts_len);
653 /* RFC 2765 SIIT, 4.1:
654 If a routing header with a non-zero Segments Left field is present
655 then the packet MUST NOT be translated, and an ICMPv6 "parameter
656 problem/ erroneous header field encountered" (Type 4/Code 0) error
657 message, with the Pointer field indicating the first byte of the
658 Segments Left field, SHOULD be returned to the sender.
659 */
660 if (ip6rt->segments_left != 0) {
661 /* Build ICMPv6 "Parameter Problem/Erroneous Header
662 Field Encountered" & drop the packet */
663 /* !!! We don't send ICMPv6 "Parameter Problem" !!! */
664 PDEBUG("ip6_ip4(): routing header type != 0\n");
665 return -1;
666 }
667 if ( (len_delta -= ip6rt->hdrlen*8 + 8) >= 0)
668 {
669 opts_len += ip6rt->hdrlen*8 + 8;
670 next_hdr = ip6rt->nexthdr;
671 }
672 else
673 {
674 PDEBUG("ip6_ip4(): routing header error, packet droped");
675 /* Generate ICMP Parameter Problem */
676 return -1;
677 }
678 }
679 }
680 /* Fragment options header */
681 else if (next_hdr == NEXTHDR_FRAGMENT)
682 {
683 if ( (len_delta -= sizeof(struct frag_hdr)) >= 0)
684 {
685 struct frag_hdr *ip6f =
686 (struct frag_hdr *)(src+sizeof(struct ipv6hdr)+opts_len);
687
688 opts_len += sizeof(struct frag_hdr); /* Frag Header Length = 8 */
689 ip_hdr->id = htons(ntohl(ip6f->identification)); /* ID field */
690 ip_hdr->frag_off = htons((ntohs(ip6f->frag_off) & IP6F_OFF_MASK) >> 3);
691 /* fragment offset */
692 ip_hdr->frag_off = htons(ntohs(ip_hdr->frag_off) |
693 ((ntohs(ip6f->frag_off) & IP6F_MORE_FRAG) << 13));
694 /* more fragments flag */
695 next_hdr = ip6f->nexthdr;
696 }
697 else
698 {
699 PDEBUG("ip6_ip4(): fragment header error, packet droped");
700 /* Generate ICMP Parameter Problem */
701 return -1;
702 }
703 }
704 /* No Next Header */
705 else if (next_hdr == NEXTHDR_NONE)
706 {
707 /* RFC 2460 IPv6 Specification, 4.7
708 4.7 No Next Header
709
710 The value 59 in the Next Header field of an IPv6 header or any
711 extension header indicates that there is nothing following that
712 header. If the Payload Length field of the IPv6 header indicates the
713 presence of octets past the end of a header whose Next Header field
714 contains 59, those octets must be ignored, and passed on unchanged if
715 the packet is forwarded.
716 */
717 break;
718 }
719 else if (next_hdr == NEXTHDR_ESP || next_hdr == NEXTHDR_AUTH)
720 {
721 PDEBUG("ip6_ip4(): cannot translate AUTH or ESP extention header, packet dropped\n");
722 return -1;
723 }
724 else if (next_hdr == NEXTHDR_IPV6)
725 {
726 PDEBUG("ip6_ip4(): cannot translate IPv6-IPv6 packet, packet dropped\n");
727 return -1;
728 }
729 else if (next_hdr == 0)
730 {
731 /* As say RFC 2460 (IPv6 Spec) we should discard the packet and send an
732 ICMP Parameter Problem message to the source of the packet, with an
733 ICMP Code value of 1 ("unrecognized Next Header type encountered")
734 and the ICMP Pointer field containing the offset of the unrecognized
735 value within the original packet
736 */
737 /* NOT IMPLEMENTED */
738 PDEBUG("ip6_ip4(): NEXTHDR in extention header = 0, packet dropped\n");
739 return -1;
740 }
741 else
742 {
743 PDEBUG("ip6_ip4(): cannot translate extention header = %d, packet dropped\n", next_hdr);
744 return -1;
745 }
746 }
747 }
748 }
749 else
750 {
751 PDEBUG("ip6_ip4(): error packet len, packet dropped.\n");
752 return -1;
753 }
754
755 /* Building ipv4 packet */
756
757 ip_hdr->version = IPVERSION;
758 ip_hdr->ihl = 5;
759
760 /* TOS see comment about TOS in ip4_ip6() */
761 if (tos_ignore_flag)
762 ip_hdr->tos = 0;
763 else {
764 ip_hdr->tos = ip6_hdr->priority << 4;
765 ip_hdr->tos = ip_hdr->tos | (ip6_hdr->flow_lbl[0] >> 4);
766 }
767
768 /* IPv4 Total Len = IPv6 Payload Len +
769 IPv4 Header Len (without options) - Options Headers Len */
770 ip6_payload_len = ntohs(ip6_hdr->payload_len);
771
772 if (ip6_payload_len == 0)
773 ntot_len = 0;
774 else
775 ntot_len = ip6_payload_len + IP4_IP6_HDR_DIFF - opts_len;
776
777 ip_hdr->tot_len = htons(ntot_len);
778
779 /* IPv4 TTL = IPv6 Hop Limit */
780 ip_hdr->ttl = ip6_hdr->hop_limit;
781
782 /* IPv4 Protocol = Next Header that will point to upper layer protocol */
783 ip_hdr->protocol = next_hdr;
784
785 /* IPv4 Src addr = last 4 bytes from IPv6 Src addr */
786 ip_hdr->saddr = ip6_hdr->saddr.s6_addr32[3];
787 /* IPv4 Dst addr = last 4 bytes from IPv6 Dst addr */
788 ip_hdr->daddr = ip6_hdr->daddr.s6_addr32[3];
789
790 /* Calculate IPv4 header checksum */
791 ip_hdr->check = 0;
792 ip_hdr->check = ip_fast_csum((unsigned char *)ip_hdr, ip_hdr->ihl);
793
794 if (len_delta > 0)
795 {
796 /* PROCESS ICMP */
797
798 if (next_hdr == NEXTHDR_ICMP)
799 {
800 struct icmp6hdr *icmp6_hdr;
801 struct icmphdr *icmp_hdr;
802
803 if ((len_delta -= sizeof(struct icmp6hdr)) >= 0)
804 {
805 icmp6_hdr = (struct icmp6hdr *)(src + sizeof(struct ipv6hdr) + opts_len);
806 icmp_hdr = (struct icmphdr *)(dst + sizeof(struct iphdr));
807
808 real_len += len_delta + sizeof(struct icmphdr);
809
810 /* There is diffirent between ICMPv4/ICMPv6 protocol codes
811 IPPROTO_ICMP = 1
812 IPPROTO_ICMPV6 = 58 */
813 ip_hdr->protocol = IPPROTO_ICMP;
814
815 if (include_flag) {
816 /* !!! Warnig !!! We discard ICMP packets with any ICMP as included
817 in ICMP Error. But ICMP Error messages can include ICMP Query message
818 */
819 if (icmp6_hdr->icmp6_type != ICMPV6_ECHO_REQUEST)
820 {
821 PDEBUG("ip6_ip4(): included ICMPv6 in ICMPv6 Error message, packet dropped\n");
822 return -1;
823 }
824 }
825
826 /* Translate ICMPv6 to ICMPv4 */
827 switch (icmp6_hdr->icmp6_type)
828 {
829 /* ICMP Error messages */
830 /* Destination Unreachable (Type 1) */
831 case ICMPV6_DEST_UNREACH: /* Type 1 */
832 icmp_hdr->type = ICMP_DEST_UNREACH; /* to Type 3 */
833 icmp_hdr->un.echo.id = 0;
834 icmp_hdr->un.echo.sequence = 0;
835 switch (icmp6_hdr->icmp6_code)
836 {
837 case ICMPV6_NOROUTE: /* Code 0 */
838 case ICMPV6_NOT_NEIGHBOUR: /* Code 2 */
839 case ICMPV6_ADDR_UNREACH: /* Code 3 */
840 icmp_hdr->code = ICMP_HOST_UNREACH; /* To Code 1 */
841 break;
842 case ICMPV6_ADM_PROHIBITED: /* Code 1 */
843 icmp_hdr->code = ICMP_HOST_ANO; /* To Code 10 */
844 break;
845 case ICMPV6_PORT_UNREACH: /* Code 4 */
846 icmp_hdr->code = ICMP_PORT_UNREACH; /* To Code 3 */
847
848 break;
849 default: /* discard any other codes */
850 PDEBUG("ip6_ip4(): Unknown ICMPv6 Type %d Code %d - packet dropped.\n",
851 ICMPV6_DEST_UNREACH, icmp6_hdr->icmp6_code);
852 return -1;
853 }
854 break;
855 /* Packet Too Big (Type 2) */
856 case ICMPV6_PKT_TOOBIG: /* Type 2 */
857 icmp_hdr->type = ICMP_DEST_UNREACH; /* to Type 3 */
858 icmp_hdr->code = ICMP_FRAG_NEEDED; /* to Code 4 */
859 /* Change MTU, RFC 2765 (SIIT), 4.2:
860 The MTU field needs to be adjusted for the difference between
861 the IPv4 and IPv6 header sizes taking into account whether or
862 not the packet in error includes a Fragment header.
863 */
864 /* !!! Don't implement !!! */
865 icmp_hdr->un.frag.mtu = (__u16) icmp6_hdr->icmp6_mtu;
866 break;
867 /* Time Exceeded (Type 3) */
868 case ICMPV6_TIME_EXCEED:
869 icmp_hdr->type = ICMP_TIME_EXCEEDED; /* to Type 11 */
870 icmp_hdr->code = icmp6_hdr->icmp6_code; /* Code unchanged */
871 break;
872 /* Parameter Problem (Type 4) */
873 case ICMPV6_PARAMPROB:
874 switch (icmp6_hdr->icmp6_code) {
875 case ICMPV6_UNK_NEXTHDR: /* Code 1 */
876 icmp_hdr->type = ICMP_DEST_UNREACH; /* to Type 3 */
877 icmp_hdr->code = ICMP_PROT_UNREACH; /* to Code 2 */
878 break;
879 default: /* if Code != 1 */
880 icmp_hdr->type = ICMP_PARAMETERPROB; /* to Type 12 */
881 icmp_hdr->code = 0; /* to Code 0 */
882 /* Update Pointer field
883 RFC 2765 (SIIT), 4.2:
884 The Pointer needs to be updated to point to the corresponding
885 field in the translated include IP header.
886 */
887 switch (ntohl(icmp6_hdr->icmp6_pointer))
888 {
889 case 0: /* IPv6 Version -> IPv4 Version */
890 icmp_hdr->un.echo.id = 0;
891 break;
892 case 4: /* IPv6 PayloadLength -> IPv4 Total Length */
893 icmp_hdr->un.echo.id = 0x0002; /* 2 */
894 break;
895 case 6: /* IPv6 Next Header-> IPv4 Protocol */
896 icmp_hdr->un.echo.id = 0x0009; /* 9 */
897 break;
898 case 7: /* IPv6 Hop Limit -> IPv4 TTL */
899 icmp_hdr->un.echo.id = 0x0008; /* 8 */
900 break;
901 case 8: /* IPv6 Src addr -> IPv4 Src addr */
902 icmp_hdr->un.echo.id = 0x000c; /* 12 */
903 break;
904 case 24: /* IPv6 Dst addr -> IPv4 Dst addr*/
905 icmp_hdr->un.echo.id = 0x0010; /* 16 */
906 break;
907 default: /* set all ones in other cases */
908 icmp_hdr->un.echo.id = 0xff;
909 break;
910 }
911 break;
912 }
913 break;
914
915 /* End of ICMP Error messages */
916
917 /* Echo Request and Echo Reply (Type 128 and 129) */
918 case ICMPV6_ECHO_REQUEST:
919 icmperr = 0; /* not error ICMP message */
920 icmp_hdr->type = ICMP_ECHO; /* to Type 8 */
921 icmp_hdr->code = 0; /* to Code 0 */
922 icmp_hdr->un.echo.id = icmp6_hdr->icmp6_identifier;
923 icmp_hdr->un.echo.sequence = icmp6_hdr->icmp6_sequence;
924 /* copy rest of ICMP data to result packet */
925 if (len_delta > 0)
926 memcpy(((char *)icmp_hdr) + sizeof(struct icmphdr),
927 ((char *)icmp6_hdr) + sizeof(struct icmp6hdr), len_delta);
928 break;
929 case ICMPV6_ECHO_REPLY:
930 icmperr = 0; /* not error ICMP message */
931 icmp_hdr->type = ICMP_ECHOREPLY; /* to Type 0 */
932 icmp_hdr->code = 0; /* to Code 0 */
933 icmp_hdr->un.echo.id = icmp6_hdr->icmp6_identifier;
934 icmp_hdr->un.echo.sequence = icmp6_hdr->icmp6_sequence;
935 /* copy rest of ICMP data */
936 if (len_delta > 0)
937 memcpy(((char *)icmp_hdr) + sizeof(struct icmphdr),
938 ((char *)icmp6_hdr) + sizeof(struct icmp6hdr), len_delta);
939 break;
940 default:
941 /* Unknown error messages. Silently drop. */
942 PDEBUG("ip6_ip4(): unknown ICMPv6 Type %d, packet dropped.\n", icmp6_hdr->icmp6_type);
943 return -1;
944 }
945
946 if (icmperr)
947 {
948 /* If ICMP Error message, we translate IP included packet*/
949 if (len_delta >= sizeof(struct ipv6hdr))
950 {
951 if((inc_opts_len = ip6_ip4((char *)icmp6_hdr + sizeof(struct icmp6hdr), len_delta,
952 (char *)icmp_hdr + sizeof(struct icmphdr), 1)) == -1) {
953 PDEBUG("ip6_ip4(): incorrect translation of ICMPv6 Error message, packet dropped\n");
954 return -1;
955 }
956 /* correct IPv4 Total Len that = old Total Len
957 - Options Headers Len in included IP packet
958 - diffirence between IPv6 Header Len and IPv4 Header Len
959 */
960 if (ntot_len != 0)
961 ip_hdr->tot_len = htons(ntot_len - inc_opts_len - IP4_IP6_HDR_DIFF);
962 real_len = real_len - inc_opts_len - IP4_IP6_HDR_DIFF;
963 }
964 else if (len_delta > 0)
965 {
966 /* May be it need set 0x0 to rest area in result IPv4 packet,
967 * but we copy rest data unchanged
968 */
969 memcpy(((char *)icmp_hdr) + sizeof(struct icmphdr),
970 ((char *)icmp6_hdr) + sizeof(struct icmp6hdr), len_delta);
971 }
972 }
973
974 /* Calculate IPv4 Header checksum */
975 ip_hdr->check = 0;
976 ip_hdr->check = ip_fast_csum((unsigned char *)ip_hdr, ip_hdr->ihl);
977
978 /* Calculate ICMPv4 checksum */
979 if (ntot_len != 0)
980 {
981 icmp_hdr->checksum = 0;
982 icmp_hdr->checksum = ip_compute_csum((unsigned char *)icmp_hdr, ntohs(ip_hdr->tot_len)
983 - sizeof(struct iphdr));
984 }
985 }
986 else
987 {
988 PDEBUG("ip6_ip4(): error length ICMP packet, packet dropped.\n");
989 return -1;
990 }
991
992 }
993 /* PROCESS TCP and UDP (and rest data) */
994
995 else {
996 real_len += len_delta;
997 /* we copy rest data to IPv4 packet without changing */
998 memcpy(dst+sizeof(struct iphdr), src + sizeof(struct ipv6hdr) + opts_len, len_delta);
999 }
1000 }
1001
1002 if (include_flag) /* if it's included IP packet */
1003 return opts_len; /* return options headers length */
1004 else
1005 return real_len; /* result packet len */
1006 }
1007
1008 /*
1009 * ip4_fragment(skb, len, hdr_len, dev, eth_h)
1010 * to fragment original IPv4 packet if result IPv6 packet will be > 1280
1011 */
1012
1013 static int ip4_fragment(struct sk_buff *skb, int len, int hdr_len, struct net_device *dev, struct ethhdr *eth_h)
1014 {
1015 struct sk_buff *skb2 = NULL; /* pointer to new struct sk_buff for transleded packet */
1016 char buff[FRAG_BUFF_SIZE+hdr_len]; /* buffer to form new fragment packet */
1017 char *cur_ptr = skb->data+hdr_len; /* pointter to current packet data with len = frag_len */
1018 struct iphdr *ih4 = (struct iphdr *) skb->data;
1019 struct iphdr *new_ih4 = (struct iphdr *) buff; /* point to new IPv4 hdr */
1020 struct ethhdr *new_eth_h; /* point to ether hdr, need to set hard header data in fragment */
1021 int data_len = len - hdr_len; /* origin packet data len */
1022 int rest_len = data_len; /* rest data to fragment */
1023 int frag_len = 0; /* current fragment len */
1024 int last_frag = 0; /* last fragment flag, if = 1, it's last fragment */
1025 int flag_last_mf = 0;
1026 __u16 new_id = 0; /* to generate identification field */
1027 __u16 frag_offset = 0; /* fragment offset */
1028 unsigned int csum;
1029 unsigned short udp_len;
1030
1031 #ifdef SIIT_DEBUG
1032 printk("siit: it's DF == 0 and result IPv6 packet will be > 1280\n");
1033 siit_print_dump(skb->data, hdr_len, "siit: (orig) ipv4_hdr dump");
1034 #endif
1035
1036 if ((ntohs(ih4->frag_off) & IP_MF) == 0 )
1037 /* it's a case we'll clear MF flag in our last packet */
1038 flag_last_mf = 1;
1039
1040 if (ih4->protocol == IPPROTO_UDP) {
1041 if ( (ntohs(ih4->frag_off) & IP_OFFSET) == 0) {
1042 struct udphdr *udp_hdr = (struct udphdr *)((char *)ih4 + hdr_len);
1043 if (!flag_last_mf) {
1044 if (udp_hdr->check == 0) {
1045 /* it's a first fragment with ZERO checksum and we drop packet */
1046 printk("siit: First fragment of UDP with zero checksum - packet droped\n");
1047 printk("siit: addr: %x src port: %d dst port: %d\n",
1048 htonl(ih4->saddr), htons(udp_hdr->source), htons(udp_hdr->dest));
1049 return -1;
1050 }
1051 }
1052 else if (udp_hdr->check == 0) {
1053 /* Calculate UDP checksum only if it's not fragment */
1054 udp_len = ntohs(udp_hdr->len);
1055 csum = 0;
1056 csum = csum_partial((unsigned char *)udp_hdr, udp_len, csum);
1057 udp_hdr->check = csum_tcpudp_magic(ih4->saddr, ih4->daddr, udp_len, IPPROTO_UDP, csum);
1058 }
1059 }
1060 }
1061
1062 frag_offset = ntohs(ih4->frag_off) & IP_OFFSET;
1063
1064 new_id = ih4->id;
1065
1066 while(1) {
1067 if (rest_len <= FRAG_BUFF_SIZE) {
1068 /* it's last fragmen */
1069 frag_len = rest_len; /* rest data */
1070 last_frag = 1;
1071 }
1072 else
1073 frag_len = FRAG_BUFF_SIZE;
1074
1075 /* copy IP header to buffer */
1076 memcpy(buff, skb->data, hdr_len);
1077 /* copy data to buffer with len = frag_len */
1078 memcpy(buff + hdr_len, cur_ptr, frag_len);
1079
1080 /* set id field in new IPv4 header*/
1081 new_ih4->id = new_id;
1082
1083 /* is it last fragmet */
1084 if(last_frag && flag_last_mf)
1085 /* clear MF flag */
1086 new_ih4->frag_off = htons(frag_offset & (~IP_MF));
1087 else
1088 /* set MF flag */
1089 new_ih4->frag_off = htons(frag_offset | IP_MF);
1090
1091 /* change packet total length */
1092 new_ih4->tot_len = htons(frag_len+hdr_len);
1093
1094 /* rebuild the header checksum (IP needs it) */
1095 new_ih4->check = 0;
1096 new_ih4->check = ip_fast_csum((unsigned char *)new_ih4,new_ih4->ihl);
1097
1098 /* Allocate new sk_buff to compose translated packet */
1099 skb2 = dev_alloc_skb(frag_len+hdr_len+dev->hard_header_len+IP4_IP6_HDR_DIFF+IP6_FRAGMENT_SIZE);
1100 if (!skb2) {
1101 printk(KERN_DEBUG "%s: alloc_skb failure - packet dropped.\n", dev->name);
1102 dev_kfree_skb(skb2);
1103 return -1;
1104 }
1105 /* allocate skb->data portion for IP header len, fragment data len and ether header len
1106 * and copy to head ether header from origin skb
1107 */
1108 memcpy(skb_put(skb2, frag_len+hdr_len+dev->hard_header_len+IP4_IP6_HDR_DIFF+IP6_FRAGMENT_SIZE), (char *) eth_h,
1109 dev->hard_header_len);
1110 /* correct ether header data, ether protocol field to ETH_P_IPV6 */
1111 new_eth_h = (struct ethhdr *)skb2->data;
1112 new_eth_h->h_proto = htons(ETH_P_IPV6);
1113
1114 /* reset the mac header */
1115 skb_reset_mac_header(skb2);
1116
1117 /* pull ether header from new skb->data */
1118 skb_pull(skb2, dev->hard_header_len);
1119 /* set skb protocol to IPV6 */
1120 skb2->protocol = htons(ETH_P_IPV6);
1121
1122 /* call translation function */
1123 if ( ip4_ip6(buff, frag_len+hdr_len, skb2->data, 0) == -1) {
1124 dev_kfree_skb(skb2);
1125 return -1;
1126 }
1127
1128 /*
1129 * Set needed fields in new sk_buff
1130 */
1131 skb2->dev = dev;
1132 skb2->ip_summed = CHECKSUM_UNNECESSARY;
1133 skb2->pkt_type = PACKET_HOST;
1134
1135 /* Add transmit statistic */
1136 siit_stats(dev)->tx_packets++;
1137 siit_stats(dev)->tx_bytes += skb2->len;
1138
1139 /* send packet to upper layer */
1140 netif_rx(skb2);
1141
1142 /* exit if it was last fragment */
1143 if (last_frag)
1144 break;
1145
1146 /* correct current data pointer */
1147 cur_ptr += frag_len;
1148 /* rest data len */
1149 rest_len -= frag_len;
1150 /* current fragment offset */
1151 frag_offset = (frag_offset*8 + frag_len)/8;
1152 }
1153
1154 return 0;
1155 }
1156 /*
1157 * Transmit a packet (called by the kernel)
1158 *
1159 * siit_xmit(skb, dev)
1160 *
1161 * where
1162 * skb - pointer to struct sk_buff with incomed packet
1163 * dev - pointer to struct device on which packet revieved
1164 *
1165 * Statistic:
1166 * for all incoming packes:
1167 * stats.rx_bytes+=skb->len
1168 * stats.rx_packets++
1169 * for packets we can't transle:
1170 * stats.tx_errors++
1171 * device busy:
1172 * stats.tx_errors++
1173 * for packets we can't allocate sk_buff:
1174 * stats.tx_dropped++
1175 * for outgoing packes:
1176 * stats.tx_packets++
1177 * stats.tx_bytes+=skb2->len !!! But we don't set skb2->len !!!
1178 */
1179
1180 static int siit_xmit(struct sk_buff *skb, struct net_device *dev)
1181 {
1182 struct sk_buff *skb2 = NULL;/* pointer to new struct sk_buff for transleded packet */
1183 struct ethhdr *eth_h; /* pointer to incoming Ether header */
1184 int len; /* original packets length */
1185 int new_packet_len;
1186 int skb_delta = 0; /* delta size for allocate new skb */
1187 char new_packet_buff[2048];
1188
1189 /* Check pointer to sk_buff and device structs */
1190 if (skb == NULL || dev == NULL)
1191 return -EINVAL;
1192
1193 /* Add receive statistic */
1194 siit_stats(dev)->rx_bytes += skb->len;
1195 siit_stats(dev)->rx_packets++;
1196
1197 dev->trans_start = jiffies;
1198
1199 /* Upper layer (IP) protocol forms sk_buff for outgoing packet
1200 * and sets IP header + Ether header too. IP layer sets outgoing
1201 * device in sk_buff->dev.
1202 * In function (from linux/net/core/dev.c) ther is a call to
1203 * device transmit function (dev->hard_start_xmit):
1204 *
1205 * dev_queue_xmit(struct sk_buff *skb)
1206 * {
1207 * ...
1208 * device *dev = skb->dev;
1209 * ...
1210 * dev->hard_start_xmit(skb, dev);
1211 * ...
1212 * }
1213 * We save pointer to ether header in eth_h and skb_pull ether header
1214 * from data field of skb_buff
1215 */
1216
1217 eth_h = (struct ethhdr *)skb->data; /* point to incoming packet Ether Header */
1218
1219 #ifdef SIIT_DEBUG
1220 siit_print_dump(skb->data, ETH_HLEN, "siit: eth_hdr dump");
1221 #endif
1222
1223 /* Remove hardware header from origin sk_buff */
1224 skb_pull(skb,dev->hard_header_len);
1225
1226 /*
1227 * Process IPv4 paket
1228 */
1229 if (ntohs(skb->protocol) == ETH_P_IP) {
1230 int hdr_len; /* IPv4 header length */
1231 int data_len; /* IPv4 data length */
1232 struct iphdr *ih4; /* pointer to IPv4 header */
1233 struct icmphdr *icmp_hdr; /* point to current ICMPv4 header struct */
1234
1235 ih4 = (struct iphdr *)skb->data; /* point to incoming packet's IPv4 header */
1236
1237 /* Check IPv4 Total Length */
1238 if (skb->len != ntohs(ih4->tot_len)) {
1239 PDEBUG("siit_xmit(): Different skb_len %x and ip4 tot_len %x - packet dropped.\n",
1240 skb->len, ih4->tot_len);
1241 siit_stats(dev)->tx_errors++;
1242 dev_kfree_skb(skb);
1243 return 0;
1244 }
1245
1246 len = skb->len; /* packet's total len */
1247 hdr_len = (int)(ih4->ihl * 4); /* packet's header len */
1248 data_len = len - hdr_len; /* packet's data len */
1249
1250 /* If DF == 0 */
1251 if ( (ntohs(ih4->frag_off) & IP_DF) == 0 ) {
1252 /* If result IPv6 packet will be > 1280
1253 we need to fragment original IPv4 packet
1254 */
1255 if ( data_len > FRAG_BUFF_SIZE ) {
1256 /* call function that fragment packet and translate to IPv6 each fragment
1257 * and send to upper layer
1258 */
1259 if ( ip4_fragment(skb, len, hdr_len, dev, eth_h) == -1) {
1260 siit_stats(dev)->tx_errors++;
1261 }
1262 /* Free incoming skb */
1263 dev_kfree_skb(skb);
1264 /* Device can accept a new packet */
1265
1266 return 0;
1267
1268 }
1269 }
1270 /* If DF == 1 && MF == 0 && Fragment Offset == 0
1271 * we don't include fragment header
1272 */
1273 if ( ntohs(ih4->frag_off) == IP_DF )
1274 skb_delta = IP4_IP6_HDR_DIFF; /* delta is +20 */
1275 else
1276 skb_delta = IP4_IP6_HDR_DIFF + IP6_FRAGMENT_SIZE; /* delta is +20 and +8 */
1277
1278 /* If it's ICMP, check is it included IP packet in it */
1279 if ( ih4->protocol == IPPROTO_ICMP) {
1280 icmp_hdr = (struct icmphdr *) (skb->data+hdr_len); /* point to ICMPv4 header */
1281 if ( icmp_hdr->type != ICMP_ECHO && icmp_hdr->type != ICMP_ECHOREPLY) {
1282 /*
1283 * It's ICMP Error that has included IP packet
1284 * we'll add only +20 because we don't include Fragment Header
1285 * into translated included IP packet
1286 */
1287 skb_delta += IP4_IP6_HDR_DIFF;
1288 }
1289 }
1290
1291 /* Allocate new sk_buff to compose translated packet */
1292 skb2 = dev_alloc_skb(len+dev->hard_header_len+skb_delta);
1293 if (!skb2) {
1294 printk(KERN_DEBUG "%s: alloc_skb failure - packet dropped.\n", dev->name);
1295 dev_kfree_skb(skb);
1296 siit_stats(dev)->rx_dropped++;
1297
1298 return 0;
1299 }
1300 /* allocate skb->data portion = IPv4 packet len + ether header len
1301 * + skb_delta (max = two times (diffirence between IPv4 header and
1302 * IPv6 header + Frag Header), second for included packet,
1303 * and copy to head of skb->data ether header from origin skb
1304 */
1305 memcpy(skb_put(skb2, len+dev->hard_header_len+skb_delta), (char *)eth_h, dev->hard_header_len);
1306 /* correct ether header data, ether protocol field to ETH_P_IPV6 */
1307 eth_h = (struct ethhdr *)skb2->data;
1308 eth_h->h_proto = htons(ETH_P_IPV6);
1309 skb_reset_mac_header(skb2);
1310 /* remove ether header from new skb->data,
1311 * NOTE! data will rest, pointer to data and data len will change
1312 */
1313 skb_pull(skb2,dev->hard_header_len);
1314 /* set skb protocol to IPV6 */
1315 skb2->protocol = htons(ETH_P_IPV6);
1316
1317 /* call translation function */
1318 if (ip4_ip6(skb->data, len, skb2->data, 0) == -1 ) {
1319 dev_kfree_skb(skb);
1320 dev_kfree_skb(skb2);
1321 siit_stats(dev)->rx_errors++;
1322
1323 return 0;
1324 }
1325 }
1326 /*
1327 * IPv6 paket
1328 */
1329 else if (ntohs(skb->protocol) == ETH_P_IPV6) {
1330
1331 #ifdef SIIT_DEBUG
1332 siit_print_dump(skb->data, sizeof(struct ipv6hdr), "siit: (in) ip6_hdr dump");
1333 #endif
1334 /* packet len = skb->data len*/
1335 len = skb->len;
1336
1337 /* call translation function */
1338 if ((new_packet_len = ip6_ip4(skb->data, len, new_packet_buff, 0)) == -1 )
1339 {
1340 PDEBUG("siit_xmit(): error translation ipv6->ipv4, packet dropped.\n");
1341 siit_stats(dev)->rx_dropped++;
1342 goto end;
1343 }
1344
1345 /* Allocate new sk_buff to compose translated packet */
1346 skb2 = dev_alloc_skb(new_packet_len + dev->hard_header_len);
1347 if (!skb2) {
1348 printk(KERN_DEBUG "%s: alloc_skb failure, packet dropped.\n", dev->name);
1349 siit_stats(dev)->rx_dropped++;
1350 goto end;
1351 }
1352 memcpy(skb_put(skb2, new_packet_len + dev->hard_header_len), (char *)eth_h, dev->hard_header_len);
1353 eth_h = (struct ethhdr *)skb2->data;
1354 eth_h->h_proto = htons(ETH_P_IP);
1355 skb_reset_mac_header(skb2);
1356 skb_pull(skb2, dev->hard_header_len);
1357 memcpy(skb2->data, new_packet_buff, new_packet_len);
1358 skb2->protocol = htons(ETH_P_IP);
1359 }
1360 else {
1361 PDEBUG("siit_xmit(): unsupported protocol family %x, packet dropped.\n", skb->protocol);
1362 goto end;
1363 }
1364
1365 /*
1366 * Set needed fields in new sk_buff
1367 */
1368 skb2->pkt_type = PACKET_HOST;
1369 skb2->dev = dev;
1370 skb2->ip_summed = CHECKSUM_UNNECESSARY;
1371
1372 /* Add transmit statistic */
1373 siit_stats(dev)->tx_packets++;
1374 siit_stats(dev)->tx_bytes += skb2->len;
1375
1376 /* Send packet to upper layer protocol */
1377 netif_rx(skb2);
1378
1379 end:
1380 dev_kfree_skb(skb);
1381
1382 return 0;
1383 }
1384
1385 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
1386 static bool header_ops_init = false;
1387 static struct header_ops siit_header_ops ____cacheline_aligned;
1388 #endif
1389
1390 /*
1391 * The init function initialize of the SIIT device..
1392 * It is invoked by register_netdev()
1393 */
1394 static void
1395 siit_init(struct net_device *dev)
1396 {
1397 ether_setup(dev); /* assign some of the fields */
1398 random_ether_addr(dev->dev_addr);
1399
1400 /*
1401 * Assign device function.
1402 */
1403 dev->open = siit_open;
1404 dev->stop = siit_release;
1405 dev->hard_start_xmit = siit_xmit;
1406 dev->flags |= IFF_NOARP; /* ARP not used */
1407 dev->tx_queue_len = 10;
1408
1409 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
1410 dev->hard_header_cache = NULL; /* Disable caching */
1411 memset(netdev_priv(dev), 0, sizeof(struct net_device_stats));
1412 dev->get_stats = siit_get_stats;
1413 #else
1414 if (!header_ops_init) {
1415 memcpy(&siit_header_ops, dev->header_ops, sizeof(struct header_ops));
1416 siit_header_ops.cache = NULL;
1417 }
1418 dev->header_ops = &siit_header_ops;
1419 #endif
1420 }
1421
1422 /*
1423 * Finally, the module stuff
1424 */
1425 static struct net_device *siit_dev = NULL;
1426
1427 int init_module(void)
1428 {
1429 int res = -ENOMEM;
1430 int priv_size;
1431
1432 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
1433 priv_size = sizeof(struct net_device_stats);
1434 #else
1435 priv_size = sizeof(struct header_ops);
1436 #endif
1437 siit_dev = alloc_netdev(priv_size, "siit%d", siit_init);
1438 if (!siit_dev)
1439 goto err_alloc;
1440
1441 res = register_netdev(siit_dev);
1442 if (res)
1443 goto err_register;
1444
1445 return 0;
1446
1447 err_register:
1448 free_netdev(siit_dev);
1449 err_alloc:
1450 printk(KERN_ERR "Error creating siit device: %d\n", res);
1451 return res;
1452 }
1453
1454 void cleanup_module(void)
1455 {
1456 unregister_netdev(siit_dev);
1457 free_netdev(siit_dev);
1458 }
1459
1460