📄 hdlc_fr.c
字号:
stats->tx_bytes += skb->len; stats->tx_packets++; if (pvc->state.fecn) /* TX Congestion counter */ stats->tx_compressed++; skb->dev = pvc->frad; dev_queue_xmit(skb); return 0; } } stats->tx_dropped++; dev_kfree_skb(skb); return 0;}static int pvc_change_mtu(struct net_device *dev, int new_mtu){ if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU)) return -EINVAL; dev->mtu = new_mtu; return 0;}static inline void fr_log_dlci_active(pvc_device *pvc){ printk(KERN_INFO "%s: DLCI %d [%s%s%s]%s %s\n", pvc->frad->name, pvc->dlci, pvc->main ? pvc->main->name : "", pvc->main && pvc->ether ? " " : "", pvc->ether ? pvc->ether->name : "", pvc->state.new ? " new" : "", !pvc->state.exist ? "deleted" : pvc->state.active ? "active" : "inactive");}static inline u8 fr_lmi_nextseq(u8 x){ x++; return x ? x : 1;}static void fr_lmi_send(struct net_device *dev, int fullrep){ hdlc_device *hdlc = dev_to_hdlc(dev); struct sk_buff *skb; pvc_device *pvc = state(hdlc)->first_pvc; int lmi = state(hdlc)->settings.lmi; int dce = state(hdlc)->settings.dce; int len = lmi == LMI_ANSI ? LMI_ANSI_LENGTH : LMI_CCITT_CISCO_LENGTH; int stat_len = (lmi == LMI_CISCO) ? 6 : 3; u8 *data; int i = 0; if (dce && fullrep) { len += state(hdlc)->dce_pvc_count * (2 + stat_len); if (len > HDLC_MAX_MRU) { printk(KERN_WARNING "%s: Too many PVCs while sending " "LMI full report\n", dev->name); return; } } skb = dev_alloc_skb(len); if (!skb) { printk(KERN_WARNING "%s: Memory squeeze on fr_lmi_send()\n", dev->name); return; } memset(skb->data, 0, len); skb_reserve(skb, 4); if (lmi == LMI_CISCO) { skb->protocol = __constant_htons(NLPID_CISCO_LMI); fr_hard_header(&skb, LMI_CISCO_DLCI); } else { skb->protocol = __constant_htons(NLPID_CCITT_ANSI_LMI); fr_hard_header(&skb, LMI_CCITT_ANSI_DLCI); } data = skb_tail_pointer(skb); data[i++] = LMI_CALLREF; data[i++] = dce ? LMI_STATUS : LMI_STATUS_ENQUIRY; if (lmi == LMI_ANSI) data[i++] = LMI_ANSI_LOCKSHIFT; data[i++] = lmi == LMI_CCITT ? LMI_CCITT_REPTYPE : LMI_ANSI_CISCO_REPTYPE; data[i++] = LMI_REPT_LEN; data[i++] = fullrep ? LMI_FULLREP : LMI_INTEGRITY; data[i++] = lmi == LMI_CCITT ? LMI_CCITT_ALIVE : LMI_ANSI_CISCO_ALIVE; data[i++] = LMI_INTEG_LEN; data[i++] = state(hdlc)->txseq = fr_lmi_nextseq(state(hdlc)->txseq); data[i++] = state(hdlc)->rxseq; if (dce && fullrep) { while (pvc) { data[i++] = lmi == LMI_CCITT ? LMI_CCITT_PVCSTAT : LMI_ANSI_CISCO_PVCSTAT; data[i++] = stat_len; /* LMI start/restart */ if (state(hdlc)->reliable && !pvc->state.exist) { pvc->state.exist = pvc->state.new = 1; fr_log_dlci_active(pvc); } /* ifconfig PVC up */ if (pvc->open_count && !pvc->state.active && pvc->state.exist && !pvc->state.new) { pvc_carrier(1, pvc); pvc->state.active = 1; fr_log_dlci_active(pvc); } if (lmi == LMI_CISCO) { data[i] = pvc->dlci >> 8; data[i + 1] = pvc->dlci & 0xFF; } else { data[i] = (pvc->dlci >> 4) & 0x3F; data[i + 1] = ((pvc->dlci << 3) & 0x78) | 0x80; data[i + 2] = 0x80; } if (pvc->state.new) data[i + 2] |= 0x08; else if (pvc->state.active) data[i + 2] |= 0x02; i += stat_len; pvc = pvc->next; } } skb_put(skb, i); skb->priority = TC_PRIO_CONTROL; skb->dev = dev; skb_reset_network_header(skb); dev_queue_xmit(skb);}static void fr_set_link_state(int reliable, struct net_device *dev){ hdlc_device *hdlc = dev_to_hdlc(dev); pvc_device *pvc = state(hdlc)->first_pvc; state(hdlc)->reliable = reliable; if (reliable) { netif_dormant_off(dev); state(hdlc)->n391cnt = 0; /* Request full status */ state(hdlc)->dce_changed = 1; if (state(hdlc)->settings.lmi == LMI_NONE) { while (pvc) { /* Activate all PVCs */ pvc_carrier(1, pvc); pvc->state.exist = pvc->state.active = 1; pvc->state.new = 0; pvc = pvc->next; } } } else { netif_dormant_on(dev); while (pvc) { /* Deactivate all PVCs */ pvc_carrier(0, pvc); pvc->state.exist = pvc->state.active = 0; pvc->state.new = 0; if (!state(hdlc)->settings.dce) pvc->state.bandwidth = 0; pvc = pvc->next; } }}static void fr_timer(unsigned long arg){ struct net_device *dev = (struct net_device *)arg; hdlc_device *hdlc = dev_to_hdlc(dev); int i, cnt = 0, reliable; u32 list; if (state(hdlc)->settings.dce) { reliable = state(hdlc)->request && time_before(jiffies, state(hdlc)->last_poll + state(hdlc)->settings.t392 * HZ); state(hdlc)->request = 0; } else { state(hdlc)->last_errors <<= 1; /* Shift the list */ if (state(hdlc)->request) { if (state(hdlc)->reliable) printk(KERN_INFO "%s: No LMI status reply " "received\n", dev->name); state(hdlc)->last_errors |= 1; } list = state(hdlc)->last_errors; for (i = 0; i < state(hdlc)->settings.n393; i++, list >>= 1) cnt += (list & 1); /* errors count */ reliable = (cnt < state(hdlc)->settings.n392); } if (state(hdlc)->reliable != reliable) { printk(KERN_INFO "%s: Link %sreliable\n", dev->name, reliable ? "" : "un"); fr_set_link_state(reliable, dev); } if (state(hdlc)->settings.dce) state(hdlc)->timer.expires = jiffies + state(hdlc)->settings.t392 * HZ; else { if (state(hdlc)->n391cnt) state(hdlc)->n391cnt--; fr_lmi_send(dev, state(hdlc)->n391cnt == 0); state(hdlc)->last_poll = jiffies; state(hdlc)->request = 1; state(hdlc)->timer.expires = jiffies + state(hdlc)->settings.t391 * HZ; } state(hdlc)->timer.function = fr_timer; state(hdlc)->timer.data = arg; add_timer(&state(hdlc)->timer);}static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb){ hdlc_device *hdlc = dev_to_hdlc(dev); pvc_device *pvc; u8 rxseq, txseq; int lmi = state(hdlc)->settings.lmi; int dce = state(hdlc)->settings.dce; int stat_len = (lmi == LMI_CISCO) ? 6 : 3, reptype, error, no_ram, i; if (skb->len < (lmi == LMI_ANSI ? LMI_ANSI_LENGTH : LMI_CCITT_CISCO_LENGTH)) { printk(KERN_INFO "%s: Short LMI frame\n", dev->name); return 1; } if (skb->data[3] != (lmi == LMI_CISCO ? NLPID_CISCO_LMI : NLPID_CCITT_ANSI_LMI)) { printk(KERN_INFO "%s: Received non-LMI frame with LMI DLCI\n", dev->name); return 1; } if (skb->data[4] != LMI_CALLREF) { printk(KERN_INFO "%s: Invalid LMI Call reference (0x%02X)\n", dev->name, skb->data[4]); return 1; } if (skb->data[5] != (dce ? LMI_STATUS_ENQUIRY : LMI_STATUS)) { printk(KERN_INFO "%s: Invalid LMI Message type (0x%02X)\n", dev->name, skb->data[5]); return 1; } if (lmi == LMI_ANSI) { if (skb->data[6] != LMI_ANSI_LOCKSHIFT) { printk(KERN_INFO "%s: Not ANSI locking shift in LMI" " message (0x%02X)\n", dev->name, skb->data[6]); return 1; } i = 7; } else i = 6; if (skb->data[i] != (lmi == LMI_CCITT ? LMI_CCITT_REPTYPE : LMI_ANSI_CISCO_REPTYPE)) { printk(KERN_INFO "%s: Not an LMI Report type IE (0x%02X)\n", dev->name, skb->data[i]); return 1; } if (skb->data[++i] != LMI_REPT_LEN) { printk(KERN_INFO "%s: Invalid LMI Report type IE length" " (%u)\n", dev->name, skb->data[i]); return 1; } reptype = skb->data[++i]; if (reptype != LMI_INTEGRITY && reptype != LMI_FULLREP) { printk(KERN_INFO "%s: Unsupported LMI Report type (0x%02X)\n", dev->name, reptype); return 1; } if (skb->data[++i] != (lmi == LMI_CCITT ? LMI_CCITT_ALIVE : LMI_ANSI_CISCO_ALIVE)) { printk(KERN_INFO "%s: Not an LMI Link integrity verification" " IE (0x%02X)\n", dev->name, skb->data[i]); return 1; } if (skb->data[++i] != LMI_INTEG_LEN) { printk(KERN_INFO "%s: Invalid LMI Link integrity verification" " IE length (%u)\n", dev->name, skb->data[i]); return 1; } i++; state(hdlc)->rxseq = skb->data[i++]; /* TX sequence from peer */ rxseq = skb->data[i++]; /* Should confirm our sequence */ txseq = state(hdlc)->txseq; if (dce) state(hdlc)->last_poll = jiffies; error = 0; if (!state(hdlc)->reliable) error = 1; if (rxseq == 0 || rxseq != txseq) { /* Ask for full report next time */ state(hdlc)->n391cnt = 0; error = 1; } if (dce) { if (state(hdlc)->fullrep_sent && !error) {/* Stop sending full report - the last one has been confirmed by DTE */ state(hdlc)->fullrep_sent = 0; pvc = state(hdlc)->first_pvc; while (pvc) { if (pvc->state.new) { pvc->state.new = 0;/* Tell DTE that new PVC is now active */ state(hdlc)->dce_changed = 1; } pvc = pvc->next; } } if (state(hdlc)->dce_changed) { reptype = LMI_FULLREP; state(hdlc)->fullrep_sent = 1; state(hdlc)->dce_changed = 0; } state(hdlc)->request = 1; /* got request */ fr_lmi_send(dev, reptype == LMI_FULLREP ? 1 : 0); return 0; } /* DTE */ state(hdlc)->request = 0; /* got response, no request pending */ if (error) return 0; if (reptype != LMI_FULLREP) return 0; pvc = state(hdlc)->first_pvc; while (pvc) { pvc->state.deleted = 1; pvc = pvc->next; } no_ram = 0; while (skb->len >= i + 2 + stat_len) { u16 dlci; u32 bw; unsigned int active, new; if (skb->data[i] != (lmi == LMI_CCITT ? LMI_CCITT_PVCSTAT : LMI_ANSI_CISCO_PVCSTAT)) { printk(KERN_INFO "%s: Not an LMI PVC status IE" " (0x%02X)\n", dev->name, skb->data[i]); return 1; } if (skb->data[++i] != stat_len) { printk(KERN_INFO "%s: Invalid LMI PVC status IE length" " (%u)\n", dev->name, skb->data[i]); return 1; } i++; new = !! (skb->data[i + 2] & 0x08); active = !! (skb->data[i + 2] & 0x02); if (lmi == LMI_CISCO) { dlci = (skb->data[i] << 8) | skb->data[i + 1]; bw = (skb->data[i + 3] << 16) | (skb->data[i + 4] << 8) | (skb->data[i + 5]); } else { dlci = ((skb->data[i] & 0x3F) << 4) | ((skb->data[i + 1] & 0x78) >> 3); bw = 0; } pvc = add_pvc(dev, dlci); if (!pvc && !no_ram) { printk(KERN_WARNING "%s: Memory squeeze on fr_lmi_recv()\n", dev->name); no_ram = 1; } if (pvc) { pvc->state.exist = 1; pvc->state.deleted = 0; if (active != pvc->state.active || new != pvc->state.new || bw != pvc->state.bandwidth || !pvc->state.exist) { pvc->state.new = new; pvc->state.active = active; pvc->state.bandwidth = bw; pvc_carrier(active, pvc); fr_log_dlci_active(pvc); } } i += stat_len; } pvc = state(hdlc)->first_pvc; while (pvc) { if (pvc->state.deleted && pvc->state.exist) { pvc_carrier(0, pvc); pvc->state.active = pvc->state.new = 0; pvc->state.exist = 0; pvc->state.bandwidth = 0; fr_log_dlci_active(pvc); } pvc = pvc->next; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -