11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** -*- linux-c -*- *********************************************************** 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Linux PPP over X/Ethernet (PPPoX/PPPoE) Sockets 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PPPoX --- Generic PPP encapsulation socket family 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PPPoE --- PPP over Ethernet (RFC 2516) 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Version: 0.5.2 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Author: Michal Ostrowski <mostrows@speakeasy.net> 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 051000 : Initialization cleanup 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * License: 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modify it under the terms of the GNU General Public License 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as published by the Free Software Foundation; either version 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2 of the License, or (at your option) any later version. 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/net.h> 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/if_pppox.h> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ppp_defs.h> 314b32da2bcf1de2b7a196a0e48389d231b4472c36Paul Mackerras#include <linux/ppp-ioctl.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ppp_channel.h> 3365def812ab25d7565756e5748d91e22e302197eeJames Chapman#include <linux/kmod.h> 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/sock.h> 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h> 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39756e64a0b106f1a2ca96889c39ea0d48131105c0Eric Dumazetstatic const struct pppox_proto *pppox_protos[PX_MAX_PROTO + 1]; 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41756e64a0b106f1a2ca96889c39ea0d48131105c0Eric Dumazetint register_pppox_proto(int proto_num, const struct pppox_proto *pp) 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (proto_num < 0 || proto_num > PX_MAX_PROTO) 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pppox_protos[proto_num]) 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EALREADY; 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pppox_protos[proto_num] = pp; 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid unregister_pppox_proto(int proto_num) 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (proto_num >= 0 && proto_num <= PX_MAX_PROTO) 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pppox_protos[proto_num] = NULL; 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid pppox_unbind_sock(struct sock *sk) 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Clear connection to ppp device, if attached. */ 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 61202a03acf9994076055df40ae093a5c5474ad0bdFlorian Zumbiehl if (sk->sk_state & (PPPOX_BOUND | PPPOX_CONNECTED | PPPOX_ZOMBIE)) { 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ppp_unregister_channel(&pppox_sk(sk)->chan); 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sk->sk_state = PPPOX_DEAD; 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(register_pppox_proto); 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(unregister_pppox_proto); 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(pppox_unbind_sock); 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7117ba15fb6264f27374bc87f4c3f8519b80289d85David S. Millerint pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sock *sk = sock->sk; 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pppox_sock *po = pppox_sk(sk); 7586c1dcfc96a778433ebc6e9b1d3e80a126cb80f2Florian Zumbiehl int rc; 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lock_sock(sk); 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PPPIOCGCHAN: { 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int index; 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -ENOTCONN; 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(sk->sk_state & PPPOX_CONNECTED)) 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EINVAL; 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds index = ppp_channel_index(&po->chan); 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (put_user(index , (int __user *) arg)) 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = 0; 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sk->sk_state |= PPPOX_BOUND; 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 9686c1dcfc96a778433ebc6e9b1d3e80a126cb80f2Florian Zumbiehl rc = pppox_protos[sk->sk_protocol]->ioctl ? 9786c1dcfc96a778433ebc6e9b1d3e80a126cb80f2Florian Zumbiehl pppox_protos[sk->sk_protocol]->ioctl(sock, cmd, arg) : -ENOTTY; 9886c1dcfc96a778433ebc6e9b1d3e80a126cb80f2Florian Zumbiehl } 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_sock(sk); 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10417ba15fb6264f27374bc87f4c3f8519b80289d85David S. MillerEXPORT_SYMBOL(pppox_ioctl); 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1063f378b684453f2a028eda463ce383370545d9cc9Eric Parisstatic int pppox_create(struct net *net, struct socket *sock, int protocol, 1073f378b684453f2a028eda463ce383370545d9cc9Eric Paris int kern) 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = -EPROTOTYPE; 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (protocol < 0 || protocol > PX_MAX_PROTO) 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EPROTONOSUPPORT; 115a65e5d782f9db2a61a914dc01a329e0c2dcf92a1Johannes Berg if (!pppox_protos[protocol]) 116a65e5d782f9db2a61a914dc01a329e0c2dcf92a1Johannes Berg request_module("pppox-proto-%d", protocol); 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!pppox_protos[protocol] || 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !try_module_get(pppox_protos[protocol]->owner)) 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1211b8d7ae42d02e483ad94035cca851e4f7fbecb40Eric W. Biederman rc = pppox_protos[protocol]->create(net, sock); 12217ba15fb6264f27374bc87f4c3f8519b80289d85David S. Miller 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds module_put(pppox_protos[protocol]->owner); 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 128ec1b4cf74c81bfd0fbe5bf62bafc86c45917e72fStephen Hemmingerstatic const struct net_proto_family pppox_proto_family = { 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .family = PF_PPPOX, 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .create = pppox_create, 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init pppox_init(void) 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sock_register(&pppox_proto_family); 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit pppox_exit(void) 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sock_unregister(PF_PPPOX); 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(pppox_init); 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(pppox_exit); 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Michal Ostrowski <mostrows@speakeasy.net>"); 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("PPP over Ethernet driver (generic socket layer)"); 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 150