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