Merge tag 'pci-v5.18-changes-2' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / drivers / staging / r8188eu / core / rtw_br_ext.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright(c) 2007 - 2011 Realtek Corporation. i*/
3
4 #define _RTW_BR_EXT_C_
5
6 #include "../include/linux/if_arp.h"
7 #include "../include/net/ip.h"
8 #include "../include/linux/atalk.h"
9 #include "../include/linux/udp.h"
10 #include "../include/linux/if_pppox.h"
11
12 #include "../include/drv_types.h"
13 #include "../include/rtw_br_ext.h"
14 #include "../include/usb_osintf.h"
15 #include "../include/recv_osdep.h"
16
17 #ifndef csum_ipv6_magic
18 #include "../include/net/ip6_checksum.h"
19 #endif
20
21 #include "../include/linux/ipv6.h"
22 #include "../include/linux/icmpv6.h"
23 #include "../include/net/ndisc.h"
24 #include "../include/net/checksum.h"
25
26 #define NAT25_IPV4              01
27 #define NAT25_IPV6              02
28 #define NAT25_IPX               03
29 #define NAT25_APPLE             04
30 #define NAT25_PPPOE             05
31
32 #define RTL_RELAY_TAG_LEN (ETH_ALEN)
33 #define TAG_HDR_LEN             4
34
35 #define MAGIC_CODE              0x8186
36 #define MAGIC_CODE_LEN  2
37 #define WAIT_TIME_PPPOE 5       /*  waiting time for pppoe server in sec */
38
39 /*-----------------------------------------------------------------
40   How database records network address:
41            0    1    2    3    4    5    6    7    8    9   10
42         |----|----|----|----|----|----|----|----|----|----|----|
43   IPv4  |type|                             |      IP addr      |
44   IPX   |type|      Net addr     |          Node addr          |
45   IPX   |type|      Net addr     |Sckt addr|
46   Apple |type| Network |node|
47   PPPoE |type|   SID   |           AC MAC            |
48 -----------------------------------------------------------------*/
49
50 /* Find a tag in pppoe frame and return the pointer */
51 static unsigned char *__nat25_find_pppoe_tag(struct pppoe_hdr *ph, unsigned short type)
52 {
53         unsigned char *cur_ptr, *start_ptr;
54         unsigned short tagLen, tagType;
55
56         start_ptr = cur_ptr = (unsigned char *)ph->tag;
57         while ((cur_ptr - start_ptr) < ntohs(ph->length)) {
58                 /*  prevent un-alignment access */
59                 tagType = (unsigned short)((cur_ptr[0] << 8) + cur_ptr[1]);
60                 tagLen  = (unsigned short)((cur_ptr[2] << 8) + cur_ptr[3]);
61                 if (tagType == type)
62                         return cur_ptr;
63                 cur_ptr = cur_ptr + TAG_HDR_LEN + tagLen;
64         }
65         return NULL;
66 }
67
68 static int __nat25_add_pppoe_tag(struct sk_buff *skb, struct pppoe_tag *tag)
69 {
70         struct pppoe_hdr *ph = (struct pppoe_hdr *)(skb->data + ETH_HLEN);
71         int data_len;
72
73         data_len = tag->tag_len + TAG_HDR_LEN;
74         if (skb_tailroom(skb) < data_len)
75                 return -1;
76
77         skb_put(skb, data_len);
78         /*  have a room for new tag */
79         memmove(((unsigned char *)ph->tag + data_len), (unsigned char *)ph->tag, ntohs(ph->length));
80         ph->length = htons(ntohs(ph->length) + data_len);
81         memcpy((unsigned char *)ph->tag, tag, data_len);
82         return data_len;
83 }
84
85 static int skb_pull_and_merge(struct sk_buff *skb, unsigned char *src, int len)
86 {
87         int tail_len;
88         unsigned long end, tail;
89
90         if ((src+len) > skb_tail_pointer(skb) || skb->len < len)
91                 return -1;
92
93         tail = (unsigned long)skb_tail_pointer(skb);
94         end = (unsigned long)src+len;
95         if (tail < end)
96                 return -1;
97
98         tail_len = (int)(tail-end);
99         if (tail_len > 0)
100                 memmove(src, src+len, tail_len);
101
102         skb_trim(skb, skb->len-len);
103         return 0;
104 }
105
106 static int  __nat25_has_expired(struct nat25_network_db_entry *fdb)
107 {
108         if (time_before_eq(fdb->ageing_timer, jiffies - NAT25_AGEING_TIME * HZ))
109                 return 1;
110
111         return 0;
112 }
113
114 static void __nat25_generate_ipv4_network_addr(unsigned char *networkAddr,
115                                 unsigned int *ipAddr)
116 {
117         memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
118
119         networkAddr[0] = NAT25_IPV4;
120         memcpy(networkAddr+7, (unsigned char *)ipAddr, 4);
121 }
122
123 static void __nat25_generate_pppoe_network_addr(unsigned char *networkAddr,
124                                 unsigned char *ac_mac, __be16 *sid)
125 {
126         memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
127
128         networkAddr[0] = NAT25_PPPOE;
129         memcpy(networkAddr+1, (unsigned char *)sid, 2);
130         memcpy(networkAddr+3, (unsigned char *)ac_mac, 6);
131 }
132
133 static  void __nat25_generate_ipv6_network_addr(unsigned char *networkAddr,
134                                 unsigned int *ipAddr)
135 {
136         memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
137
138         networkAddr[0] = NAT25_IPV6;
139         memcpy(networkAddr+1, (unsigned char *)ipAddr, 16);
140 }
141
142 static unsigned char *scan_tlv(unsigned char *data, int len, unsigned char tag, unsigned char len8b)
143 {
144         while (len > 0) {
145                 if (*data == tag && *(data+1) == len8b && len >= len8b*8)
146                         return data+2;
147
148                 len -= (*(data+1))*8;
149                 data += (*(data+1))*8;
150         }
151         return NULL;
152 }
153
154 static int update_nd_link_layer_addr(unsigned char *data, int len, unsigned char *replace_mac)
155 {
156         struct icmp6hdr *icmphdr = (struct icmp6hdr *)data;
157         unsigned char *mac;
158
159         if (icmphdr->icmp6_type == NDISC_ROUTER_SOLICITATION) {
160                 if (len >= 8) {
161                         mac = scan_tlv(&data[8], len-8, 1, 1);
162                         if (mac) {
163                                 memcpy(mac, replace_mac, 6);
164                                 return 1;
165                         }
166                 }
167         } else if (icmphdr->icmp6_type == NDISC_ROUTER_ADVERTISEMENT) {
168                 if (len >= 16) {
169                         mac = scan_tlv(&data[16], len-16, 1, 1);
170                         if (mac) {
171                                 memcpy(mac, replace_mac, 6);
172                                 return 1;
173                         }
174                 }
175         } else if (icmphdr->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) {
176                 if (len >= 24) {
177                         mac = scan_tlv(&data[24], len-24, 1, 1);
178                         if (mac) {
179                                 memcpy(mac, replace_mac, 6);
180                                 return 1;
181                         }
182                 }
183         } else if (icmphdr->icmp6_type == NDISC_NEIGHBOUR_ADVERTISEMENT) {
184                 if (len >= 24) {
185                         mac = scan_tlv(&data[24], len-24, 2, 1);
186                         if (mac) {
187                                 memcpy(mac, replace_mac, 6);
188                                 return 1;
189                         }
190                 }
191         } else if (icmphdr->icmp6_type == NDISC_REDIRECT) {
192                 if (len >= 40) {
193                         mac = scan_tlv(&data[40], len-40, 2, 1);
194                         if (mac) {
195                                 memcpy(mac, replace_mac, 6);
196                                 return 1;
197                         }
198                 }
199         }
200         return 0;
201 }
202
203 static int __nat25_network_hash(unsigned char *networkAddr)
204 {
205         if (networkAddr[0] == NAT25_IPV4) {
206                 unsigned long x;
207
208                 x = networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10];
209
210                 return x & (NAT25_HASH_SIZE - 1);
211         } else if (networkAddr[0] == NAT25_IPX) {
212                 unsigned long x;
213
214                 x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^
215                         networkAddr[6] ^ networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10];
216
217                 return x & (NAT25_HASH_SIZE - 1);
218         } else if (networkAddr[0] == NAT25_APPLE) {
219                 unsigned long x;
220
221                 x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3];
222
223                 return x & (NAT25_HASH_SIZE - 1);
224         } else if (networkAddr[0] == NAT25_PPPOE) {
225                 unsigned long x;
226
227                 x = networkAddr[0] ^ networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^ networkAddr[6] ^ networkAddr[7] ^ networkAddr[8];
228
229                 return x & (NAT25_HASH_SIZE - 1);
230         } else if (networkAddr[0] == NAT25_IPV6) {
231                 unsigned long x;
232
233                 x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^
234                         networkAddr[6] ^ networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10] ^
235                         networkAddr[11] ^ networkAddr[12] ^ networkAddr[13] ^ networkAddr[14] ^ networkAddr[15] ^
236                         networkAddr[16];
237
238                 return x & (NAT25_HASH_SIZE - 1);
239         } else {
240                 unsigned long x = 0;
241                 int i;
242
243                 for (i = 0; i < MAX_NETWORK_ADDR_LEN; i++)
244                         x ^= networkAddr[i];
245
246                 return x & (NAT25_HASH_SIZE - 1);
247         }
248 }
249
250 static void __network_hash_link(struct adapter *priv,
251                                 struct nat25_network_db_entry *ent, int hash)
252 {
253         /*  Caller must spin_lock already! */
254         ent->next_hash = priv->nethash[hash];
255         if (ent->next_hash)
256                 ent->next_hash->pprev_hash = &ent->next_hash;
257         priv->nethash[hash] = ent;
258         ent->pprev_hash = &priv->nethash[hash];
259 }
260
261 static void __network_hash_unlink(struct nat25_network_db_entry *ent)
262 {
263         /*  Caller must spin_lock already! */
264         *ent->pprev_hash = ent->next_hash;
265         if (ent->next_hash)
266                 ent->next_hash->pprev_hash = ent->pprev_hash;
267         ent->next_hash = NULL;
268         ent->pprev_hash = NULL;
269 }
270
271 static void __nat25_db_network_insert(struct adapter *priv,
272                                 unsigned char *macAddr, unsigned char *networkAddr)
273 {
274         struct nat25_network_db_entry *db;
275         int hash;
276
277         spin_lock_bh(&priv->br_ext_lock);
278         hash = __nat25_network_hash(networkAddr);
279         db = priv->nethash[hash];
280         while (db) {
281                 if (!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) {
282                         memcpy(db->macAddr, macAddr, ETH_ALEN);
283                         db->ageing_timer = jiffies;
284                         spin_unlock_bh(&priv->br_ext_lock);
285                         return;
286                 }
287                 db = db->next_hash;
288         }
289         db = kmalloc(sizeof(*db), GFP_ATOMIC);
290         if (!db) {
291                 spin_unlock_bh(&priv->br_ext_lock);
292                 return;
293         }
294         memcpy(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN);
295         memcpy(db->macAddr, macAddr, ETH_ALEN);
296         atomic_set(&db->use_count, 1);
297         db->ageing_timer = jiffies;
298
299         __network_hash_link(priv, db, hash);
300
301         spin_unlock_bh(&priv->br_ext_lock);
302 }
303
304 /*
305  *      NAT2.5 interface
306  */
307
308 void nat25_db_cleanup(struct adapter *priv)
309 {
310         int i;
311
312         spin_lock_bh(&priv->br_ext_lock);
313
314         for (i = 0; i < NAT25_HASH_SIZE; i++) {
315                 struct nat25_network_db_entry *f;
316                 f = priv->nethash[i];
317                 while (f) {
318                         struct nat25_network_db_entry *g;
319
320                         g = f->next_hash;
321                         if (priv->scdb_entry == f) {
322                                 memset(priv->scdb_mac, 0, ETH_ALEN);
323                                 memset(priv->scdb_ip, 0, 4);
324                                 priv->scdb_entry = NULL;
325                         }
326                         __network_hash_unlink(f);
327                         kfree(f);
328                         f = g;
329                 }
330         }
331         spin_unlock_bh(&priv->br_ext_lock);
332 }
333
334 void nat25_db_expire(struct adapter *priv)
335 {
336         int i;
337
338         spin_lock_bh(&priv->br_ext_lock);
339
340         for (i = 0; i < NAT25_HASH_SIZE; i++) {
341                 struct nat25_network_db_entry *f;
342                 f = priv->nethash[i];
343
344                 while (f) {
345                         struct nat25_network_db_entry *g;
346                         g = f->next_hash;
347
348                         if (__nat25_has_expired(f)) {
349                                 if (atomic_dec_and_test(&f->use_count)) {
350                                         if (priv->scdb_entry == f) {
351                                                 memset(priv->scdb_mac, 0, ETH_ALEN);
352                                                 memset(priv->scdb_ip, 0, 4);
353                                                 priv->scdb_entry = NULL;
354                                         }
355                                         __network_hash_unlink(f);
356                                         kfree(f);
357                                 }
358                         }
359                         f = g;
360                 }
361         }
362         spin_unlock_bh(&priv->br_ext_lock);
363 }
364
365 int nat25_db_handle(struct adapter *priv, struct sk_buff *skb, int method)
366 {
367         unsigned short protocol;
368         unsigned char networkAddr[MAX_NETWORK_ADDR_LEN];
369         unsigned int tmp;
370
371         if (!skb)
372                 return -1;
373
374         if ((method <= NAT25_MIN) || (method >= NAT25_MAX))
375                 return -1;
376
377         protocol = be16_to_cpu(*((__be16 *)(skb->data + 2 * ETH_ALEN)));
378
379         /*---------------------------------------------------*/
380         /*                 Handle IP frame                   */
381         /*---------------------------------------------------*/
382         if (protocol == ETH_P_IP) {
383                 struct iphdr *iph = (struct iphdr *)(skb->data + ETH_HLEN);
384
385                 if (((unsigned char *)(iph) + (iph->ihl << 2)) >= (skb->data + ETH_HLEN + skb->len))
386                         return -1;
387
388                 switch (method) {
389                 case NAT25_CHECK:
390                         return -1;
391                 case NAT25_INSERT:
392                         /* some multicast with source IP is all zero, maybe other case is illegal */
393                         /* in class A, B, C, host address is all zero or all one is illegal */
394                         if (iph->saddr == 0)
395                                 return 0;
396                         tmp = be32_to_cpu(iph->saddr);
397                         __nat25_generate_ipv4_network_addr(networkAddr, &tmp);
398                         /* record source IP address and , source mac address into db */
399                         __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
400                         return 0;
401                 default:
402                         return -1;
403                 }
404         } else if (protocol == ETH_P_ARP) {
405                 /*---------------------------------------------------*/
406                 /*                 Handle ARP frame                  */
407                 /*---------------------------------------------------*/
408                 struct arphdr *arp = (struct arphdr *)(skb->data + ETH_HLEN);
409                 unsigned char *arp_ptr = (unsigned char *)(arp + 1);
410                 unsigned int *sender;
411
412                 if (arp->ar_pro != htons(ETH_P_IP))
413                         return -1;
414
415                 switch (method) {
416                 case NAT25_CHECK:
417                         return 0;       /*  skb_copy for all ARP frame */
418                 case NAT25_INSERT:
419                         /*  change to ARP sender mac address to wlan STA address */
420                         memcpy(arp_ptr, GET_MY_HWADDR(priv), ETH_ALEN);
421                         arp_ptr += arp->ar_hln;
422                         sender = (unsigned int *)arp_ptr;
423                         __nat25_generate_ipv4_network_addr(networkAddr, sender);
424                         __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
425                         return 0;
426                 default:
427                         return -1;
428                 }
429         } else if ((protocol == ETH_P_PPP_DISC) ||
430                    (protocol == ETH_P_PPP_SES)) {
431                 /*---------------------------------------------------*/
432                 /*                Handle PPPoE frame                 */
433                 /*---------------------------------------------------*/
434                 struct pppoe_hdr *ph = (struct pppoe_hdr *)(skb->data + ETH_HLEN);
435                 unsigned short *pMagic;
436
437                 switch (method) {
438                 case NAT25_CHECK:
439                         if (ph->sid == 0)
440                                 return 0;
441                         return 1;
442                 case NAT25_INSERT:
443                         if (ph->sid == 0) {     /*  Discovery phase according to tag */
444                                 if (ph->code == PADI_CODE || ph->code == PADR_CODE) {
445                                         if (priv->ethBrExtInfo.addPPPoETag) {
446                                                 struct pppoe_tag *tag, *pOldTag;
447                                                 unsigned char tag_buf[40];
448                                                 int old_tag_len = 0;
449
450                                                 tag = (struct pppoe_tag *)tag_buf;
451                                                 pOldTag = (struct pppoe_tag *)__nat25_find_pppoe_tag(ph, ntohs(PTT_RELAY_SID));
452                                                 if (pOldTag) { /*  if SID existed, copy old value and delete it */
453                                                         old_tag_len = ntohs(pOldTag->tag_len);
454                                                         if (old_tag_len +
455                                                             TAG_HDR_LEN +
456                                                             MAGIC_CODE_LEN +
457                                                             RTL_RELAY_TAG_LEN >
458                                                             sizeof(tag_buf))
459                                                                 return -1;
460
461                                                         memcpy(tag->tag_data+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN,
462                                                                 pOldTag->tag_data, old_tag_len);
463
464                                                         if (skb_pull_and_merge(skb, (unsigned char *)pOldTag, TAG_HDR_LEN+old_tag_len) < 0)
465                                                                 return -1;
466
467                                                         ph->length = htons(ntohs(ph->length)-TAG_HDR_LEN-old_tag_len);
468                                                 }
469
470                                                 tag->tag_type = PTT_RELAY_SID;
471                                                 tag->tag_len = htons(MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN+old_tag_len);
472
473                                                 /*  insert the magic_code+client mac in relay tag */
474                                                 pMagic = (unsigned short *)tag->tag_data;
475                                                 *pMagic = htons(MAGIC_CODE);
476                                                 memcpy(tag->tag_data+MAGIC_CODE_LEN, skb->data+ETH_ALEN, ETH_ALEN);
477
478                                                 /* Add relay tag */
479                                                 if (__nat25_add_pppoe_tag(skb, tag) < 0)
480                                                         return -1;
481                                         } else { /*  not add relay tag */
482                                                 if (priv->pppoe_connection_in_progress &&
483                                                     memcmp(skb->data + ETH_ALEN,
484                                                            priv->pppoe_addr,
485                                                            ETH_ALEN))
486                                                         return -2;
487
488                                                 if (priv->pppoe_connection_in_progress == 0)
489                                                         memcpy(priv->pppoe_addr, skb->data+ETH_ALEN, ETH_ALEN);
490
491                                                 priv->pppoe_connection_in_progress = WAIT_TIME_PPPOE;
492                                         }
493                                 } else {
494                                         return -1;
495                                 }
496                         } else {        /*  session phase */
497                                 __nat25_generate_pppoe_network_addr(networkAddr, skb->data, &ph->sid);
498
499                                 __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
500
501                                 if (!priv->ethBrExtInfo.addPPPoETag &&
502                                     priv->pppoe_connection_in_progress &&
503                                     !memcmp(skb->data+ETH_ALEN, priv->pppoe_addr, ETH_ALEN))
504                                         priv->pppoe_connection_in_progress = 0;
505                         }
506                         return 0;
507                 default:
508                         return -1;
509                 }
510         } else if (protocol == 0x888e) {
511                 /*---------------------------------------------------*/
512                 /*                 Handle EAP frame                  */
513                 /*---------------------------------------------------*/
514                 switch (method) {
515                 case NAT25_CHECK:
516                         return -1;
517                 case NAT25_INSERT:
518                         return 0;
519                 default:
520                         return -1;
521                 }
522         } else if ((protocol == 0xe2ae) || (protocol == 0xe2af)) {
523                 /*---------------------------------------------------*/
524                 /*         Handle C-Media proprietary frame          */
525                 /*---------------------------------------------------*/
526                 switch (method) {
527                 case NAT25_CHECK:
528                         return -1;
529                 case NAT25_INSERT:
530                         return 0;
531                 default:
532                         return -1;
533                 }
534         } else if (protocol == ETH_P_IPV6) {
535                 /*------------------------------------------------*/
536                 /*         Handle IPV6 frame                      */
537                 /*------------------------------------------------*/
538                 struct ipv6hdr *iph = (struct ipv6hdr *)(skb->data + ETH_HLEN);
539
540                 if (sizeof(*iph) >= (skb->len - ETH_HLEN))
541                         return -1;
542
543                 switch (method) {
544                 case NAT25_CHECK:
545                         if (skb->data[0] & 1)
546                                 return 0;
547                         return -1;
548                 case NAT25_INSERT:
549                         if (memcmp(&iph->saddr, "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0", 16)) {
550                                 __nat25_generate_ipv6_network_addr(networkAddr, (unsigned int *)&iph->saddr);
551                                 __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
552
553                                 if (iph->nexthdr == IPPROTO_ICMPV6 &&
554                                                 skb->len > (ETH_HLEN +  sizeof(*iph) + 4)) {
555                                         if (update_nd_link_layer_addr(skb->data + ETH_HLEN + sizeof(*iph),
556                                                                       skb->len - ETH_HLEN - sizeof(*iph), GET_MY_HWADDR(priv))) {
557                                                 struct icmp6hdr  *hdr = (struct icmp6hdr *)(skb->data + ETH_HLEN + sizeof(*iph));
558                                                 hdr->icmp6_cksum = 0;
559                                                 hdr->icmp6_cksum = csum_ipv6_magic(&iph->saddr, &iph->daddr,
560                                                                                 iph->payload_len,
561                                                                                 IPPROTO_ICMPV6,
562                                                                                 csum_partial((__u8 *)hdr, iph->payload_len, 0));
563                                         }
564                                 }
565                         }
566                         return 0;
567                 default:
568                         return -1;
569                 }
570         }
571         return -1;
572 }
573
574 #define SERVER_PORT                     67
575 #define CLIENT_PORT                     68
576 #define DHCP_MAGIC                      0x63825363
577 #define BROADCAST_FLAG          0x8000
578
579 struct dhcpMessage {
580         u_int8_t op;
581         u_int8_t htype;
582         u_int8_t hlen;
583         u_int8_t hops;
584         u_int32_t xid;
585         __be16 secs;
586         __be16 flags;
587         __be32 ciaddr;
588         __be32 yiaddr;
589         __be32 siaddr;
590         __be32 giaddr;
591         u_int8_t chaddr[16];
592         u_int8_t sname[64];
593         u_int8_t file[128];
594         __be32 cookie;
595         u_int8_t options[308]; /* 312 - cookie */
596 };
597
598 void dhcp_flag_bcast(struct adapter *priv, struct sk_buff *skb)
599 {
600         if (!skb)
601                 return;
602
603         if (!priv->ethBrExtInfo.dhcp_bcst_disable) {
604                 __be16 protocol = *((__be16 *)(skb->data + 2 * ETH_ALEN));
605
606                 if (protocol == __constant_htons(ETH_P_IP)) { /*  IP */
607                         struct iphdr *iph = (struct iphdr *)(skb->data + ETH_HLEN);
608
609                         if (iph->protocol == IPPROTO_UDP) { /*  UDP */
610                                 struct udphdr *udph = (struct udphdr *)((size_t)iph + (iph->ihl << 2));
611
612                                 if ((udph->source == __constant_htons(CLIENT_PORT)) &&
613                                     (udph->dest == __constant_htons(SERVER_PORT))) { /*  DHCP request */
614                                         struct dhcpMessage *dhcph =
615                                                 (struct dhcpMessage *)((size_t)udph + sizeof(struct udphdr));
616                                         u32 cookie = be32_to_cpu((__be32)dhcph->cookie);
617
618                                         if (cookie == DHCP_MAGIC) { /*  match magic word */
619                                                 if (!(dhcph->flags & htons(BROADCAST_FLAG))) {
620                                                         /*  if not broadcast */
621                                                         register int sum = 0;
622
623                                                         /*  or BROADCAST flag */
624                                                         dhcph->flags |= htons(BROADCAST_FLAG);
625                                                         /*  recalculate checksum */
626                                                         sum = ~(udph->check) & 0xffff;
627                                                         sum += be16_to_cpu(dhcph->flags);
628                                                         while (sum >> 16)
629                                                                 sum = (sum & 0xffff) + (sum >> 16);
630                                                         udph->check = ~sum;
631                                                 }
632                                         }
633                                 }
634                         }
635                 }
636         }
637 }
638
639 void *scdb_findEntry(struct adapter *priv, unsigned char *ipAddr)
640 {
641         unsigned char networkAddr[MAX_NETWORK_ADDR_LEN];
642         struct nat25_network_db_entry *db;
643         int hash;
644
645         __nat25_generate_ipv4_network_addr(networkAddr, (unsigned int *)ipAddr);
646         hash = __nat25_network_hash(networkAddr);
647         db = priv->nethash[hash];
648         while (db) {
649                 if (!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) {
650                         return (void *)db;
651                 }
652
653                 db = db->next_hash;
654         }
655
656         return NULL;
657 }