1/** -*- linux-c -*- *********************************************************** 2 * Linux PPP over X/Ethernet (PPPoX/PPPoE) Sockets 3 * 4 * PPPoX --- Generic PPP encapsulation socket family 5 * PPPoE --- PPP over Ethernet (RFC 2516) 6 * 7 * 8 * Version: 0.5.2 9 * 10 * Author: Michal Ostrowski <mostrows@speakeasy.net> 11 * 12 * 051000 : Initialization cleanup 13 * 14 * License: 15 * This program is free software; you can redistribute it and/or 16 * modify it under the terms of the GNU General Public License 17 * as published by the Free Software Foundation; either version 18 * 2 of the License, or (at your option) any later version. 19 * 20 */ 21 22#include <linux/string.h> 23#include <linux/module.h> 24 25#include <asm/uaccess.h> 26 27#include <linux/kernel.h> 28#include <linux/sched.h> 29#include <linux/slab.h> 30#include <linux/errno.h> 31 32#include <linux/netdevice.h> 33#include <linux/net.h> 34#include <linux/init.h> 35#include <linux/if_pppox.h> 36#include <net/sock.h> 37#include <linux/ppp_defs.h> 38#include <linux/if_ppp.h> 39#include <linux/ppp_channel.h> 40 41static struct pppox_proto *proto[PX_MAX_PROTO+1]; 42 43int register_pppox_proto(int proto_num, struct pppox_proto *pp) 44{ 45 if (proto_num < 0 || proto_num > PX_MAX_PROTO) { 46 return -EINVAL; 47 } 48 49 if (proto[proto_num]) 50 return -EALREADY; 51 52 MOD_INC_USE_COUNT; 53 54 proto[proto_num] = pp; 55 return 0; 56} 57 58void unregister_pppox_proto(int proto_num) 59{ 60 if (proto_num >= 0 && proto_num <= PX_MAX_PROTO) { 61 proto[proto_num] = NULL; 62 MOD_DEC_USE_COUNT; 63 } 64} 65 66void pppox_unbind_sock(struct sock *sk) 67{ 68 /* Clear connection to ppp device, if attached. */ 69 70 if (sk->state & (PPPOX_BOUND|PPPOX_ZOMBIE)) { 71 ppp_unregister_channel(&sk->protinfo.pppox->chan); 72 sk->state = PPPOX_DEAD; 73 } 74} 75 76EXPORT_SYMBOL(register_pppox_proto); 77EXPORT_SYMBOL(unregister_pppox_proto); 78EXPORT_SYMBOL(pppox_unbind_sock); 79 80int pppox_ioctl(struct socket* sock, unsigned int cmd, 81 unsigned long arg) 82{ 83 struct sock *sk = sock->sk; 84 struct pppox_opt *po; 85 int err = 0; 86 87 po = sk->protinfo.pppox; 88 89 lock_sock(sk); 90 91 switch (cmd) { 92 case PPPIOCGCHAN:{ 93 int index; 94 err = -ENOTCONN; 95 if (!(sk->state & PPPOX_CONNECTED)) 96 break; 97 98 err = -EINVAL; 99 index = ppp_channel_index(&po->chan); 100 if (put_user(index , (int *) arg)) 101 break; 102 103 err = 0; 104 sk->state |= PPPOX_BOUND; 105 break; 106 } 107 default: 108 if (proto[sk->protocol]->ioctl) 109 err = (*proto[sk->protocol]->ioctl)(sock, cmd, arg); 110 111 break; 112 }; 113 114 release_sock(sk); 115 return err; 116} 117 118EXPORT_SYMBOL(pppox_ioctl); 119 120static int pppox_create(struct socket *sock, int protocol) 121{ 122 int err = 0; 123 124 if (protocol < 0 || protocol > PX_MAX_PROTO) 125 return -EPROTOTYPE; 126 127#ifdef CONFIG_KMOD 128 if (proto[protocol] == NULL) { 129 char buffer[32]; 130 sprintf(buffer, "pppox-proto-%d", protocol); 131 request_module(buffer); 132 } 133#endif 134 if (proto[protocol] == NULL) 135 return -EPROTONOSUPPORT; 136 137 err = (*proto[protocol]->create)(sock); 138 139 if (err == 0) { 140 /* We get to set the ioctl handler. */ 141 /* For everything else, pppox is just a shell. */ 142 sock->ops->ioctl = pppox_ioctl; 143 } 144 145 return err; 146} 147 148static struct net_proto_family pppox_proto_family = { 149 PF_PPPOX, 150 pppox_create 151}; 152 153static int __init pppox_init(void) 154{ 155 int err = 0; 156 157 err = sock_register(&pppox_proto_family); 158 159 return err; 160} 161 162static void __exit pppox_exit(void) 163{ 164 sock_unregister(PF_PPPOX); 165} 166 167module_init(pppox_init); 168module_exit(pppox_exit); 169 170MODULE_AUTHOR("Michal Ostrowski <mostrows@speakeasy.net>"); 171MODULE_DESCRIPTION("PPP over Ethernet driver (generic socket layer)"); 172MODULE_LICENSE("GPL"); 173