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

📄 pppoe.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	/* Signal the death of the socket. */	sk->state = PPPOX_DEAD;	po = sk->protinfo.pppox;	if (po->pppoe_pa.sid)		delete_item(po->pppoe_pa.sid, po->pppoe_pa.remote);			if (po->pppoe_dev)	    dev_put(po->pppoe_dev);	sock_orphan(sk);	sock->sk = NULL;	skb_queue_purge(&sk->receive_queue);	sock_put(sk);	return error;}int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,		  int sockaddr_len, int flags){	struct sock *sk = sock->sk;	struct net_device *dev = NULL;	struct sockaddr_pppox *sp = (struct sockaddr_pppox *) uservaddr;	struct pppox_opt  *po=sk->protinfo.pppox;	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->state & PPPOX_CONNECTED) && sp->sa_addr.pppoe.sid)		goto end;	/* Check for already disconnected sockets,	   on attempts to disconnect */	error = -EALREADY;	if((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);		dev_put(po->pppoe_dev);		memset(po, 0, sizeof(struct pppox_opt));		po->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;		if( ! (dev->flags & IFF_UP) )			goto end;		memcpy(&po->pppoe_pa,		       &sp->sa_addr.pppoe,		       sizeof(struct pppoe_addr));		error = set_item(po);		if (error < 0)			goto end;		po->pppoe_dev = dev;		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);		sk->state = PPPOX_CONNECTED;	}	sk->num = sp->sa_addr.pppoe.sid; end:	release_sock(sk);	return error;}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, &sock->sk->protinfo.pppox->pppoe_pa,	       sizeof(struct pppoe_addr));	memcpy(uaddr, &sp, len);	*usockaddr_len = len;	return 0;}int pppoe_ioctl(struct socket *sock, unsigned int cmd,		unsigned long arg){	struct sock *sk = sock->sk;	struct pppox_opt *po;	int val = 0;	int err = 0;	po = sk->protinfo.pppox;	switch (cmd) {	case PPPIOCGMRU:		err = -ENXIO;		if (!(sk->state & PPPOX_CONNECTED))			break;		err = -EFAULT;		if (put_user(po->pppoe_dev->mtu -			     sizeof(struct pppoe_hdr) -			     PPP_HDRLEN,			     (int *) arg))			break;		err = 0;		break;	case PPPIOCSMRU:		err = -ENXIO;		if (!(sk->state & PPPOX_CONNECTED))			break;		err = -EFAULT;		if (get_user(val,(int *) 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 *) arg))			break;		err = 0;		break;	case PPPOEIOCSFWD:	{		struct pppox_opt *relay_po;		err = -EBUSY;		if (sk->state & PPPOX_BOUND)			break;		err = -ENOTCONN;		if (!(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*)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->state |= PPPOX_RELAY;		err = 0;		break;	}	case PPPOEIOCDFWD:		err = -EALREADY;		if (!(sk->state & PPPOX_RELAY))			break;		sk->state &= ~PPPOX_RELAY;		err = 0;		break;	default:	};	return err;}int pppoe_sendmsg(struct socket *sock, struct msghdr *m,		  int total_len, struct scm_cookie *scm){	struct sk_buff *skb = NULL;	struct sock *sk = sock->sk;	int error = 0;	struct pppoe_hdr hdr;	struct pppoe_hdr *ph;	struct net_device *dev;	char *start;	if (sk->dead || !(sk->state & PPPOX_CONNECTED)) {		error = -ENOTCONN;		goto end;	}	hdr.ver = 1;	hdr.type = 1;	hdr.code = 0;	hdr.sid = sk->num;	lock_sock(sk);	dev = sk->protinfo.pppox->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->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,			 sk->protinfo.pppox->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. * ***********************************************************************/int __pppoe_xmit(struct sock *sk, struct sk_buff *skb){	struct net_device *dev = sk->protinfo.pppox->pppoe_dev;	struct pppoe_hdr hdr;	struct pppoe_hdr *ph;	int headroom = skb_headroom(skb);	int data_len = skb->len;	if (sk->dead  || !(sk->state & PPPOX_CONNECTED)) {		goto abort;	}	hdr.ver	= 1;	hdr.type = 1;	hdr.code = 0;	hdr.sid	= sk->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)) {		struct sk_buff *skb2;		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);		skb_unlink(skb);		kfree_skb(skb);		skb = skb2;	}	ph = (struct pppoe_hdr *) skb_push(skb, sizeof(struct pppoe_hdr));	memcpy(ph, &hdr, sizeof(struct pppoe_hdr));	skb->protocol = __constant_htons(ETH_P_PPP_SES);	skb->nh.raw = skb->data;	skb->dev = dev;	dev->hard_header(skb, dev, ETH_P_PPP_SES,			 sk->protinfo.pppox->pppoe_pa.remote,			 NULL, data_len);	if (dev_queue_xmit(skb) < 0)		goto abort;	return 1; abort:	return 0;}/************************************************************************ * * xmit function called by generic PPP driver * sends PPP frame over PPPoE socket * ***********************************************************************/int pppoe_xmit(struct ppp_channel *chan, struct sk_buff *skb){	struct sock *sk = (struct sock *) chan->private;	return __pppoe_xmit(sk, skb);}struct ppp_channel_ops pppoe_chan_ops = { pppoe_xmit , NULL };int pppoe_rcvmsg(struct socket *sock, struct msghdr *m, int total_len, int flags, struct scm_cookie *scm){	struct sock *sk = sock->sk;	struct sk_buff *skb = NULL;	int error = 0;	int len;	struct pppoe_hdr *ph = NULL;	if (sk->state & PPPOX_BOUND) {		error = -EIO;		goto end;	}	skb = skb_recv_datagram(sk, flags, 0, &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;}int pppoe_proc_info(char *buffer, char **start, off_t offset, int length){	struct pppox_opt *po;	int len = 0;	off_t pos = 0;	off_t begin = 0;	int size;	int i;		len += sprintf(buffer,		       "Id       Address              Device\n");	pos = len;	write_lock_bh(&pppoe_hash_lock);	for (i = 0; i < PPPOE_HASH_SIZE; i++) {		po = item_hash_table[i];		while (po) {			char *dev = po->pppoe_pa.dev;			size = sprintf(buffer + len,				       "%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);			len += size;			pos += size;			if (pos < offset) {				len = 0;				begin = pos;			}			if (pos > offset + length)				break;			po = po->next;		}		if (po)			break;  	}	write_unlock_bh(&pppoe_hash_lock);  	*start = buffer + (offset - begin);  	len -= (offset - begin);  	if (len > length)  		len = length;	if (len < 0)		len = 0;  	return len;}struct proto_ops pppoe_ops = {    family:		AF_PPPOX,    release:		pppoe_release,    bind:		sock_no_bind,    connect:		pppoe_connect,    socketpair:		sock_no_socketpair,    accept:		sock_no_accept,    getname:		pppoe_getname,    poll:		datagram_poll,    ioctl:		pppoe_ioctl,    listen:		sock_no_listen,    shutdown:		sock_no_shutdown,    setsockopt:		sock_no_setsockopt,    getsockopt:		sock_no_getsockopt,    sendmsg:		pppoe_sendmsg,    recvmsg:		pppoe_rcvmsg,    mmap:		sock_no_mmap};struct pppox_proto pppoe_proto = {    create:	pppoe_create,    ioctl:	pppoe_ioctl};int __init pppoe_init(void){ 	int err = register_pppox_proto(PX_PROTO_OE, &pppoe_proto);	if (err == 0) {		printk(KERN_INFO "Registered PPPoE v0.6.4\n");		dev_add_pack(&pppoes_ptype);		register_netdevice_notifier(&pppoe_notifier);		proc_net_create("pppoe", 0, pppoe_proc_info);	}	return err;}void __exit pppoe_exit(void){	unregister_pppox_proto(PX_PROTO_OE);	dev_remove_pack(&pppoes_ptype);	unregister_netdevice_notifier(&pppoe_notifier);	proc_net_remove("pppoe");}module_init(pppoe_init);module_exit(pppoe_exit);

⌨️ 快捷键说明

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