xref: /openbmc/linux/drivers/net/ppp/pppox.c (revision 055d8824)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2224cf5adSJeff Kirsher /** -*- linux-c -*- ***********************************************************
3224cf5adSJeff Kirsher  * Linux PPP over X/Ethernet (PPPoX/PPPoE) Sockets
4224cf5adSJeff Kirsher  *
5224cf5adSJeff Kirsher  * PPPoX --- Generic PPP encapsulation socket family
6224cf5adSJeff Kirsher  * PPPoE --- PPP over Ethernet (RFC 2516)
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  */
16224cf5adSJeff Kirsher 
17224cf5adSJeff Kirsher #include <linux/string.h>
18224cf5adSJeff Kirsher #include <linux/module.h>
19224cf5adSJeff Kirsher #include <linux/kernel.h>
20055d8824SArnd Bergmann #include <linux/compat.h>
21224cf5adSJeff Kirsher #include <linux/errno.h>
22224cf5adSJeff Kirsher #include <linux/netdevice.h>
23224cf5adSJeff Kirsher #include <linux/net.h>
24224cf5adSJeff Kirsher #include <linux/init.h>
25224cf5adSJeff Kirsher #include <linux/if_pppox.h>
26224cf5adSJeff Kirsher #include <linux/ppp_defs.h>
274b32da2bSPaul Mackerras #include <linux/ppp-ioctl.h>
28224cf5adSJeff Kirsher #include <linux/ppp_channel.h>
29224cf5adSJeff Kirsher #include <linux/kmod.h>
30224cf5adSJeff Kirsher 
31224cf5adSJeff Kirsher #include <net/sock.h>
32224cf5adSJeff Kirsher 
337c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
34224cf5adSJeff Kirsher 
35224cf5adSJeff Kirsher static const struct pppox_proto *pppox_protos[PX_MAX_PROTO + 1];
36224cf5adSJeff Kirsher 
register_pppox_proto(int proto_num,const struct pppox_proto * pp)37224cf5adSJeff Kirsher int register_pppox_proto(int proto_num, const struct pppox_proto *pp)
38224cf5adSJeff Kirsher {
39224cf5adSJeff Kirsher 	if (proto_num < 0 || proto_num > PX_MAX_PROTO)
40224cf5adSJeff Kirsher 		return -EINVAL;
41224cf5adSJeff Kirsher 	if (pppox_protos[proto_num])
42224cf5adSJeff Kirsher 		return -EALREADY;
43224cf5adSJeff Kirsher 	pppox_protos[proto_num] = pp;
44224cf5adSJeff Kirsher 	return 0;
45224cf5adSJeff Kirsher }
46224cf5adSJeff Kirsher 
unregister_pppox_proto(int proto_num)47224cf5adSJeff Kirsher void unregister_pppox_proto(int proto_num)
48224cf5adSJeff Kirsher {
49224cf5adSJeff Kirsher 	if (proto_num >= 0 && proto_num <= PX_MAX_PROTO)
50224cf5adSJeff Kirsher 		pppox_protos[proto_num] = NULL;
51224cf5adSJeff Kirsher }
52224cf5adSJeff Kirsher 
pppox_unbind_sock(struct sock * sk)53224cf5adSJeff Kirsher void pppox_unbind_sock(struct sock *sk)
54224cf5adSJeff Kirsher {
55224cf5adSJeff Kirsher 	/* Clear connection to ppp device, if attached. */
56224cf5adSJeff Kirsher 
57a8acce6aSGuillaume Nault 	if (sk->sk_state & (PPPOX_BOUND | PPPOX_CONNECTED)) {
58224cf5adSJeff Kirsher 		ppp_unregister_channel(&pppox_sk(sk)->chan);
59224cf5adSJeff Kirsher 		sk->sk_state = PPPOX_DEAD;
60224cf5adSJeff Kirsher 	}
61224cf5adSJeff Kirsher }
62224cf5adSJeff Kirsher 
63224cf5adSJeff Kirsher EXPORT_SYMBOL(register_pppox_proto);
64224cf5adSJeff Kirsher EXPORT_SYMBOL(unregister_pppox_proto);
65224cf5adSJeff Kirsher EXPORT_SYMBOL(pppox_unbind_sock);
66224cf5adSJeff Kirsher 
pppox_ioctl(struct socket * sock,unsigned int cmd,unsigned long arg)67224cf5adSJeff Kirsher int pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
68224cf5adSJeff Kirsher {
69224cf5adSJeff Kirsher 	struct sock *sk = sock->sk;
70224cf5adSJeff Kirsher 	struct pppox_sock *po = pppox_sk(sk);
71224cf5adSJeff Kirsher 	int rc;
72224cf5adSJeff Kirsher 
73224cf5adSJeff Kirsher 	lock_sock(sk);
74224cf5adSJeff Kirsher 
75224cf5adSJeff Kirsher 	switch (cmd) {
76224cf5adSJeff Kirsher 	case PPPIOCGCHAN: {
77224cf5adSJeff Kirsher 		int index;
78224cf5adSJeff Kirsher 		rc = -ENOTCONN;
79224cf5adSJeff Kirsher 		if (!(sk->sk_state & PPPOX_CONNECTED))
80224cf5adSJeff Kirsher 			break;
81224cf5adSJeff Kirsher 
82224cf5adSJeff Kirsher 		rc = -EINVAL;
83224cf5adSJeff Kirsher 		index = ppp_channel_index(&po->chan);
84224cf5adSJeff Kirsher 		if (put_user(index , (int __user *) arg))
85224cf5adSJeff Kirsher 			break;
86224cf5adSJeff Kirsher 
87224cf5adSJeff Kirsher 		rc = 0;
88224cf5adSJeff Kirsher 		sk->sk_state |= PPPOX_BOUND;
89224cf5adSJeff Kirsher 		break;
90224cf5adSJeff Kirsher 	}
91224cf5adSJeff Kirsher 	default:
92224cf5adSJeff Kirsher 		rc = pppox_protos[sk->sk_protocol]->ioctl ?
93224cf5adSJeff Kirsher 			pppox_protos[sk->sk_protocol]->ioctl(sock, cmd, arg) : -ENOTTY;
94224cf5adSJeff Kirsher 	}
95224cf5adSJeff Kirsher 
96224cf5adSJeff Kirsher 	release_sock(sk);
97224cf5adSJeff Kirsher 	return rc;
98224cf5adSJeff Kirsher }
99224cf5adSJeff Kirsher 
100224cf5adSJeff Kirsher EXPORT_SYMBOL(pppox_ioctl);
101224cf5adSJeff Kirsher 
102055d8824SArnd Bergmann #ifdef CONFIG_COMPAT
pppox_compat_ioctl(struct socket * sock,unsigned int cmd,unsigned long arg)103055d8824SArnd Bergmann int pppox_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
104055d8824SArnd Bergmann {
105055d8824SArnd Bergmann 	if (cmd == PPPOEIOCSFWD32)
106055d8824SArnd Bergmann 		cmd = PPPOEIOCSFWD;
107055d8824SArnd Bergmann 
108055d8824SArnd Bergmann 	return pppox_ioctl(sock, cmd, (unsigned long)compat_ptr(arg));
109055d8824SArnd Bergmann }
110055d8824SArnd Bergmann 
111055d8824SArnd Bergmann EXPORT_SYMBOL(pppox_compat_ioctl);
112055d8824SArnd Bergmann #endif
113055d8824SArnd Bergmann 
pppox_create(struct net * net,struct socket * sock,int protocol,int kern)114224cf5adSJeff Kirsher static int pppox_create(struct net *net, struct socket *sock, int protocol,
115224cf5adSJeff Kirsher 			int kern)
116224cf5adSJeff Kirsher {
117224cf5adSJeff Kirsher 	int rc = -EPROTOTYPE;
118224cf5adSJeff Kirsher 
119224cf5adSJeff Kirsher 	if (protocol < 0 || protocol > PX_MAX_PROTO)
120224cf5adSJeff Kirsher 		goto out;
121224cf5adSJeff Kirsher 
122224cf5adSJeff Kirsher 	rc = -EPROTONOSUPPORT;
123224cf5adSJeff Kirsher 	if (!pppox_protos[protocol])
124681b4d88SGuillaume Nault 		request_module("net-pf-%d-proto-%d", PF_PPPOX, protocol);
125224cf5adSJeff Kirsher 	if (!pppox_protos[protocol] ||
126224cf5adSJeff Kirsher 	    !try_module_get(pppox_protos[protocol]->owner))
127224cf5adSJeff Kirsher 		goto out;
128224cf5adSJeff Kirsher 
12911aa9c28SEric W. Biederman 	rc = pppox_protos[protocol]->create(net, sock, kern);
130224cf5adSJeff Kirsher 
131224cf5adSJeff Kirsher 	module_put(pppox_protos[protocol]->owner);
132224cf5adSJeff Kirsher out:
133224cf5adSJeff Kirsher 	return rc;
134224cf5adSJeff Kirsher }
135224cf5adSJeff Kirsher 
136224cf5adSJeff Kirsher static const struct net_proto_family pppox_proto_family = {
137224cf5adSJeff Kirsher 	.family	= PF_PPPOX,
138224cf5adSJeff Kirsher 	.create	= pppox_create,
139224cf5adSJeff Kirsher 	.owner	= THIS_MODULE,
140224cf5adSJeff Kirsher };
141224cf5adSJeff Kirsher 
pppox_init(void)142224cf5adSJeff Kirsher static int __init pppox_init(void)
143224cf5adSJeff Kirsher {
144224cf5adSJeff Kirsher 	return sock_register(&pppox_proto_family);
145224cf5adSJeff Kirsher }
146224cf5adSJeff Kirsher 
pppox_exit(void)147224cf5adSJeff Kirsher static void __exit pppox_exit(void)
148224cf5adSJeff Kirsher {
149224cf5adSJeff Kirsher 	sock_unregister(PF_PPPOX);
150224cf5adSJeff Kirsher }
151224cf5adSJeff Kirsher 
152224cf5adSJeff Kirsher module_init(pppox_init);
153224cf5adSJeff Kirsher module_exit(pppox_exit);
154224cf5adSJeff Kirsher 
155224cf5adSJeff Kirsher MODULE_AUTHOR("Michal Ostrowski <mostrows@speakeasy.net>");
156224cf5adSJeff Kirsher MODULE_DESCRIPTION("PPP over Ethernet driver (generic socket layer)");
157224cf5adSJeff Kirsher MODULE_LICENSE("GPL");
158681b4d88SGuillaume Nault MODULE_ALIAS_NETPROTO(PF_PPPOX);
159