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

📄 pppoe.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	struct pppox_sock *po = pppox_sk(sk);	int error;	lock_sock(sk);	error = -EINVAL;	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,po->pppoe_ifindex);		if(po->pppoe_dev)			dev_put(po->pppoe_dev);		memset(sk_pppox(po) + 1, 0,		       sizeof(struct pppox_sock) - sizeof(struct sock));		sk->sk_state = PPPOX_NONE;	}	/* Don't re-bind if sid==0 */	if (sp->sa_addr.pppoe.sid != 0) {		dev = dev_get_by_name(&init_net, sp->sa_addr.pppoe.dev);		error = -ENODEV;		if (!dev)			goto end;		po->pppoe_dev = dev;		po->pppoe_ifindex = dev->ifindex;		write_lock_bh(&pppoe_hash_lock);		if (!(dev->flags & IFF_UP)){			write_unlock_bh(&pppoe_hash_lock);			goto err_put;		}		memcpy(&po->pppoe_pa,		       &sp->sa_addr.pppoe,		       sizeof(struct pppoe_addr));		error = __set_item(po);		write_unlock_bh(&pppoe_hash_lock);		if (error < 0)			goto err_put;		po->chan.hdrlen = (sizeof(struct pppoe_hdr) +				   dev->hard_header_len);		po->chan.mtu = dev->mtu - sizeof(struct pppoe_hdr);		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_sock *po = pppox_sk(sk);	int val;	int err;	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_sock *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 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(sk_pppox(relay_po));		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:		err = -ENOTTY;	}	return err;}static int pppoe_sendmsg(struct kiocb *iocb, struct socket *sock,		  struct msghdr *m, size_t total_len){	struct sk_buff *skb;	struct sock *sk = sock->sk;	struct pppox_sock *po = pppox_sk(sk);	int error;	struct pppoe_hdr hdr;	struct pppoe_hdr *ph;	struct net_device *dev;	char *start;	lock_sock(sk);	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;	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_reset_network_header(skb);	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_sock *po = pppox_sk(sk);	struct net_device *dev = po->pppoe_dev;	struct pppoe_hdr *ph;	int data_len = skb->len;	if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))		goto abort;	if (!dev)		goto abort;	/* Copy the data if there is no space for the header or if it's	 * read-only.	 */	if (skb_cow_head(skb, sizeof(*ph) + dev->hard_header_len))		goto abort;	__skb_push(skb, sizeof(*ph));	skb_reset_network_header(skb);	ph = pppoe_hdr(skb);	ph->ver	= 1;	ph->type = 1;	ph->code = 0;	ph->sid	= po->num;	ph->length = htons(data_len);	skb->protocol = __constant_htons(ETH_P_PPP_SES);	skb->dev = dev;	dev_hard_header(skb, dev, ETH_P_PPP_SES,			po->pppoe_pa.remote, NULL, data_len);	dev_queue_xmit(skb);	return 1;abort:	kfree_skb(skb);	return 1;}/************************************************************************ * * 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;	int error = 0;	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) {		struct pppoe_hdr *ph = pppoe_hdr(skb);		const int len = ntohs(ph->length);		error = memcpy_toiovec(m->msg_iov, (unsigned char *) &ph->tag[0], len);		if (error == 0)			error = len;	}	kfree_skb(skb);end:	return error;}#ifdef CONFIG_PROC_FSstatic int pppoe_seq_show(struct seq_file *seq, void *v){	struct pppox_sock *po;	char *dev_name;	DECLARE_MAC_BUF(mac);	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 %s %8s\n",		   po->pppoe_pa.sid, print_mac(mac, po->pppoe_pa.remote), dev_name);out:	return 0;}static __inline__ struct pppox_sock *pppoe_get_idx(loff_t pos){	struct pppox_sock *po;	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_sock *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);}static 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 const 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, init_net.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 */static const 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,    .ioctl		= pppox_ioctl,};static struct pppox_proto pppoe_proto = {    .create	= pppoe_create,    .ioctl	= pppoe_ioctl,    .owner	= THIS_MODULE,};static int __init pppoe_init(void){	int err = proto_register(&pppoe_sk_proto, 0);	if (err)		goto out; 	err = register_pppox_proto(PX_PROTO_OE, &pppoe_proto);	if (err)		goto out_unregister_pppoe_proto;	err = pppoe_proc_init();	if (err)		goto out_unregister_pppox_proto;	dev_add_pack(&pppoes_ptype);	dev_add_pack(&pppoed_ptype);	register_netdevice_notifier(&pppoe_notifier);out:	return err;out_unregister_pppox_proto:	unregister_pppox_proto(PX_PROTO_OE);out_unregister_pppoe_proto:	proto_unregister(&pppoe_sk_proto);	goto out;}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", init_net.proc_net);	proto_unregister(&pppoe_sk_proto);}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 + -