diff options
| -rw-r--r-- | Documentation/networking/generic-hdlc.txt | 51 | ||||
| -rw-r--r-- | drivers/net/wan/hdlc_fr.c | 320 | ||||
| -rw-r--r-- | drivers/net/wan/hdlc_generic.c | 16 | ||||
| -rw-r--r-- | include/linux/hdlc.h | 4 |
4 files changed, 216 insertions, 175 deletions
diff --git a/Documentation/networking/generic-hdlc.txt b/Documentation/networking/generic-hdlc.txt index 7d1dc6b884f3..31bc8b759b75 100644 --- a/Documentation/networking/generic-hdlc.txt +++ b/Documentation/networking/generic-hdlc.txt | |||
| @@ -1,21 +1,21 @@ | |||
| 1 | Generic HDLC layer | 1 | Generic HDLC layer |
| 2 | Krzysztof Halasa <khc@pm.waw.pl> | 2 | Krzysztof Halasa <khc@pm.waw.pl> |
| 3 | January, 2003 | ||
| 4 | 3 | ||
| 5 | 4 | ||
| 6 | Generic HDLC layer currently supports: | 5 | Generic HDLC layer currently supports: |
| 7 | - Frame Relay (ANSI, CCITT and no LMI), with ARP support (no InARP). | 6 | 1. Frame Relay (ANSI, CCITT, Cisco and no LMI). |
| 8 | Normal (routed) and Ethernet-bridged (Ethernet device emulation) | 7 | - Normal (routed) and Ethernet-bridged (Ethernet device emulation) |
| 9 | interfaces can share a single PVC. | 8 | interfaces can share a single PVC. |
| 10 | - raw HDLC - either IP (IPv4) interface or Ethernet device emulation. | 9 | - ARP support (no InARP support in the kernel - there is an |
| 11 | - Cisco HDLC, | 10 | experimental InARP user-space daemon available on: |
| 12 | - PPP (uses syncppp.c), | 11 | http://www.kernel.org/pub/linux/utils/net/hdlc/). |
| 13 | - X.25 (uses X.25 routines). | 12 | 2. raw HDLC - either IP (IPv4) interface or Ethernet device emulation. |
| 14 | 13 | 3. Cisco HDLC. | |
| 15 | There are hardware drivers for the following cards: | 14 | 4. PPP (uses syncppp.c). |
| 16 | - C101 by Moxa Technologies Co., Ltd. | 15 | 5. X.25 (uses X.25 routines). |
| 17 | - RISCom/N2 by SDL Communications Inc. | 16 | |
| 18 | - and others, some not in the official kernel. | 17 | Generic HDLC is a protocol driver only - it needs a low-level driver |
| 18 | for your particular hardware. | ||
| 19 | 19 | ||
| 20 | Ethernet device emulation (using HDLC or Frame-Relay PVC) is compatible | 20 | Ethernet device emulation (using HDLC or Frame-Relay PVC) is compatible |
| 21 | with IEEE 802.1Q (VLANs) and 802.1D (Ethernet bridging). | 21 | with IEEE 802.1Q (VLANs) and 802.1D (Ethernet bridging). |
| @@ -24,7 +24,7 @@ with IEEE 802.1Q (VLANs) and 802.1D (Ethernet bridging). | |||
| 24 | Make sure the hdlc.o and the hardware driver are loaded. It should | 24 | Make sure the hdlc.o and the hardware driver are loaded. It should |
| 25 | create a number of "hdlc" (hdlc0 etc) network devices, one for each | 25 | create a number of "hdlc" (hdlc0 etc) network devices, one for each |
| 26 | WAN port. You'll need the "sethdlc" utility, get it from: | 26 | WAN port. You'll need the "sethdlc" utility, get it from: |
| 27 | http://hq.pm.waw.pl/hdlc/ | 27 | http://www.kernel.org/pub/linux/utils/net/hdlc/ |
| 28 | 28 | ||
| 29 | Compile sethdlc.c utility: | 29 | Compile sethdlc.c utility: |
| 30 | gcc -O2 -Wall -o sethdlc sethdlc.c | 30 | gcc -O2 -Wall -o sethdlc sethdlc.c |
| @@ -52,12 +52,12 @@ Setting interface: | |||
| 52 | * v35 | rs232 | x21 | t1 | e1 - sets physical interface for a given port | 52 | * v35 | rs232 | x21 | t1 | e1 - sets physical interface for a given port |
| 53 | if the card has software-selectable interfaces | 53 | if the card has software-selectable interfaces |
| 54 | loopback - activate hardware loopback (for testing only) | 54 | loopback - activate hardware loopback (for testing only) |
| 55 | * clock ext - external clock (uses DTE RX and TX clock) | 55 | * clock ext - both RX clock and TX clock external |
| 56 | * clock int - internal clock (provides clock signal on DCE clock output) | 56 | * clock int - both RX clock and TX clock internal |
| 57 | * clock txint - TX internal, RX external (provides TX clock on DCE output) | 57 | * clock txint - RX clock external, TX clock internal |
| 58 | * clock txfromrx - TX clock derived from RX clock (TX clock on DCE output) | 58 | * clock txfromrx - RX clock external, TX clock derived from RX clock |
| 59 | * rate - sets clock rate in bps (not required for external clock or | 59 | * rate - sets clock rate in bps (for "int" or "txint" clock only) |
| 60 | for txfromrx) | 60 | |
| 61 | 61 | ||
| 62 | Setting protocol: | 62 | Setting protocol: |
| 63 | 63 | ||
| @@ -79,7 +79,7 @@ Setting protocol: | |||
| 79 | * x25 - sets X.25 mode | 79 | * x25 - sets X.25 mode |
| 80 | 80 | ||
| 81 | * fr - Frame Relay mode | 81 | * fr - Frame Relay mode |
| 82 | lmi ansi / ccitt / none - LMI (link management) type | 82 | lmi ansi / ccitt / cisco / none - LMI (link management) type |
| 83 | dce - Frame Relay DCE (network) side LMI instead of default DTE (user). | 83 | dce - Frame Relay DCE (network) side LMI instead of default DTE (user). |
| 84 | It has nothing to do with clocks! | 84 | It has nothing to do with clocks! |
| 85 | t391 - link integrity verification polling timer (in seconds) - user | 85 | t391 - link integrity verification polling timer (in seconds) - user |
| @@ -119,13 +119,14 @@ or | |||
| 119 | 119 | ||
| 120 | 120 | ||
| 121 | 121 | ||
| 122 | If you have a problem with N2 or C101 card, you can issue the "private" | 122 | If you have a problem with N2, C101 or PLX200SYN card, you can issue the |
| 123 | command to see port's packet descriptor rings (in kernel logs): | 123 | "private" command to see port's packet descriptor rings (in kernel logs): |
| 124 | 124 | ||
| 125 | sethdlc hdlc0 private | 125 | sethdlc hdlc0 private |
| 126 | 126 | ||
| 127 | The hardware driver has to be build with CONFIG_HDLC_DEBUG_RINGS. | 127 | The hardware driver has to be build with #define DEBUG_RINGS. |
| 128 | Attaching this info to bug reports would be helpful. Anyway, let me know | 128 | Attaching this info to bug reports would be helpful. Anyway, let me know |
| 129 | if you have problems using this. | 129 | if you have problems using this. |
| 130 | 130 | ||
| 131 | For patches and other info look at http://hq.pm.waw.pl/hdlc/ | 131 | For patches and other info look at: |
| 132 | <http://www.kernel.org/pub/linux/utils/net/hdlc/>. | ||
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 | ||
| 93 | typedef struct { | 93 | typedef struct { |
| @@ -223,51 +223,34 @@ static inline struct net_device** get_dev_p(pvc_device *pvc, int type) | |||
| 223 | } | 223 | } |
| 224 | 224 | ||
| 225 | 225 | ||
| 226 | static 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 | |||
| 235 | static 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 | |||
| 249 | static int fr_hard_header(struct sk_buff **skb_p, u16 dlci) | 226 | static 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) | |||
| 634 | static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb) | 635 | static 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 || |
diff --git a/drivers/net/wan/hdlc_generic.c b/drivers/net/wan/hdlc_generic.c index 6ed064cb4469..a63f6a2cc4f7 100644 --- a/drivers/net/wan/hdlc_generic.c +++ b/drivers/net/wan/hdlc_generic.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Generic HDLC support routines for Linux | 2 | * Generic HDLC support routines for Linux |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 1999 - 2003 Krzysztof Halasa <khc@pm.waw.pl> | 4 | * Copyright (C) 1999 - 2005 Krzysztof Halasa <khc@pm.waw.pl> |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
| 7 | * under the terms of version 2 of the GNU General Public License | 7 | * under the terms of version 2 of the GNU General Public License |
| @@ -38,7 +38,7 @@ | |||
| 38 | #include <linux/hdlc.h> | 38 | #include <linux/hdlc.h> |
| 39 | 39 | ||
| 40 | 40 | ||
| 41 | static const char* version = "HDLC support module revision 1.17"; | 41 | static const char* version = "HDLC support module revision 1.18"; |
| 42 | 42 | ||
| 43 | #undef DEBUG_LINK | 43 | #undef DEBUG_LINK |
| 44 | 44 | ||
| @@ -126,10 +126,13 @@ void hdlc_set_carrier(int on, struct net_device *dev) | |||
| 126 | if (!hdlc->open) | 126 | if (!hdlc->open) |
| 127 | goto carrier_exit; | 127 | goto carrier_exit; |
| 128 | 128 | ||
| 129 | if (hdlc->carrier) | 129 | if (hdlc->carrier) { |
| 130 | printk(KERN_INFO "%s: Carrier detected\n", dev->name); | ||
| 130 | __hdlc_set_carrier_on(dev); | 131 | __hdlc_set_carrier_on(dev); |
| 131 | else | 132 | } else { |
| 133 | printk(KERN_INFO "%s: Carrier lost\n", dev->name); | ||
| 132 | __hdlc_set_carrier_off(dev); | 134 | __hdlc_set_carrier_off(dev); |
| 135 | } | ||
| 133 | 136 | ||
| 134 | carrier_exit: | 137 | carrier_exit: |
| 135 | spin_unlock_irqrestore(&hdlc->state_lock, flags); | 138 | spin_unlock_irqrestore(&hdlc->state_lock, flags); |
| @@ -157,8 +160,11 @@ int hdlc_open(struct net_device *dev) | |||
| 157 | 160 | ||
| 158 | spin_lock_irq(&hdlc->state_lock); | 161 | spin_lock_irq(&hdlc->state_lock); |
| 159 | 162 | ||
| 160 | if (hdlc->carrier) | 163 | if (hdlc->carrier) { |
| 164 | printk(KERN_INFO "%s: Carrier detected\n", dev->name); | ||
| 161 | __hdlc_set_carrier_on(dev); | 165 | __hdlc_set_carrier_on(dev); |
| 166 | } else | ||
| 167 | printk(KERN_INFO "%s: No carrier\n", dev->name); | ||
| 162 | 168 | ||
| 163 | hdlc->open = 1; | 169 | hdlc->open = 1; |
| 164 | 170 | ||
diff --git a/include/linux/hdlc.h b/include/linux/hdlc.h index 503194e62fe1..ed2927ef1ff7 100644 --- a/include/linux/hdlc.h +++ b/include/linux/hdlc.h | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Generic HDLC support routines for Linux | 2 | * Generic HDLC support routines for Linux |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 1999-2003 Krzysztof Halasa <khc@pm.waw.pl> | 4 | * Copyright (C) 1999-2005 Krzysztof Halasa <khc@pm.waw.pl> |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
| 7 | * under the terms of version 2 of the GNU General Public License | 7 | * under the terms of version 2 of the GNU General Public License |
| @@ -41,6 +41,7 @@ | |||
| 41 | #define LMI_NONE 1 /* No LMI, all PVCs are static */ | 41 | #define LMI_NONE 1 /* No LMI, all PVCs are static */ |
| 42 | #define LMI_ANSI 2 /* ANSI Annex D */ | 42 | #define LMI_ANSI 2 /* ANSI Annex D */ |
| 43 | #define LMI_CCITT 3 /* ITU-T Annex A */ | 43 | #define LMI_CCITT 3 /* ITU-T Annex A */ |
| 44 | #define LMI_CISCO 4 /* The "original" LMI, aka Gang of Four */ | ||
| 44 | 45 | ||
| 45 | #define HDLC_MAX_MTU 1500 /* Ethernet 1500 bytes */ | 46 | #define HDLC_MAX_MTU 1500 /* Ethernet 1500 bytes */ |
| 46 | #define HDLC_MAX_MRU (HDLC_MAX_MTU + 10 + 14 + 4) /* for ETH+VLAN over FR */ | 47 | #define HDLC_MAX_MRU (HDLC_MAX_MTU + 10 + 14 + 4) /* for ETH+VLAN over FR */ |
| @@ -89,6 +90,7 @@ typedef struct pvc_device_struct { | |||
| 89 | unsigned int deleted: 1; | 90 | unsigned int deleted: 1; |
| 90 | unsigned int fecn: 1; | 91 | unsigned int fecn: 1; |
| 91 | unsigned int becn: 1; | 92 | unsigned int becn: 1; |
| 93 | unsigned int bandwidth; /* Cisco LMI reporting only */ | ||
| 92 | }state; | 94 | }state; |
| 93 | }pvc_device; | 95 | }pvc_device; |
| 94 | 96 | ||
