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 = &uml_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, &eth_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(&eth->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, &eth_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(&uml_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 + -
显示快捷键?