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