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

📄 pppoe.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 2 页
字号:
	if (sp->sa_protocol != PX_PROTO_OE)		goto end;	/* Check for already bound sockets */	error = -EBUSY;	if ((sk->sk_state & PPPOX_CONNECTED) && sp->sa_addr.pppoe.sid)		goto end;	/* Check for already disconnected sockets, on attempts to disconnect */	error = -EALREADY;	if ((sk->sk_state & PPPOX_DEAD) && !sp->sa_addr.pppoe.sid )		goto end;	error = 0;	if (po->pppoe_pa.sid) {		pppox_unbind_sock(sk);		/* Delete the old binding */		delete_item(po->pppoe_pa.sid,po->pppoe_pa.remote);		if(po->pppoe_dev)			dev_put(po->pppoe_dev);		memset(po, 0, sizeof(struct pppox_opt));		po->sk = sk;		sk->sk_state = PPPOX_NONE;	}	/* Don't re-bind if sid==0 */	if (sp->sa_addr.pppoe.sid != 0) {		dev = dev_get_by_name(sp->sa_addr.pppoe.dev);		error = -ENODEV;		if (!dev)			goto end;		po->pppoe_dev = dev;		if (!(dev->flags & IFF_UP))			goto err_put;		memcpy(&po->pppoe_pa,		       &sp->sa_addr.pppoe,		       sizeof(struct pppoe_addr));		error = set_item(po);		if (error < 0)			goto err_put;		po->chan.hdrlen = (sizeof(struct pppoe_hdr) +				   dev->hard_header_len);		po->chan.private = sk;		po->chan.ops = &pppoe_chan_ops;		error = ppp_register_channel(&po->chan);		if (error)			goto err_put;		sk->sk_state = PPPOX_CONNECTED;	}	po->num = sp->sa_addr.pppoe.sid; end:	release_sock(sk);	return error;err_put:	if (po->pppoe_dev) {		dev_put(po->pppoe_dev);		po->pppoe_dev = NULL;	}	goto end;}static int pppoe_getname(struct socket *sock, struct sockaddr *uaddr,		  int *usockaddr_len, int peer){	int len = sizeof(struct sockaddr_pppox);	struct sockaddr_pppox sp;	sp.sa_family	= AF_PPPOX;	sp.sa_protocol	= PX_PROTO_OE;	memcpy(&sp.sa_addr.pppoe, &pppox_sk(sock->sk)->pppoe_pa,	       sizeof(struct pppoe_addr));	memcpy(uaddr, &sp, len);	*usockaddr_len = len;	return 0;}static int pppoe_ioctl(struct socket *sock, unsigned int cmd,		unsigned long arg){	struct sock *sk = sock->sk;	struct pppox_opt *po = pppox_sk(sk);	int val = 0;	int err = 0;	switch (cmd) {	case PPPIOCGMRU:		err = -ENXIO;		if (!(sk->sk_state & PPPOX_CONNECTED))			break;		err = -EFAULT;		if (put_user(po->pppoe_dev->mtu -			     sizeof(struct pppoe_hdr) -			     PPP_HDRLEN,			     (int __user *) arg))			break;		err = 0;		break;	case PPPIOCSMRU:		err = -ENXIO;		if (!(sk->sk_state & PPPOX_CONNECTED))			break;		err = -EFAULT;		if (get_user(val,(int __user *) arg))			break;		if (val < (po->pppoe_dev->mtu			   - sizeof(struct pppoe_hdr)			   - PPP_HDRLEN))			err = 0;		else			err = -EINVAL;		break;	case PPPIOCSFLAGS:		err = -EFAULT;		if (get_user(val, (int __user *) arg))			break;		err = 0;		break;	case PPPOEIOCSFWD:	{		struct pppox_opt *relay_po;		err = -EBUSY;		if (sk->sk_state & (PPPOX_BOUND | PPPOX_ZOMBIE | PPPOX_DEAD))			break;		err = -ENOTCONN;		if (!(sk->sk_state & PPPOX_CONNECTED))			break;		/* PPPoE address from the user specifies an outbound		   PPPoE address to which frames are forwarded to */		err = -EFAULT;		if (copy_from_user(&po->pppoe_relay,				   (void __user *)arg,				   sizeof(struct sockaddr_pppox)))			break;		err = -EINVAL;		if (po->pppoe_relay.sa_family != AF_PPPOX ||		    po->pppoe_relay.sa_protocol!= PX_PROTO_OE)			break;		/* Check that the socket referenced by the address		   actually exists. */		relay_po = get_item_by_addr(&po->pppoe_relay);		if (!relay_po)			break;		sock_put(relay_po->sk);		sk->sk_state |= PPPOX_RELAY;		err = 0;		break;	}	case PPPOEIOCDFWD:		err = -EALREADY;		if (!(sk->sk_state & PPPOX_RELAY))			break;		sk->sk_state &= ~PPPOX_RELAY;		err = 0;		break;	default:;	};	return err;}static int pppoe_sendmsg(struct kiocb *iocb, struct socket *sock, 		  struct msghdr *m, size_t total_len){	struct sk_buff *skb = NULL;	struct sock *sk = sock->sk;	struct pppox_opt *po = pppox_sk(sk);	int error = 0;	struct pppoe_hdr hdr;	struct pppoe_hdr *ph;	struct net_device *dev;	char *start;	if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) {		error = -ENOTCONN;		goto end;	}	hdr.ver = 1;	hdr.type = 1;	hdr.code = 0;	hdr.sid = po->num;	lock_sock(sk);	dev = po->pppoe_dev;	error = -EMSGSIZE; 	if (total_len > (dev->mtu + dev->hard_header_len))		goto end;	skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32,			   0, GFP_KERNEL);	if (!skb) {		error = -ENOMEM;		goto end;	}	/* Reserve space for headers. */	skb_reserve(skb, dev->hard_header_len);	skb->nh.raw = skb->data;	skb->dev = dev;	skb->priority = sk->sk_priority;	skb->protocol = __constant_htons(ETH_P_PPP_SES);	ph = (struct pppoe_hdr *) skb_put(skb, total_len + sizeof(struct pppoe_hdr));	start = (char *) &ph->tag[0];	error = memcpy_fromiovec(start, m->msg_iov, total_len);	if (error < 0) {		kfree_skb(skb);		goto end;	}	error = total_len;	dev->hard_header(skb, dev, ETH_P_PPP_SES,			 po->pppoe_pa.remote, NULL, total_len);	memcpy(ph, &hdr, sizeof(struct pppoe_hdr));	ph->length = htons(total_len);	dev_queue_xmit(skb);end:	release_sock(sk);	return error;}/************************************************************************ * * xmit function for internal use. * ***********************************************************************/static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb){	struct pppox_opt *po = pppox_sk(sk);	struct net_device *dev = po->pppoe_dev;	struct pppoe_hdr hdr;	struct pppoe_hdr *ph;	int headroom = skb_headroom(skb);	int data_len = skb->len;	struct sk_buff *skb2;	if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))		goto abort;	hdr.ver	= 1;	hdr.type = 1;	hdr.code = 0;	hdr.sid	= po->num;	hdr.length = htons(skb->len);	if (!dev)		goto abort;	/* Copy the skb if there is no space for the header. */	if (headroom < (sizeof(struct pppoe_hdr) + dev->hard_header_len)) {		skb2 = dev_alloc_skb(32+skb->len +				     sizeof(struct pppoe_hdr) +				     dev->hard_header_len);		if (skb2 == NULL)			goto abort;		skb_reserve(skb2, dev->hard_header_len + sizeof(struct pppoe_hdr));		memcpy(skb_put(skb2, skb->len), skb->data, skb->len);	} else {		/* Make a clone so as to not disturb the original skb,		 * give dev_queue_xmit something it can free.		 */		skb2 = skb_clone(skb, GFP_ATOMIC);	}	ph = (struct pppoe_hdr *) skb_push(skb2, sizeof(struct pppoe_hdr));	memcpy(ph, &hdr, sizeof(struct pppoe_hdr));	skb2->protocol = __constant_htons(ETH_P_PPP_SES);	skb2->nh.raw = skb2->data;	skb2->dev = dev;	dev->hard_header(skb2, dev, ETH_P_PPP_SES,			 po->pppoe_pa.remote, NULL, data_len);	/* We're transmitting skb2, and assuming that dev_queue_xmit	 * will free it.  The generic ppp layer however, is expecting	 * that we give back 'skb' (not 'skb2') in case of failure,	 * but free it in case of success.	 */	if (dev_queue_xmit(skb2) < 0)		goto abort;	kfree_skb(skb);	return 1;abort:	return 0;}/************************************************************************ * * xmit function called by generic PPP driver * sends PPP frame over PPPoE socket * ***********************************************************************/static int pppoe_xmit(struct ppp_channel *chan, struct sk_buff *skb){	struct sock *sk = (struct sock *) chan->private;	return __pppoe_xmit(sk, skb);}static struct ppp_channel_ops pppoe_chan_ops = { 	.start_xmit = pppoe_xmit, };static int pppoe_recvmsg(struct kiocb *iocb, struct socket *sock,		  struct msghdr *m, size_t total_len, int flags){	struct sock *sk = sock->sk;	struct sk_buff *skb = NULL;	int error = 0;	int len;	struct pppoe_hdr *ph = NULL;	if (sk->sk_state & PPPOX_BOUND) {		error = -EIO;		goto end;	}	skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,				flags & MSG_DONTWAIT, &error);	if (error < 0) {		goto end;	}	m->msg_namelen = 0;	if (skb) {		error = 0;		ph = (struct pppoe_hdr *) skb->nh.raw;		len = ntohs(ph->length);		error = memcpy_toiovec(m->msg_iov, (unsigned char *) &ph->tag[0], len);		if (error < 0)			goto do_skb_free;		error = len;	}do_skb_free:	if (skb)		kfree_skb(skb);end:	return error;}#ifdef CONFIG_PROC_FSstatic int pppoe_seq_show(struct seq_file *seq, void *v){	struct pppox_opt *po;	char *dev_name;	if (v == SEQ_START_TOKEN) {		seq_puts(seq, "Id       Address              Device\n");		goto out;	}	po = v;	dev_name = po->pppoe_pa.dev;	seq_printf(seq, "%08X %02X:%02X:%02X:%02X:%02X:%02X %8s\n",		   po->pppoe_pa.sid,		   po->pppoe_pa.remote[0], po->pppoe_pa.remote[1],		   po->pppoe_pa.remote[2], po->pppoe_pa.remote[3],		   po->pppoe_pa.remote[4], po->pppoe_pa.remote[5], dev_name);out:	return 0;}static __inline__ struct pppox_opt *pppoe_get_idx(loff_t pos){	struct pppox_opt *po = NULL;	int i = 0;	for (; i < PPPOE_HASH_SIZE; i++) {		po = item_hash_table[i];		while (po) {			if (!pos--)				goto out;			po = po->next;		}	}out:	return po;}static void *pppoe_seq_start(struct seq_file *seq, loff_t *pos){	loff_t l = *pos;	read_lock_bh(&pppoe_hash_lock);	return l ? pppoe_get_idx(--l) : SEQ_START_TOKEN;}static void *pppoe_seq_next(struct seq_file *seq, void *v, loff_t *pos){	struct pppox_opt *po;	++*pos;	if (v == SEQ_START_TOKEN) {		po = pppoe_get_idx(0);		goto out;	}	po = v;	if (po->next) 		po = po->next;	else {		int hash = hash_item(po->pppoe_pa.sid, po->pppoe_pa.remote);		while (++hash < PPPOE_HASH_SIZE) {			po = item_hash_table[hash];			if (po)				break;		}	}out:	return po;}static void pppoe_seq_stop(struct seq_file *seq, void *v){	read_unlock_bh(&pppoe_hash_lock);}struct seq_operations pppoe_seq_ops = {	.start		= pppoe_seq_start,	.next		= pppoe_seq_next,	.stop		= pppoe_seq_stop,	.show		= pppoe_seq_show,};static int pppoe_seq_open(struct inode *inode, struct file *file){	return seq_open(file, &pppoe_seq_ops);}static struct file_operations pppoe_seq_fops = {	.owner		= THIS_MODULE,	.open		= pppoe_seq_open,	.read		= seq_read,	.llseek		= seq_lseek,	.release	= seq_release,};static int __init pppoe_proc_init(void){	struct proc_dir_entry *p;	p = create_proc_entry("pppoe", S_IRUGO, proc_net);	if (!p)		return -ENOMEM;	p->proc_fops = &pppoe_seq_fops;	return 0;}#else /* CONFIG_PROC_FS */static inline int pppoe_proc_init(void) { return 0; }#endif /* CONFIG_PROC_FS *//* ->ioctl are set at pppox_create */static struct proto_ops pppoe_ops = {    .family		= AF_PPPOX,    .owner		= THIS_MODULE,    .release		= pppoe_release,    .bind		= sock_no_bind,    .connect		= pppoe_connect,    .socketpair		= sock_no_socketpair,    .accept		= sock_no_accept,    .getname		= pppoe_getname,    .poll		= datagram_poll,    .listen		= sock_no_listen,    .shutdown		= sock_no_shutdown,    .setsockopt		= sock_no_setsockopt,    .getsockopt		= sock_no_getsockopt,    .sendmsg		= pppoe_sendmsg,    .recvmsg		= pppoe_recvmsg,    .mmap		= sock_no_mmap};static struct pppox_proto pppoe_proto = {    .create	= pppoe_create,    .ioctl	= pppoe_ioctl,    .owner	= THIS_MODULE,};static int __init pppoe_init(void){ 	int err = register_pppox_proto(PX_PROTO_OE, &pppoe_proto);	if (err)		goto out;	err = pppoe_proc_init();	if (err) {		unregister_pppox_proto(PX_PROTO_OE);		goto out;	}		dev_add_pack(&pppoes_ptype);	dev_add_pack(&pppoed_ptype);	register_netdevice_notifier(&pppoe_notifier);out:	return err;}static void __exit pppoe_exit(void){	unregister_pppox_proto(PX_PROTO_OE);	dev_remove_pack(&pppoes_ptype);	dev_remove_pack(&pppoed_ptype);	unregister_netdevice_notifier(&pppoe_notifier);	remove_proc_entry("pppoe", proc_net);}module_init(pppoe_init);module_exit(pppoe_exit);MODULE_AUTHOR("Michal Ostrowski <mostrows@speakeasy.net>");MODULE_DESCRIPTION("PPP over Ethernet driver");MODULE_LICENSE("GPL");MODULE_ALIAS_NETPROTO(PF_PPPOX);

⌨️ 快捷键说明

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