linux/drivers/staging/r8188eu/core/rtw_br_ext.c
<<
>>
Prefs
   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 */
  51static 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
  68static 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                _DEBUG_ERR("skb_tailroom() failed in add SID tag!\n");
  76                return -1;
  77        }
  78
  79        skb_put(skb, data_len);
  80        /*  have a room for new tag */
  81        memmove(((unsigned char *)ph->tag + data_len), (unsigned char *)ph->tag, ntohs(ph->length));
  82        ph->length = htons(ntohs(ph->length) + data_len);
  83        memcpy((unsigned char *)ph->tag, tag, data_len);
  84        return data_len;
  85}
  86
  87static int skb_pull_and_merge(struct sk_buff *skb, unsigned char *src, int len)
  88{
  89        int tail_len;
  90        unsigned long end, tail;
  91
  92        if ((src+len) > skb_tail_pointer(skb) || skb->len < len)
  93                return -1;
  94
  95        tail = (unsigned long)skb_tail_pointer(skb);
  96        end = (unsigned long)src+len;
  97        if (tail < end)
  98                return -1;
  99
 100        tail_len = (int)(tail-end);
 101        if (tail_len > 0)
 102                memmove(src, src+len, tail_len);
 103
 104        skb_trim(skb, skb->len-len);
 105        return 0;
 106}
 107
 108static unsigned long __nat25_timeout(struct adapter *priv)
 109{
 110        unsigned long timeout;
 111
 112        timeout = jiffies - NAT25_AGEING_TIME*HZ;
 113
 114        return timeout;
 115}
 116
 117static int  __nat25_has_expired(struct adapter *priv,
 118                                struct nat25_network_db_entry *fdb)
 119{
 120        if (time_before_eq(fdb->ageing_timer, __nat25_timeout(priv)))
 121                return 1;
 122
 123        return 0;
 124}
 125
 126static void __nat25_generate_ipv4_network_addr(unsigned char *networkAddr,
 127                                unsigned int *ipAddr)
 128{
 129        memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
 130
 131        networkAddr[0] = NAT25_IPV4;
 132        memcpy(networkAddr+7, (unsigned char *)ipAddr, 4);
 133}
 134
 135static void __nat25_generate_pppoe_network_addr(unsigned char *networkAddr,
 136                                unsigned char *ac_mac, __be16 *sid)
 137{
 138        memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
 139
 140        networkAddr[0] = NAT25_PPPOE;
 141        memcpy(networkAddr+1, (unsigned char *)sid, 2);
 142        memcpy(networkAddr+3, (unsigned char *)ac_mac, 6);
 143}
 144
 145static  void __nat25_generate_ipv6_network_addr(unsigned char *networkAddr,
 146                                unsigned int *ipAddr)
 147{
 148        memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN);
 149
 150        networkAddr[0] = NAT25_IPV6;
 151        memcpy(networkAddr+1, (unsigned char *)ipAddr, 16);
 152}
 153
 154static unsigned char *scan_tlv(unsigned char *data, int len, unsigned char tag, unsigned char len8b)
 155{
 156        while (len > 0) {
 157                if (*data == tag && *(data+1) == len8b && len >= len8b*8)
 158                        return data+2;
 159
 160                len -= (*(data+1))*8;
 161                data += (*(data+1))*8;
 162        }
 163        return NULL;
 164}
 165
 166static int update_nd_link_layer_addr(unsigned char *data, int len, unsigned char *replace_mac)
 167{
 168        struct icmp6hdr *icmphdr = (struct icmp6hdr *)data;
 169        unsigned char *mac;
 170
 171        if (icmphdr->icmp6_type == NDISC_ROUTER_SOLICITATION) {
 172                if (len >= 8) {
 173                        mac = scan_tlv(&data[8], len-8, 1, 1);
 174                        if (mac) {
 175                                _DEBUG_INFO("Router Solicitation, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
 176                                        mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
 177                                        replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
 178                                memcpy(mac, replace_mac, 6);
 179                                return 1;
 180                        }
 181                }
 182        } else if (icmphdr->icmp6_type == NDISC_ROUTER_ADVERTISEMENT) {
 183                if (len >= 16) {
 184                        mac = scan_tlv(&data[16], len-16, 1, 1);
 185                        if (mac) {
 186                                _DEBUG_INFO("Router Advertisement, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
 187                                        mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
 188                                        replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
 189                                memcpy(mac, replace_mac, 6);
 190                                return 1;
 191                        }
 192                }
 193        } else if (icmphdr->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) {
 194                if (len >= 24) {
 195                        mac = scan_tlv(&data[24], len-24, 1, 1);
 196                        if (mac) {
 197                                _DEBUG_INFO("Neighbor Solicitation, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
 198                                        mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
 199                                        replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
 200                                memcpy(mac, replace_mac, 6);
 201                                return 1;
 202                        }
 203                }
 204        } else if (icmphdr->icmp6_type == NDISC_NEIGHBOUR_ADVERTISEMENT) {
 205                if (len >= 24) {
 206                        mac = scan_tlv(&data[24], len-24, 2, 1);
 207                        if (mac) {
 208                                _DEBUG_INFO("Neighbor Advertisement, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
 209                                        mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
 210                                        replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
 211                                memcpy(mac, replace_mac, 6);
 212                                return 1;
 213                        }
 214                }
 215        } else if (icmphdr->icmp6_type == NDISC_REDIRECT) {
 216                if (len >= 40) {
 217                        mac = scan_tlv(&data[40], len-40, 2, 1);
 218                        if (mac) {
 219                                _DEBUG_INFO("Redirect,  replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n",
 220                                        mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
 221                                        replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]);
 222                                memcpy(mac, replace_mac, 6);
 223                                return 1;
 224                        }
 225                }
 226        }
 227        return 0;
 228}
 229
 230static int __nat25_network_hash(unsigned char *networkAddr)
 231{
 232        if (networkAddr[0] == NAT25_IPV4) {
 233                unsigned long x;
 234
 235                x = networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10];
 236
 237                return x & (NAT25_HASH_SIZE - 1);
 238        } else if (networkAddr[0] == NAT25_IPX) {
 239                unsigned long x;
 240
 241                x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^
 242                        networkAddr[6] ^ networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10];
 243
 244                return x & (NAT25_HASH_SIZE - 1);
 245        } else if (networkAddr[0] == NAT25_APPLE) {
 246                unsigned long x;
 247
 248                x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3];
 249
 250                return x & (NAT25_HASH_SIZE - 1);
 251        } else if (networkAddr[0] == NAT25_PPPOE) {
 252                unsigned long x;
 253
 254                x = networkAddr[0] ^ networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^ networkAddr[6] ^ networkAddr[7] ^ networkAddr[8];
 255
 256                return x & (NAT25_HASH_SIZE - 1);
 257        } else if (networkAddr[0] == NAT25_IPV6) {
 258                unsigned long x;
 259
 260                x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^
 261                        networkAddr[6] ^ networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10] ^
 262                        networkAddr[11] ^ networkAddr[12] ^ networkAddr[13] ^ networkAddr[14] ^ networkAddr[15] ^
 263                        networkAddr[16];
 264
 265                return x & (NAT25_HASH_SIZE - 1);
 266        } else {
 267                unsigned long x = 0;
 268                int i;
 269
 270                for (i = 0; i < MAX_NETWORK_ADDR_LEN; i++)
 271                        x ^= networkAddr[i];
 272
 273                return x & (NAT25_HASH_SIZE - 1);
 274        }
 275}
 276
 277static void __network_hash_link(struct adapter *priv,
 278                                struct nat25_network_db_entry *ent, int hash)
 279{
 280        /*  Caller must spin_lock already! */
 281        ent->next_hash = priv->nethash[hash];
 282        if (ent->next_hash)
 283                ent->next_hash->pprev_hash = &ent->next_hash;
 284        priv->nethash[hash] = ent;
 285        ent->pprev_hash = &priv->nethash[hash];
 286}
 287
 288static void __network_hash_unlink(struct nat25_network_db_entry *ent)
 289{
 290        /*  Caller must spin_lock already! */
 291        *ent->pprev_hash = ent->next_hash;
 292        if (ent->next_hash)
 293                ent->next_hash->pprev_hash = ent->pprev_hash;
 294        ent->next_hash = NULL;
 295        ent->pprev_hash = NULL;
 296}
 297
 298static void __nat25_db_network_insert(struct adapter *priv,
 299                                unsigned char *macAddr, unsigned char *networkAddr)
 300{
 301        struct nat25_network_db_entry *db;
 302        int hash;
 303
 304        spin_lock_bh(&priv->br_ext_lock);
 305        hash = __nat25_network_hash(networkAddr);
 306        db = priv->nethash[hash];
 307        while (db) {
 308                if (!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) {
 309                        memcpy(db->macAddr, macAddr, ETH_ALEN);
 310                        db->ageing_timer = jiffies;
 311                        spin_unlock_bh(&priv->br_ext_lock);
 312                        return;
 313                }
 314                db = db->next_hash;
 315        }
 316        db = kmalloc(sizeof(*db), GFP_ATOMIC);
 317        if (!db) {
 318                spin_unlock_bh(&priv->br_ext_lock);
 319                return;
 320        }
 321        memcpy(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN);
 322        memcpy(db->macAddr, macAddr, ETH_ALEN);
 323        atomic_set(&db->use_count, 1);
 324        db->ageing_timer = jiffies;
 325
 326        __network_hash_link(priv, db, hash);
 327
 328        spin_unlock_bh(&priv->br_ext_lock);
 329}
 330
 331static void __nat25_db_print(struct adapter *priv)
 332{
 333}
 334
 335/*
 336 *      NAT2.5 interface
 337 */
 338
 339void nat25_db_cleanup(struct adapter *priv)
 340{
 341        int i;
 342
 343        spin_lock_bh(&priv->br_ext_lock);
 344
 345        for (i = 0; i < NAT25_HASH_SIZE; i++) {
 346                struct nat25_network_db_entry *f;
 347                f = priv->nethash[i];
 348                while (f) {
 349                        struct nat25_network_db_entry *g;
 350
 351                        g = f->next_hash;
 352                        if (priv->scdb_entry == f) {
 353                                memset(priv->scdb_mac, 0, ETH_ALEN);
 354                                memset(priv->scdb_ip, 0, 4);
 355                                priv->scdb_entry = NULL;
 356                        }
 357                        __network_hash_unlink(f);
 358                        kfree(f);
 359                        f = g;
 360                }
 361        }
 362        spin_unlock_bh(&priv->br_ext_lock);
 363}
 364
 365void nat25_db_expire(struct adapter *priv)
 366{
 367        int i;
 368
 369        spin_lock_bh(&priv->br_ext_lock);
 370
 371        for (i = 0; i < NAT25_HASH_SIZE; i++) {
 372                struct nat25_network_db_entry *f;
 373                f = priv->nethash[i];
 374
 375                while (f) {
 376                        struct nat25_network_db_entry *g;
 377                        g = f->next_hash;
 378
 379                        if (__nat25_has_expired(priv, f)) {
 380                                if (atomic_dec_and_test(&f->use_count)) {
 381                                        if (priv->scdb_entry == f) {
 382                                                memset(priv->scdb_mac, 0, ETH_ALEN);
 383                                                memset(priv->scdb_ip, 0, 4);
 384                                                priv->scdb_entry = NULL;
 385                                        }
 386                                        __network_hash_unlink(f);
 387                                        kfree(f);
 388                                }
 389                        }
 390                        f = g;
 391                }
 392        }
 393        spin_unlock_bh(&priv->br_ext_lock);
 394}
 395
 396int nat25_db_handle(struct adapter *priv, struct sk_buff *skb, int method)
 397{
 398        unsigned short protocol;
 399        unsigned char networkAddr[MAX_NETWORK_ADDR_LEN];
 400        unsigned int tmp;
 401
 402        if (!skb)
 403                return -1;
 404
 405        if ((method <= NAT25_MIN) || (method >= NAT25_MAX))
 406                return -1;
 407
 408        protocol = be16_to_cpu(*((__be16 *)(skb->data + 2 * ETH_ALEN)));
 409
 410        /*---------------------------------------------------*/
 411        /*                 Handle IP frame                   */
 412        /*---------------------------------------------------*/
 413        if (protocol == ETH_P_IP) {
 414                struct iphdr *iph = (struct iphdr *)(skb->data + ETH_HLEN);
 415
 416                if (((unsigned char *)(iph) + (iph->ihl<<2)) >= (skb->data + ETH_HLEN + skb->len)) {
 417                        DEBUG_WARN("NAT25: malformed IP packet !\n");
 418                        return -1;
 419                }
 420
 421                switch (method) {
 422                case NAT25_CHECK:
 423                        return -1;
 424                case NAT25_INSERT:
 425                        /* some multicast with source IP is all zero, maybe other case is illegal */
 426                        /* in class A, B, C, host address is all zero or all one is illegal */
 427                        if (iph->saddr == 0)
 428                                return 0;
 429                        tmp = be32_to_cpu(iph->saddr);
 430                        DEBUG_INFO("NAT25: Insert IP, SA =%08x, DA =%08x\n", tmp, iph->daddr);
 431                        __nat25_generate_ipv4_network_addr(networkAddr, &tmp);
 432                        /* record source IP address and , source mac address into db */
 433                        __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
 434
 435                        __nat25_db_print(priv);
 436                        return 0;
 437                default:
 438                        return -1;
 439                }
 440        } else if (protocol == ETH_P_ARP) {
 441                /*---------------------------------------------------*/
 442                /*                 Handle ARP frame                  */
 443                /*---------------------------------------------------*/
 444                struct arphdr *arp = (struct arphdr *)(skb->data + ETH_HLEN);
 445                unsigned char *arp_ptr = (unsigned char *)(arp + 1);
 446                unsigned int *sender;
 447
 448                if (arp->ar_pro != __constant_htons(ETH_P_IP)) {
 449                        DEBUG_WARN("NAT25: arp protocol unknown (%4x)!\n", be16_to_cpu(arp->ar_pro));
 450                        return -1;
 451                }
 452
 453                switch (method) {
 454                case NAT25_CHECK:
 455                        return 0;       /*  skb_copy for all ARP frame */
 456                case NAT25_INSERT:
 457                        DEBUG_INFO("NAT25: Insert ARP, MAC =%02x%02x%02x%02x%02x%02x\n", arp_ptr[0],
 458                                arp_ptr[1], arp_ptr[2], arp_ptr[3], arp_ptr[4], arp_ptr[5]);
 459
 460                        /*  change to ARP sender mac address to wlan STA address */
 461                        memcpy(arp_ptr, GET_MY_HWADDR(priv), ETH_ALEN);
 462                        arp_ptr += arp->ar_hln;
 463                        sender = (unsigned int *)arp_ptr;
 464                        __nat25_generate_ipv4_network_addr(networkAddr, sender);
 465                        __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
 466                        __nat25_db_print(priv);
 467                        return 0;
 468                default:
 469                        return -1;
 470                }
 471        } else if ((protocol == ETH_P_PPP_DISC) ||
 472                   (protocol == ETH_P_PPP_SES)) {
 473                /*---------------------------------------------------*/
 474                /*                Handle PPPoE frame                 */
 475                /*---------------------------------------------------*/
 476                struct pppoe_hdr *ph = (struct pppoe_hdr *)(skb->data + ETH_HLEN);
 477                unsigned short *pMagic;
 478
 479                switch (method) {
 480                case NAT25_CHECK:
 481                        if (ph->sid == 0)
 482                                return 0;
 483                        return 1;
 484                case NAT25_INSERT:
 485                        if (ph->sid == 0) {     /*  Discovery phase according to tag */
 486                                if (ph->code == PADI_CODE || ph->code == PADR_CODE) {
 487                                        if (priv->ethBrExtInfo.addPPPoETag) {
 488                                                struct pppoe_tag *tag, *pOldTag;
 489                                                unsigned char tag_buf[40];
 490                                                int old_tag_len = 0;
 491
 492                                                tag = (struct pppoe_tag *)tag_buf;
 493                                                pOldTag = (struct pppoe_tag *)__nat25_find_pppoe_tag(ph, ntohs(PTT_RELAY_SID));
 494                                                if (pOldTag) { /*  if SID existed, copy old value and delete it */
 495                                                        old_tag_len = ntohs(pOldTag->tag_len);
 496                                                        if (old_tag_len+TAG_HDR_LEN+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN > sizeof(tag_buf)) {
 497                                                                DEBUG_ERR("SID tag length too long!\n");
 498                                                                return -1;
 499                                                        }
 500
 501                                                        memcpy(tag->tag_data+MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN,
 502                                                                pOldTag->tag_data, old_tag_len);
 503
 504                                                        if (skb_pull_and_merge(skb, (unsigned char *)pOldTag, TAG_HDR_LEN+old_tag_len) < 0) {
 505                                                                DEBUG_ERR("call skb_pull_and_merge() failed in PADI/R packet!\n");
 506                                                                return -1;
 507                                                        }
 508                                                        ph->length = htons(ntohs(ph->length)-TAG_HDR_LEN-old_tag_len);
 509                                                }
 510
 511                                                tag->tag_type = PTT_RELAY_SID;
 512                                                tag->tag_len = htons(MAGIC_CODE_LEN+RTL_RELAY_TAG_LEN+old_tag_len);
 513
 514                                                /*  insert the magic_code+client mac in relay tag */
 515                                                pMagic = (unsigned short *)tag->tag_data;
 516                                                *pMagic = htons(MAGIC_CODE);
 517                                                memcpy(tag->tag_data+MAGIC_CODE_LEN, skb->data+ETH_ALEN, ETH_ALEN);
 518
 519                                                /* Add relay tag */
 520                                                if (__nat25_add_pppoe_tag(skb, tag) < 0)
 521                                                        return -1;
 522
 523                                                DEBUG_INFO("NAT25: Insert PPPoE, forward %s packet\n",
 524                                                                                (ph->code == PADI_CODE ? "PADI" : "PADR"));
 525                                        } else { /*  not add relay tag */
 526                                                if (priv->pppoe_connection_in_progress &&
 527                                                                memcmp(skb->data+ETH_ALEN, priv->pppoe_addr, ETH_ALEN))  {
 528                                                        DEBUG_ERR("Discard PPPoE packet due to another PPPoE connection is in progress!\n");
 529                                                        return -2;
 530                                                }
 531
 532                                                if (priv->pppoe_connection_in_progress == 0)
 533                                                        memcpy(priv->pppoe_addr, skb->data+ETH_ALEN, ETH_ALEN);
 534
 535                                                priv->pppoe_connection_in_progress = WAIT_TIME_PPPOE;
 536                                        }
 537                                } else {
 538                                        return -1;
 539                                }
 540                        } else {        /*  session phase */
 541                                DEBUG_INFO("NAT25: Insert PPPoE, insert session packet to %s\n", skb->dev->name);
 542
 543                                __nat25_generate_pppoe_network_addr(networkAddr, skb->data, &ph->sid);
 544
 545                                __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
 546
 547                                __nat25_db_print(priv);
 548
 549                                if (!priv->ethBrExtInfo.addPPPoETag &&
 550                                    priv->pppoe_connection_in_progress &&
 551                                    !memcmp(skb->data+ETH_ALEN, priv->pppoe_addr, ETH_ALEN))
 552                                        priv->pppoe_connection_in_progress = 0;
 553                        }
 554                        return 0;
 555                default:
 556                        return -1;
 557                }
 558        } else if (protocol == 0x888e) {
 559                /*---------------------------------------------------*/
 560                /*                 Handle EAP frame                  */
 561                /*---------------------------------------------------*/
 562                switch (method) {
 563                case NAT25_CHECK:
 564                        return -1;
 565                case NAT25_INSERT:
 566                        return 0;
 567                default:
 568                        return -1;
 569                }
 570        } else if ((protocol == 0xe2ae) || (protocol == 0xe2af)) {
 571                /*---------------------------------------------------*/
 572                /*         Handle C-Media proprietary frame          */
 573                /*---------------------------------------------------*/
 574                switch (method) {
 575                case NAT25_CHECK:
 576                        return -1;
 577                case NAT25_INSERT:
 578                        return 0;
 579                default:
 580                        return -1;
 581                }
 582        } else if (protocol == ETH_P_IPV6) {
 583                /*------------------------------------------------*/
 584                /*         Handle IPV6 frame                      */
 585                /*------------------------------------------------*/
 586                struct ipv6hdr *iph = (struct ipv6hdr *)(skb->data + ETH_HLEN);
 587
 588                if (sizeof(*iph) >= (skb->len - ETH_HLEN)) {
 589                        DEBUG_WARN("NAT25: malformed IPv6 packet !\n");
 590                        return -1;
 591                }
 592
 593                switch (method) {
 594                case NAT25_CHECK:
 595                        if (skb->data[0] & 1)
 596                                return 0;
 597                        return -1;
 598                case NAT25_INSERT:
 599                        DEBUG_INFO("NAT25: Insert IP, SA =%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x,"
 600                                                        " DA =%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x\n",
 601                                iph->saddr.s6_addr16[0], iph->saddr.s6_addr16[1], iph->saddr.s6_addr16[2], iph->saddr.s6_addr16[3],
 602                                iph->saddr.s6_addr16[4], iph->saddr.s6_addr16[5], iph->saddr.s6_addr16[6], iph->saddr.s6_addr16[7],
 603                                iph->daddr.s6_addr16[0], iph->daddr.s6_addr16[1], iph->daddr.s6_addr16[2], iph->daddr.s6_addr16[3],
 604                                iph->daddr.s6_addr16[4], iph->daddr.s6_addr16[5], iph->daddr.s6_addr16[6], iph->daddr.s6_addr16[7]);
 605
 606                        if (memcmp(&iph->saddr, "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0", 16)) {
 607                                __nat25_generate_ipv6_network_addr(networkAddr, (unsigned int *)&iph->saddr);
 608                                __nat25_db_network_insert(priv, skb->data+ETH_ALEN, networkAddr);
 609                                __nat25_db_print(priv);
 610
 611                                if (iph->nexthdr == IPPROTO_ICMPV6 &&
 612                                                skb->len > (ETH_HLEN +  sizeof(*iph) + 4)) {
 613                                        if (update_nd_link_layer_addr(skb->data + ETH_HLEN + sizeof(*iph),
 614                                                                      skb->len - ETH_HLEN - sizeof(*iph), GET_MY_HWADDR(priv))) {
 615                                                struct icmp6hdr  *hdr = (struct icmp6hdr *)(skb->data + ETH_HLEN + sizeof(*iph));
 616                                                hdr->icmp6_cksum = 0;
 617                                                hdr->icmp6_cksum = csum_ipv6_magic(&iph->saddr, &iph->daddr,
 618                                                                                iph->payload_len,
 619                                                                                IPPROTO_ICMPV6,
 620                                                                                csum_partial((__u8 *)hdr, iph->payload_len, 0));
 621                                        }
 622                                }
 623                        }
 624                        return 0;
 625                default:
 626                        return -1;
 627                }
 628        }
 629        return -1;
 630}
 631
 632#define SERVER_PORT                     67
 633#define CLIENT_PORT                     68
 634#define DHCP_MAGIC                      0x63825363
 635#define BROADCAST_FLAG          0x8000
 636
 637struct dhcpMessage {
 638        u_int8_t op;
 639        u_int8_t htype;
 640        u_int8_t hlen;
 641        u_int8_t hops;
 642        u_int32_t xid;
 643        __be16 secs;
 644        __be16 flags;
 645        __be32 ciaddr;
 646        __be32 yiaddr;
 647        __be32 siaddr;
 648        __be32 giaddr;
 649        u_int8_t chaddr[16];
 650        u_int8_t sname[64];
 651        u_int8_t file[128];
 652        __be32 cookie;
 653        u_int8_t options[308]; /* 312 - cookie */
 654};
 655
 656void dhcp_flag_bcast(struct adapter *priv, struct sk_buff *skb)
 657{
 658        if (!skb)
 659                return;
 660
 661        if (!priv->ethBrExtInfo.dhcp_bcst_disable) {
 662                __be16 protocol = *((__be16 *)(skb->data + 2 * ETH_ALEN));
 663
 664                if (protocol == __constant_htons(ETH_P_IP)) { /*  IP */
 665                        struct iphdr *iph = (struct iphdr *)(skb->data + ETH_HLEN);
 666
 667                        if (iph->protocol == IPPROTO_UDP) { /*  UDP */
 668                                struct udphdr *udph = (struct udphdr *)((size_t)iph + (iph->ihl << 2));
 669
 670                                if ((udph->source == __constant_htons(CLIENT_PORT)) &&
 671                                    (udph->dest == __constant_htons(SERVER_PORT))) { /*  DHCP request */
 672                                        struct dhcpMessage *dhcph =
 673                                                (struct dhcpMessage *)((size_t)udph + sizeof(struct udphdr));
 674                                        u32 cookie = be32_to_cpu((__be32)dhcph->cookie);
 675
 676                                        if (cookie == DHCP_MAGIC) { /*  match magic word */
 677                                                if (!(dhcph->flags & htons(BROADCAST_FLAG))) {
 678                                                        /*  if not broadcast */
 679                                                        register int sum = 0;
 680
 681                                                        DEBUG_INFO("DHCP: change flag of DHCP request to broadcast.\n");
 682                                                        /*  or BROADCAST flag */
 683                                                        dhcph->flags |= htons(BROADCAST_FLAG);
 684                                                        /*  recalculate checksum */
 685                                                        sum = ~(udph->check) & 0xffff;
 686                                                        sum += be16_to_cpu(dhcph->flags);
 687                                                        while (sum >> 16)
 688                                                                sum = (sum & 0xffff) + (sum >> 16);
 689                                                        udph->check = ~sum;
 690                                                }
 691                                        }
 692                                }
 693                        }
 694                }
 695        }
 696}
 697
 698void *scdb_findEntry(struct adapter *priv, unsigned char *macAddr,
 699                                unsigned char *ipAddr)
 700{
 701        unsigned char networkAddr[MAX_NETWORK_ADDR_LEN];
 702        struct nat25_network_db_entry *db;
 703        int hash;
 704
 705        __nat25_generate_ipv4_network_addr(networkAddr, (unsigned int *)ipAddr);
 706        hash = __nat25_network_hash(networkAddr);
 707        db = priv->nethash[hash];
 708        while (db) {
 709                if (!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) {
 710                        return (void *)db;
 711                }
 712
 713                db = db->next_hash;
 714        }
 715
 716        return NULL;
 717}
 718