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