lede-packages-rs

git clone git://archive.git.mtrnord.blog/MTRNord/lede-packages-rs.git
Log | Files | Refs | README | LICENSE

siit.c (45686B)


      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");