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

📄 clip.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 2 页
字号:
	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;		}		DPRINTK("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) DPRINTK("setentry: add\n");		else {			DPRINTK("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;	DPRINTK("registered (net:%s)\n",dev->name);	return number;}static int clip_device_event(struct notifier_block *this,unsigned long event,    void *dev){	/* ignore non-CLIP devices */	if (((struct net_device *) dev)->type != ARPHRD_ATM ||	    ((struct net_device *) dev)->hard_start_xmit != clip_start_xmit)		return NOTIFY_DONE;	switch (event) {		case NETDEV_UP:			DPRINTK("clip_device_event NETDEV_UP\n");			(void) to_atmarpd(act_up,PRIV(dev)->number,0);			break;		case NETDEV_GOING_DOWN:			DPRINTK("clip_device_event NETDEV_DOWN\n");			(void) to_atmarpd(act_down,PRIV(dev)->number,0);			break;		case NETDEV_CHANGE:		case NETDEV_CHANGEMTU:			DPRINTK("clip_device_event NETDEV_CHANGE*\n");			(void) to_atmarpd(act_change,PRIV(dev)->number,0);			break;		case NETDEV_REBOOT:		case NETDEV_REGISTER:		case NETDEV_DOWN:			DPRINTK("clip_device_event %ld\n",event);			/* ignore */			break;		default:			printk(KERN_WARNING "clip_device_event: unknown event "			    "%ld\n",event);			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 = {	clip_device_event,	NULL,	0};static struct notifier_block clip_inet_notifier = {	clip_inet_event,	NULL,	0};static void atmarpd_close(struct atm_vcc *vcc){	DPRINTK("atmarpd_close\n");	atmarpd = NULL; /* assumed to be atomic */	barrier();	unregister_inetaddr_notifier(&clip_inet_notifier);	unregister_netdevice_notifier(&clip_dev_notifier);	if (skb_peek(&vcc->sk->sk_receive_queue))		printk(KERN_ERR "atmarpd_close: closing with requests "		    "pending\n");	skb_queue_purge(&vcc->sk->sk_receive_queue);	DPRINTK("(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};static int atm_init_atmarp(struct atm_vcc *vcc){	if (atmarpd) return -EADDRINUSE;	if (start_timer) {		start_timer = 0;		init_timer(&idle_timer);		idle_timer.expires = jiffies+CLIP_CHECK_INTERVAL*HZ;		idle_timer.function = idle_timer_check;		add_timer(&idle_timer);	}	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(vcc->sk);	vcc->push = NULL;	vcc->pop = NULL; /* crash */	vcc->push_oam = NULL; /* crash */	if (register_netdevice_notifier(&clip_dev_notifier))		printk(KERN_ERR "register_netdevice_notifier failed\n");	if (register_inetaddr_notifier(&clip_inet_notifier))		printk(KERN_ERR "register_inetaddr_notifier failed\n");	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, 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) ||	       (clip_vcc->vcc->sk->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 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 = kmalloc(sizeof(*state), GFP_KERNEL);	if (!state) {		rc = -ENOMEM;		goto out_kfree;	}	memset(state, 0, sizeof(*state));	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 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(&clip_tbl);	clip_tbl_hook = &clip_tbl;	register_atm_ioctl(&clip_ioctl_ops);#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);	deregister_atm_ioctl(&clip_ioctl_ops);	/* First, stop the idle timer, so it stops banging	 * on the table.	 */	if (start_timer == 0)		del_timer(&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_LICENSE("GPL");

⌨️ 快捷键说明

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