📄 dn_dev.c
字号:
if (dn_db->parms.forwarding == 0) dev_mc_add(dev, dn_rt_all_end_mcast, ETH_ALEN, 0); else dev_mc_add(dev, dn_rt_all_rt_mcast, ETH_ALEN, 0); dev_mc_upload(dev); dn_db->use_long = 1; return 0;}static void dn_eth_down(struct net_device *dev){ struct dn_dev *dn_db = dev->dn_ptr; if (dn_db->parms.forwarding == 0) dev_mc_delete(dev, dn_rt_all_end_mcast, ETH_ALEN, 0); else dev_mc_delete(dev, dn_rt_all_rt_mcast, ETH_ALEN, 0);}static void dn_dev_set_timer(struct net_device *dev);static void dn_dev_timer_func(unsigned long arg){ struct net_device *dev = (struct net_device *)arg; struct dn_dev *dn_db = dev->dn_ptr; struct dn_ifaddr *ifa; if (dn_db->t3 <= dn_db->parms.t2) { if (dn_db->parms.timer3) { for(ifa = dn_db->ifa_list; ifa; ifa = ifa->ifa_next) { if (!(ifa->ifa_flags & IFA_F_SECONDARY)) dn_db->parms.timer3(dev, ifa); } } dn_db->t3 = dn_db->parms.t3; } else { dn_db->t3 -= dn_db->parms.t2; } dn_dev_set_timer(dev);}static void dn_dev_set_timer(struct net_device *dev){ struct dn_dev *dn_db = dev->dn_ptr; if (dn_db->parms.t2 > dn_db->parms.t3) dn_db->parms.t2 = dn_db->parms.t3; dn_db->timer.data = (unsigned long)dev; dn_db->timer.function = dn_dev_timer_func; dn_db->timer.expires = jiffies + (dn_db->parms.t2 * HZ); add_timer(&dn_db->timer);}struct dn_dev *dn_dev_create(struct net_device *dev, int *err){ int i; struct dn_dev_parms *p = dn_dev_list; struct dn_dev *dn_db; for(i = 0; i < DN_DEV_LIST_SIZE; i++, p++) { if (p->type == dev->type) break; } *err = -ENODEV; if (i == DN_DEV_LIST_SIZE) return NULL; *err = -ENOBUFS; if ((dn_db = kmalloc(sizeof(struct dn_dev), GFP_ATOMIC)) == NULL) return NULL; memset(dn_db, 0, sizeof(struct dn_dev)); memcpy(&dn_db->parms, p, sizeof(struct dn_dev_parms)); smp_wmb(); dev->dn_ptr = dn_db; dn_db->dev = dev; init_timer(&dn_db->timer); dn_db->uptime = jiffies; if (dn_db->parms.up) { if (dn_db->parms.up(dev) < 0) { dev->dn_ptr = NULL; kfree(dn_db); return NULL; } } dn_db->neigh_parms = neigh_parms_alloc(dev, &dn_neigh_table); dn_dev_sysctl_register(dev, &dn_db->parms); dn_dev_set_timer(dev); *err = 0; return dn_db;}/* * This processes a device up event. We only start up * the loopback device & ethernet devices with correct * MAC addreses automatically. Others must be started * specifically. * * FIXME: How should we configure the loopback address ? If we could dispense * with using decnet_address here and for autobind, it will be one less thing * for users to worry about setting up. */void dn_dev_up(struct net_device *dev){ struct dn_ifaddr *ifa; dn_address addr = decnet_address; int maybe_default = 0; struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr; if ((dev->type != ARPHRD_ETHER) && (dev->type != ARPHRD_LOOPBACK)) return; /* * Need to ensure that loopback device has a dn_db attached to it * to allow creation of neighbours against it, even though it might * not have a local address of its own. Might as well do the same for * all autoconfigured interfaces. */ if (dn_db == NULL) { int err; dn_db = dn_dev_create(dev, &err); if (dn_db == NULL) return; } if (dev->type == ARPHRD_ETHER) { if (memcmp(dev->dev_addr, dn_hiord, 4) != 0) return; addr = dn_htons(dn_eth2dn(dev->dev_addr)); maybe_default = 1; } if (addr == 0) return; if ((ifa = dn_dev_alloc_ifa()) == NULL) return; ifa->ifa_local = ifa->ifa_address = addr; ifa->ifa_flags = 0; ifa->ifa_scope = RT_SCOPE_UNIVERSE; strcpy(ifa->ifa_label, dev->name); dn_dev_set_ifa(dev, ifa); /* * Automagically set the default device to the first automatically * configured ethernet card in the system. */ if (maybe_default) { dev_hold(dev); if (dn_dev_set_default(dev, 0)) dev_put(dev); }}static void dn_dev_delete(struct net_device *dev){ struct dn_dev *dn_db = dev->dn_ptr; if (dn_db == NULL) return; del_timer_sync(&dn_db->timer); dn_dev_sysctl_unregister(&dn_db->parms); dn_dev_check_default(dev); neigh_ifdown(&dn_neigh_table, dev); if (dn_db->parms.down) dn_db->parms.down(dev); dev->dn_ptr = NULL; neigh_parms_release(&dn_neigh_table, dn_db->neigh_parms); neigh_ifdown(&dn_neigh_table, dev); if (dn_db->router) neigh_release(dn_db->router); if (dn_db->peer) neigh_release(dn_db->peer); kfree(dn_db);}void dn_dev_down(struct net_device *dev){ struct dn_dev *dn_db = dev->dn_ptr; struct dn_ifaddr *ifa; if (dn_db == NULL) return; while((ifa = dn_db->ifa_list) != NULL) { dn_dev_del_ifa(dn_db, &dn_db->ifa_list, 0); dn_dev_free_ifa(ifa); } dn_dev_delete(dev);}void dn_dev_init_pkt(struct sk_buff *skb){ return;}void dn_dev_veri_pkt(struct sk_buff *skb){ return;}void dn_dev_hello(struct sk_buff *skb){ return;}void dn_dev_devices_off(void){ struct net_device *dev; rtnl_lock(); for(dev = dev_base; dev; dev = dev->next) dn_dev_down(dev); rtnl_unlock();}void dn_dev_devices_on(void){ struct net_device *dev; rtnl_lock(); for(dev = dev_base; dev; dev = dev->next) { if (dev->flags & IFF_UP) dn_dev_up(dev); } rtnl_unlock();}int register_dnaddr_notifier(struct notifier_block *nb){ return notifier_chain_register(&dnaddr_chain, nb);}int unregister_dnaddr_notifier(struct notifier_block *nb){ return notifier_chain_unregister(&dnaddr_chain, nb);}#ifdef CONFIG_DECNET_SIOCGIFCONF/* * Now we support multiple addresses per interface. * Since we don't want to break existing code, you have to enable * it as a compile time option. Probably you should use the * rtnetlink interface instead. */int dnet_gifconf(struct net_device *dev, char __user *buf, int len){ struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr; struct dn_ifaddr *ifa; char buffer[DN_IFREQ_SIZE]; struct ifreq *ifr = (struct ifreq *)buffer; struct sockaddr_dn *addr = (struct sockaddr_dn *)&ifr->ifr_addr; int done = 0; if ((dn_db == NULL) || ((ifa = dn_db->ifa_list) == NULL)) return 0; for(; ifa; ifa = ifa->ifa_next) { if (!buf) { done += sizeof(DN_IFREQ_SIZE); continue; } if (len < DN_IFREQ_SIZE) return done; memset(buffer, 0, DN_IFREQ_SIZE); if (ifa->ifa_label) strcpy(ifr->ifr_name, ifa->ifa_label); else strcpy(ifr->ifr_name, dev->name); addr->sdn_family = AF_DECnet; addr->sdn_add.a_len = 2; memcpy(addr->sdn_add.a_addr, &ifa->ifa_local, sizeof(dn_address)); if (copy_to_user(buf, buffer, DN_IFREQ_SIZE)) { done = -EFAULT; break; } buf += DN_IFREQ_SIZE; len -= DN_IFREQ_SIZE; done += DN_IFREQ_SIZE; } return done;}#endif /* CONFIG_DECNET_SIOCGIFCONF */#ifdef CONFIG_PROC_FSstatic inline struct net_device *dn_dev_get_next(struct seq_file *seq, struct net_device *dev){ do { dev = dev->next; } while(dev && !dev->dn_ptr); return dev;}static struct net_device *dn_dev_get_idx(struct seq_file *seq, loff_t pos){ struct net_device *dev; dev = dev_base; if (dev && !dev->dn_ptr) dev = dn_dev_get_next(seq, dev); if (pos) { while(dev && (dev = dn_dev_get_next(seq, dev))) --pos; } return dev;}static void *dn_dev_seq_start(struct seq_file *seq, loff_t *pos){ if (*pos) { struct net_device *dev; read_lock(&dev_base_lock); dev = dn_dev_get_idx(seq, *pos - 1); if (dev == NULL) read_unlock(&dev_base_lock); return dev; } return SEQ_START_TOKEN;}static void *dn_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos){ struct net_device *dev = v; loff_t one = 1; if (v == SEQ_START_TOKEN) { dev = dn_dev_seq_start(seq, &one); } else { dev = dn_dev_get_next(seq, dev); if (dev == NULL) read_unlock(&dev_base_lock); } ++*pos; return dev;}static void dn_dev_seq_stop(struct seq_file *seq, void *v){ if (v && v != SEQ_START_TOKEN) read_unlock(&dev_base_lock);}static char *dn_type2asc(char type){ switch(type) { case DN_DEV_BCAST: return "B"; case DN_DEV_UCAST: return "U"; case DN_DEV_MPOINT: return "M"; } return "?";}static int dn_dev_seq_show(struct seq_file *seq, void *v){ if (v == SEQ_START_TOKEN) seq_puts(seq, "Name Flags T1 Timer1 T3 Timer3 BlkSize Pri State DevType Router Peer\n"); else { struct net_device *dev = v; char peer_buf[DN_ASCBUF_LEN]; char router_buf[DN_ASCBUF_LEN]; struct dn_dev *dn_db = dev->dn_ptr; seq_printf(seq, "%-8s %1s %04u %04u %04lu %04lu" " %04hu %03d %02x %-10s %-7s %-7s\n", dev->name ? dev->name : "???", dn_type2asc(dn_db->parms.mode), 0, 0, dn_db->t3, dn_db->parms.t3, mtu2blksize(dev), dn_db->parms.priority, dn_db->parms.state, dn_db->parms.name, dn_db->router ? dn_addr2asc(dn_ntohs(*(dn_address *)dn_db->router->primary_key), router_buf) : "", dn_db->peer ? dn_addr2asc(dn_ntohs(*(dn_address *)dn_db->peer->primary_key), peer_buf) : ""); } return 0;}static struct seq_operations dn_dev_seq_ops = { .start = dn_dev_seq_start, .next = dn_dev_seq_next, .stop = dn_dev_seq_stop, .show = dn_dev_seq_show,};static int dn_dev_seq_open(struct inode *inode, struct file *file){ return seq_open(file, &dn_dev_seq_ops);}static struct file_operations dn_dev_seq_fops = { .owner = THIS_MODULE, .open = dn_dev_seq_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release,};#endif /* CONFIG_PROC_FS */static struct rtnetlink_link dnet_rtnetlink_table[RTM_MAX-RTM_BASE+1] = { [4] = { .doit = dn_dev_rtm_newaddr, }, [5] = { .doit = dn_dev_rtm_deladdr, }, [6] = { .dumpit = dn_dev_dump_ifaddr, },#ifdef CONFIG_DECNET_ROUTER [8] = { .doit = dn_fib_rtm_newroute, }, [9] = { .doit = dn_fib_rtm_delroute, }, [10] = { .doit = dn_cache_getroute, .dumpit = dn_fib_dump, }, [16] = { .doit = dn_fib_rtm_newrule, }, [17] = { .doit = dn_fib_rtm_delrule, }, [18] = { .dumpit = dn_fib_dump_rules, },#else [10] = { .doit = dn_cache_getroute, .dumpit = dn_cache_dump, },#endif};static int __initdata addr[2];static int __initdata num;module_param_array(addr, int, num, 0444);MODULE_PARM_DESC(addr, "The DECnet address of this machine: area,node");void __init dn_dev_init(void){ if (addr[0] > 63 || addr[0] < 0) { printk(KERN_ERR "DECnet: Area must be between 0 and 63"); return; } if (addr[1] > 1023 || addr[1] < 0) { printk(KERN_ERR "DECnet: Node must be between 0 and 1023"); return; } decnet_address = dn_htons((addr[0] << 10) | addr[1]); dn_dev_devices_on();#ifdef CONFIG_DECNET_SIOCGIFCONF register_gifconf(PF_DECnet, dnet_gifconf);#endif /* CONFIG_DECNET_SIOCGIFCONF */ rtnetlink_links[PF_DECnet] = dnet_rtnetlink_table; proc_net_fops_create("decnet_dev", S_IRUGO, &dn_dev_seq_fops);#ifdef CONFIG_SYSCTL { int i; for(i = 0; i < DN_DEV_LIST_SIZE; i++) dn_dev_sysctl_register(NULL, &dn_dev_list[i]); }#endif /* CONFIG_SYSCTL */}void __exit dn_dev_cleanup(void){ rtnetlink_links[PF_DECnet] = NULL;#ifdef CONFIG_DECNET_SIOCGIFCONF unregister_gifconf(PF_DECnet);#endif /* CONFIG_DECNET_SIOCGIFCONF */#ifdef CONFIG_SYSCTL { int i; for(i = 0; i < DN_DEV_LIST_SIZE; i++) dn_dev_sysctl_unregister(&dn_dev_list[i]); }#endif /* CONFIG_SYSCTL */ proc_net_remove("decnet_dev"); dn_dev_devices_off();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -