Merge branch 'x86-intel-mid-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[cascardo/linux.git] / drivers / staging / rtl8188eu / core / rtw_br_ext.c
1 /******************************************************************************
2  *
3  * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of version 2 of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
17  *
18  *
19  ******************************************************************************/
20 #define _RTW_BR_EXT_C_
21
22 #include <linux/if_arp.h>
23 #include <net/ip.h>
24 #include <net/ipx.h>
25 #include <linux/atalk.h>
26 #include <linux/udp.h>
27 #include <linux/if_pppox.h>
28
29 #include <drv_types.h>
30 #include "rtw_br_ext.h"
31 #include <usb_osintf.h>
32 #include <recv_osdep.h>
33
34 #ifndef csum_ipv6_magic
35 #include <net/ip6_checksum.h>
36 #endif
37
38 #include <linux/ipv6.h>
39 #include <linux/icmpv6.h>
40 #include <net/ndisc.h>
41 #include <net/checksum.h>
42
43 #define NAT25_IPV4              01
44 #define NAT25_IPV6              02
45 #define NAT25_IPX               03
46 #define NAT25_APPLE             04
47 #define NAT25_PPPOE             05
48
49 #define RTL_RELAY_TAG_LEN (ETH_ALEN)
50 #define TAG_HDR_LEN             4
51
52 #define MAGIC_CODE              0x8186
53 #define MAGIC_CODE_LEN  2
54 #define WAIT_TIME_PPPOE 5       /*  waiting time for pppoe server in sec */
55
56 /*-----------------------------------------------------------------
57   How database records network address:
58            0    1    2    3    4    5    6    7    8    9   10
59         |----|----|----|----|----|----|----|----|----|----|----|
60   IPv4  |type|                             |      IP addr      |
61   IPX   |type|      Net addr     |          Node addr          |
62   IPX   |type|      Net addr     |Sckt addr|
63   Apple |type| Network |node|
64   PPPoE |type|   SID   |           AC MAC            |
65 -----------------------------------------------------------------*/
66
67
68 /* Find a tag in pppoe frame and return the pointer */
69 static inline unsigned char *__nat25_find_pppoe_tag(struct pppoe_hdr *ph, unsigned short type)
70 {
71         unsigned char *cur_ptr, *start_ptr;
72         unsigned short tagLen, tagType;
73
74         start_ptr = cur_ptr = (unsigned char *)ph->tag;
75         while ((cur_ptr - start_ptr) < ntohs(ph->length)) {
76                 /*  prevent un-alignment access */
77                 tagType = (unsigned short)((cur_ptr[0] << 8) + cur_ptr[1]);
78                 tagLen  = (unsigned short)((cur_ptr[2] << 8) + cur_ptr[3]);
79                 if (tagType == type)
80                         return cur_ptr;
81                 cur_ptr = cur_ptr + TAG_HDR_LEN + tagLen;
82         }
83         return NULL;
84 }
85
86
87 static inline int __nat25_add_pppoe_tag(struct sk_buff *skb, struct pppoe_tag *tag)
88 {
89         struct pppoe_hdr *ph = (struct pppoe_hdr *)(skb->data + ETH_HLEN);
90         int data_len;
91
92         data_len = be16_to_cpu(tag->tag_len) + TAG_HDR_LEN;
93         if (skb_tailroom(skb) < data_len) {
94                 _DEBUG_ERR("skb_tailroom() failed in add SID tag!\n");
95                 return -1;
96         }
97
98         skb_put(skb, data_len);
99         /*  have a room for new tag */
100         memmove(((unsigned char *)ph->tag + data_len), (unsigned char *)ph->tag, ntohs(ph->length));
101         ph->length = htons(ntohs(ph->length) + data_len);
102         memcpy((unsigned char *)ph->tag, tag, data_len);
103         return data_len;
104 }
105
106 static int skb_pull_and_merge(struct sk_buff *skb, unsigned char *src, int len)
107 {
108         int tail_len;
109         unsigned long end, tail;
110
111         if ((src+len) > skb_tail_pointer(skb) || skb->len < len)
112                 return -1;
113
114         tail = (unsigned long)skb_tail_pointer(skb);
115         end = (unsigned long)src+len;
116         if (tail < end)
117                 return -1;
118
119         tail_len = (int)(tail-end);
120         if (tail_len > 0)
121                 memmove(src, src+len, tail_len);
122
123         skb_trim(skb, skb->len-len);
124         return 0;
125 }
126
127 static inline unsigned long __nat25_timeout(struct adapter *priv)
128 {
129         unsigned long timeout;
130
131         timeout = jiffies - NAT25_AGEING_TIME*HZ;
132
133         return timeout;
134 }
135
136
137 static inline int  __nat25_has_expired(struct adapter *priv,
138                                 struct nat25_network_db_entry *fdb)
139 {
140         if (time_before_eq(fdb->ageing_timer, __nat25_timeout(priv)))
141                 return 1;
142
143         return 0;
144 }
145
146
147 static inline void __nat25_generate_ipv4_network_addr(unsigned char *networkAddr,
148                                 unsigned int *ipAddr)
149 {
150         memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
151
152         networkAddr[0] = NAT25_IPV4;
153         memcpy(networkAddr+7, (unsigned char *)ipAddr, 4);
154 }
155
156
157 static inline void __nat25_generate_ipx_network_addr_with_node(unsigned char *networkAddr,
158                                 __be32 *ipxNetAddr, unsigned char *ipxNodeAddr)
159 {
160         memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
161
162         networkAddr[0] = NAT25_IPX;
163         memcpy(networkAddr+1, (unsigned char *)ipxNetAddr, 4);
164         memcpy(networkAddr+5, ipxNodeAddr, 6);
165 }
166
167
168 static inline void __nat25_generate_ipx_network_addr_with_socket(unsigned char *networkAddr,
169                                 __be32 *ipxNetAddr, __be16 *ipxSocketAddr)
170 {
171         memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
172
173         networkAddr[0] = NAT25_IPX;
174         memcpy(networkAddr+1, (unsigned char *)ipxNetAddr, 4);
175         memcpy(networkAddr+5, (unsigned char *)ipxSocketAddr, 2);
176 }
177
178
179 static inline void __nat25_generate_apple_network_addr(unsigned char *networkAddr,
180                                 __be16 *network, unsigned char *node)
181 {
182         memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
183
184         networkAddr[0] = NAT25_APPLE;
185         memcpy(networkAddr+1, (unsigned char *)network, 2);
186         networkAddr[3] = *node;
187 }
188
189 static inline void __nat25_generate_pppoe_network_addr(unsigned char *networkAddr,
190                                 unsigned char *ac_mac, __be16 *sid)
191 {
192         memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
193
194         networkAddr[0] = NAT25_PPPOE;
195         memcpy(networkAddr+1, (unsigned char *)sid, 2);
196         memcpy(networkAddr+3, (unsigned char *)ac_mac, 6);
197 }
198
199 static  void __nat25_generate_ipv6_network_addr(unsigned char *networkAddr,
200                                 __be32 *ipAddr)
201 {
202         memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
203
204         networkAddr[0] = NAT25_IPV6;
205         memcpy(networkAddr+1, (unsigned char *)ipAddr, 16);
206 }
207
208 static unsigned char *scan_tlv(unsigned char *data, int len, unsigned char tag, unsigned char len8b)
209 {
210         while (len > 0) {
211                 if (*data == tag && *(data+1) == len8b && len >= len8b*8)
212                         return data+2;
213
214                 len -= (*(data+1))*8;
215                 data += (*(data+1))*8;
216         }
217         return NULL;
218 }
219
220 static int update_nd_link_layer_addr(unsigned char *data, int len, unsigned char *replace_mac)
221 {
222         struct icmp6hdr *icmphdr = (struct icmp6hdr *)data;
223         unsigned char *mac;
224
225         if (icmphdr->icmp6_type == NDISC_ROUTER_SOLICITATION) {
226                 if (len >= 8) {
227                         mac = scan_tlv(&data[8], len-8, 1, 1);
228                         if (mac) {
229                                 _DEBUG_INFO("Router Solicitation, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
230                                         mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
231                                         replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
232                                 memcpy(mac, replace_mac, 6);
233                                 return 1;
234                         }
235                 }
236         } else if (icmphdr->icmp6_type == NDISC_ROUTER_ADVERTISEMENT) {
237                 if (len >= 16) {
238                         mac = scan_tlv(&data[16], len-16, 1, 1);
239                         if (mac) {
240                                 _DEBUG_INFO("Router Advertisement, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
241                                         mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
242                                         replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
243                                 memcpy(mac, replace_mac, 6);
244                                 return 1;
245                         }
246                 }
247         } else if (icmphdr->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) {
248                 if (len >= 24) {
249                         mac = scan_tlv(&data[24], len-24, 1, 1);
250                         if (mac) {
251                                 _DEBUG_INFO("Neighbor Solicitation, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
252                                         mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
253                                         replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
254                                 memcpy(mac, replace_mac, 6);
255                                 return 1;
256                         }
257                 }
258         } else if (icmphdr->icmp6_type == NDISC_NEIGHBOUR_ADVERTISEMENT) {
259                 if (len >= 24) {
260                         mac = scan_tlv(&data[24], len-24, 2, 1);
261                         if (mac) {
262                                 _DEBUG_INFO("Neighbor Advertisement, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
263                                         mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
264                                         replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
265                                 memcpy(mac, replace_mac, 6);
266                                 return 1;
267                         }
268                 }
269         } else if (icmphdr->icmp6_type == NDISC_REDIRECT) {
270                 if (len >= 40) {
271                         mac = scan_tlv(&data[40], len-40, 2, 1);
272                         if (mac) {
273                                 _DEBUG_INFO("Redirect,  replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
274                                         mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
275                                         replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
276                                 memcpy(mac, replace_mac, 6);
277                                 return 1;
278                         }
279                 }
280         }
281         return 0;
282 }
283
284 static inline int __nat25_network_hash(unsigned char *networkAddr)
285 {
286         if (networkAddr[0] == NAT25_IPV4) {
287                 unsigned long x;
288
289                 x = networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10];
290
291                 return x & (NAT25_HASH_SIZE - 1);
292         } else if (networkAddr[0] == NAT25_IPX) {
293                 unsigned long x;
294
295                 x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^
296                         networkAddr[6] ^ networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10];
297
298                 return x & (NAT25_HASH_SIZE - 1);
299         } else if (networkAddr[0] == NAT25_APPLE) {
300                 unsigned long x;
301
302                 x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3];
303
304                 return x & (NAT25_HASH_SIZE - 1);
305         } else if (networkAddr[0] == NAT25_PPPOE) {
306                 unsigned long x;
307
308                 x = networkAddr[0] ^ networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^ networkAddr[6] ^ networkAddr[7] ^ networkAddr[8];
309
310                 return x & (NAT25_HASH_SIZE - 1);
311         } else if (networkAddr[0] == NAT25_IPV6) {
312                 unsigned long x;
313
314                 x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^
315                         networkAddr[6] ^ networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10] ^
316                         networkAddr[11] ^ networkAddr[12] ^ networkAddr[13] ^ networkAddr[14] ^ networkAddr[15] ^
317                         networkAddr[16];
318
319                 return x & (NAT25_HASH_SIZE - 1);
320         } else {
321                 unsigned long x = 0;
322                 int i;
323
324                 for (i = 0; i < MAX_NETWORK_ADDR_LEN; i++)
325                         x ^= networkAddr[i];
326
327                 return x & (NAT25_HASH_SIZE - 1);
328         }
329 }
330
331 static inline void __network_hash_link(struct adapter *priv,
332                                 struct nat25_network_db_entry *ent, int hash)
333 {
334         /*  Caller must spin_lock_bh already! */
335         ent->next_hash = priv->nethash[hash];
336         if (ent->next_hash != NULL)
337                 ent->next_hash->pprev_hash = &ent->next_hash;
338         priv->nethash[hash] = ent;
339         ent->pprev_hash = &priv->nethash[hash];
340 }
341
342 static inline void __network_hash_unlink(struct nat25_network_db_entry *ent)
343 {
344         /*  Caller must spin_lock_bh already! */
345         *(ent->pprev_hash) = ent->next_hash;
346         if (ent->next_hash != NULL)
347                 ent->next_hash->pprev_hash = ent->pprev_hash;
348         ent->next_hash = NULL;
349         ent->pprev_hash = NULL;
350 }
351
352 static int __nat25_db_network_lookup_and_replace(struct adapter *priv,
353                                 struct sk_buff *skb, unsigned char *networkAddr)
354 {
355         struct nat25_network_db_entry *db;
356         spin_lock_bh(&priv->br_ext_lock);
357
358         db = priv->nethash[__nat25_network_hash(networkAddr)];
359         while (db != NULL) {
360                 if (!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) {
361                         if (!__nat25_has_expired(priv, db)) {
362                                 /*  replace the destination mac address */
363                                 memcpy(skb->data, db->macAddr, ETH_ALEN);
364                                 atomic_inc(&db->use_count);
365
366                                 DEBUG_INFO("NAT25: Lookup M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
367                                                         "%02x%02x%02x%02x%02x%02x\n",
368                                         db->macAddr[0],
369                                         db->macAddr[1],
370                                         db->macAddr[2],
371                                         db->macAddr[3],
372                                         db->macAddr[4],
373                                         db->macAddr[5],
374                                         db->networkAddr[0],
375                                         db->networkAddr[1],
376                                         db->networkAddr[2],
377                                         db->networkAddr[3],
378                                         db->networkAddr[4],
379                                         db->networkAddr[5],
380                                         db->networkAddr[6],
381                                         db->networkAddr[7],
382                                         db->networkAddr[8],
383                                         db->networkAddr[9],
384                                         db->networkAddr[10],
385                                         db->networkAddr[11],
386                                         db->networkAddr[12],
387                                         db->networkAddr[13],
388                                         db->networkAddr[14],
389                                         db->networkAddr[15],
390                                         db->networkAddr[16]);
391                         }
392                         spin_unlock_bh(&priv->br_ext_lock);
393                         return 1;
394                 }
395                 db = db->next_hash;
396         }
397         spin_unlock_bh(&priv->br_ext_lock);
398         return 0;
399 }
400
401 static void __nat25_db_network_insert(struct adapter *priv,
402                                 unsigned char *macAddr, unsigned char *networkAddr)
403 {
404         struct nat25_network_db_entry *db;
405         int hash;
406
407         spin_lock_bh(&priv->br_ext_lock);
408         hash = __nat25_network_hash(networkAddr);
409         db = priv->nethash[hash];
410         while (db != NULL) {
411                 if (!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) {
412                         memcpy(db->macAddr, macAddr, ETH_ALEN);
413                         db->ageing_timer = jiffies;
414                         spin_unlock_bh(&priv->br_ext_lock);
415                         return;
416                 }
417                 db = db->next_hash;
418         }
419         db = (struct nat25_network_db_entry *) rtw_malloc(sizeof(*db));
420         if (db == NULL) {
421                 spin_unlock_bh(&priv->br_ext_lock);
422                 return;
423         }
424         memcpy(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN);
425         memcpy(db->macAddr, macAddr, ETH_ALEN);
426         atomic_set(&db->use_count, 1);
427         db->ageing_timer = jiffies;
428
429         __network_hash_link(priv, db, hash);
430
431         spin_unlock_bh(&priv->br_ext_lock);
432 }
433
434 static void __nat25_db_print(struct adapter *priv)
435 {
436 }
437
438 /*
439  *      NAT2.5 interface
440  */
441
442 void nat25_db_cleanup(struct adapter *priv)
443 {
444         int i;
445         spin_lock_bh(&priv->br_ext_lock);
446
447         for (i = 0; i < NAT25_HASH_SIZE; i++) {
448                 struct nat25_network_db_entry *f;
449                 f = priv->nethash[i];
450                 while (f != NULL) {
451                         struct nat25_network_db_entry *g;
452
453                         g = f->next_hash;
454                         if (priv->scdb_entry == f) {
455                                 memset(priv->scdb_mac, 0, ETH_ALEN);
456                                 memset(priv->scdb_ip, 0, 4);
457                                 priv->scdb_entry = NULL;
458                         }
459                         __network_hash_unlink(f);
460                         kfree(f);
461                         f = g;
462                 }
463         }
464         spin_unlock_bh(&priv->br_ext_lock);
465 }
466
467 void nat25_db_expire(struct adapter *priv)
468 {
469         int i;
470         spin_lock_bh(&priv->br_ext_lock);
471
472         for (i = 0; i < NAT25_HASH_SIZE; i++) {
473                 struct nat25_network_db_entry *f;
474                 f = priv->nethash[i];
475
476                 while (f != NULL) {
477                         struct nat25_network_db_entry *g;
478                         g = f->next_hash;
479
480                         if (__nat25_has_expired(priv, f)) {
481                                 if (atomic_dec_and_test(&f->use_count)) {
482                                         if (priv->scdb_entry == f) {
483                                                 memset(priv->scdb_mac, 0, ETH_ALEN);
484                                                 memset(priv->scdb_ip, 0, 4);
485                                                 priv->scdb_entry = NULL;
486                                         }
487                                         __network_hash_unlink(f);
488                                         kfree(f);
489                                 }
490                         }
491                         f = g;
492                 }
493         }
494         spin_unlock_bh(&priv->br_ext_lock);
495 }
496
497 int nat25_db_handle(struct adapter *priv, struct sk_buff *skb, int method)
498 {
499         unsigned short protocol;
500         unsigned char networkAddr[MAX_NETWORK_ADDR_LEN];
501         unsigned int tmp;
502
503         if (skb == NULL)
504                 return -1;
505
506         if ((method <= NAT25_MIN) || (method >= NAT25_MAX))
507                 return -1;
508
509         protocol = be16_to_cpu(*((__be16 *)(skb->data + 2 * ETH_ALEN)));
510
511         /*---------------------------------------------------*/
512         /*                 Handle IP frame                   */
513         /*---------------------------------------------------*/
514         if (protocol == ETH_P_IP) {
515                 struct iphdr *iph = (struct iphdr *)(skb->data + ETH_HLEN);
516
517                 if (((unsigned char *)(iph) + (iph->ihl<<2)) >= (skb->data + ETH_HLEN + skb->len)) {
518                         DEBUG_WARN("NAT25: malformed IP packet !\n");
519                         return -1;
520                 }
521
522                 switch (method) {
523                 case NAT25_CHECK:
524                         return -1;
525                 case NAT25_INSERT:
526                         /* some multicast with source IP is all zero, maybe other case is illegal */
527                         /* in class A, B, C, host address is all zero or all one is illegal */
528                         if (iph->saddr == 0)
529                                 return 0;
530                         tmp = be32_to_cpu(iph->saddr);
531                         DEBUG_INFO("NAT25: Insert IP, SA =%08x, DA =%08x\n", tmp, iph->daddr);
532                         __nat25_generate_ipv4_network_addr(networkAddr, &tmp);
533                         /* record source IP address and , source mac address into db */
534                         __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
535
536                         __nat25_db_print(priv);
537                         return 0;
538                 case NAT25_LOOKUP:
539                         DEBUG_INFO("NAT25: Lookup IP, SA =%08x, DA =%08x\n", iph->saddr, iph->daddr);
540                         tmp = be32_to_cpu(iph->daddr);
541                         __nat25_generate_ipv4_network_addr(networkAddr, &tmp);
542
543                         if (!__nat25_db_network_lookup_and_replace(priv, skb, networkAddr)) {
544                                 if (*((unsigned char *)&iph->daddr + 3) == 0xff) {
545                                         /*  L2 is unicast but L3 is broadcast, make L2 bacome broadcast */
546                                         DEBUG_INFO("NAT25: Set DA as boardcast\n");
547                                         memset(skb->data, 0xff, ETH_ALEN);
548                                 } else {
549                                         /*  forward unknow IP packet to upper TCP/IP */
550                                         DEBUG_INFO("NAT25: Replace DA with BR's MAC\n");
551                                         if ((*(u32 *)priv->br_mac) == 0 && (*(u16 *)(priv->br_mac+4)) == 0) {
552                                                 printk("Re-init netdev_br_init() due to br_mac == 0!\n");
553                                                 netdev_br_init(priv->pnetdev);
554                                         }
555                                         memcpy(skb->data, priv->br_mac, ETH_ALEN);
556                                 }
557                         }
558                         return 0;
559                 default:
560                         return -1;
561                 }
562         } else if (protocol == ETH_P_ARP) {
563                 /*---------------------------------------------------*/
564                 /*                 Handle ARP frame                  */
565                 /*---------------------------------------------------*/
566                 struct arphdr *arp = (struct arphdr *)(skb->data + ETH_HLEN);
567                 unsigned char *arp_ptr = (unsigned char *)(arp + 1);
568                 unsigned int *sender, *target;
569
570                 if (arp->ar_pro != __constant_htons(ETH_P_IP)) {
571                         DEBUG_WARN("NAT25: arp protocol unknown (%4x)!\n", be16_to_cpu(arp->ar_pro));
572                         return -1;
573                 }
574
575                 switch (method) {
576                 case NAT25_CHECK:
577                         return 0;       /*  skb_copy for all ARP frame */
578                 case NAT25_INSERT:
579                         DEBUG_INFO("NAT25: Insert ARP, MAC =%02x%02x%02x%02x%02x%02x\n", arp_ptr[0],
580                                 arp_ptr[1], arp_ptr[2], arp_ptr[3], arp_ptr[4], arp_ptr[5]);
581
582                         /*  change to ARP sender mac address to wlan STA address */
583                         memcpy(arp_ptr, GET_MY_HWADDR(priv), ETH_ALEN);
584                         arp_ptr += arp->ar_hln;
585                         sender = (unsigned int *)arp_ptr;
586                         __nat25_generate_ipv4_network_addr(networkAddr, sender);
587                         __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
588                         __nat25_db_print(priv);
589                         return 0;
590                 case NAT25_LOOKUP:
591                         DEBUG_INFO("NAT25: Lookup ARP\n");
592
593                         arp_ptr += arp->ar_hln;
594                         sender = (unsigned int *)arp_ptr;
595                         arp_ptr += (arp->ar_hln + arp->ar_pln);
596                         target = (unsigned int *)arp_ptr;
597                         __nat25_generate_ipv4_network_addr(networkAddr, target);
598                         __nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
599                         /*  change to ARP target mac address to Lookup result */
600                         arp_ptr = (unsigned char *)(arp + 1);
601                         arp_ptr += (arp->ar_hln + arp->ar_pln);
602                         memcpy(arp_ptr, skb->data, ETH_ALEN);
603                         return 0;
604                 default:
605                         return -1;
606                 }
607         } else if ((protocol == ETH_P_IPX) ||
608                    (protocol <= ETH_FRAME_LEN)) {
609                 /*---------------------------------------------------*/
610                 /*         Handle IPX and Apple Talk frame           */
611                 /*---------------------------------------------------*/
612                 unsigned char ipx_header[2] = {0xFF, 0xFF};
613                 struct ipxhdr   *ipx = NULL;
614                 struct elapaarp *ea = NULL;
615                 struct ddpehdr  *ddp = NULL;
616                 unsigned char *framePtr = skb->data + ETH_HLEN;
617
618                 if (protocol == ETH_P_IPX) {
619                         DEBUG_INFO("NAT25: Protocol = IPX (Ethernet II)\n");
620                         ipx = (struct ipxhdr *)framePtr;
621                 } else if (protocol <= ETH_FRAME_LEN) {
622                         if (!memcmp(ipx_header, framePtr, 2)) {
623                                 DEBUG_INFO("NAT25: Protocol = IPX (Ethernet 802.3)\n");
624                                 ipx = (struct ipxhdr *)framePtr;
625                         } else {
626                                 unsigned char ipx_8022_type =  0xE0;
627                                 unsigned char snap_8022_type = 0xAA;
628
629                                 if (*framePtr == snap_8022_type) {
630                                         unsigned char ipx_snap_id[5] = {0x0, 0x0, 0x0, 0x81, 0x37};             /*  IPX SNAP ID */
631                                         unsigned char aarp_snap_id[5] = {0x00, 0x00, 0x00, 0x80, 0xF3}; /*  Apple Talk AARP SNAP ID */
632                                         unsigned char ddp_snap_id[5] = {0x08, 0x00, 0x07, 0x80, 0x9B};  /*  Apple Talk DDP SNAP ID */
633
634                                         framePtr += 3;  /*  eliminate the 802.2 header */
635
636                                         if (!memcmp(ipx_snap_id, framePtr, 5)) {
637                                                 framePtr += 5;  /*  eliminate the SNAP header */
638
639                                                 DEBUG_INFO("NAT25: Protocol = IPX (Ethernet SNAP)\n");
640                                                 ipx = (struct ipxhdr *)framePtr;
641                                         } else if (!memcmp(aarp_snap_id, framePtr, 5)) {
642                                                 framePtr += 5;  /*  eliminate the SNAP header */
643
644                                                 ea = (struct elapaarp *)framePtr;
645                                         } else if (!memcmp(ddp_snap_id, framePtr, 5)) {
646                                                 framePtr += 5;  /*  eliminate the SNAP header */
647
648                                                 ddp = (struct ddpehdr *)framePtr;
649                                         } else {
650                                                 DEBUG_WARN("NAT25: Protocol = Ethernet SNAP %02x%02x%02x%02x%02x\n", framePtr[0],
651                                                         framePtr[1], framePtr[2], framePtr[3], framePtr[4]);
652                                                 return -1;
653                                         }
654                                 } else if (*framePtr == ipx_8022_type) {
655                                         framePtr += 3;  /*  eliminate the 802.2 header */
656
657                                         if (!memcmp(ipx_header, framePtr, 2)) {
658                                                 DEBUG_INFO("NAT25: Protocol = IPX (Ethernet 802.2)\n");
659                                                 ipx = (struct ipxhdr *)framePtr;
660                                         } else {
661                                                 return -1;
662                                         }
663                                 } else {
664                                         return -1;
665                                 }
666                         }
667                 } else {
668                         return -1;
669                 }
670
671                 /*   IPX   */
672                 if (ipx != NULL) {
673                         switch (method) {
674                         case NAT25_CHECK:
675                                 if (!memcmp(skb->data+ETH_ALEN, ipx->ipx_source.node, ETH_ALEN))
676                                         DEBUG_INFO("NAT25: Check IPX skb_copy\n");
677                                 return 0;
678                         case NAT25_INSERT:
679                                 DEBUG_INFO("NAT25: Insert IPX, Dest =%08x,%02x%02x%02x%02x%02x%02x,%04x Source =%08x,%02x%02x%02x%02x%02x%02x,%04x\n",
680                                         ipx->ipx_dest.net,
681                                         ipx->ipx_dest.node[0],
682                                         ipx->ipx_dest.node[1],
683                                         ipx->ipx_dest.node[2],
684                                         ipx->ipx_dest.node[3],
685                                         ipx->ipx_dest.node[4],
686                                         ipx->ipx_dest.node[5],
687                                         ipx->ipx_dest.sock,
688                                         ipx->ipx_source.net,
689                                         ipx->ipx_source.node[0],
690                                         ipx->ipx_source.node[1],
691                                         ipx->ipx_source.node[2],
692                                         ipx->ipx_source.node[3],
693                                         ipx->ipx_source.node[4],
694                                         ipx->ipx_source.node[5],
695                                         ipx->ipx_source.sock);
696
697                                 if (!memcmp(skb->data+ETH_ALEN, ipx->ipx_source.node, ETH_ALEN)) {
698                                         DEBUG_INFO("NAT25: Use IPX Net, and Socket as network addr\n");
699
700                                         __nat25_generate_ipx_network_addr_with_socket(networkAddr, &ipx->ipx_source.net, &ipx->ipx_source.sock);
701
702                                         /*  change IPX source node addr to wlan STA address */
703                                         memcpy(ipx->ipx_source.node, GET_MY_HWADDR(priv), ETH_ALEN);
704                                 } else {
705                                         __nat25_generate_ipx_network_addr_with_node(networkAddr, &ipx->ipx_source.net, ipx->ipx_source.node);
706                                 }
707                                 __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
708                                 __nat25_db_print(priv);
709                                 return 0;
710                         case NAT25_LOOKUP:
711                                 if (!memcmp(GET_MY_HWADDR(priv), ipx->ipx_dest.node, ETH_ALEN)) {
712                                         DEBUG_INFO("NAT25: Lookup IPX, Modify Destination IPX Node addr\n");
713
714                                         __nat25_generate_ipx_network_addr_with_socket(networkAddr, &ipx->ipx_dest.net, &ipx->ipx_dest.sock);
715
716                                         __nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
717
718                                         /*  replace IPX destination node addr with Lookup destination MAC addr */
719                                         memcpy(ipx->ipx_dest.node, skb->data, ETH_ALEN);
720                                 } else {
721                                         __nat25_generate_ipx_network_addr_with_node(networkAddr, &ipx->ipx_dest.net, ipx->ipx_dest.node);
722
723                                         __nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
724                                 }
725                                 return 0;
726                         default:
727                                 return -1;
728                         }
729                 } else if (ea != NULL) {
730                         /* Sanity check fields. */
731                         if (ea->hw_len != ETH_ALEN || ea->pa_len != AARP_PA_ALEN) {
732                                 DEBUG_WARN("NAT25: Appletalk AARP Sanity check fail!\n");
733                                 return -1;
734                         }
735
736                         switch (method) {
737                         case NAT25_CHECK:
738                                 return 0;
739                         case NAT25_INSERT:
740                                 /*  change to AARP source mac address to wlan STA address */
741                                 memcpy(ea->hw_src, GET_MY_HWADDR(priv), ETH_ALEN);
742
743                                 DEBUG_INFO("NAT25: Insert AARP, Source =%d,%d Destination =%d,%d\n",
744                                         ea->pa_src_net,
745                                         ea->pa_src_node,
746                                         ea->pa_dst_net,
747                                         ea->pa_dst_node);
748
749                                 __nat25_generate_apple_network_addr(networkAddr, &ea->pa_src_net, &ea->pa_src_node);
750
751                                 __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
752
753                                 __nat25_db_print(priv);
754                                 return 0;
755                         case NAT25_LOOKUP:
756                                 DEBUG_INFO("NAT25: Lookup AARP, Source =%d,%d Destination =%d,%d\n",
757                                         ea->pa_src_net,
758                                         ea->pa_src_node,
759                                         ea->pa_dst_net,
760                                         ea->pa_dst_node);
761
762                                 __nat25_generate_apple_network_addr(networkAddr, &ea->pa_dst_net, &ea->pa_dst_node);
763
764                                 __nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
765
766                                 /*  change to AARP destination mac address to Lookup result */
767                                 memcpy(ea->hw_dst, skb->data, ETH_ALEN);
768                                 return 0;
769                         default:
770                                 return -1;
771                         }
772                 } else if (ddp != NULL) {
773                         switch (method) {
774                         case NAT25_CHECK:
775                                 return -1;
776                         case NAT25_INSERT:
777                                 DEBUG_INFO("NAT25: Insert DDP, Source =%d,%d Destination =%d,%d\n",
778                                         ddp->deh_snet,
779                                         ddp->deh_snode,
780                                         ddp->deh_dnet,
781                                         ddp->deh_dnode);
782
783                                 __nat25_generate_apple_network_addr(networkAddr, &ddp->deh_snet, &ddp->deh_snode);
784
785                                 __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
786
787                                 __nat25_db_print(priv);
788                                 return 0;
789                         case NAT25_LOOKUP:
790                                 DEBUG_INFO("NAT25: Lookup DDP, Source =%d,%d Destination =%d,%d\n",
791                                         ddp->deh_snet,
792                                         ddp->deh_snode,
793                                         ddp->deh_dnet,
794                                         ddp->deh_dnode);
795                                 __nat25_generate_apple_network_addr(networkAddr, &ddp->deh_dnet, &ddp->deh_dnode);
796                                 __nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
797                                 return 0;
798                         default:
799                                 return -1;
800                         }
801                 }
802
803                 return -1;
804         } else if ((protocol == ETH_P_PPP_DISC) ||
805                    (protocol == ETH_P_PPP_SES)) {
806                 /*---------------------------------------------------*/
807                 /*                Handle PPPoE frame                 */
808                 /*---------------------------------------------------*/
809                 struct pppoe_hdr *ph = (struct pppoe_hdr *)(skb->data + ETH_HLEN);
810                 __be16 *pMagic;
811
812                 switch (method) {
813                 case NAT25_CHECK:
814                         if (ph->sid == 0)
815                                 return 0;
816                         return 1;
817                 case NAT25_INSERT:
818                         if (ph->sid == 0) {     /*  Discovery phase according to tag */
819                                 if (ph->code == PADI_CODE || ph->code == PADR_CODE) {
820                                         if (priv->ethBrExtInfo.addPPPoETag) {
821                                                 struct pppoe_tag *tag, *pOldTag;
822                                                 unsigned char tag_buf[40];
823                                                 int old_tag_len = 0;
824
825                                                 tag = (struct pppoe_tag *)tag_buf;
826                                                 pOldTag = (struct pppoe_tag *)__nat25_find_pppoe_tag(ph, ntohs(PTT_RELAY_SID));
827                                                 if (pOldTag) { /*  if SID existed, copy old value and delete it */
828                                                         old_tag_len = ntohs(pOldTag->tag_len);
829                                                         if (old_tag_len+TAG_HDR_LEN+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN > sizeof(tag_buf)) {
830                                                                 DEBUG_ERR("SID tag length too long!\n");
831                                                                 return -1;
832                                                         }
833
834                                                         memcpy(tag->tag_data+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN,
835                                                                 pOldTag->tag_data, old_tag_len);
836
837                                                         if (skb_pull_and_merge(skb, (unsigned char *)pOldTag, TAG_HDR_LEN+old_tag_len) < 0) {
838                                                                 DEBUG_ERR("call skb_pull_and_merge() failed in PADI/R packet!\n");
839                                                                 return -1;
840                                                         }
841                                                         ph->length = htons(ntohs(ph->length)-TAG_HDR_LEN-old_tag_len);
842                                                 }
843
844                                                 tag->tag_type = PTT_RELAY_SID;
845                                                 tag->tag_len = htons(MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN+old_tag_len);
846
847                                                 /*  insert the magic_code+client mac in relay tag */
848                                                 pMagic = (__be16 *)tag->tag_data;
849                                                 *pMagic = htons(MAGIC_CODE);
850                                                 memcpy(tag->tag_data+MAGIC_CODE_LEN, skb->data+ETH_ALEN, ETH_ALEN);
851
852                                                 /* Add relay tag */
853                                                 if (__nat25_add_pppoe_tag(skb, tag) < 0)
854                                                         return -1;
855
856                                                 DEBUG_INFO("NAT25: Insert PPPoE, forward %s packet\n",
857                                                                                 (ph->code == PADI_CODE ? "PADI" : "PADR"));
858                                         } else { /*  not add relay tag */
859                                                 if (priv->pppoe_connection_in_progress &&
860                                                                 memcmp(skb->data+ETH_ALEN, priv->pppoe_addr, ETH_ALEN))  {
861                                                         DEBUG_ERR("Discard PPPoE packet due to another PPPoE connection is in progress!\n");
862                                                         return -2;
863                                                 }
864
865                                                 if (priv->pppoe_connection_in_progress == 0)
866                                                         memcpy(priv->pppoe_addr, skb->data+ETH_ALEN, ETH_ALEN);
867
868                                                 priv->pppoe_connection_in_progress = WAIT_TIME_PPPOE;
869                                         }
870                                 } else {
871                                         return -1;
872                                 }
873                         } else {        /*  session phase */
874                                 DEBUG_INFO("NAT25: Insert PPPoE, insert session packet to %s\n", skb->dev->name);
875
876                                 __nat25_generate_pppoe_network_addr(networkAddr, skb->data, &(ph->sid));
877
878                                 __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
879
880                                 __nat25_db_print(priv);
881
882                                 if (!priv->ethBrExtInfo.addPPPoETag &&
883                                     priv->pppoe_connection_in_progress &&
884                                     !memcmp(skb->data+ETH_ALEN, priv->pppoe_addr, ETH_ALEN))
885                                         priv->pppoe_connection_in_progress = 0;
886                         }
887                         return 0;
888                 case NAT25_LOOKUP:
889                         if (ph->code == PADO_CODE || ph->code == PADS_CODE) {
890                                 if (priv->ethBrExtInfo.addPPPoETag) {
891                                         struct pppoe_tag *tag;
892                                         unsigned char *ptr;
893                                         unsigned short tagType, tagLen;
894                                         int offset = 0;
895
896                                         ptr = __nat25_find_pppoe_tag(ph, ntohs(PTT_RELAY_SID));
897                                         if (ptr == NULL) {
898                                                 DEBUG_ERR("Fail to find PTT_RELAY_SID in FADO!\n");
899                                                 return -1;
900                                         }
901
902                                         tag = (struct pppoe_tag *)ptr;
903                                         tagType = (unsigned short)((ptr[0] << 8) + ptr[1]);
904                                         tagLen = (unsigned short)((ptr[2] << 8) + ptr[3]);
905
906                                         if ((tagType != ntohs(PTT_RELAY_SID)) || (tagLen < (MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN))) {
907                                                 DEBUG_ERR("Invalid PTT_RELAY_SID tag length [%d]!\n", tagLen);
908                                                 return -1;
909                                         }
910
911                                         pMagic = (__be16 *)tag->tag_data;
912                                         if (ntohs(*pMagic) != MAGIC_CODE) {
913                                                 DEBUG_ERR("Can't find MAGIC_CODE in %s packet!\n",
914                                                         (ph->code == PADO_CODE ? "PADO" : "PADS"));
915                                                 return -1;
916                                         }
917
918                                         memcpy(skb->data, tag->tag_data+MAGIC_CODE_LEN, ETH_ALEN);
919
920                                         if (tagLen > MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN)
921                                                 offset = TAG_HDR_LEN;
922
923                                         if (skb_pull_and_merge(skb, ptr+offset, TAG_HDR_LEN+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN-offset) < 0) {
924                                                 DEBUG_ERR("call skb_pull_and_merge() failed in PADO packet!\n");
925                                                 return -1;
926                                         }
927                                         ph->length = htons(ntohs(ph->length)-(TAG_HDR_LEN+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN-offset));
928                                         if (offset > 0)
929                                                 tag->tag_len = htons(tagLen-MAGIC_CODE_LEN-RTL_RELAY_TAG_LEN);
930
931                                         DEBUG_INFO("NAT25: Lookup PPPoE, forward %s Packet from %s\n",
932                                                 (ph->code == PADO_CODE ? "PADO" : "PADS"),      skb->dev->name);
933                                 } else { /*  not add relay tag */
934                                         if (!priv->pppoe_connection_in_progress) {
935                                                 DEBUG_ERR("Discard PPPoE packet due to no connection in progresss!\n");
936                                                 return -1;
937                                         }
938                                         memcpy(skb->data, priv->pppoe_addr, ETH_ALEN);
939                                         priv->pppoe_connection_in_progress = WAIT_TIME_PPPOE;
940                                 }
941                         } else {
942                                 if (ph->sid != 0) {
943                                         DEBUG_INFO("NAT25: Lookup PPPoE, lookup session packet from %s\n", skb->dev->name);
944                                         __nat25_generate_pppoe_network_addr(networkAddr, skb->data+ETH_ALEN, &(ph->sid));
945                                         __nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
946                                         __nat25_db_print(priv);
947                                 } else {
948                                         return -1;
949                                 }
950                         }
951                         return 0;
952                 default:
953                         return -1;
954                 }
955         } else if (protocol == 0x888e) {
956                 /*---------------------------------------------------*/
957                 /*                 Handle EAP frame                  */
958                 /*---------------------------------------------------*/
959                 switch (method) {
960                 case NAT25_CHECK:
961                         return -1;
962                 case NAT25_INSERT:
963                         return 0;
964                 case NAT25_LOOKUP:
965                         return 0;
966                 default:
967                         return -1;
968                 }
969         } else if ((protocol == 0xe2ae) || (protocol == 0xe2af)) {
970                 /*---------------------------------------------------*/
971                 /*         Handle C-Media proprietary frame          */
972                 /*---------------------------------------------------*/
973                 switch (method) {
974                 case NAT25_CHECK:
975                         return -1;
976                 case NAT25_INSERT:
977                         return 0;
978                 case NAT25_LOOKUP:
979                         return 0;
980                 default:
981                         return -1;
982                 }
983         } else if (protocol == ETH_P_IPV6) {
984                 /*------------------------------------------------*/
985                 /*         Handle IPV6 frame                      */
986                 /*------------------------------------------------*/
987                 struct ipv6hdr *iph = (struct ipv6hdr *)(skb->data + ETH_HLEN);
988
989                 if (sizeof(*iph) >= (skb->len - ETH_HLEN)) {
990                         DEBUG_WARN("NAT25: malformed IPv6 packet !\n");
991                         return -1;
992                 }
993
994                 switch (method) {
995                 case NAT25_CHECK:
996                         if (skb->data[0] & 1)
997                                 return 0;
998                         return -1;
999                 case NAT25_INSERT:
1000                         DEBUG_INFO("NAT25: Insert IP, SA =%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x,"
1001                                                         " DA =%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x\n",
1002                                 iph->saddr.s6_addr16[0], iph->saddr.s6_addr16[1], iph->saddr.s6_addr16[2], iph->saddr.s6_addr16[3],
1003                                 iph->saddr.s6_addr16[4], iph->saddr.s6_addr16[5], iph->saddr.s6_addr16[6], iph->saddr.s6_addr16[7],
1004                                 iph->daddr.s6_addr16[0], iph->daddr.s6_addr16[1], iph->daddr.s6_addr16[2], iph->daddr.s6_addr16[3],
1005                                 iph->daddr.s6_addr16[4], iph->daddr.s6_addr16[5], iph->daddr.s6_addr16[6], iph->daddr.s6_addr16[7]);
1006
1007                         if (memcmp(&iph->saddr, "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0", 16)) {
1008                                 __nat25_generate_ipv6_network_addr(networkAddr, (__be32 *)&iph->saddr);
1009                                 __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
1010                                 __nat25_db_print(priv);
1011
1012                                 if (iph->nexthdr == IPPROTO_ICMPV6 &&
1013                                                 skb->len > (ETH_HLEN +  sizeof(*iph) + 4)) {
1014                                         if (update_nd_link_layer_addr(skb->data + ETH_HLEN + sizeof(*iph),
1015                                                                       skb->len - ETH_HLEN - sizeof(*iph), GET_MY_HWADDR(priv))) {
1016                                                 struct icmp6hdr  *hdr = (struct icmp6hdr *)(skb->data + ETH_HLEN + sizeof(*iph));
1017                                                 hdr->icmp6_cksum = 0;
1018                                                 hdr->icmp6_cksum = csum_ipv6_magic(&iph->saddr, &iph->daddr,
1019                                                                                 be16_to_cpu(iph->payload_len),
1020                                                                                 IPPROTO_ICMPV6,
1021                                                                                 csum_partial((__u8 *)hdr,
1022                                                                                 be16_to_cpu(iph->payload_len), 0));
1023                                         }
1024                                 }
1025                         }
1026                         return 0;
1027                 case NAT25_LOOKUP:
1028                         DEBUG_INFO("NAT25: Lookup IP, SA =%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x, DA =%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x\n",
1029                                    iph->saddr.s6_addr16[0], iph->saddr.s6_addr16[1], iph->saddr.s6_addr16[2], iph->saddr.s6_addr16[3],
1030                                    iph->saddr.s6_addr16[4], iph->saddr.s6_addr16[5], iph->saddr.s6_addr16[6], iph->saddr.s6_addr16[7],
1031                                    iph->daddr.s6_addr16[0], iph->daddr.s6_addr16[1], iph->daddr.s6_addr16[2], iph->daddr.s6_addr16[3],
1032                                    iph->daddr.s6_addr16[4], iph->daddr.s6_addr16[5], iph->daddr.s6_addr16[6], iph->daddr.s6_addr16[7]);
1033                         __nat25_generate_ipv6_network_addr(networkAddr, (__be32 *)&iph->daddr);
1034                         __nat25_db_network_lookup_and_replace(priv, skb, networkAddr);
1035                         return 0;
1036                 default:
1037                         return -1;
1038                 }
1039         }
1040         return -1;
1041 }
1042
1043 int nat25_handle_frame(struct adapter *priv, struct sk_buff *skb)
1044 {
1045         if (!(skb->data[0] & 1)) {
1046                 int is_vlan_tag = 0, i, retval = 0;
1047                 unsigned short vlan_hdr = 0;
1048                 unsigned short protocol;
1049
1050                 protocol = be16_to_cpu(*((__be16 *)(skb->data + 2 * ETH_ALEN)));
1051                 if (protocol == ETH_P_8021Q) {
1052                         is_vlan_tag = 1;
1053                         vlan_hdr = *((unsigned short *)(skb->data+ETH_ALEN*2+2));
1054                         for (i = 0; i < 6; i++)
1055                                 *((unsigned short *)(skb->data+ETH_ALEN*2+2-i*2)) = *((unsigned short *)(skb->data+ETH_ALEN*2-2-i*2));
1056                         skb_pull(skb, 4);
1057                 }
1058
1059                 if (!priv->ethBrExtInfo.nat25_disable) {
1060                         spin_lock_bh(&priv->br_ext_lock);
1061                         /*
1062                          *      This function look up the destination network address from
1063                          *      the NAT2.5 database. Return value = -1 means that the
1064                          *      corresponding network protocol is NOT support.
1065                          */
1066                         if (!priv->ethBrExtInfo.nat25sc_disable &&
1067                             (be16_to_cpu(*((__be16 *)(skb->data+ETH_ALEN*2))) == ETH_P_IP) &&
1068                             !memcmp(priv->scdb_ip, skb->data+ETH_HLEN+16, 4)) {
1069                                 memcpy(skb->data, priv->scdb_mac, ETH_ALEN);
1070
1071                                 spin_unlock_bh(&priv->br_ext_lock);
1072                         } else {
1073                                 spin_unlock_bh(&priv->br_ext_lock);
1074
1075                                 retval = nat25_db_handle(priv, skb, NAT25_LOOKUP);
1076                         }
1077                 } else {
1078                         if (((be16_to_cpu(*((__be16 *)(skb->data+ETH_ALEN*2))) == ETH_P_IP) &&
1079                             !memcmp(priv->br_ip, skb->data+ETH_HLEN+16, 4)) ||
1080                             ((be16_to_cpu(*((__be16 *)(skb->data+ETH_ALEN*2))) == ETH_P_ARP) &&
1081                             !memcmp(priv->br_ip, skb->data+ETH_HLEN+24, 4))) {
1082                                 /*  for traffic to upper TCP/IP */
1083                                 retval = nat25_db_handle(priv, skb, NAT25_LOOKUP);
1084                         }
1085                 }
1086
1087                 if (is_vlan_tag) {
1088                         skb_push(skb, 4);
1089                         for (i = 0; i < 6; i++)
1090                                 *((unsigned short *)(skb->data+i*2)) = *((unsigned short *)(skb->data+4+i*2));
1091                         *((__be16 *)(skb->data+ETH_ALEN*2)) = __constant_htons(ETH_P_8021Q);
1092                         *((unsigned short *)(skb->data+ETH_ALEN*2+2)) = vlan_hdr;
1093                 }
1094
1095                 if (retval == -1) {
1096                         /* DEBUG_ERR("NAT25: Lookup fail!\n"); */
1097                         return -1;
1098                 }
1099         }
1100
1101         return 0;
1102 }
1103
1104 #define SERVER_PORT                     67
1105 #define CLIENT_PORT                     68
1106 #define DHCP_MAGIC                      0x63825363
1107 #define BROADCAST_FLAG          0x8000
1108
1109 struct dhcpMessage {
1110         u_int8_t op;
1111         u_int8_t htype;
1112         u_int8_t hlen;
1113         u_int8_t hops;
1114         __be32 xid;
1115         __be16 secs;
1116         __be16 flags;
1117         __be32 ciaddr;
1118         __be32 yiaddr;
1119         __be32 siaddr;
1120         __be32 giaddr;
1121         u_int8_t chaddr[16];
1122         u_int8_t sname[64];
1123         u_int8_t file[128];
1124         __be32 cookie;
1125         u_int8_t options[308]; /* 312 - cookie */
1126 };
1127
1128 void dhcp_flag_bcast(struct adapter *priv, struct sk_buff *skb)
1129 {
1130         if (skb == NULL)
1131                 return;
1132
1133         if (!priv->ethBrExtInfo.dhcp_bcst_disable) {
1134                 __be16 protocol = *((__be16 *)(skb->data + 2 * ETH_ALEN));
1135
1136                 if (protocol == __constant_htons(ETH_P_IP)) { /*  IP */
1137                         struct iphdr *iph = (struct iphdr *)(skb->data + ETH_HLEN);
1138
1139                         if (iph->protocol == IPPROTO_UDP) { /*  UDP */
1140                                 struct udphdr *udph = (struct udphdr *)((size_t)iph + (iph->ihl << 2));
1141
1142                                 if ((udph->source == __constant_htons(CLIENT_PORT)) &&
1143                                     (udph->dest == __constant_htons(SERVER_PORT))) { /*  DHCP request */
1144                                         struct dhcpMessage *dhcph =
1145                                                 (struct dhcpMessage *)((size_t)udph + sizeof(struct udphdr));
1146                                         u32 cookie = be32_to_cpu((__be32)dhcph->cookie);
1147
1148                                         if (cookie == DHCP_MAGIC) { /*  match magic word */
1149                                                 if (!(dhcph->flags & htons(BROADCAST_FLAG))) {
1150                                                         /*  if not broadcast */
1151                                                         register int sum = 0;
1152
1153                                                         DEBUG_INFO("DHCP: change flag of DHCP request to broadcast.\n");
1154                                                         /*  or BROADCAST flag */
1155                                                         dhcph->flags |= htons(BROADCAST_FLAG);
1156                                                         /*  recalculate checksum */
1157                                                         sum = ~(udph->check) & 0xffff;
1158                                                         sum += be16_to_cpu(dhcph->flags);
1159                                                         while (sum >> 16)
1160                                                                 sum = (sum & 0xffff) + (sum >> 16);
1161                                                         udph->check = ~sum;
1162                                                 }
1163                                         }
1164                                 }
1165                         }
1166                 }
1167         }
1168 }
1169
1170
1171 void *scdb_findEntry(struct adapter *priv, unsigned char *macAddr,
1172                                 unsigned char *ipAddr)
1173 {
1174         unsigned char networkAddr[MAX_NETWORK_ADDR_LEN];
1175         struct nat25_network_db_entry *db;
1176         int hash;
1177
1178         __nat25_generate_ipv4_network_addr(networkAddr, (unsigned int *)ipAddr);
1179         hash = __nat25_network_hash(networkAddr);
1180         db = priv->nethash[hash];
1181         while (db != NULL) {
1182                 if (!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN))
1183                         return (void *)db;
1184
1185                 db = db->next_hash;
1186         }
1187
1188         return NULL;
1189 }