linux-old/drivers/net/wan/hdlc_fr.c
<<
>>
Prefs
   1/*
   2 * Generic HDLC support routines for Linux
   3 * Frame Relay support
   4 *
   5 * Copyright (C) 1999 - 2003 Krzysztof Halasa <khc@pm.waw.pl>
   6 *
   7 * This program is free software; you can redistribute it and/or modify it
   8 * under the terms of version 2 of the GNU General Public License
   9 * as published by the Free Software Foundation.
  10 *
  11
  12 Theory of PVC state in DCE mode:
  13
  14 (exist,new) -> 0,0 when "PVC create" or if "link unreliable"
  15         0,x -> 1,1 if "link reliable" when sending FULL STATUS
  16         1,1 -> 1,0 if received FULL STATUS ACK
  17
  18 (active)    -> 0 when "ifconfig PVC down" or "link unreliable" or "PVC create"
  19             -> 1 when "PVC up" and (exist,new) = 1,0
  20*/
  21
  22#include <linux/module.h>
  23#include <linux/kernel.h>
  24#include <linux/slab.h>
  25#include <linux/poll.h>
  26#include <linux/errno.h>
  27#include <linux/if_arp.h>
  28#include <linux/init.h>
  29#include <linux/skbuff.h>
  30#include <linux/pkt_sched.h>
  31#include <linux/random.h>
  32#include <linux/inetdevice.h>
  33#include <linux/lapb.h>
  34#include <linux/rtnetlink.h>
  35#include <linux/etherdevice.h>
  36#include <linux/hdlc.h>
  37
  38#undef DEBUG_PKT
  39#undef DEBUG_ECN
  40
  41#define MAXLEN_LMISTAT  20      /* max size of status enquiry frame */
  42
  43#define PVC_STATE_NEW    0x01
  44#define PVC_STATE_ACTIVE 0x02
  45#define PVC_STATE_FECN   0x08 /* FECN condition */
  46#define PVC_STATE_BECN   0x10 /* BECN condition */
  47
  48
  49#define FR_UI            0x03
  50#define FR_PAD           0x00
  51
  52#define NLPID_IP         0xCC
  53#define NLPID_IPV6       0x8E
  54#define NLPID_SNAP       0x80
  55#define NLPID_PAD        0x00
  56#define NLPID_Q933       0x08
  57
  58
  59#define LMI_DLCI                   0 /* LMI DLCI */
  60#define LMI_PROTO               0x08
  61#define LMI_CALLREF             0x00 /* Call Reference */
  62#define LMI_ANSI_LOCKSHIFT      0x95 /* ANSI lockshift */
  63#define LMI_REPTYPE                1 /* report type */
  64#define LMI_CCITT_REPTYPE       0x51
  65#define LMI_ALIVE                  3 /* keep alive */
  66#define LMI_CCITT_ALIVE         0x53
  67#define LMI_PVCSTAT                7 /* pvc status */
  68#define LMI_CCITT_PVCSTAT       0x57
  69#define LMI_FULLREP                0 /* full report  */
  70#define LMI_INTEGRITY              1 /* link integrity report */
  71#define LMI_SINGLE                 2 /* single pvc report */
  72#define LMI_STATUS_ENQUIRY      0x75
  73#define LMI_STATUS              0x7D /* reply */
  74
  75#define LMI_REPT_LEN               1 /* report type element length */
  76#define LMI_INTEG_LEN              2 /* link integrity element length */
  77
  78#define LMI_LENGTH                13 /* standard LMI frame length */
  79#define LMI_ANSI_LENGTH           14
  80
  81
  82typedef struct {
  83#if defined(__LITTLE_ENDIAN_BITFIELD)
  84        unsigned ea1:   1;
  85        unsigned cr:    1;
  86        unsigned dlcih: 6;
  87  
  88        unsigned ea2:   1;
  89        unsigned de:    1;
  90        unsigned becn:  1;
  91        unsigned fecn:  1;
  92        unsigned dlcil: 4;
  93#else
  94        unsigned dlcih: 6;
  95        unsigned cr:    1;
  96        unsigned ea1:   1;
  97
  98        unsigned dlcil: 4;
  99        unsigned fecn:  1;
 100        unsigned becn:  1;
 101        unsigned de:    1;
 102        unsigned ea2:   1;
 103#endif
 104}__attribute__ ((packed)) fr_hdr;
 105
 106
 107static inline u16 q922_to_dlci(u8 *hdr)
 108{
 109        return ((hdr[0] & 0xFC) << 2) | ((hdr[1] & 0xF0) >> 4);
 110}
 111
 112
 113
 114static inline void dlci_to_q922(u8 *hdr, u16 dlci)
 115{
 116        hdr[0] = (dlci >> 2) & 0xFC;
 117        hdr[1] = ((dlci << 4) & 0xF0) | 0x01;
 118}
 119
 120
 121
 122static inline pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci)
 123{
 124        pvc_device *pvc = hdlc->state.fr.first_pvc;
 125
 126        while (pvc) {
 127                if (pvc->dlci == dlci)
 128                        return pvc;
 129                if (pvc->dlci > dlci)
 130                        return NULL; /* the listed is sorted */
 131                pvc = pvc->next;
 132        }
 133
 134        return NULL;
 135}
 136
 137
 138static inline pvc_device* add_pvc(hdlc_device *hdlc, u16 dlci)
 139{
 140        pvc_device *pvc, **pvc_p = &hdlc->state.fr.first_pvc;
 141
 142        while (*pvc_p) {
 143                if ((*pvc_p)->dlci == dlci)
 144                        return *pvc_p;
 145                if ((*pvc_p)->dlci > dlci)
 146                        break;  /* the list is sorted */
 147                pvc_p = &(*pvc_p)->next;
 148        }
 149
 150        pvc = kmalloc(sizeof(pvc_device), GFP_ATOMIC);
 151        if (!pvc)
 152                return NULL;
 153
 154        memset(pvc, 0, sizeof(pvc_device));
 155        pvc->dlci = dlci;
 156        pvc->master = hdlc;
 157        pvc->next = *pvc_p;     /* Put it in the chain */
 158        *pvc_p = pvc;
 159        return pvc;
 160}
 161
 162
 163static inline int pvc_is_used(pvc_device *pvc)
 164{
 165        return pvc->main != NULL || pvc->ether != NULL;
 166}
 167
 168
 169static inline void delete_unused_pvcs(hdlc_device *hdlc)
 170{
 171        pvc_device **pvc_p = &hdlc->state.fr.first_pvc;
 172
 173        while (*pvc_p) {
 174                if (!pvc_is_used(*pvc_p)) {
 175                        pvc_device *pvc = *pvc_p;
 176                        *pvc_p = pvc->next;
 177                        kfree(pvc);
 178                        continue;
 179                }
 180                pvc_p = &(*pvc_p)->next;
 181        }
 182}
 183
 184
 185static inline struct net_device** get_dev_p(pvc_device *pvc, int type)
 186{
 187        if (type == ARPHRD_ETHER)
 188                return &pvc->ether;
 189        else
 190                return &pvc->main;
 191}
 192
 193
 194static inline u16 status_to_dlci(u8 *status, int *active, int *new)
 195{
 196        *new = (status[2] & 0x08) ? 1 : 0;
 197        *active = (status[2] & 0x02) ? 1 : 0;
 198
 199        return ((status[0] & 0x3F) << 4) | ((status[1] & 0x78) >> 3);
 200}
 201
 202
 203static inline void dlci_to_status(u16 dlci, u8 *status, int active, int new)
 204{
 205        status[0] = (dlci >> 4) & 0x3F;
 206        status[1] = ((dlci << 3) & 0x78) | 0x80;
 207        status[2] = 0x80;
 208
 209        if (new)
 210                status[2] |= 0x08;
 211        else if (active)
 212                status[2] |= 0x02;
 213}
 214
 215
 216
 217static int fr_hard_header(struct sk_buff **skb_p, u16 dlci)
 218{
 219        u16 head_len;
 220        struct sk_buff *skb = *skb_p;
 221
 222        switch (skb->protocol) {
 223        case __constant_ntohs(ETH_P_IP):
 224                head_len = 4;
 225                skb_push(skb, head_len);
 226                skb->data[3] = NLPID_IP;
 227                break;
 228
 229        case __constant_ntohs(ETH_P_IPV6):
 230                head_len = 4;
 231                skb_push(skb, head_len);
 232                skb->data[3] = NLPID_IPV6;
 233                break;
 234
 235        case __constant_ntohs(LMI_PROTO):
 236                head_len = 4;
 237                skb_push(skb, head_len);
 238                skb->data[3] = LMI_PROTO;
 239                break;
 240
 241        case __constant_ntohs(ETH_P_802_3):
 242                head_len = 10;
 243                if (skb_headroom(skb) < head_len) {
 244                        struct sk_buff *skb2 = skb_realloc_headroom(skb,
 245                                                                    head_len);
 246                        if (!skb2)
 247                                return -ENOBUFS;
 248                        dev_kfree_skb(skb);
 249                        skb = *skb_p = skb2;
 250                }
 251                skb_push(skb, head_len);
 252                skb->data[3] = FR_PAD;
 253                skb->data[4] = NLPID_SNAP;
 254                skb->data[5] = FR_PAD;
 255                skb->data[6] = 0x80;
 256                skb->data[7] = 0xC2;
 257                skb->data[8] = 0x00;
 258                skb->data[9] = 0x07; /* bridged Ethernet frame w/out FCS */
 259                break;
 260
 261        default:
 262                head_len = 10;
 263                skb_push(skb, head_len);
 264                skb->data[3] = FR_PAD;
 265                skb->data[4] = NLPID_SNAP;
 266                skb->data[5] = FR_PAD;
 267                skb->data[6] = FR_PAD;
 268                skb->data[7] = FR_PAD;
 269                *(u16*)(skb->data + 8) = skb->protocol;
 270        }
 271
 272        dlci_to_q922(skb->data, dlci);
 273        skb->data[2] = FR_UI;
 274        return 0;
 275}
 276
 277
 278
 279static int pvc_open(struct net_device *dev)
 280{
 281        pvc_device *pvc = dev_to_pvc(dev);
 282
 283        if ((hdlc_to_dev(pvc->master)->flags & IFF_UP) == 0)
 284                return -EIO;  /* Master must be UP in order to activate PVC */
 285
 286        if (pvc->open_count++ == 0) {
 287                if (pvc->master->state.fr.settings.lmi == LMI_NONE)
 288                        pvc->state.active = 1;
 289
 290                pvc->master->state.fr.dce_changed = 1;
 291        }
 292        return 0;
 293}
 294
 295
 296
 297static int pvc_close(struct net_device *dev)
 298{
 299        pvc_device *pvc = dev_to_pvc(dev);
 300
 301        if (--pvc->open_count == 0) {
 302                if (pvc->master->state.fr.settings.lmi == LMI_NONE)
 303                        pvc->state.active = 0;
 304
 305                if (pvc->master->state.fr.settings.dce) {
 306                        pvc->master->state.fr.dce_changed = 1;
 307                        pvc->state.active = 0;
 308                }
 309        }
 310        return 0;
 311}
 312
 313
 314
 315int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 316{
 317        pvc_device *pvc = dev_to_pvc(dev);
 318        fr_proto_pvc_info info;
 319
 320        if (ifr->ifr_settings.type == IF_GET_PROTO) {
 321                if (dev->type == ARPHRD_ETHER)
 322                        ifr->ifr_settings.type = IF_PROTO_FR_ETH_PVC;
 323                else
 324                        ifr->ifr_settings.type = IF_PROTO_FR_PVC;
 325
 326                if (ifr->ifr_settings.size < sizeof(info)) {
 327                        /* data size wanted */
 328                        ifr->ifr_settings.size = sizeof(info);
 329                        return -ENOBUFS;
 330                }
 331
 332                info.dlci = pvc->dlci;
 333                memcpy(info.master, hdlc_to_name(pvc->master), IFNAMSIZ);
 334                if (copy_to_user(ifr->ifr_settings.ifs_ifsu.fr_pvc_info,
 335                                 &info, sizeof(info)))
 336                        return -EFAULT;
 337                return 0;
 338        }
 339
 340        return -EINVAL;
 341}
 342
 343
 344static inline struct net_device_stats *pvc_get_stats(struct net_device *dev)
 345{
 346        return (struct net_device_stats *)
 347                ((char *)dev + sizeof(struct net_device));
 348}
 349
 350
 351
 352static int pvc_xmit(struct sk_buff *skb, struct net_device *dev)
 353{
 354        pvc_device *pvc = dev_to_pvc(dev);
 355        struct net_device_stats *stats = pvc_get_stats(dev);
 356
 357        if (pvc->state.active) {
 358                if (dev->type == ARPHRD_ETHER) {
 359                        int pad = ETH_ZLEN - skb->len;
 360                        if (pad > 0) { /* Pad the frame with zeros */
 361                                int len = skb->len;
 362                                if (skb_tailroom(skb) < pad)
 363                                        if (pskb_expand_head(skb, 0, pad,
 364                                                             GFP_ATOMIC)) {
 365                                                stats->tx_dropped++;
 366                                                dev_kfree_skb(skb);
 367                                                return 0;
 368                                        }
 369                                skb_put(skb, pad);
 370                                memset(skb->data + len, 0, pad);
 371                        }
 372                        skb->protocol = __constant_htons(ETH_P_802_3);
 373                }
 374                if (!fr_hard_header(&skb, pvc->dlci)) {
 375                        stats->tx_bytes += skb->len;
 376                        stats->tx_packets++;
 377                        if (pvc->state.fecn) /* TX Congestion counter */
 378                                stats->tx_compressed++;
 379                        skb->dev = hdlc_to_dev(pvc->master);
 380                        dev_queue_xmit(skb);
 381                        return 0;
 382                }
 383        }
 384
 385        stats->tx_dropped++;
 386        dev_kfree_skb(skb);
 387        return 0;
 388}
 389
 390
 391
 392static int pvc_change_mtu(struct net_device *dev, int new_mtu)
 393{
 394        if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU))
 395                return -EINVAL;
 396        dev->mtu = new_mtu;
 397        return 0;
 398}
 399
 400
 401
 402static inline void fr_log_dlci_active(pvc_device *pvc)
 403{
 404        printk(KERN_INFO "%s: DLCI %d [%s%s%s]%s %s\n",
 405               hdlc_to_name(pvc->master),
 406               pvc->dlci,
 407               pvc->main ? pvc->main->name : "",
 408               pvc->main && pvc->ether ? " " : "",
 409               pvc->ether ? pvc->ether->name : "",
 410               pvc->state.new ? " new" : "",
 411               !pvc->state.exist ? "deleted" :
 412               pvc->state.active ? "active" : "inactive");
 413}
 414
 415
 416
 417static inline u8 fr_lmi_nextseq(u8 x)
 418{
 419        x++;
 420        return x ? x : 1;
 421}
 422
 423
 424
 425static void fr_lmi_send(hdlc_device *hdlc, int fullrep)
 426{
 427        struct sk_buff *skb;
 428        pvc_device *pvc = hdlc->state.fr.first_pvc;
 429        int len = (hdlc->state.fr.settings.lmi == LMI_ANSI) ? LMI_ANSI_LENGTH
 430                : LMI_LENGTH;
 431        int stat_len = 3;
 432        u8 *data;
 433        int i = 0;
 434
 435        if (hdlc->state.fr.settings.dce && fullrep) {
 436                len += hdlc->state.fr.dce_pvc_count * (2 + stat_len);
 437                if (len > HDLC_MAX_MRU) {
 438                        printk(KERN_WARNING "%s: Too many PVCs while sending "
 439                               "LMI full report\n", hdlc_to_name(hdlc));
 440                        return;
 441                }
 442        }
 443
 444        skb = dev_alloc_skb(len);
 445        if (!skb) {
 446                printk(KERN_WARNING "%s: Memory squeeze on fr_lmi_send()\n",
 447                       hdlc_to_name(hdlc));
 448                return;
 449        }
 450        memset(skb->data, 0, len);
 451        skb_reserve(skb, 4);
 452        skb->protocol = __constant_htons(LMI_PROTO);
 453        fr_hard_header(&skb, LMI_DLCI);
 454        data = skb->tail;
 455        data[i++] = LMI_CALLREF;
 456        data[i++] = hdlc->state.fr.settings.dce
 457                ? LMI_STATUS : LMI_STATUS_ENQUIRY;
 458        if (hdlc->state.fr.settings.lmi == LMI_ANSI)
 459                data[i++] = LMI_ANSI_LOCKSHIFT;
 460        data[i++] = (hdlc->state.fr.settings.lmi == LMI_CCITT)
 461                ? LMI_CCITT_REPTYPE : LMI_REPTYPE;
 462        data[i++] = LMI_REPT_LEN;
 463        data[i++] = fullrep ? LMI_FULLREP : LMI_INTEGRITY;
 464
 465        data[i++] = (hdlc->state.fr.settings.lmi == LMI_CCITT)
 466                ? LMI_CCITT_ALIVE : LMI_ALIVE;
 467        data[i++] = LMI_INTEG_LEN;
 468        data[i++] = hdlc->state.fr.txseq =fr_lmi_nextseq(hdlc->state.fr.txseq);
 469        data[i++] = hdlc->state.fr.rxseq;
 470
 471        if (hdlc->state.fr.settings.dce && fullrep) {
 472                while (pvc) {
 473                        data[i++] = (hdlc->state.fr.settings.lmi == LMI_CCITT)
 474                                ? LMI_CCITT_PVCSTAT : LMI_PVCSTAT;
 475                        data[i++] = stat_len;
 476
 477                        /* LMI start/restart */
 478                        if (hdlc->state.fr.reliable && !pvc->state.exist) {
 479                                pvc->state.exist = pvc->state.new = 1;
 480                                fr_log_dlci_active(pvc);
 481                        }
 482
 483                        /* ifconfig PVC up */
 484                        if (pvc->open_count && !pvc->state.active &&
 485                            pvc->state.exist && !pvc->state.new) {
 486                                pvc->state.active = 1;
 487                                fr_log_dlci_active(pvc);
 488                        }
 489
 490                        dlci_to_status(pvc->dlci, data + i,
 491                                       pvc->state.active, pvc->state.new);
 492                        i += stat_len;
 493                        pvc = pvc->next;
 494                }
 495        }
 496
 497        skb_put(skb, i);
 498        skb->priority = TC_PRIO_CONTROL;
 499        skb->dev = hdlc_to_dev(hdlc);
 500        skb->nh.raw = skb->data;
 501
 502        dev_queue_xmit(skb);
 503}
 504
 505
 506
 507static void fr_timer(unsigned long arg)
 508{
 509        hdlc_device *hdlc = (hdlc_device*)arg;
 510        int i, cnt = 0, reliable;
 511        u32 list;
 512
 513        if (hdlc->state.fr.settings.dce)
 514                reliable = (jiffies - hdlc->state.fr.last_poll <
 515                            hdlc->state.fr.settings.t392 * HZ);
 516        else {
 517                hdlc->state.fr.last_errors <<= 1; /* Shift the list */
 518                if (hdlc->state.fr.request) {
 519                        if (hdlc->state.fr.reliable)
 520                                printk(KERN_INFO "%s: No LMI status reply "
 521                                       "received\n", hdlc_to_name(hdlc));
 522                        hdlc->state.fr.last_errors |= 1;
 523                }
 524
 525                list = hdlc->state.fr.last_errors;
 526                for (i = 0; i < hdlc->state.fr.settings.n393; i++, list >>= 1)
 527                        cnt += (list & 1);      /* errors count */
 528
 529                reliable = (cnt < hdlc->state.fr.settings.n392);
 530        }
 531
 532        if (hdlc->state.fr.reliable != reliable) {
 533                pvc_device *pvc = hdlc->state.fr.first_pvc;
 534
 535                hdlc->state.fr.reliable = reliable;
 536                printk(KERN_INFO "%s: Link %sreliable\n", hdlc_to_name(hdlc),
 537                       reliable ? "" : "un");
 538
 539                if (reliable) {
 540                        hdlc->state.fr.n391cnt = 0; /* Request full status */
 541                        hdlc->state.fr.dce_changed = 1;
 542                } else {
 543                        while (pvc) {   /* Deactivate all PVCs */
 544                                pvc->state.exist = 0;
 545                                pvc->state.active = pvc->state.new = 0;
 546                                pvc = pvc->next;
 547                        }
 548                }
 549        }
 550
 551        if (hdlc->state.fr.settings.dce)
 552                hdlc->state.fr.timer.expires = jiffies +
 553                        hdlc->state.fr.settings.t392 * HZ;
 554        else {
 555                if (hdlc->state.fr.n391cnt)
 556                        hdlc->state.fr.n391cnt--;
 557
 558                fr_lmi_send(hdlc, hdlc->state.fr.n391cnt == 0);
 559
 560                hdlc->state.fr.request = 1;
 561                hdlc->state.fr.timer.expires = jiffies +
 562                        hdlc->state.fr.settings.t391 * HZ;
 563        }
 564
 565        hdlc->state.fr.timer.function = fr_timer;
 566        hdlc->state.fr.timer.data = arg;
 567        add_timer(&hdlc->state.fr.timer);
 568}
 569
 570
 571
 572static int fr_lmi_recv(hdlc_device *hdlc, struct sk_buff *skb)
 573{
 574        int stat_len;
 575        pvc_device *pvc;
 576        int reptype = -1, error, no_ram;
 577        u8 rxseq, txseq;
 578        int i;
 579
 580        if (skb->len < ((hdlc->state.fr.settings.lmi == LMI_ANSI)
 581                        ? LMI_ANSI_LENGTH : LMI_LENGTH)) {
 582                printk(KERN_INFO "%s: Short LMI frame\n", hdlc_to_name(hdlc));
 583                return 1;
 584        }
 585
 586        if (skb->data[5] != (!hdlc->state.fr.settings.dce ?
 587                             LMI_STATUS : LMI_STATUS_ENQUIRY)) {
 588                printk(KERN_INFO "%s: LMI msgtype=%x, Not LMI status %s\n",
 589                       hdlc_to_name(hdlc), skb->data[2],
 590                       hdlc->state.fr.settings.dce ? "enquiry" : "reply");
 591                return 1;
 592        }
 593
 594        i = (hdlc->state.fr.settings.lmi == LMI_ANSI) ? 7 : 6;
 595
 596        if (skb->data[i] !=
 597            ((hdlc->state.fr.settings.lmi == LMI_CCITT)
 598             ? LMI_CCITT_REPTYPE : LMI_REPTYPE)) {
 599                printk(KERN_INFO "%s: Not a report type=%x\n",
 600                       hdlc_to_name(hdlc), skb->data[i]);
 601                return 1;
 602        }
 603        i++;
 604
 605        i++;                            /* Skip length field */
 606
 607        reptype = skb->data[i++];
 608
 609        if (skb->data[i]!=
 610            ((hdlc->state.fr.settings.lmi == LMI_CCITT)
 611             ? LMI_CCITT_ALIVE : LMI_ALIVE)) {
 612                printk(KERN_INFO "%s: Unsupported status element=%x\n",
 613                       hdlc_to_name(hdlc), skb->data[i]);
 614                return 1;
 615        }
 616        i++;
 617
 618        i++;                    /* Skip length field */
 619
 620        hdlc->state.fr.rxseq = skb->data[i++]; /* TX sequence from peer */
 621        rxseq = skb->data[i++]; /* Should confirm our sequence */
 622
 623        txseq = hdlc->state.fr.txseq;
 624
 625        if (hdlc->state.fr.settings.dce) {
 626                if (reptype != LMI_FULLREP && reptype != LMI_INTEGRITY) {
 627                        printk(KERN_INFO "%s: Unsupported report type=%x\n",
 628                               hdlc_to_name(hdlc), reptype);
 629                        return 1;
 630                }
 631        }
 632
 633        error = 0;
 634        if (!hdlc->state.fr.reliable)
 635                error = 1;
 636
 637        if (rxseq == 0 || rxseq != txseq) {
 638                hdlc->state.fr.n391cnt = 0; /* Ask for full report next time */
 639                error = 1;
 640        }
 641
 642        if (hdlc->state.fr.settings.dce) {
 643                if (hdlc->state.fr.fullrep_sent && !error) {
 644/* Stop sending full report - the last one has been confirmed by DTE */
 645                        hdlc->state.fr.fullrep_sent = 0;
 646                        pvc = hdlc->state.fr.first_pvc;
 647                        while (pvc) {
 648                                if (pvc->state.new) {
 649                                        pvc->state.new = 0;
 650
 651/* Tell DTE that new PVC is now active */
 652                                        hdlc->state.fr.dce_changed = 1;
 653                                }
 654                                pvc = pvc->next;
 655                        }
 656                }
 657
 658                if (hdlc->state.fr.dce_changed) {
 659                        reptype = LMI_FULLREP;
 660                        hdlc->state.fr.fullrep_sent = 1;
 661                        hdlc->state.fr.dce_changed = 0;
 662                }
 663
 664                fr_lmi_send(hdlc, reptype == LMI_FULLREP ? 1 : 0);
 665                return 0;
 666        }
 667
 668        /* DTE */
 669
 670        if (reptype != LMI_FULLREP || error)
 671                return 0;
 672
 673        stat_len = 3;
 674        pvc = hdlc->state.fr.first_pvc;
 675
 676        while (pvc) {
 677                pvc->state.deleted = 1;
 678                pvc = pvc->next;
 679        }
 680
 681        no_ram = 0;
 682        while (skb->len >= i + 2 + stat_len) {
 683                u16 dlci;
 684                unsigned int active, new;
 685
 686                if (skb->data[i] != ((hdlc->state.fr.settings.lmi == LMI_CCITT)
 687                                     ? LMI_CCITT_PVCSTAT : LMI_PVCSTAT)) {
 688                        printk(KERN_WARNING "%s: Invalid PVCSTAT ID: %x\n",
 689                               hdlc_to_name(hdlc), skb->data[i]);
 690                        return 1;
 691                }
 692                i++;
 693
 694                if (skb->data[i] != stat_len) {
 695                        printk(KERN_WARNING "%s: Invalid PVCSTAT length: %x\n",
 696                               hdlc_to_name(hdlc), skb->data[i]);
 697                        return 1;
 698                }
 699                i++;
 700
 701                dlci = status_to_dlci(skb->data + i, &active, &new);
 702
 703                pvc = add_pvc(hdlc, dlci);
 704
 705                if (!pvc && !no_ram) {
 706                        printk(KERN_WARNING
 707                               "%s: Memory squeeze on fr_lmi_recv()\n",
 708                               hdlc_to_name(hdlc));
 709                        no_ram = 1;
 710                }
 711
 712                if (pvc) {
 713                        pvc->state.exist = 1;
 714                        pvc->state.deleted = 0;
 715                        if (active != pvc->state.active ||
 716                            new != pvc->state.new) {
 717                                pvc->state.new = new;
 718                                pvc->state.active = active;
 719                                fr_log_dlci_active(pvc);
 720                        }
 721                }
 722
 723                i += stat_len;
 724        }
 725
 726        pvc = hdlc->state.fr.first_pvc;
 727
 728        while (pvc) {
 729                if (pvc->state.deleted && pvc->state.exist) {
 730                        pvc->state.active = pvc->state.new = 0;
 731                        pvc->state.exist = 0;
 732                        fr_log_dlci_active(pvc);
 733                }
 734                pvc = pvc->next;
 735        }
 736
 737        /* Next full report after N391 polls */
 738        hdlc->state.fr.n391cnt = hdlc->state.fr.settings.n391;
 739
 740        return 0;
 741}
 742
 743
 744
 745static void fr_rx(struct sk_buff *skb)
 746{
 747        hdlc_device *hdlc = dev_to_hdlc(skb->dev);
 748        fr_hdr *fh = (fr_hdr*)skb->data;
 749        u8 *data = skb->data;
 750        u16 dlci;
 751        pvc_device *pvc;
 752        struct net_device *dev = NULL;
 753
 754        if (skb->len <= 4 || fh->ea1 || data[2] != FR_UI)
 755                goto rx_error;
 756
 757        dlci = q922_to_dlci(skb->data);
 758
 759        if (dlci == LMI_DLCI) {
 760                if (hdlc->state.fr.settings.lmi == LMI_NONE)
 761                        goto rx_error; /* LMI packet with no LMI? */
 762
 763                if (data[3] == LMI_PROTO) {
 764                        if (fr_lmi_recv(hdlc, skb))
 765                                goto rx_error;
 766                        else {
 767                                /* No request pending */
 768                                hdlc->state.fr.request = 0;
 769                                hdlc->state.fr.last_poll = jiffies;
 770                                dev_kfree_skb_any(skb);
 771                                return;
 772                        }
 773                }
 774
 775                printk(KERN_INFO "%s: Received non-LMI frame with LMI DLCI\n",
 776                       hdlc_to_name(hdlc));
 777                goto rx_error;
 778        }
 779
 780        pvc = find_pvc(hdlc, dlci);
 781        if (!pvc) {
 782#ifdef DEBUG_PKT
 783                printk(KERN_INFO "%s: No PVC for received frame's DLCI %d\n",
 784                       hdlc_to_name(hdlc), dlci);
 785#endif
 786                dev_kfree_skb_any(skb);
 787                return;
 788        }
 789
 790        if (pvc->state.fecn != fh->fecn) {
 791#ifdef DEBUG_ECN
 792                printk(KERN_DEBUG "%s: DLCI %d FECN O%s\n", hdlc_to_name(pvc),
 793                       dlci, fh->fecn ? "N" : "FF");
 794#endif
 795                pvc->state.fecn ^= 1;
 796        }
 797
 798        if (pvc->state.becn != fh->becn) {
 799#ifdef DEBUG_ECN
 800                printk(KERN_DEBUG "%s: DLCI %d BECN O%s\n", hdlc_to_name(pvc),
 801                       dlci, fh->becn ? "N" : "FF");
 802#endif
 803                pvc->state.becn ^= 1;
 804        }
 805
 806
 807        if (data[3] == NLPID_IP) {
 808                skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */
 809                dev = pvc->main;
 810                skb->protocol = htons(ETH_P_IP);
 811
 812        } else if (data[3] == NLPID_IPV6) {
 813                skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */
 814                dev = pvc->main;
 815                skb->protocol = htons(ETH_P_IPV6);
 816
 817        } else if (skb->len > 10 && data[3] == FR_PAD &&
 818                   data[4] == NLPID_SNAP && data[5] == FR_PAD) {
 819                u16 oui = ntohs(*(u16*)(data + 6));
 820                u16 pid = ntohs(*(u16*)(data + 8));
 821                skb_pull(skb, 10);
 822
 823                switch ((((u32)oui) << 16) | pid) {
 824                case ETH_P_ARP: /* routed frame with SNAP */
 825                case ETH_P_IPX:
 826                case ETH_P_IP:  /* a long variant */
 827                case ETH_P_IPV6:
 828                        dev = pvc->main;
 829                        skb->protocol = htons(pid);
 830                        break;
 831
 832                case 0x80C20007: /* bridged Ethernet frame */
 833                        if ((dev = pvc->ether) != NULL)
 834                                skb->protocol = eth_type_trans(skb, dev);
 835                        break;
 836
 837                default:
 838                        printk(KERN_INFO "%s: Unsupported protocol, OUI=%x "
 839                               "PID=%x\n", hdlc_to_name(hdlc), oui, pid);
 840                        dev_kfree_skb_any(skb);
 841                        return;
 842                }
 843        } else {
 844                printk(KERN_INFO "%s: Unsupported protocol, NLPID=%x "
 845                       "length = %i\n", hdlc_to_name(hdlc), data[3], skb->len);
 846                dev_kfree_skb_any(skb);
 847                return;
 848        }
 849
 850        if (dev) {
 851                struct net_device_stats *stats = pvc_get_stats(dev);
 852                stats->rx_packets++; /* PVC traffic */
 853                stats->rx_bytes += skb->len;
 854                if (pvc->state.becn)
 855                        stats->rx_compressed++;
 856                skb->dev = dev;
 857                netif_rx(skb);
 858        } else
 859                dev_kfree_skb_any(skb);
 860
 861        return;
 862
 863 rx_error:
 864        hdlc->stats.rx_errors++; /* Mark error */
 865        dev_kfree_skb_any(skb);
 866}
 867
 868
 869
 870static int fr_open(hdlc_device *hdlc)
 871{
 872        if (hdlc->state.fr.settings.lmi != LMI_NONE) {
 873                hdlc->state.fr.last_poll = 0;
 874                hdlc->state.fr.reliable = 0;
 875                hdlc->state.fr.dce_changed = 1;
 876                hdlc->state.fr.request = 0;
 877                hdlc->state.fr.fullrep_sent = 0;
 878                hdlc->state.fr.last_errors = 0xFFFFFFFF;
 879                hdlc->state.fr.n391cnt = 0;
 880                hdlc->state.fr.txseq = hdlc->state.fr.rxseq = 0;
 881
 882                init_timer(&hdlc->state.fr.timer);
 883                /* First poll after 1 s */
 884                hdlc->state.fr.timer.expires = jiffies + HZ;
 885                hdlc->state.fr.timer.function = fr_timer;
 886                hdlc->state.fr.timer.data = (unsigned long)hdlc;
 887                add_timer(&hdlc->state.fr.timer);
 888        } else
 889                hdlc->state.fr.reliable = 1;
 890
 891        return 0;
 892}
 893
 894
 895
 896static void fr_close(hdlc_device *hdlc)
 897{
 898        pvc_device *pvc = hdlc->state.fr.first_pvc;
 899
 900        if (hdlc->state.fr.settings.lmi != LMI_NONE)
 901                del_timer_sync(&hdlc->state.fr.timer);
 902
 903        while (pvc) {           /* Shutdown all PVCs for this FRAD */
 904                if (pvc->main)
 905                        dev_close(pvc->main);
 906                if (pvc->ether)
 907                        dev_close(pvc->ether);
 908                pvc->state.active = pvc->state.new = pvc->state.fecn =
 909                        pvc->state.becn = 0;
 910                pvc->state.exist = 0;
 911                pvc = pvc->next;
 912        }
 913}
 914
 915
 916static int fr_add_pvc(hdlc_device *hdlc, unsigned int dlci, int type)
 917{
 918        pvc_device *pvc = NULL;
 919        struct net_device *dev;
 920        int result, used;
 921        char * prefix = "pvc%d";
 922
 923        if (type == ARPHRD_ETHER)
 924                prefix = "pvceth%d";
 925
 926        if ((pvc = add_pvc(hdlc, dlci)) == NULL) {
 927                printk(KERN_WARNING "%s: Memory squeeze on fr_add_pvc()\n",
 928                       hdlc_to_name(hdlc));
 929                return -ENOBUFS;
 930        }
 931
 932        if (*get_dev_p(pvc, type))
 933                return -EEXIST;
 934
 935        used = pvc_is_used(pvc);
 936
 937        dev = kmalloc(sizeof(struct net_device) +
 938                      sizeof(struct net_device_stats), GFP_KERNEL);
 939        if (!dev) {
 940                printk(KERN_WARNING "%s: Memory squeeze on fr_pvc()\n",
 941                       hdlc_to_name(hdlc));
 942                delete_unused_pvcs(hdlc);
 943                return -ENOBUFS;
 944        }
 945        memset(dev, 0, sizeof(struct net_device) +
 946               sizeof(struct net_device_stats));
 947
 948        if (type == ARPHRD_ETHER) {
 949                ether_setup(dev);
 950                memcpy(dev->dev_addr, "\x00\x01", 2);
 951                get_random_bytes(dev->dev_addr + 2, ETH_ALEN - 2);
 952        } else {
 953                dev->type = ARPHRD_DLCI;
 954                dev->flags = IFF_POINTOPOINT;
 955                dev->hard_header_len = 10;
 956                dev->addr_len = 2;
 957                *(u16*)dev->dev_addr = htons(dlci);
 958                dlci_to_q922(dev->broadcast, dlci);
 959        }
 960        dev->hard_start_xmit = pvc_xmit;
 961        dev->get_stats = pvc_get_stats;
 962        dev->open = pvc_open;
 963        dev->stop = pvc_close;
 964        dev->do_ioctl = pvc_ioctl;
 965        dev->change_mtu = pvc_change_mtu;
 966        dev->mtu = HDLC_MAX_MTU;
 967        dev->tx_queue_len = 0;
 968        dev->priv = pvc;
 969
 970        result = dev_alloc_name(dev, prefix);
 971        if (result < 0) {
 972                kfree(dev);
 973                delete_unused_pvcs(hdlc);
 974                return result;
 975        }
 976
 977        if (register_netdevice(dev) != 0) {
 978                kfree(dev);
 979                delete_unused_pvcs(hdlc);
 980                return -EIO;
 981        }
 982
 983        *get_dev_p(pvc, type) = dev;
 984        if (!used) {
 985                hdlc->state.fr.dce_changed = 1;
 986                hdlc->state.fr.dce_pvc_count++;
 987        }
 988        return 0;
 989}
 990
 991
 992
 993static int fr_del_pvc(hdlc_device *hdlc, unsigned int dlci, int type)
 994{
 995        pvc_device *pvc;
 996        struct net_device *dev;
 997
 998        if ((pvc = find_pvc(hdlc, dlci)) == NULL)
 999                return -ENOENT;
1000
1001        if ((dev = *get_dev_p(pvc, type)) == NULL)
1002                return -ENOENT;
1003
1004        if (dev->flags & IFF_UP)
1005                return -EBUSY;          /* PVC in use */
1006
1007        unregister_netdevice(dev);
1008        kfree(dev);
1009        *get_dev_p(pvc, type) = NULL;
1010
1011        if (!pvc_is_used(pvc)) {
1012                hdlc->state.fr.dce_pvc_count--;
1013                hdlc->state.fr.dce_changed = 1;
1014        }
1015        delete_unused_pvcs(hdlc);
1016        return 0;
1017}
1018
1019
1020
1021static void fr_destroy(hdlc_device *hdlc)
1022{
1023        pvc_device *pvc = hdlc->state.fr.first_pvc;
1024        while (pvc) {
1025                pvc_device *next = pvc->next;
1026                if (pvc->main) {
1027                        unregister_netdevice(pvc->main);
1028                        kfree(pvc->main);
1029                }
1030                if (pvc->ether) {
1031                        unregister_netdevice(pvc->ether);
1032                        kfree(pvc->ether);
1033                }
1034                kfree(pvc);
1035                pvc = next;
1036        }
1037
1038        hdlc->state.fr.first_pvc = NULL; /* All PVCs destroyed */
1039        hdlc->state.fr.dce_pvc_count = 0;
1040        hdlc->state.fr.dce_changed = 1;
1041}
1042
1043
1044
1045int hdlc_fr_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
1046{
1047        fr_proto *fr_s = ifr->ifr_settings.ifs_ifsu.fr;
1048        const size_t size = sizeof(fr_proto);
1049        fr_proto new_settings;
1050        struct net_device *dev = hdlc_to_dev(hdlc);
1051        fr_proto_pvc pvc;
1052        int result;
1053
1054        switch (ifr->ifr_settings.type) {
1055        case IF_GET_PROTO:
1056                ifr->ifr_settings.type = IF_PROTO_FR;
1057                if (ifr->ifr_settings.size < size) {
1058                        ifr->ifr_settings.size = size; /* data size wanted */
1059                        return -ENOBUFS;
1060                }
1061                if (copy_to_user(fr_s, &hdlc->state.fr.settings, size))
1062                        return -EFAULT;
1063                return 0;
1064
1065        case IF_PROTO_FR:
1066                if(!capable(CAP_NET_ADMIN))
1067                        return -EPERM;
1068
1069                if(dev->flags & IFF_UP)
1070                        return -EBUSY;
1071
1072                if (copy_from_user(&new_settings, fr_s, size))
1073                        return -EFAULT;
1074
1075                if (new_settings.lmi == LMI_DEFAULT)
1076                        new_settings.lmi = LMI_ANSI;
1077
1078                if ((new_settings.lmi != LMI_NONE &&
1079                     new_settings.lmi != LMI_ANSI &&
1080                     new_settings.lmi != LMI_CCITT) ||
1081                    new_settings.t391 < 1 ||
1082                    new_settings.t392 < 2 ||
1083                    new_settings.n391 < 1 ||
1084                    new_settings.n392 < 1 ||
1085                    new_settings.n393 < new_settings.n392 ||
1086                    new_settings.n393 > 32 ||
1087                    (new_settings.dce != 0 &&
1088                     new_settings.dce != 1))
1089                        return -EINVAL;
1090
1091                result=hdlc->attach(hdlc, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
1092                if (result)
1093                        return result;
1094
1095                if (hdlc->proto != IF_PROTO_FR) {
1096                        hdlc_proto_detach(hdlc);
1097                        hdlc->state.fr.first_pvc = NULL;
1098                        hdlc->state.fr.dce_pvc_count = 0;
1099                }
1100                memcpy(&hdlc->state.fr.settings, &new_settings, size);
1101
1102                hdlc->open = fr_open;
1103                hdlc->stop = fr_close;
1104                hdlc->netif_rx = fr_rx;
1105                hdlc->type_trans = NULL;
1106                hdlc->proto_detach = fr_destroy;
1107                hdlc->proto = IF_PROTO_FR;
1108                dev->hard_start_xmit = hdlc->xmit;
1109                dev->hard_header = NULL;
1110                dev->type = ARPHRD_FRAD;
1111                dev->flags = IFF_POINTOPOINT | IFF_NOARP;
1112                dev->addr_len = 0;
1113                return 0;
1114
1115        case IF_PROTO_FR_ADD_PVC:
1116        case IF_PROTO_FR_DEL_PVC:
1117        case IF_PROTO_FR_ADD_ETH_PVC:
1118        case IF_PROTO_FR_DEL_ETH_PVC:
1119                if(!capable(CAP_NET_ADMIN))
1120                        return -EPERM;
1121
1122                if (copy_from_user(&pvc, ifr->ifr_settings.ifs_ifsu.fr_pvc,
1123                                   sizeof(fr_proto_pvc)))
1124                        return -EFAULT;
1125
1126                if (pvc.dlci <= 0 || pvc.dlci >= 1024)
1127                        return -EINVAL; /* Only 10 bits, DLCI 0 reserved */
1128
1129                if (ifr->ifr_settings.type == IF_PROTO_FR_ADD_ETH_PVC ||
1130                    ifr->ifr_settings.type == IF_PROTO_FR_DEL_ETH_PVC)
1131                        result = ARPHRD_ETHER; /* bridged Ethernet device */
1132                else
1133                        result = ARPHRD_DLCI;
1134
1135                if (ifr->ifr_settings.type == IF_PROTO_FR_ADD_PVC ||
1136                    ifr->ifr_settings.type == IF_PROTO_FR_ADD_ETH_PVC)
1137                        return fr_add_pvc(hdlc, pvc.dlci, result);
1138                else
1139                        return fr_del_pvc(hdlc, pvc.dlci, result);
1140        }
1141
1142        return -EINVAL;
1143}
1144
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.