📄 lec.c
字号:
"ESI_FORWARD_DIRECT" }; if (status > ESI_FORWARD_DIRECT) status = 3; /* ESI_UNDEFINED */ return lec_arp_status_string[status];}static void lec_info(struct seq_file *seq, struct lec_arp_table *entry){ int i; for (i = 0; i < ETH_ALEN; i++) seq_printf(seq, "%2.2x", entry->mac_addr[i] & 0xff); seq_printf(seq, " "); for (i = 0; i < ATM_ESA_LEN; i++) seq_printf(seq, "%2.2x", entry->atm_addr[i] & 0xff); seq_printf(seq, " %s %4.4x", lec_arp_get_status_string(entry->status), entry->flags & 0xffff); if (entry->vcc) seq_printf(seq, "%3d %3d ", entry->vcc->vpi, entry->vcc->vci); else seq_printf(seq, " "); if (entry->recv_vcc) { seq_printf(seq, " %3d %3d", entry->recv_vcc->vpi, entry->recv_vcc->vci); } seq_putc(seq, '\n');}struct lec_state { unsigned long flags; struct lec_priv *locked; struct hlist_node *node; struct net_device *dev; int itf; int arp_table; int misc_table;};static void *lec_tbl_walk(struct lec_state *state, struct hlist_head *tbl, loff_t *l){ struct hlist_node *e = state->node; struct lec_arp_table *tmp; if (!e) e = tbl->first; if (e == (void *)1) { e = tbl->first; --*l; } hlist_for_each_entry_from(tmp, e, next) { if (--*l < 0) break; } state->node = e; return (*l < 0) ? state : NULL;}static void *lec_arp_walk(struct lec_state *state, loff_t *l, struct lec_priv *priv){ void *v = NULL; int p; for (p = state->arp_table; p < LEC_ARP_TABLE_SIZE; p++) { v = lec_tbl_walk(state, &priv->lec_arp_tables[p], l); if (v) break; } state->arp_table = p; return v;}static void *lec_misc_walk(struct lec_state *state, loff_t *l, struct lec_priv *priv){ struct hlist_head *lec_misc_tables[] = { &priv->lec_arp_empty_ones, &priv->lec_no_forward, &priv->mcast_fwds }; void *v = NULL; int q; for (q = state->misc_table; q < ARRAY_SIZE(lec_misc_tables); q++) { v = lec_tbl_walk(state, lec_misc_tables[q], l); if (v) break; } state->misc_table = q; return v;}static void *lec_priv_walk(struct lec_state *state, loff_t *l, struct lec_priv *priv){ if (!state->locked) { state->locked = priv; spin_lock_irqsave(&priv->lec_arp_lock, state->flags); } if (!lec_arp_walk(state, l, priv) && !lec_misc_walk(state, l, priv)) { spin_unlock_irqrestore(&priv->lec_arp_lock, state->flags); state->locked = NULL; /* Partial state reset for the next time we get called */ state->arp_table = state->misc_table = 0; } return state->locked;}static void *lec_itf_walk(struct lec_state *state, loff_t *l){ struct net_device *dev; void *v; dev = state->dev ? state->dev : dev_lec[state->itf]; v = (dev && dev->priv) ? lec_priv_walk(state, l, dev->priv) : NULL; if (!v && dev) { dev_put(dev); /* Partial state reset for the next time we get called */ dev = NULL; } state->dev = dev; return v;}static void *lec_get_idx(struct lec_state *state, loff_t l){ void *v = NULL; for (; state->itf < MAX_LEC_ITF; state->itf++) { v = lec_itf_walk(state, &l); if (v) break; } return v;}static void *lec_seq_start(struct seq_file *seq, loff_t *pos){ struct lec_state *state = seq->private; state->itf = 0; state->dev = NULL; state->locked = NULL; state->arp_table = 0; state->misc_table = 0; state->node = (void *)1; return *pos ? lec_get_idx(state, *pos) : (void *)1;}static void lec_seq_stop(struct seq_file *seq, void *v){ struct lec_state *state = seq->private; if (state->dev) { spin_unlock_irqrestore(&state->locked->lec_arp_lock, state->flags); dev_put(state->dev); }}static void *lec_seq_next(struct seq_file *seq, void *v, loff_t *pos){ struct lec_state *state = seq->private; v = lec_get_idx(state, 1); *pos += !!PTR_ERR(v); return v;}static int lec_seq_show(struct seq_file *seq, void *v){ static char lec_banner[] = "Itf MAC ATM destination" " Status Flags " "VPI/VCI Recv VPI/VCI\n"; if (v == (void *)1) seq_puts(seq, lec_banner); else { struct lec_state *state = seq->private; struct net_device *dev = state->dev; struct lec_arp_table *entry = hlist_entry(state->node, struct lec_arp_table, next); seq_printf(seq, "%s ", dev->name); lec_info(seq, entry); } return 0;}static const struct seq_operations lec_seq_ops = { .start = lec_seq_start, .next = lec_seq_next, .stop = lec_seq_stop, .show = lec_seq_show,};static int lec_seq_open(struct inode *inode, struct file *file){ struct lec_state *state; struct seq_file *seq; int rc = -EAGAIN; state = kmalloc(sizeof(*state), GFP_KERNEL); if (!state) { rc = -ENOMEM; goto out; } rc = seq_open(file, &lec_seq_ops); if (rc) goto out_kfree; seq = file->private_data; seq->private = state;out: return rc;out_kfree: kfree(state); goto out;}static int lec_seq_release(struct inode *inode, struct file *file){ return seq_release_private(inode, file);}static const struct file_operations lec_seq_fops = { .owner = THIS_MODULE, .open = lec_seq_open, .read = seq_read, .llseek = seq_lseek, .release = lec_seq_release,};#endifstatic int lane_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg){ struct atm_vcc *vcc = ATM_SD(sock); int err = 0; switch (cmd) { case ATMLEC_CTRL: case ATMLEC_MCAST: case ATMLEC_DATA: if (!capable(CAP_NET_ADMIN)) return -EPERM; break; default: return -ENOIOCTLCMD; } switch (cmd) { case ATMLEC_CTRL: err = lecd_attach(vcc, (int)arg); if (err >= 0) sock->state = SS_CONNECTED; break; case ATMLEC_MCAST: err = lec_mcast_attach(vcc, (int)arg); break; case ATMLEC_DATA: err = lec_vcc_attach(vcc, (void __user *)arg); break; } return err;}static struct atm_ioctl lane_ioctl_ops = { .owner = THIS_MODULE, .ioctl = lane_ioctl,};static int __init lane_module_init(void){#ifdef CONFIG_PROC_FS struct proc_dir_entry *p; p = create_proc_entry("lec", S_IRUGO, atm_proc_root); if (p) p->proc_fops = &lec_seq_fops;#endif register_atm_ioctl(&lane_ioctl_ops); printk("lec.c: " __DATE__ " " __TIME__ " initialized\n"); return 0;}static void __exit lane_module_cleanup(void){ int i; struct lec_priv *priv; remove_proc_entry("lec", atm_proc_root); deregister_atm_ioctl(&lane_ioctl_ops); for (i = 0; i < MAX_LEC_ITF; i++) { if (dev_lec[i] != NULL) { priv = (struct lec_priv *)dev_lec[i]->priv; unregister_netdev(dev_lec[i]); free_netdev(dev_lec[i]); dev_lec[i] = NULL; } } return;}module_init(lane_module_init);module_exit(lane_module_cleanup);/* * LANE2: 3.1.3, LE_RESOLVE.request * Non force allocates memory and fills in *tlvs, fills in *sizeoftlvs. * If sizeoftlvs == NULL the default TLVs associated with with this * lec will be used. * If dst_mac == NULL, targetless LE_ARP will be sent */static int lane2_resolve(struct net_device *dev, u8 *dst_mac, int force, u8 **tlvs, u32 *sizeoftlvs){ unsigned long flags; struct lec_priv *priv = (struct lec_priv *)dev->priv; struct lec_arp_table *table; struct sk_buff *skb; int retval; if (force == 0) { spin_lock_irqsave(&priv->lec_arp_lock, flags); table = lec_arp_find(priv, dst_mac); spin_unlock_irqrestore(&priv->lec_arp_lock, flags); if (table == NULL) return -1; *tlvs = kmemdup(table->tlvs, table->sizeoftlvs, GFP_ATOMIC); if (*tlvs == NULL) return -1; *sizeoftlvs = table->sizeoftlvs; return 0; } if (sizeoftlvs == NULL) retval = send_to_lecd(priv, l_arp_xmt, dst_mac, NULL, NULL); else { skb = alloc_skb(*sizeoftlvs, GFP_ATOMIC); if (skb == NULL) return -1; skb->len = *sizeoftlvs; skb_copy_to_linear_data(skb, *tlvs, *sizeoftlvs); retval = send_to_lecd(priv, l_arp_xmt, dst_mac, NULL, skb); } return retval;}/* * LANE2: 3.1.4, LE_ASSOCIATE.request * Associate the *tlvs with the *lan_dst address. * Will overwrite any previous association * Returns 1 for success, 0 for failure (out of memory) * */static int lane2_associate_req(struct net_device *dev, u8 *lan_dst, u8 *tlvs, u32 sizeoftlvs){ int retval; struct sk_buff *skb; struct lec_priv *priv = (struct lec_priv *)dev->priv; if (compare_ether_addr(lan_dst, dev->dev_addr)) return (0); /* not our mac address */ kfree(priv->tlvs); /* NULL if there was no previous association */ priv->tlvs = kmemdup(tlvs, sizeoftlvs, GFP_KERNEL); if (priv->tlvs == NULL) return (0); priv->sizeoftlvs = sizeoftlvs; skb = alloc_skb(sizeoftlvs, GFP_ATOMIC); if (skb == NULL) return 0; skb->len = sizeoftlvs; skb_copy_to_linear_data(skb, tlvs, sizeoftlvs); retval = send_to_lecd(priv, l_associate_req, NULL, NULL, skb); if (retval != 0) printk("lec.c: lane2_associate_req() failed\n"); /* * If the previous association has changed we must * somehow notify other LANE entities about the change */ return (1);}/* * LANE2: 3.1.5, LE_ASSOCIATE.indication * */static void lane2_associate_ind(struct net_device *dev, u8 *mac_addr, u8 *tlvs, u32 sizeoftlvs){#if 0 int i = 0;#endif struct lec_priv *priv = (struct lec_priv *)dev->priv;#if 0 /* * Why have the TLVs in LE_ARP entries * since we do not use them? When you * uncomment this code, make sure the * TLVs get freed when entry is killed */ struct lec_arp_table *entry = lec_arp_find(priv, mac_addr); if (entry == NULL) return; /* should not happen */ kfree(entry->tlvs); entry->tlvs = kmemdup(tlvs, sizeoftlvs, GFP_KERNEL); if (entry->tlvs == NULL) return; entry->sizeoftlvs = sizeoftlvs;#endif#if 0 printk("lec.c: lane2_associate_ind()\n"); printk("dump of tlvs, sizeoftlvs=%d\n", sizeoftlvs); while (i < sizeoftlvs) printk("%02x ", tlvs[i++]); printk("\n");#endif /* tell MPOA about the TLVs we saw */ if (priv->lane2_ops && priv->lane2_ops->associate_indicator) { priv->lane2_ops->associate_indicator(dev, mac_addr, tlvs, sizeoftlvs); } return;}/* * Here starts what used to lec_arpc.c * * lec_arpc.c was added here when making * lane client modular. October 1997 */#include <linux/types.h>#include <linux/timer.h>#include <asm/param.h>#include <asm/atomic.h>#include <linux/inetdevice.h>#include <net/route.h>#if 0#define pr_debug(format,args...)/*#define pr_debug printk*/#endif#define DEBUG_ARP_TABLE 0#define LEC_ARP_REFRESH_INTERVAL (3*HZ)static void lec_arp_check_expire(struct work_struct *work);static void lec_arp_expire_arp(unsigned long data);/* * Arp table funcs */#define HASH(ch) (ch & (LEC_ARP_TABLE_SIZE -1))/* * Initialization of arp-cache */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -