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