📄 net_kern.c
字号:
if(*str != '='){ printk(KERN_ERR "eth_setup: expected '=' after device number\n"); return(1); } str++; if(find_device(n)){ printk(KERN_ERR "eth_setup: Device %d already configured\n", n); return(1); } if(index_out) *index_out = n; *str_out = str; return(0);}struct eth_init { struct list_head list; char *init; int index;};/* Filled in at boot time. Will need locking if the transports become * modular. */struct list_head transports = LIST_HEAD_INIT(transports);/* Filled in during early boot */struct list_head eth_cmd_line = LIST_HEAD_INIT(eth_cmd_line);static int check_transport(struct transport *transport, char *eth, int n, void **init_out, char **mac_out){ int len; len = strlen(transport->name); if(strncmp(eth, transport->name, len)) return(0); eth += len; if(*eth == ',') eth++; else if(*eth != '\0') return(0); *init_out = kmalloc(transport->setup_size, GFP_KERNEL); if(*init_out == NULL) return(1); if(!transport->setup(eth, mac_out, *init_out)){ kfree(*init_out); *init_out = NULL; } return(1);}void register_transport(struct transport *new){ struct list_head *ele, *next; struct eth_init *eth; void *init; char *mac = NULL; int match; list_add(&new->list, &transports); list_for_each_safe(ele, next, ð_cmd_line){ eth = list_entry(ele, struct eth_init, list); match = check_transport(new, eth->init, eth->index, &init, &mac); if(!match) continue; else if(init != NULL){ eth_configure(eth->index, init, mac, new); kfree(init); } list_del(ð->list); }}static int eth_setup_common(char *str, int index){ struct list_head *ele; struct transport *transport; void *init; char *mac = NULL; list_for_each(ele, &transports){ transport = list_entry(ele, struct transport, list); if(!check_transport(transport, str, index, &init, &mac)) continue; if(init != NULL){ eth_configure(index, init, mac, transport); kfree(init); } return(1); } return(0);}static int eth_setup(char *str){ struct eth_init *new; int n, err; err = eth_parse(str, &n, &str); if(err) return(1); new = alloc_bootmem(sizeof(new)); if (new == NULL){ printk("eth_init : alloc_bootmem failed\n"); return(1); } INIT_LIST_HEAD(&new->list); new->index = n; new->init = str; list_add_tail(&new->list, ð_cmd_line); return(1);}__setup("eth", eth_setup);__uml_help(eth_setup,"eth[0-9]+=<transport>,<options>\n"" Configure a network device.\n\n");#if 0static int eth_init(void){ struct list_head *ele, *next; struct eth_init *eth; list_for_each_safe(ele, next, ð_cmd_line){ eth = list_entry(ele, struct eth_init, list); if(eth_setup_common(eth->init, eth->index)) list_del(ð->list); } return(1);}__initcall(eth_init);#endifstatic int net_config(char *str){ int n, err; err = eth_parse(str, &n, &str); if(err) return(err); str = uml_strdup(str); if(str == NULL){ printk(KERN_ERR "net_config failed to strdup string\n"); return(-1); } err = !eth_setup_common(str, n); if(err) kfree(str); return(err);}static int net_id(char **str, int *start_out, int *end_out){ char *end; int n; n = simple_strtoul(*str, &end, 0); if((*end != '\0') || (end == *str)) return -1; *start_out = n; *end_out = n; *str = end; return n;}static int net_remove(int n){ struct uml_net *device; struct net_device *dev; struct uml_net_private *lp; device = find_device(n); if(device == NULL) return -ENODEV; dev = device->dev; lp = dev->priv; if(lp->fd > 0) return -EBUSY; if(lp->remove != NULL) (*lp->remove)(&lp->user); unregister_netdev(dev); platform_device_unregister(&device->pdev); list_del(&device->list); kfree(device); free_netdev(dev); return 0;}static struct mc_device net_mc = { .name = "eth", .config = net_config, .get_config = NULL, .id = net_id, .remove = net_remove,};static int uml_inetaddr_event(struct notifier_block *this, unsigned long event, void *ptr){ struct in_ifaddr *ifa = ptr; struct net_device *dev = ifa->ifa_dev->dev; struct uml_net_private *lp; void (*proc)(unsigned char *, unsigned char *, void *); unsigned char addr_buf[4], netmask_buf[4]; if(dev->open != uml_net_open) return(NOTIFY_DONE); lp = dev->priv; proc = NULL; switch (event){ case NETDEV_UP: proc = lp->add_address; break; case NETDEV_DOWN: proc = lp->delete_address; break; } if(proc != NULL){ memcpy(addr_buf, &ifa->ifa_address, sizeof(addr_buf)); memcpy(netmask_buf, &ifa->ifa_mask, sizeof(netmask_buf)); (*proc)(addr_buf, netmask_buf, &lp->user); } return(NOTIFY_DONE);}struct notifier_block uml_inetaddr_notifier = { .notifier_call = uml_inetaddr_event,};static int uml_net_init(void){ struct list_head *ele; struct uml_net_private *lp; struct in_device *ip; struct in_ifaddr *in; mconsole_register_dev(&net_mc); register_inetaddr_notifier(¨_inetaddr_notifier); /* Devices may have been opened already, so the uml_inetaddr_notifier * didn't get a chance to run for them. This fakes it so that * addresses which have already been set up get handled properly. */ list_for_each(ele, &opened){ lp = list_entry(ele, struct uml_net_private, list); ip = lp->dev->ip_ptr; if(ip == NULL) continue; in = ip->ifa_list; while(in != NULL){ uml_inetaddr_event(NULL, NETDEV_UP, in); in = in->ifa_next; } } return(0);}__initcall(uml_net_init);static void close_devices(void){ struct list_head *ele; struct uml_net_private *lp; list_for_each(ele, &opened){ lp = list_entry(ele, struct uml_net_private, list); if((lp->close != NULL) && (lp->fd >= 0)) (*lp->close)(lp->fd, &lp->user); if(lp->remove != NULL) (*lp->remove)(&lp->user); }}__uml_exitcall(close_devices);int setup_etheraddr(char *str, unsigned char *addr){ char *end; int i; if(str == NULL) return(0); for(i=0;i<6;i++){ addr[i] = simple_strtoul(str, &end, 16); if((end == str) || ((*end != ':') && (*end != ',') && (*end != '\0'))){ printk(KERN_ERR "setup_etheraddr: failed to parse '%s' " "as an ethernet address\n", str); return(0); } str = end + 1; } if(addr[0] & 1){ printk(KERN_ERR "Attempt to assign a broadcast ethernet address to a " "device disallowed\n"); return(0); } return(1);}void dev_ip_addr(void *d, unsigned char *bin_buf){ struct net_device *dev = d; struct in_device *ip = dev->ip_ptr; struct in_ifaddr *in; if((ip == NULL) || ((in = ip->ifa_list) == NULL)){ printk(KERN_WARNING "dev_ip_addr - device not assigned an " "IP address\n"); return; } memcpy(bin_buf, &in->ifa_address, sizeof(in->ifa_address));}void set_ether_mac(void *d, unsigned char *addr){ struct net_device *dev = d; memcpy(dev->dev_addr, addr, ETH_ALEN); }struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra){ if((skb != NULL) && (skb_tailroom(skb) < extra)){ struct sk_buff *skb2; skb2 = skb_copy_expand(skb, 0, extra, GFP_ATOMIC); dev_kfree_skb(skb); skb = skb2; } if(skb != NULL) skb_put(skb, extra); return(skb);}void iter_addresses(void *d, void (*cb)(unsigned char *, unsigned char *, void *), void *arg){ struct net_device *dev = d; struct in_device *ip = dev->ip_ptr; struct in_ifaddr *in; unsigned char address[4], netmask[4]; if(ip == NULL) return; in = ip->ifa_list; while(in != NULL){ memcpy(address, &in->ifa_address, sizeof(address)); memcpy(netmask, &in->ifa_mask, sizeof(netmask)); (*cb)(address, netmask, arg); in = in->ifa_next; }}int dev_netmask(void *d, void *m){ struct net_device *dev = d; struct in_device *ip = dev->ip_ptr; struct in_ifaddr *in; __u32 *mask_out = m; if(ip == NULL) return(1); in = ip->ifa_list; if(in == NULL) return(1); *mask_out = in->ifa_mask; return(0);}void *get_output_buffer(int *len_out){ void *ret; ret = (void *) __get_free_pages(GFP_KERNEL, 0); if(ret) *len_out = PAGE_SIZE; else *len_out = 0; return(ret);}void free_output_buffer(void *buffer){ free_pages((unsigned long) buffer, 0);}int tap_setup_common(char *str, char *type, char **dev_name, char **mac_out, char **gate_addr){ char *remain; remain = split_if_spec(str, dev_name, mac_out, gate_addr, NULL); if(remain != NULL){ printk("tap_setup_common - Extra garbage on specification : " "'%s'\n", remain); return(1); } return(0);}unsigned short eth_protocol(struct sk_buff *skb){ return(eth_type_trans(skb, skb->dev));}/* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically * adjust the settings for this buffer only. This must remain at the end * of the file. * --------------------------------------------------------------------------- * Local variables: * c-file-style: "linux" * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -