xref: /openbmc/linux/drivers/net/ppp/pppox.c (revision 11aa9c28)
1224cf5adSJeff Kirsher /** -*- linux-c -*- ***********************************************************
2224cf5adSJeff Kirsher  * Linux PPP over X/Ethernet (PPPoX/PPPoE) Sockets
3224cf5adSJeff Kirsher  *
4224cf5adSJeff Kirsher  * PPPoX --- Generic PPP encapsulation socket family
5224cf5adSJeff Kirsher  * PPPoE --- PPP over Ethernet (RFC 2516)
6224cf5adSJeff Kirsher  *
7224cf5adSJeff Kirsher  *
8224cf5adSJeff Kirsher  * Version:	0.5.2
9224cf5adSJeff Kirsher  *
10224cf5adSJeff Kirsher  * Author:	Michal Ostrowski <mostrows@speakeasy.net>
11224cf5adSJeff Kirsher  *
12224cf5adSJeff Kirsher  * 051000 :	Initialization cleanup
13224cf5adSJeff Kirsher  *
14224cf5adSJeff Kirsher  * License:
15224cf5adSJeff Kirsher  *		This program is free software; you can redistribute it and/or
16224cf5adSJeff Kirsher  *		modify it under the terms of the GNU General Public License
17224cf5adSJeff Kirsher  *		as published by the Free Software Foundation; either version
18224cf5adSJeff Kirsher  *		2 of the License, or (at your option) any later version.
19224cf5adSJeff Kirsher  *
20224cf5adSJeff Kirsher  */
21224cf5adSJeff Kirsher 
22224cf5adSJeff Kirsher #include <linux/string.h>
23224cf5adSJeff Kirsher #include <linux/module.h>
24224cf5adSJeff Kirsher #include <linux/kernel.h>
25224cf5adSJeff Kirsher #include <linux/errno.h>
26224cf5adSJeff Kirsher #include <linux/netdevice.h>
27224cf5adSJeff Kirsher #include <linux/net.h>
28224cf5adSJeff Kirsher #include <linux/init.h>
29224cf5adSJeff Kirsher #include <linux/if_pppox.h>
30224cf5adSJeff Kirsher #include <linux/ppp_defs.h>
314b32da2bSPaul Mackerras #include <linux/ppp-ioctl.h>
32224cf5adSJeff Kirsher #include <linux/ppp_channel.h>
33224cf5adSJeff Kirsher #include <linux/kmod.h>
34224cf5adSJeff Kirsher 
35224cf5adSJeff Kirsher #include <net/sock.h>
36224cf5adSJeff Kirsher 
37224cf5adSJeff Kirsher #include <asm/uaccess.h>
38224cf5adSJeff Kirsher 
39224cf5adSJeff Kirsher static const struct pppox_proto *pppox_protos[PX_MAX_PROTO + 1];
40224cf5adSJeff Kirsher 
41224cf5adSJeff Kirsher int register_pppox_proto(int proto_num, const struct pppox_proto *pp)
42224cf5adSJeff Kirsher {
43224cf5adSJeff Kirsher 	if (proto_num < 0 || proto_num > PX_MAX_PROTO)
44224cf5adSJeff Kirsher 		return -EINVAL;
45224cf5adSJeff Kirsher 	if (pppox_protos[proto_num])
46224cf5adSJeff Kirsher 		return -EALREADY;
47224cf5adSJeff Kirsher 	pppox_protos[proto_num] = pp;
48224cf5adSJeff Kirsher 	return 0;
49224cf5adSJeff Kirsher }
50224cf5adSJeff Kirsher 
51224cf5adSJeff Kirsher void unregister_pppox_proto(int proto_num)
52224cf5adSJeff Kirsher {
53224cf5adSJeff Kirsher 	if (proto_num >= 0 && proto_num <= PX_MAX_PROTO)
54224cf5adSJeff Kirsher 		pppox_protos[proto_num] = NULL;
55224cf5adSJeff Kirsher }
56224cf5adSJeff Kirsher 
57224cf5adSJeff Kirsher void pppox_unbind_sock(struct sock *sk)
58224cf5adSJeff Kirsher {
59224cf5adSJeff Kirsher 	/* Clear connection to ppp device, if attached. */
60224cf5adSJeff Kirsher 
61224cf5adSJeff Kirsher 	if (sk->sk_state & (PPPOX_BOUND | PPPOX_CONNECTED | PPPOX_ZOMBIE)) {
62224cf5adSJeff Kirsher 		ppp_unregister_channel(&pppox_sk(sk)->chan);
63224cf5adSJeff Kirsher 		sk->sk_state = PPPOX_DEAD;
64224cf5adSJeff Kirsher 	}
65224cf5adSJeff Kirsher }
66224cf5adSJeff Kirsher 
67224cf5adSJeff Kirsher EXPORT_SYMBOL(register_pppox_proto);
68224cf5adSJeff Kirsher EXPORT_SYMBOL(unregister_pppox_proto);
69224cf5adSJeff Kirsher EXPORT_SYMBOL(pppox_unbind_sock);
70224cf5adSJeff Kirsher 
71224cf5adSJeff Kirsher int pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
72224cf5adSJeff Kirsher {
73224cf5adSJeff Kirsher 	struct sock *sk = sock->sk;
74224cf5adSJeff Kirsher 	struct pppox_sock *po = pppox_sk(sk);
75224cf5adSJeff Kirsher 	int rc;
76224cf5adSJeff Kirsher 
77224cf5adSJeff Kirsher 	lock_sock(sk);
78224cf5adSJeff Kirsher 
79224cf5adSJeff Kirsher 	switch (cmd) {
80224cf5adSJeff Kirsher 	case PPPIOCGCHAN: {
81224cf5adSJeff Kirsher 		int index;
82224cf5adSJeff Kirsher 		rc = -ENOTCONN;
83224cf5adSJeff Kirsher 		if (!(sk->sk_state & PPPOX_CONNECTED))
84224cf5adSJeff Kirsher 			break;
85224cf5adSJeff Kirsher 
86224cf5adSJeff Kirsher 		rc = -EINVAL;
87224cf5adSJeff Kirsher 		index = ppp_channel_index(&po->chan);
88224cf5adSJeff Kirsher 		if (put_user(index , (int __user *) arg))
89224cf5adSJeff Kirsher 			break;
90224cf5adSJeff Kirsher 
91224cf5adSJeff Kirsher 		rc = 0;
92224cf5adSJeff Kirsher 		sk->sk_state |= PPPOX_BOUND;
93224cf5adSJeff Kirsher 		break;
94224cf5adSJeff Kirsher 	}
95224cf5adSJeff Kirsher 	default:
96224cf5adSJeff Kirsher 		rc = pppox_protos[sk->sk_protocol]->ioctl ?
97224cf5adSJeff Kirsher 			pppox_protos[sk->sk_protocol]->ioctl(sock, cmd, arg) : -ENOTTY;
98224cf5adSJeff Kirsher 	}
99224cf5adSJeff Kirsher 
100224cf5adSJeff Kirsher 	release_sock(sk);
101224cf5adSJeff Kirsher 	return rc;
102224cf5adSJeff Kirsher }
103224cf5adSJeff Kirsher 
104224cf5adSJeff Kirsher EXPORT_SYMBOL(pppox_ioctl);
105224cf5adSJeff Kirsher 
106224cf5adSJeff Kirsher static int pppox_create(struct net *net, struct socket *sock, int protocol,
107224cf5adSJeff Kirsher 			int kern)
108224cf5adSJeff Kirsher {
109224cf5adSJeff Kirsher 	int rc = -EPROTOTYPE;
110224cf5adSJeff Kirsher 
111224cf5adSJeff Kirsher 	if (protocol < 0 || protocol > PX_MAX_PROTO)
112224cf5adSJeff Kirsher 		goto out;
113224cf5adSJeff Kirsher 
114224cf5adSJeff Kirsher 	rc = -EPROTONOSUPPORT;
115224cf5adSJeff Kirsher 	if (!pppox_protos[protocol])
116224cf5adSJeff Kirsher 		request_module("pppox-proto-%d", protocol);
117224cf5adSJeff Kirsher 	if (!pppox_protos[protocol] ||
118224cf5adSJeff Kirsher 	    !try_module_get(pppox_protos[protocol]->owner))
119224cf5adSJeff Kirsher 		goto out;
120224cf5adSJeff Kirsher 
12111aa9c28SEric W. Biederman 	rc = pppox_protos[protocol]->create(net, sock, kern);
122224cf5adSJeff Kirsher 
123224cf5adSJeff Kirsher 	module_put(pppox_protos[protocol]->owner);
124224cf5adSJeff Kirsher out:
125224cf5adSJeff Kirsher 	return rc;
126224cf5adSJeff Kirsher }
127224cf5adSJeff Kirsher 
128224cf5adSJeff Kirsher static const struct net_proto_family pppox_proto_family = {
129224cf5adSJeff Kirsher 	.family	= PF_PPPOX,
130224cf5adSJeff Kirsher 	.create	= pppox_create,
131224cf5adSJeff Kirsher 	.owner	= THIS_MODULE,
132224cf5adSJeff Kirsher };
133224cf5adSJeff Kirsher 
134224cf5adSJeff Kirsher static int __init pppox_init(void)
135224cf5adSJeff Kirsher {
136224cf5adSJeff Kirsher 	return sock_register(&pppox_proto_family);
137224cf5adSJeff Kirsher }
138224cf5adSJeff Kirsher 
139224cf5adSJeff Kirsher static void __exit pppox_exit(void)
140224cf5adSJeff Kirsher {
141224cf5adSJeff Kirsher 	sock_unregister(PF_PPPOX);
142224cf5adSJeff Kirsher }
143224cf5adSJeff Kirsher 
144224cf5adSJeff Kirsher module_init(pppox_init);
145224cf5adSJeff Kirsher module_exit(pppox_exit);
146224cf5adSJeff Kirsher 
147224cf5adSJeff Kirsher MODULE_AUTHOR("Michal Ostrowski <mostrows@speakeasy.net>");
148224cf5adSJeff Kirsher MODULE_DESCRIPTION("PPP over Ethernet driver (generic socket layer)");
149224cf5adSJeff Kirsher MODULE_LICENSE("GPL");
150