⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 clip.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	int error;	struct clip_vcc *clip_vcc;	struct flowi fl = { .nl_u = { .ip4_u = { .daddr = ip, .tos = 1}} };	struct rtable *rt;	if (vcc->push != clip_push) {		printk(KERN_WARNING "clip_setentry: non-CLIP VCC\n");		return -EBADF;	}	clip_vcc = CLIP_VCC(vcc);	if (!ip) {		if (!clip_vcc->entry) {			printk(KERN_ERR "hiding hidden ATMARP entry\n");			return 0;		}		pr_debug("setentry: remove\n");		unlink_clip_vcc(clip_vcc);		return 0;	}	error = ip_route_output_key(&rt, &fl);	if (error)		return error;	neigh = __neigh_lookup(&clip_tbl, &ip, rt->u.dst.dev, 1);	ip_rt_put(rt);	if (!neigh)		return -ENOMEM;	entry = NEIGH2ENTRY(neigh);	if (entry != clip_vcc->entry) {		if (!clip_vcc->entry)			pr_debug("setentry: add\n");		else {			pr_debug("setentry: update\n");			unlink_clip_vcc(clip_vcc);		}		link_vcc(clip_vcc, entry);	}	error = neigh_update(neigh, llc_oui, NUD_PERMANENT,			     NEIGH_UPDATE_F_OVERRIDE | NEIGH_UPDATE_F_ADMIN);	neigh_release(neigh);	return error;}static void clip_setup(struct net_device *dev){	dev->hard_start_xmit = clip_start_xmit;	/* sg_xmit ... */	dev->get_stats = clip_get_stats;	dev->type = ARPHRD_ATM;	dev->hard_header_len = RFC1483LLC_LEN;	dev->mtu = RFC1626_MTU;	dev->tx_queue_len = 100;	/* "normal" queue (packets) */	/* When using a "real" qdisc, the qdisc determines the queue */	/* length. tx_queue_len is only used for the default case, */	/* without any more elaborate queuing. 100 is a reasonable */	/* compromise between decent burst-tolerance and protection */	/* against memory hogs. */}static int clip_create(int number){	struct net_device *dev;	struct clip_priv *clip_priv;	int error;	if (number != -1) {		for (dev = clip_devs; dev; dev = PRIV(dev)->next)			if (PRIV(dev)->number == number)				return -EEXIST;	} else {		number = 0;		for (dev = clip_devs; dev; dev = PRIV(dev)->next)			if (PRIV(dev)->number >= number)				number = PRIV(dev)->number + 1;	}	dev = alloc_netdev(sizeof(struct clip_priv), "", clip_setup);	if (!dev)		return -ENOMEM;	clip_priv = PRIV(dev);	sprintf(dev->name, "atm%d", number);	spin_lock_init(&clip_priv->xoff_lock);	clip_priv->number = number;	error = register_netdev(dev);	if (error) {		free_netdev(dev);		return error;	}	clip_priv->next = clip_devs;	clip_devs = dev;	pr_debug("registered (net:%s)\n", dev->name);	return number;}static int clip_device_event(struct notifier_block *this, unsigned long event,			     void *arg){	struct net_device *dev = arg;	if (dev->nd_net != &init_net)		return NOTIFY_DONE;	if (event == NETDEV_UNREGISTER) {		neigh_ifdown(&clip_tbl, dev);		return NOTIFY_DONE;	}	/* ignore non-CLIP devices */	if (dev->type != ARPHRD_ATM || dev->hard_start_xmit != clip_start_xmit)		return NOTIFY_DONE;	switch (event) {	case NETDEV_UP:		pr_debug("clip_device_event NETDEV_UP\n");		to_atmarpd(act_up, PRIV(dev)->number, 0);		break;	case NETDEV_GOING_DOWN:		pr_debug("clip_device_event NETDEV_DOWN\n");		to_atmarpd(act_down, PRIV(dev)->number, 0);		break;	case NETDEV_CHANGE:	case NETDEV_CHANGEMTU:		pr_debug("clip_device_event NETDEV_CHANGE*\n");		to_atmarpd(act_change, PRIV(dev)->number, 0);		break;	}	return NOTIFY_DONE;}static int clip_inet_event(struct notifier_block *this, unsigned long event,			   void *ifa){	struct in_device *in_dev;	in_dev = ((struct in_ifaddr *)ifa)->ifa_dev;	if (!in_dev || !in_dev->dev) {		printk(KERN_WARNING "clip_inet_event: no device\n");		return NOTIFY_DONE;	}	/*	 * Transitions are of the down-change-up type, so it's sufficient to	 * handle the change on up.	 */	if (event != NETDEV_UP)		return NOTIFY_DONE;	return clip_device_event(this, NETDEV_CHANGE, in_dev->dev);}static struct notifier_block clip_dev_notifier = {	.notifier_call = clip_device_event,};static struct notifier_block clip_inet_notifier = {	.notifier_call = clip_inet_event,};static void atmarpd_close(struct atm_vcc *vcc){	pr_debug("atmarpd_close\n");	rtnl_lock();	atmarpd = NULL;	skb_queue_purge(&sk_atm(vcc)->sk_receive_queue);	rtnl_unlock();	pr_debug("(done)\n");	module_put(THIS_MODULE);}static struct atmdev_ops atmarpd_dev_ops = {	.close = atmarpd_close};static struct atm_dev atmarpd_dev = {	.ops =			&atmarpd_dev_ops,	.type =			"arpd",	.number = 		999,	.lock =			__SPIN_LOCK_UNLOCKED(atmarpd_dev.lock)};static int atm_init_atmarp(struct atm_vcc *vcc){	rtnl_lock();	if (atmarpd) {		rtnl_unlock();		return -EADDRINUSE;	}	mod_timer(&idle_timer, jiffies+CLIP_CHECK_INTERVAL*HZ);	atmarpd = vcc;	set_bit(ATM_VF_META,&vcc->flags);	set_bit(ATM_VF_READY,&vcc->flags);	    /* allow replies and avoid getting closed if signaling dies */	vcc->dev = &atmarpd_dev;	vcc_insert_socket(sk_atm(vcc));	vcc->push = NULL;	vcc->pop = NULL; /* crash */	vcc->push_oam = NULL; /* crash */	rtnl_unlock();	return 0;}static int clip_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg){	struct atm_vcc *vcc = ATM_SD(sock);	int err = 0;	switch (cmd) {	case SIOCMKCLIP:	case ATMARPD_CTRL:	case ATMARP_MKIP:	case ATMARP_SETENTRY:	case ATMARP_ENCAP:		if (!capable(CAP_NET_ADMIN))			return -EPERM;		break;	default:		return -ENOIOCTLCMD;	}	switch (cmd) {	case SIOCMKCLIP:		err = clip_create(arg);		break;	case ATMARPD_CTRL:		err = atm_init_atmarp(vcc);		if (!err) {			sock->state = SS_CONNECTED;			__module_get(THIS_MODULE);		}		break;	case ATMARP_MKIP:		err = clip_mkip(vcc, arg);		break;	case ATMARP_SETENTRY:		err = clip_setentry(vcc, (__force __be32)arg);		break;	case ATMARP_ENCAP:		err = clip_encap(vcc, arg);		break;	}	return err;}static struct atm_ioctl clip_ioctl_ops = {	.owner = THIS_MODULE,	.ioctl = clip_ioctl,};#ifdef CONFIG_PROC_FSstatic void svc_addr(struct seq_file *seq, struct sockaddr_atmsvc *addr){	static int code[] = { 1, 2, 10, 6, 1, 0 };	static int e164[] = { 1, 8, 4, 6, 1, 0 };	if (*addr->sas_addr.pub) {		seq_printf(seq, "%s", addr->sas_addr.pub);		if (*addr->sas_addr.prv)			seq_putc(seq, '+');	} else if (!*addr->sas_addr.prv) {		seq_printf(seq, "%s", "(none)");		return;	}	if (*addr->sas_addr.prv) {		unsigned char *prv = addr->sas_addr.prv;		int *fields;		int i, j;		fields = *prv == ATM_AFI_E164 ? e164 : code;		for (i = 0; fields[i]; i++) {			for (j = fields[i]; j; j--)				seq_printf(seq, "%02X", *prv++);			if (fields[i + 1])				seq_putc(seq, '.');		}	}}/* This means the neighbour entry has no attached VCC objects. */#define SEQ_NO_VCC_TOKEN	((void *) 2)static void atmarp_info(struct seq_file *seq, struct net_device *dev,			struct atmarp_entry *entry, struct clip_vcc *clip_vcc){	unsigned long exp;	char buf[17];	int svc, llc, off;	svc = ((clip_vcc == SEQ_NO_VCC_TOKEN) ||	       (sk_atm(clip_vcc->vcc)->sk_family == AF_ATMSVC));	llc = ((clip_vcc == SEQ_NO_VCC_TOKEN) || clip_vcc->encap);	if (clip_vcc == SEQ_NO_VCC_TOKEN)		exp = entry->neigh->used;	else		exp = clip_vcc->last_use;	exp = (jiffies - exp) / HZ;	seq_printf(seq, "%-6s%-4s%-4s%5ld ",		   dev->name, svc ? "SVC" : "PVC", llc ? "LLC" : "NULL", exp);	off = scnprintf(buf, sizeof(buf) - 1, "%d.%d.%d.%d",			NIPQUAD(entry->ip));	while (off < 16)		buf[off++] = ' ';	buf[off] = '\0';	seq_printf(seq, "%s", buf);	if (clip_vcc == SEQ_NO_VCC_TOKEN) {		if (time_before(jiffies, entry->expires))			seq_printf(seq, "(resolving)\n");		else			seq_printf(seq, "(expired, ref %d)\n",				   atomic_read(&entry->neigh->refcnt));	} else if (!svc) {		seq_printf(seq, "%d.%d.%d\n",			   clip_vcc->vcc->dev->number,			   clip_vcc->vcc->vpi, clip_vcc->vcc->vci);	} else {		svc_addr(seq, &clip_vcc->vcc->remote);		seq_putc(seq, '\n');	}}struct clip_seq_state {	/* This member must be first. */	struct neigh_seq_state ns;	/* Local to clip specific iteration. */	struct clip_vcc *vcc;};static struct clip_vcc *clip_seq_next_vcc(struct atmarp_entry *e,					  struct clip_vcc *curr){	if (!curr) {		curr = e->vccs;		if (!curr)			return SEQ_NO_VCC_TOKEN;		return curr;	}	if (curr == SEQ_NO_VCC_TOKEN)		return NULL;	curr = curr->next;	return curr;}static void *clip_seq_vcc_walk(struct clip_seq_state *state,			       struct atmarp_entry *e, loff_t * pos){	struct clip_vcc *vcc = state->vcc;	vcc = clip_seq_next_vcc(e, vcc);	if (vcc && pos != NULL) {		while (*pos) {			vcc = clip_seq_next_vcc(e, vcc);			if (!vcc)				break;			--(*pos);		}	}	state->vcc = vcc;	return vcc;}static void *clip_seq_sub_iter(struct neigh_seq_state *_state,			       struct neighbour *n, loff_t * pos){	struct clip_seq_state *state = (struct clip_seq_state *)_state;	return clip_seq_vcc_walk(state, NEIGH2ENTRY(n), pos);}static void *clip_seq_start(struct seq_file *seq, loff_t * pos){	return neigh_seq_start(seq, pos, &clip_tbl, NEIGH_SEQ_NEIGH_ONLY);}static int clip_seq_show(struct seq_file *seq, void *v){	static char atm_arp_banner[] =	    "IPitf TypeEncp Idle IP address      ATM address\n";	if (v == SEQ_START_TOKEN) {		seq_puts(seq, atm_arp_banner);	} else {		struct clip_seq_state *state = seq->private;		struct neighbour *n = v;		struct clip_vcc *vcc = state->vcc;		atmarp_info(seq, n->dev, NEIGH2ENTRY(n), vcc);	}	return 0;}static const struct seq_operations arp_seq_ops = {	.start	= clip_seq_start,	.next	= neigh_seq_next,	.stop	= neigh_seq_stop,	.show	= clip_seq_show,};static int arp_seq_open(struct inode *inode, struct file *file){	struct clip_seq_state *state;	struct seq_file *seq;	int rc = -EAGAIN;	state = kzalloc(sizeof(*state), GFP_KERNEL);	if (!state) {		rc = -ENOMEM;		goto out_kfree;	}	state->ns.neigh_sub_iter = clip_seq_sub_iter;	rc = seq_open(file, &arp_seq_ops);	if (rc)		goto out_kfree;	seq = file->private_data;	seq->private = state;out:	return rc;out_kfree:	kfree(state);	goto out;}static const struct file_operations arp_seq_fops = {	.open		= arp_seq_open,	.read		= seq_read,	.llseek		= seq_lseek,	.release	= seq_release_private,	.owner		= THIS_MODULE};#endifstatic int __init atm_clip_init(void){	neigh_table_init_no_netlink(&clip_tbl);	clip_tbl_hook = &clip_tbl;	register_atm_ioctl(&clip_ioctl_ops);	register_netdevice_notifier(&clip_dev_notifier);	register_inetaddr_notifier(&clip_inet_notifier);	setup_timer(&idle_timer, idle_timer_check, 0);#ifdef CONFIG_PROC_FS	{		struct proc_dir_entry *p;		p = create_proc_entry("arp", S_IRUGO, atm_proc_root);		if (p)			p->proc_fops = &arp_seq_fops;	}#endif	return 0;}static void __exit atm_clip_exit(void){	struct net_device *dev, *next;	remove_proc_entry("arp", atm_proc_root);	unregister_inetaddr_notifier(&clip_inet_notifier);	unregister_netdevice_notifier(&clip_dev_notifier);	deregister_atm_ioctl(&clip_ioctl_ops);	/* First, stop the idle timer, so it stops banging	 * on the table.	 */	del_timer_sync(&idle_timer);	/* Next, purge the table, so that the device	 * unregister loop below does not hang due to	 * device references remaining in the table.	 */	neigh_ifdown(&clip_tbl, NULL);	dev = clip_devs;	while (dev) {		next = PRIV(dev)->next;		unregister_netdev(dev);		free_netdev(dev);		dev = next;	}	/* Now it is safe to fully shutdown whole table. */	neigh_table_clear(&clip_tbl);	clip_tbl_hook = NULL;}module_init(atm_clip_init);module_exit(atm_clip_exit);MODULE_AUTHOR("Werner Almesberger");MODULE_DESCRIPTION("Classical/IP over ATM interface");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -