📄 dn_dev.c
字号:
ptr += 7; i2 = ptr++; n = dn_neigh_elist(dev, ptr, n); *i2 = 7 * n; *i1 = 8 + *i2; skb_trim(skb, (27 + *i2)); pktlen = (__le16 *)skb_push(skb, 2); *pktlen = dn_htons(skb->len - 2); skb_reset_network_header(skb); if (dn_am_i_a_router(dn, dn_db, ifa)) { struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC); if (skb2) { dn_rt_finish_output(skb2, dn_rt_all_end_mcast, src); } } dn_rt_finish_output(skb, dn_rt_all_rt_mcast, src);}static void dn_send_brd_hello(struct net_device *dev, struct dn_ifaddr *ifa){ struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr; if (dn_db->parms.forwarding == 0) dn_send_endnode_hello(dev, ifa); else dn_send_router_hello(dev, ifa);}static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa){ int tdlen = 16; int size = dev->hard_header_len + 2 + 4 + tdlen; struct sk_buff *skb = dn_alloc_skb(NULL, size, GFP_ATOMIC); int i; unsigned char *ptr; char src[ETH_ALEN]; if (skb == NULL) return ; skb->dev = dev; skb_push(skb, dev->hard_header_len); ptr = skb_put(skb, 2 + 4 + tdlen); *ptr++ = DN_RT_PKT_HELO; *((__le16 *)ptr) = ifa->ifa_local; ptr += 2; *ptr++ = tdlen; for(i = 0; i < tdlen; i++) *ptr++ = 0252; dn_dn2eth(src, ifa->ifa_local); dn_rt_finish_output(skb, dn_rt_all_rt_mcast, src);}static int dn_eth_up(struct net_device *dev){ struct dn_dev *dn_db = dev->dn_ptr; 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); 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 = kzalloc(sizeof(struct dn_dev), GFP_ATOMIC)) == NULL) return NULL; 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; dn_db->neigh_parms = neigh_parms_alloc(dev, &dn_neigh_table); if (!dn_db->neigh_parms) { dev->dn_ptr = NULL; kfree(dn_db); return NULL; } if (dn_db->parms.up) { if (dn_db->parms.up(dev) < 0) { neigh_parms_release(&dn_neigh_table, dn_db->neigh_parms); dev->dn_ptr = NULL; kfree(dn_db); return NULL; } } 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; __le16 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_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_each_netdev(&init_net, dev) dn_dev_down(dev); rtnl_unlock();}void dn_dev_devices_on(void){ struct net_device *dev; rtnl_lock(); for_each_netdev(&init_net, dev) { if (dev->flags & IFF_UP) dn_dev_up(dev); } rtnl_unlock();}int register_dnaddr_notifier(struct notifier_block *nb){ return blocking_notifier_chain_register(&dnaddr_chain, nb);}int unregister_dnaddr_notifier(struct notifier_block *nb){ return blocking_notifier_chain_unregister(&dnaddr_chain, nb);}#ifdef CONFIG_PROC_FSstatic inline int is_dn_dev(struct net_device *dev){ return dev->dn_ptr != NULL;}static void *dn_dev_seq_start(struct seq_file *seq, loff_t *pos){ int i; struct net_device *dev; read_lock(&dev_base_lock); if (*pos == 0) return SEQ_START_TOKEN; i = 1; for_each_netdev(&init_net, dev) { if (!is_dn_dev(dev)) continue; if (i++ == *pos) return dev; } return NULL;}static void *dn_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos){ struct net_device *dev; ++*pos; dev = (struct net_device *)v; if (v == SEQ_START_TOKEN) dev = net_device_entry(&init_net.dev_base_head); for_each_netdev_continue(&init_net, dev) { if (!is_dn_dev(dev)) continue; return dev; } return NULL;}static void dn_dev_seq_stop(struct seq_file *seq, void *v){ 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(*(__le16 *)dn_db->router->primary_key), router_buf) : "", dn_db->peer ? dn_addr2asc(dn_ntohs(*(__le16 *)dn_db->peer->primary_key), peer_buf) : ""); } return 0;}static const 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 const 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 int addr[2];module_param_array(addr, int, NULL, 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(); rtnl_register(PF_DECnet, RTM_NEWADDR, dn_nl_newaddr, NULL); rtnl_register(PF_DECnet, RTM_DELADDR, dn_nl_deladdr, NULL); rtnl_register(PF_DECnet, RTM_GETADDR, NULL, dn_nl_dump_ifaddr); proc_net_fops_create(&init_net, "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){#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(&init_net, "decnet_dev"); dn_dev_devices_off();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -