📄 lec.c
字号:
&ioc_data, vcc, vcc->push); vcc->proto_data = dev_lec[ioc_data.dev_num]; vcc->push = lec_push; return 0;}int lec_mcast_attach(struct atm_vcc *vcc, int arg){ if (arg <0 || arg >= MAX_LEC_ITF || !dev_lec[arg]) return -EINVAL; vcc->proto_data = dev_lec[arg]; return (lec_mcast_make((struct lec_priv*)dev_lec[arg]->priv, vcc));}/* Initialize device. */int lecd_attach(struct atm_vcc *vcc, int arg){ int i; struct lec_priv *priv; if (arg<0) i = 0; else i = arg;#ifdef CONFIG_TR if (arg >= MAX_LEC_ITF) return -EINVAL;#else /* Reserve the top NUM_TR_DEVS for TR */ if (arg >= (MAX_LEC_ITF-NUM_TR_DEVS)) return -EINVAL;#endif if (!dev_lec[i]) { int is_trdev, size; is_trdev = 0; if (i >= (MAX_LEC_ITF - NUM_TR_DEVS)) is_trdev = 1; size = sizeof(struct lec_priv);#ifdef CONFIG_TR if (is_trdev) dev_lec[i] = alloc_trdev(size); else#endif dev_lec[i] = alloc_etherdev(size); if (!dev_lec[i]) return -ENOMEM; snprintf(dev_lec[i]->name, IFNAMSIZ, "lec%d", i); if (register_netdev(dev_lec[i])) { free_netdev(dev_lec[i]); return -EINVAL; } priv = dev_lec[i]->priv; priv->is_trdev = is_trdev; lec_init(dev_lec[i]); } else { priv = dev_lec[i]->priv; if (priv->lecd) return -EADDRINUSE; } lec_arp_init(priv); priv->itfnum = i; /* LANE2 addition */ priv->lecd = vcc; vcc->dev = &lecatm_dev; vcc_insert_socket(vcc->sk); vcc->proto_data = dev_lec[i]; set_bit(ATM_VF_META,&vcc->flags); set_bit(ATM_VF_READY,&vcc->flags); /* Set default values to these variables */ priv->maximum_unknown_frame_count = 1; priv->max_unknown_frame_time = (1*HZ); priv->vcc_timeout_period = (1200*HZ); priv->max_retry_count = 1; priv->aging_time = (300*HZ); priv->forward_delay_time = (15*HZ); priv->topology_change = 0; priv->arp_response_time = (1*HZ); priv->flush_timeout = (4*HZ); priv->path_switching_delay = (6*HZ); if (dev_lec[i]->flags & IFF_UP) { netif_start_queue(dev_lec[i]); } __module_get(THIS_MODULE); return i;}#ifdef CONFIG_PROC_FSstatic char* lec_arp_get_status_string(unsigned char status){ static char *lec_arp_status_string[] = { "ESI_UNKNOWN ", "ESI_ARP_PENDING ", "ESI_VC_PENDING ", "<Undefined> ", "ESI_FLUSH_PENDING ", "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 lec_arp_table *entry; struct net_device *dev; int itf; int arp_table; int misc_table;};static void *lec_tbl_walk(struct lec_state *state, struct lec_arp_table *tbl, loff_t *l){ struct lec_arp_table *e = state->entry; if (!e) e = tbl; if (e == (void *)1) { e = tbl; --*l; } for (; e; e = e->next) { if (--*l < 0) break; } state->entry = 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 lec_arp_table *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->entry = (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; seq_printf(seq, "%s ", dev->name); lec_info(seq, state->entry); } return 0;}static 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 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -