net_kern.c
来自「linux 内核源代码」· C语言 代码 · 共 925 行 · 第 1/2 页
C
925 行
.remove = transport->user->remove, .read = transport->kern->read, .write = transport->kern->write, .add_address = transport->user->add_address, .delete_address = transport->user->delete_address }); init_timer(&lp->tl); spin_lock_init(&lp->lock); lp->tl.function = uml_net_user_timer_expire; memcpy(lp->mac, device->mac, sizeof(lp->mac)); if ((transport->user->init != NULL) && ((*transport->user->init)(&lp->user, dev) != 0)) goto out_unregister; set_ether_mac(dev, device->mac); dev->mtu = transport->user->mtu; dev->open = uml_net_open; dev->hard_start_xmit = uml_net_start_xmit; dev->stop = uml_net_close; dev->get_stats = uml_net_get_stats; dev->set_multicast_list = uml_net_set_multicast_list; dev->tx_timeout = uml_net_tx_timeout; dev->set_mac_address = uml_net_set_mac; dev->change_mtu = uml_net_change_mtu; dev->ethtool_ops = ¨_net_ethtool_ops; dev->watchdog_timeo = (HZ >> 1); dev->irq = UM_ETH_IRQ; err = update_drop_skb(lp->max_packet); if (err) goto out_undo_user_init; rtnl_lock(); err = register_netdevice(dev); rtnl_unlock(); if (err) goto out_undo_user_init; spin_lock(&devices_lock); list_add(&device->list, &devices); spin_unlock(&devices_lock); return;out_undo_user_init: if (transport->user->remove != NULL) (*transport->user->remove)(&lp->user);out_unregister: platform_device_unregister(&device->pdev); return; /* platform_device_unregister frees dev and device */out_free_netdev: free_netdev(dev);out_free_device: kfree(device);}static struct uml_net *find_device(int n){ struct uml_net *device; struct list_head *ele; spin_lock(&devices_lock); list_for_each(ele, &devices) { device = list_entry(ele, struct uml_net, list); if (device->index == n) goto out; } device = NULL; out: spin_unlock(&devices_lock); return device;}static int eth_parse(char *str, int *index_out, char **str_out, char **error_out){ char *end; int n, err = -EINVAL;; n = simple_strtoul(str, &end, 0); if (end == str) { *error_out = "Bad device number"; return err; } str = end; if (*str != '=') { *error_out = "Expected '=' after device number"; return err; } str++; if (find_device(n)) { *error_out = "Device already configured"; return err; } *index_out = n; *str_out = str; return 0;}struct eth_init { struct list_head list; char *init; int index;};static DEFINE_SPINLOCK(transports_lock);static LIST_HEAD(transports);/* Filled in during early boot */static LIST_HEAD(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; spin_lock(&transports_lock); BUG_ON(!list_empty(&new->list)); list_add(&new->list, &transports); spin_unlock(&transports_lock); 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; int found = 0; spin_lock(&transports_lock); 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); } found = 1; break; } spin_unlock(&transports_lock); return found;}static int __init eth_setup(char *str){ struct eth_init *new; char *error; int n, err; err = eth_parse(str, &n, &str, &error); if (err) { printk(KERN_ERR "eth_setup - Couldn't parse '%s' : %s\n", str, error); return 1; } new = alloc_bootmem(sizeof(*new)); if (new == NULL) { printk(KERN_ERR "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");static int net_config(char *str, char **error_out){ int n, err; err = eth_parse(str, &n, &str, error_out); if (err) return err; /* This string is broken up and the pieces used by the underlying * driver. So, it is freed only if eth_setup_common fails. */ str = kstrdup(str, GFP_KERNEL); if (str == NULL) { *error_out = "net_config failed to strdup string"; return -ENOMEM; } 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, char **error_out){ 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; unregister_netdev(dev); platform_device_unregister(&device->pdev); return 0;}static struct mc_device net_mc = { .list = LIST_HEAD_INIT(net_mc.list), .name = "eth", .config = net_config, .get_config = NULL, .id = net_id, .remove = net_remove,};#ifdef CONFIG_INETstatic 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;}/* uml_net_init shouldn't be called twice on two CPUs at the same time */struct notifier_block uml_inetaddr_notifier = { .notifier_call = uml_inetaddr_event,};static void inet_register(void){ struct list_head *ele; struct uml_net_private *lp; struct in_device *ip; struct in_ifaddr *in; 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. */ spin_lock(&opened_lock); 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; } } spin_unlock(&opened_lock);}#elsestatic inline void inet_register(void){}#endifstatic int uml_net_init(void){ mconsole_register_dev(&net_mc); inet_register(); return 0;}__initcall(uml_net_init);static void close_devices(void){ struct list_head *ele; struct uml_net_private *lp; spin_lock(&opened_lock); list_for_each(ele, &opened) { lp = list_entry(ele, struct uml_net_private, list); free_irq(lp->dev->irq, lp->dev); if ((lp->close != NULL) && (lp->fd >= 0)) (*lp->close)(lp->fd, &lp->user); if (lp->remove != NULL) (*lp->remove)(&lp->user); } spin_unlock(&opened_lock);}__uml_exitcall(close_devices);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; __be32 *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(KERN_ERR "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);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?