aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wan/hdlc_fr.c
diff options
context:
space:
mode:
authorKrzysztof Halasa <khc@pm.waw.pl>2005-04-21 09:57:25 -0400
committerJeff Garzik <jgarzik@pobox.com>2005-05-15 22:24:12 -0400
commitb3dd65f958354226275522b5a64157834bdc5415 (patch)
tree851d12ea34fb9e5e5eb439a774da5a6a862ca762 /drivers/net/wan/hdlc_fr.c
parent88d7bd8cb9eb8d64bf7997600b0d64f7834047c5 (diff)
[PATCH] Generic HDLC update
The attached patch updates generic HDLC to version 1.18. FR Cisco LMI production-tested. Please apply to Linux 2.6. Thanks. Changes: - doc updates - added Cisco LMI support to Frame-Relay code - cleaned hdlc_fr.c a bit, removed some orphaned #defines etc. - fixed a problem with non-functional LMI in FR DCE mode. - changed diagnostic messages to better conform to FR standards - all protocols: information about carrier changes (DCD line) is now printed to kernel logs. Signed-Off-By: Krzysztof Halasa <khc@pm.waw.pl>
Diffstat (limited to 'drivers/net/wan/hdlc_fr.c')
-rw-r--r--drivers/net/wan/hdlc_fr.c320
1 files changed, 176 insertions, 144 deletions
diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c
index 7f450b51a6cb..a5d6891c9d4c 100644
--- a/drivers/net/wan/hdlc_fr.c
+++ b/drivers/net/wan/hdlc_fr.c
@@ -2,7 +2,7 @@
2 * Generic HDLC support routines for Linux 2 * Generic HDLC support routines for Linux
3 * Frame Relay support 3 * Frame Relay support
4 * 4 *
5 * Copyright (C) 1999 - 2003 Krzysztof Halasa <khc@pm.waw.pl> 5 * Copyright (C) 1999 - 2005 Krzysztof Halasa <khc@pm.waw.pl>
6 * 6 *
7 * This program is free software; you can redistribute it and/or modify it 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 8 * under the terms of version 2 of the GNU General Public License
@@ -27,6 +27,10 @@
27 active = open and "link reliable" 27 active = open and "link reliable"
28 exist = new = not used 28 exist = new = not used
29 29
30 CCITT LMI: ITU-T Q.933 Annex A
31 ANSI LMI: ANSI T1.617 Annex D
32 CISCO LMI: the original, aka "Gang of Four" LMI
33
30*/ 34*/
31 35
32#include <linux/module.h> 36#include <linux/module.h>
@@ -49,45 +53,41 @@
49#undef DEBUG_ECN 53#undef DEBUG_ECN
50#undef DEBUG_LINK 54#undef DEBUG_LINK
51 55
52#define MAXLEN_LMISTAT 20 /* max size of status enquiry frame */ 56#define FR_UI 0x03
53 57#define FR_PAD 0x00
54#define PVC_STATE_NEW 0x01 58
55#define PVC_STATE_ACTIVE 0x02 59#define NLPID_IP 0xCC
56#define PVC_STATE_FECN 0x08 /* FECN condition */ 60#define NLPID_IPV6 0x8E
57#define PVC_STATE_BECN 0x10 /* BECN condition */ 61#define NLPID_SNAP 0x80
58 62#define NLPID_PAD 0x00
59 63#define NLPID_CCITT_ANSI_LMI 0x08
60#define FR_UI 0x03 64#define NLPID_CISCO_LMI 0x09
61#define FR_PAD 0x00 65
62 66
63#define NLPID_IP 0xCC 67#define LMI_CCITT_ANSI_DLCI 0 /* LMI DLCI */
64#define NLPID_IPV6 0x8E 68#define LMI_CISCO_DLCI 1023
65#define NLPID_SNAP 0x80 69
66#define NLPID_PAD 0x00 70#define LMI_CALLREF 0x00 /* Call Reference */
67#define NLPID_Q933 0x08 71#define LMI_ANSI_LOCKSHIFT 0x95 /* ANSI locking shift */
68 72#define LMI_ANSI_CISCO_REPTYPE 0x01 /* report type */
69 73#define LMI_CCITT_REPTYPE 0x51
70#define LMI_DLCI 0 /* LMI DLCI */ 74#define LMI_ANSI_CISCO_ALIVE 0x03 /* keep alive */
71#define LMI_PROTO 0x08 75#define LMI_CCITT_ALIVE 0x53
72#define LMI_CALLREF 0x00 /* Call Reference */ 76#define LMI_ANSI_CISCO_PVCSTAT 0x07 /* PVC status */
73#define LMI_ANSI_LOCKSHIFT 0x95 /* ANSI lockshift */ 77#define LMI_CCITT_PVCSTAT 0x57
74#define LMI_REPTYPE 1 /* report type */ 78
75#define LMI_CCITT_REPTYPE 0x51 79#define LMI_FULLREP 0x00 /* full report */
76#define LMI_ALIVE 3 /* keep alive */ 80#define LMI_INTEGRITY 0x01 /* link integrity report */
77#define LMI_CCITT_ALIVE 0x53 81#define LMI_SINGLE 0x02 /* single PVC report */
78#define LMI_PVCSTAT 7 /* pvc status */ 82
79#define LMI_CCITT_PVCSTAT 0x57
80#define LMI_FULLREP 0 /* full report */
81#define LMI_INTEGRITY 1 /* link integrity report */
82#define LMI_SINGLE 2 /* single pvc report */
83#define LMI_STATUS_ENQUIRY 0x75 83#define LMI_STATUS_ENQUIRY 0x75
84#define LMI_STATUS 0x7D /* reply */ 84#define LMI_STATUS 0x7D /* reply */
85 85
86#define LMI_REPT_LEN 1 /* report type element length */ 86#define LMI_REPT_LEN 1 /* report type element length */
87#define LMI_INTEG_LEN 2 /* link integrity element length */ 87#define LMI_INTEG_LEN 2 /* link integrity element length */
88 88
89#define LMI_LENGTH 13 /* standard LMI frame length */ 89#define LMI_CCITT_CISCO_LENGTH 13 /* LMI frame lengths */
90#define LMI_ANSI_LENGTH 14 90#define LMI_ANSI_LENGTH 14
91 91
92 92
93typedef struct { 93typedef struct {
@@ -223,51 +223,34 @@ static inline struct net_device** get_dev_p(pvc_device *pvc, int type)
223} 223}
224 224
225 225
226static inline u16 status_to_dlci(u8 *status, int *active, int *new)
227{
228 *new = (status[2] & 0x08) ? 1 : 0;
229 *active = (status[2] & 0x02) ? 1 : 0;
230
231 return ((status[0] & 0x3F) << 4) | ((status[1] & 0x78) >> 3);
232}
233
234
235static inline void dlci_to_status(u16 dlci, u8 *status, int active, int new)
236{
237 status[0] = (dlci >> 4) & 0x3F;
238 status[1] = ((dlci << 3) & 0x78) | 0x80;
239 status[2] = 0x80;
240
241 if (new)
242 status[2] |= 0x08;
243 else if (active)
244 status[2] |= 0x02;
245}
246
247
248
249static int fr_hard_header(struct sk_buff **skb_p, u16 dlci) 226static int fr_hard_header(struct sk_buff **skb_p, u16 dlci)
250{ 227{
251 u16 head_len; 228 u16 head_len;
252 struct sk_buff *skb = *skb_p; 229 struct sk_buff *skb = *skb_p;
253 230
254 switch (skb->protocol) { 231 switch (skb->protocol) {
255 case __constant_ntohs(ETH_P_IP): 232 case __constant_ntohs(NLPID_CCITT_ANSI_LMI):
256 head_len = 4; 233 head_len = 4;
257 skb_push(skb, head_len); 234 skb_push(skb, head_len);
258 skb->data[3] = NLPID_IP; 235 skb->data[3] = NLPID_CCITT_ANSI_LMI;
259 break; 236 break;
260 237
261 case __constant_ntohs(ETH_P_IPV6): 238 case __constant_ntohs(NLPID_CISCO_LMI):
262 head_len = 4; 239 head_len = 4;
263 skb_push(skb, head_len); 240 skb_push(skb, head_len);
264 skb->data[3] = NLPID_IPV6; 241 skb->data[3] = NLPID_CISCO_LMI;
265 break; 242 break;
266 243
267 case __constant_ntohs(LMI_PROTO): 244 case __constant_ntohs(ETH_P_IP):
245 head_len = 4;
246 skb_push(skb, head_len);
247 skb->data[3] = NLPID_IP;
248 break;
249
250 case __constant_ntohs(ETH_P_IPV6):
268 head_len = 4; 251 head_len = 4;
269 skb_push(skb, head_len); 252 skb_push(skb, head_len);
270 skb->data[3] = LMI_PROTO; 253 skb->data[3] = NLPID_IPV6;
271 break; 254 break;
272 255
273 case __constant_ntohs(ETH_P_802_3): 256 case __constant_ntohs(ETH_P_802_3):
@@ -461,13 +444,14 @@ static void fr_lmi_send(struct net_device *dev, int fullrep)
461 hdlc_device *hdlc = dev_to_hdlc(dev); 444 hdlc_device *hdlc = dev_to_hdlc(dev);
462 struct sk_buff *skb; 445 struct sk_buff *skb;
463 pvc_device *pvc = hdlc->state.fr.first_pvc; 446 pvc_device *pvc = hdlc->state.fr.first_pvc;
464 int len = (hdlc->state.fr.settings.lmi == LMI_ANSI) ? LMI_ANSI_LENGTH 447 int lmi = hdlc->state.fr.settings.lmi;
465 : LMI_LENGTH; 448 int dce = hdlc->state.fr.settings.dce;
466 int stat_len = 3; 449 int len = lmi == LMI_ANSI ? LMI_ANSI_LENGTH : LMI_CCITT_CISCO_LENGTH;
450 int stat_len = (lmi == LMI_CISCO) ? 6 : 3;
467 u8 *data; 451 u8 *data;
468 int i = 0; 452 int i = 0;
469 453
470 if (hdlc->state.fr.settings.dce && fullrep) { 454 if (dce && fullrep) {
471 len += hdlc->state.fr.dce_pvc_count * (2 + stat_len); 455 len += hdlc->state.fr.dce_pvc_count * (2 + stat_len);
472 if (len > HDLC_MAX_MRU) { 456 if (len > HDLC_MAX_MRU) {
473 printk(KERN_WARNING "%s: Too many PVCs while sending " 457 printk(KERN_WARNING "%s: Too many PVCs while sending "
@@ -484,29 +468,31 @@ static void fr_lmi_send(struct net_device *dev, int fullrep)
484 } 468 }
485 memset(skb->data, 0, len); 469 memset(skb->data, 0, len);
486 skb_reserve(skb, 4); 470 skb_reserve(skb, 4);
487 skb->protocol = __constant_htons(LMI_PROTO); 471 if (lmi == LMI_CISCO) {
488 fr_hard_header(&skb, LMI_DLCI); 472 skb->protocol = __constant_htons(NLPID_CISCO_LMI);
473 fr_hard_header(&skb, LMI_CISCO_DLCI);
474 } else {
475 skb->protocol = __constant_htons(NLPID_CCITT_ANSI_LMI);
476 fr_hard_header(&skb, LMI_CCITT_ANSI_DLCI);
477 }
489 data = skb->tail; 478 data = skb->tail;
490 data[i++] = LMI_CALLREF; 479 data[i++] = LMI_CALLREF;
491 data[i++] = hdlc->state.fr.settings.dce 480 data[i++] = dce ? LMI_STATUS : LMI_STATUS_ENQUIRY;
492 ? LMI_STATUS : LMI_STATUS_ENQUIRY; 481 if (lmi == LMI_ANSI)
493 if (hdlc->state.fr.settings.lmi == LMI_ANSI)
494 data[i++] = LMI_ANSI_LOCKSHIFT; 482 data[i++] = LMI_ANSI_LOCKSHIFT;
495 data[i++] = (hdlc->state.fr.settings.lmi == LMI_CCITT) 483 data[i++] = lmi == LMI_CCITT ? LMI_CCITT_REPTYPE :
496 ? LMI_CCITT_REPTYPE : LMI_REPTYPE; 484 LMI_ANSI_CISCO_REPTYPE;
497 data[i++] = LMI_REPT_LEN; 485 data[i++] = LMI_REPT_LEN;
498 data[i++] = fullrep ? LMI_FULLREP : LMI_INTEGRITY; 486 data[i++] = fullrep ? LMI_FULLREP : LMI_INTEGRITY;
499 487 data[i++] = lmi == LMI_CCITT ? LMI_CCITT_ALIVE : LMI_ANSI_CISCO_ALIVE;
500 data[i++] = (hdlc->state.fr.settings.lmi == LMI_CCITT)
501 ? LMI_CCITT_ALIVE : LMI_ALIVE;
502 data[i++] = LMI_INTEG_LEN; 488 data[i++] = LMI_INTEG_LEN;
503 data[i++] = hdlc->state.fr.txseq =fr_lmi_nextseq(hdlc->state.fr.txseq); 489 data[i++] = hdlc->state.fr.txseq =fr_lmi_nextseq(hdlc->state.fr.txseq);
504 data[i++] = hdlc->state.fr.rxseq; 490 data[i++] = hdlc->state.fr.rxseq;
505 491
506 if (hdlc->state.fr.settings.dce && fullrep) { 492 if (dce && fullrep) {
507 while (pvc) { 493 while (pvc) {
508 data[i++] = (hdlc->state.fr.settings.lmi == LMI_CCITT) 494 data[i++] = lmi == LMI_CCITT ? LMI_CCITT_PVCSTAT :
509 ? LMI_CCITT_PVCSTAT : LMI_PVCSTAT; 495 LMI_ANSI_CISCO_PVCSTAT;
510 data[i++] = stat_len; 496 data[i++] = stat_len;
511 497
512 /* LMI start/restart */ 498 /* LMI start/restart */
@@ -523,8 +509,20 @@ static void fr_lmi_send(struct net_device *dev, int fullrep)
523 fr_log_dlci_active(pvc); 509 fr_log_dlci_active(pvc);
524 } 510 }
525 511
526 dlci_to_status(pvc->dlci, data + i, 512 if (lmi == LMI_CISCO) {
527 pvc->state.active, pvc->state.new); 513 data[i] = pvc->dlci >> 8;
514 data[i + 1] = pvc->dlci & 0xFF;
515 } else {
516 data[i] = (pvc->dlci >> 4) & 0x3F;
517 data[i + 1] = ((pvc->dlci << 3) & 0x78) | 0x80;
518 data[i + 2] = 0x80;
519 }
520
521 if (pvc->state.new)
522 data[i + 2] |= 0x08;
523 else if (pvc->state.active)
524 data[i + 2] |= 0x02;
525
528 i += stat_len; 526 i += stat_len;
529 pvc = pvc->next; 527 pvc = pvc->next;
530 } 528 }
@@ -569,6 +567,8 @@ static void fr_set_link_state(int reliable, struct net_device *dev)
569 pvc_carrier(0, pvc); 567 pvc_carrier(0, pvc);
570 pvc->state.exist = pvc->state.active = 0; 568 pvc->state.exist = pvc->state.active = 0;
571 pvc->state.new = 0; 569 pvc->state.new = 0;
570 if (!hdlc->state.fr.settings.dce)
571 pvc->state.bandwidth = 0;
572 pvc = pvc->next; 572 pvc = pvc->next;
573 } 573 }
574 } 574 }
@@ -583,11 +583,12 @@ static void fr_timer(unsigned long arg)
583 int i, cnt = 0, reliable; 583 int i, cnt = 0, reliable;
584 u32 list; 584 u32 list;
585 585
586 if (hdlc->state.fr.settings.dce) 586 if (hdlc->state.fr.settings.dce) {
587 reliable = hdlc->state.fr.request && 587 reliable = hdlc->state.fr.request &&
588 time_before(jiffies, hdlc->state.fr.last_poll + 588 time_before(jiffies, hdlc->state.fr.last_poll +
589 hdlc->state.fr.settings.t392 * HZ); 589 hdlc->state.fr.settings.t392 * HZ);
590 else { 590 hdlc->state.fr.request = 0;
591 } else {
591 hdlc->state.fr.last_errors <<= 1; /* Shift the list */ 592 hdlc->state.fr.last_errors <<= 1; /* Shift the list */
592 if (hdlc->state.fr.request) { 593 if (hdlc->state.fr.request) {
593 if (hdlc->state.fr.reliable) 594 if (hdlc->state.fr.reliable)
@@ -634,65 +635,88 @@ static void fr_timer(unsigned long arg)
634static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb) 635static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
635{ 636{
636 hdlc_device *hdlc = dev_to_hdlc(dev); 637 hdlc_device *hdlc = dev_to_hdlc(dev);
637 int stat_len;
638 pvc_device *pvc; 638 pvc_device *pvc;
639 int reptype = -1, error, no_ram;
640 u8 rxseq, txseq; 639 u8 rxseq, txseq;
641 int i; 640 int lmi = hdlc->state.fr.settings.lmi;
641 int dce = hdlc->state.fr.settings.dce;
642 int stat_len = (lmi == LMI_CISCO) ? 6 : 3, reptype, error, no_ram, i;
642 643
643 if (skb->len < ((hdlc->state.fr.settings.lmi == LMI_ANSI) 644 if (skb->len < (lmi == LMI_ANSI ? LMI_ANSI_LENGTH :
644 ? LMI_ANSI_LENGTH : LMI_LENGTH)) { 645 LMI_CCITT_CISCO_LENGTH)) {
645 printk(KERN_INFO "%s: Short LMI frame\n", dev->name); 646 printk(KERN_INFO "%s: Short LMI frame\n", dev->name);
646 return 1; 647 return 1;
647 } 648 }
648 649
649 if (skb->data[5] != (!hdlc->state.fr.settings.dce ? 650 if (skb->data[3] != (lmi == LMI_CISCO ? NLPID_CISCO_LMI :
650 LMI_STATUS : LMI_STATUS_ENQUIRY)) { 651 NLPID_CCITT_ANSI_LMI)) {
651 printk(KERN_INFO "%s: LMI msgtype=%x, Not LMI status %s\n", 652 printk(KERN_INFO "%s: Received non-LMI frame with LMI"
652 dev->name, skb->data[2], 653 " DLCI\n", dev->name);
653 hdlc->state.fr.settings.dce ? "enquiry" : "reply"); 654 return 1;
655 }
656
657 if (skb->data[4] != LMI_CALLREF) {
658 printk(KERN_INFO "%s: Invalid LMI Call reference (0x%02X)\n",
659 dev->name, skb->data[4]);
660 return 1;
661 }
662
663 if (skb->data[5] != (dce ? LMI_STATUS_ENQUIRY : LMI_STATUS)) {
664 printk(KERN_INFO "%s: Invalid LMI Message type (0x%02X)\n",
665 dev->name, skb->data[5]);
654 return 1; 666 return 1;
655 } 667 }
656 668
657 i = (hdlc->state.fr.settings.lmi == LMI_ANSI) ? 7 : 6; 669 if (lmi == LMI_ANSI) {
670 if (skb->data[6] != LMI_ANSI_LOCKSHIFT) {
671 printk(KERN_INFO "%s: Not ANSI locking shift in LMI"
672 " message (0x%02X)\n", dev->name, skb->data[6]);
673 return 1;
674 }
675 i = 7;
676 } else
677 i = 6;
658 678
659 if (skb->data[i] != 679 if (skb->data[i] != (lmi == LMI_CCITT ? LMI_CCITT_REPTYPE :
660 ((hdlc->state.fr.settings.lmi == LMI_CCITT) 680 LMI_ANSI_CISCO_REPTYPE)) {
661 ? LMI_CCITT_REPTYPE : LMI_REPTYPE)) { 681 printk(KERN_INFO "%s: Not an LMI Report type IE (0x%02X)\n",
662 printk(KERN_INFO "%s: Not a report type=%x\n",
663 dev->name, skb->data[i]); 682 dev->name, skb->data[i]);
664 return 1; 683 return 1;
665 } 684 }
666 i++;
667 685
668 i++; /* Skip length field */ 686 if (skb->data[++i] != LMI_REPT_LEN) {
687 printk(KERN_INFO "%s: Invalid LMI Report type IE length"
688 " (%u)\n", dev->name, skb->data[i]);
689 return 1;
690 }
669 691
670 reptype = skb->data[i++]; 692 reptype = skb->data[++i];
693 if (reptype != LMI_INTEGRITY && reptype != LMI_FULLREP) {
694 printk(KERN_INFO "%s: Unsupported LMI Report type (0x%02X)\n",
695 dev->name, reptype);
696 return 1;
697 }
671 698
672 if (skb->data[i]!= 699 if (skb->data[++i] != (lmi == LMI_CCITT ? LMI_CCITT_ALIVE :
673 ((hdlc->state.fr.settings.lmi == LMI_CCITT) 700 LMI_ANSI_CISCO_ALIVE)) {
674 ? LMI_CCITT_ALIVE : LMI_ALIVE)) { 701 printk(KERN_INFO "%s: Not an LMI Link integrity verification"
675 printk(KERN_INFO "%s: Unsupported status element=%x\n", 702 " IE (0x%02X)\n", dev->name, skb->data[i]);
676 dev->name, skb->data[i]);
677 return 1; 703 return 1;
678 } 704 }
679 i++;
680 705
681 i++; /* Skip length field */ 706 if (skb->data[++i] != LMI_INTEG_LEN) {
707 printk(KERN_INFO "%s: Invalid LMI Link integrity verification"
708 " IE length (%u)\n", dev->name, skb->data[i]);
709 return 1;
710 }
711 i++;
682 712
683 hdlc->state.fr.rxseq = skb->data[i++]; /* TX sequence from peer */ 713 hdlc->state.fr.rxseq = skb->data[i++]; /* TX sequence from peer */
684 rxseq = skb->data[i++]; /* Should confirm our sequence */ 714 rxseq = skb->data[i++]; /* Should confirm our sequence */
685 715
686 txseq = hdlc->state.fr.txseq; 716 txseq = hdlc->state.fr.txseq;
687 717
688 if (hdlc->state.fr.settings.dce) { 718 if (dce)
689 if (reptype != LMI_FULLREP && reptype != LMI_INTEGRITY) {
690 printk(KERN_INFO "%s: Unsupported report type=%x\n",
691 dev->name, reptype);
692 return 1;
693 }
694 hdlc->state.fr.last_poll = jiffies; 719 hdlc->state.fr.last_poll = jiffies;
695 }
696 720
697 error = 0; 721 error = 0;
698 if (!hdlc->state.fr.reliable) 722 if (!hdlc->state.fr.reliable)
@@ -703,7 +727,7 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
703 error = 1; 727 error = 1;
704 } 728 }
705 729
706 if (hdlc->state.fr.settings.dce) { 730 if (dce) {
707 if (hdlc->state.fr.fullrep_sent && !error) { 731 if (hdlc->state.fr.fullrep_sent && !error) {
708/* Stop sending full report - the last one has been confirmed by DTE */ 732/* Stop sending full report - the last one has been confirmed by DTE */
709 hdlc->state.fr.fullrep_sent = 0; 733 hdlc->state.fr.fullrep_sent = 0;
@@ -725,6 +749,7 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
725 hdlc->state.fr.dce_changed = 0; 749 hdlc->state.fr.dce_changed = 0;
726 } 750 }
727 751
752 hdlc->state.fr.request = 1; /* got request */
728 fr_lmi_send(dev, reptype == LMI_FULLREP ? 1 : 0); 753 fr_lmi_send(dev, reptype == LMI_FULLREP ? 1 : 0);
729 return 0; 754 return 0;
730 } 755 }
@@ -739,7 +764,6 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
739 if (reptype != LMI_FULLREP) 764 if (reptype != LMI_FULLREP)
740 return 0; 765 return 0;
741 766
742 stat_len = 3;
743 pvc = hdlc->state.fr.first_pvc; 767 pvc = hdlc->state.fr.first_pvc;
744 768
745 while (pvc) { 769 while (pvc) {
@@ -750,24 +774,35 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
750 no_ram = 0; 774 no_ram = 0;
751 while (skb->len >= i + 2 + stat_len) { 775 while (skb->len >= i + 2 + stat_len) {
752 u16 dlci; 776 u16 dlci;
777 u32 bw;
753 unsigned int active, new; 778 unsigned int active, new;
754 779
755 if (skb->data[i] != ((hdlc->state.fr.settings.lmi == LMI_CCITT) 780 if (skb->data[i] != (lmi == LMI_CCITT ? LMI_CCITT_PVCSTAT :
756 ? LMI_CCITT_PVCSTAT : LMI_PVCSTAT)) { 781 LMI_ANSI_CISCO_PVCSTAT)) {
757 printk(KERN_WARNING "%s: Invalid PVCSTAT ID: %x\n", 782 printk(KERN_INFO "%s: Not an LMI PVC status IE"
758 dev->name, skb->data[i]); 783 " (0x%02X)\n", dev->name, skb->data[i]);
759 return 1; 784 return 1;
760 } 785 }
761 i++;
762 786
763 if (skb->data[i] != stat_len) { 787 if (skb->data[++i] != stat_len) {
764 printk(KERN_WARNING "%s: Invalid PVCSTAT length: %x\n", 788 printk(KERN_INFO "%s: Invalid LMI PVC status IE length"
765 dev->name, skb->data[i]); 789 " (%u)\n", dev->name, skb->data[i]);
766 return 1; 790 return 1;
767 } 791 }
768 i++; 792 i++;
769 793
770 dlci = status_to_dlci(skb->data + i, &active, &new); 794 new = !! (skb->data[i + 2] & 0x08);
795 active = !! (skb->data[i + 2] & 0x02);
796 if (lmi == LMI_CISCO) {
797 dlci = (skb->data[i] << 8) | skb->data[i + 1];
798 bw = (skb->data[i + 3] << 16) |
799 (skb->data[i + 4] << 8) |
800 (skb->data[i + 5]);
801 } else {
802 dlci = ((skb->data[i] & 0x3F) << 4) |
803 ((skb->data[i + 1] & 0x78) >> 3);
804 bw = 0;
805 }
771 806
772 pvc = add_pvc(dev, dlci); 807 pvc = add_pvc(dev, dlci);
773 808
@@ -783,9 +818,11 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
783 pvc->state.deleted = 0; 818 pvc->state.deleted = 0;
784 if (active != pvc->state.active || 819 if (active != pvc->state.active ||
785 new != pvc->state.new || 820 new != pvc->state.new ||
821 bw != pvc->state.bandwidth ||
786 !pvc->state.exist) { 822 !pvc->state.exist) {
787 pvc->state.new = new; 823 pvc->state.new = new;
788 pvc->state.active = active; 824 pvc->state.active = active;
825 pvc->state.bandwidth = bw;
789 pvc_carrier(active, pvc); 826 pvc_carrier(active, pvc);
790 fr_log_dlci_active(pvc); 827 fr_log_dlci_active(pvc);
791 } 828 }
@@ -801,6 +838,7 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
801 pvc_carrier(0, pvc); 838 pvc_carrier(0, pvc);
802 pvc->state.active = pvc->state.new = 0; 839 pvc->state.active = pvc->state.new = 0;
803 pvc->state.exist = 0; 840 pvc->state.exist = 0;
841 pvc->state.bandwidth = 0;
804 fr_log_dlci_active(pvc); 842 fr_log_dlci_active(pvc);
805 } 843 }
806 pvc = pvc->next; 844 pvc = pvc->next;
@@ -829,22 +867,15 @@ static int fr_rx(struct sk_buff *skb)
829 867
830 dlci = q922_to_dlci(skb->data); 868 dlci = q922_to_dlci(skb->data);
831 869
832 if (dlci == LMI_DLCI) { 870 if ((dlci == LMI_CCITT_ANSI_DLCI &&
833 if (hdlc->state.fr.settings.lmi == LMI_NONE) 871 (hdlc->state.fr.settings.lmi == LMI_ANSI ||
834 goto rx_error; /* LMI packet with no LMI? */ 872 hdlc->state.fr.settings.lmi == LMI_CCITT)) ||
835 873 (dlci == LMI_CISCO_DLCI &&
836 if (data[3] == LMI_PROTO) { 874 hdlc->state.fr.settings.lmi == LMI_CISCO)) {
837 if (fr_lmi_recv(ndev, skb)) 875 if (fr_lmi_recv(ndev, skb))
838 goto rx_error; 876 goto rx_error;
839 else { 877 dev_kfree_skb_any(skb);
840 dev_kfree_skb_any(skb); 878 return NET_RX_SUCCESS;
841 return NET_RX_SUCCESS;
842 }
843 }
844
845 printk(KERN_INFO "%s: Received non-LMI frame with LMI DLCI\n",
846 ndev->name);
847 goto rx_error;
848 } 879 }
849 880
850 pvc = find_pvc(hdlc, dlci); 881 pvc = find_pvc(hdlc, dlci);
@@ -1170,7 +1201,8 @@ int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr)
1170 1201
1171 if ((new_settings.lmi != LMI_NONE && 1202 if ((new_settings.lmi != LMI_NONE &&
1172 new_settings.lmi != LMI_ANSI && 1203 new_settings.lmi != LMI_ANSI &&
1173 new_settings.lmi != LMI_CCITT) || 1204 new_settings.lmi != LMI_CCITT &&
1205 new_settings.lmi != LMI_CISCO) ||
1174 new_settings.t391 < 1 || 1206 new_settings.t391 < 1 ||
1175 new_settings.t392 < 2 || 1207 new_settings.t392 < 2 ||
1176 new_settings.n391 < 1 || 1208 new_settings.n391 < 1 ||