18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/** -*- linux-c -*- *********************************************************** 38c2ecf20Sopenharmony_ci * Linux PPP over Ethernet (PPPoX/PPPoE) Sockets 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * PPPoX --- Generic PPP encapsulation socket family 68c2ecf20Sopenharmony_ci * PPPoE --- PPP over Ethernet (RFC 2516) 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Version: 0.7.0 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * 070228 : Fix to allow multiple sessions with same remote MAC and same 118c2ecf20Sopenharmony_ci * session id by including the local device ifindex in the 128c2ecf20Sopenharmony_ci * tuple identifying a session. This also ensures packets can't 138c2ecf20Sopenharmony_ci * be injected into a session from interfaces other than the one 148c2ecf20Sopenharmony_ci * specified by userspace. Florian Zumbiehl <florz@florz.de> 158c2ecf20Sopenharmony_ci * (Oh, BTW, this one is YYMMDD, in case you were wondering ...) 168c2ecf20Sopenharmony_ci * 220102 : Fix module use count on failure in pppoe_create, pppox_sk -acme 178c2ecf20Sopenharmony_ci * 030700 : Fixed connect logic to allow for disconnect. 188c2ecf20Sopenharmony_ci * 270700 : Fixed potential SMP problems; we must protect against 198c2ecf20Sopenharmony_ci * simultaneous invocation of ppp_input 208c2ecf20Sopenharmony_ci * and ppp_unregister_channel. 218c2ecf20Sopenharmony_ci * 040800 : Respect reference count mechanisms on net-devices. 228c2ecf20Sopenharmony_ci * 200800 : fix kfree(skb) in pppoe_rcv (acme) 238c2ecf20Sopenharmony_ci * Module reference count is decremented in the right spot now, 248c2ecf20Sopenharmony_ci * guards against sock_put not actually freeing the sk 258c2ecf20Sopenharmony_ci * in pppoe_release. 268c2ecf20Sopenharmony_ci * 051000 : Initialization cleanup. 278c2ecf20Sopenharmony_ci * 111100 : Fix recvmsg. 288c2ecf20Sopenharmony_ci * 050101 : Fix PADT procesing. 298c2ecf20Sopenharmony_ci * 140501 : Use pppoe_rcv_core to handle all backlog. (Alexey) 308c2ecf20Sopenharmony_ci * 170701 : Do not lock_sock with rwlock held. (DaveM) 318c2ecf20Sopenharmony_ci * Ignore discovery frames if user has socket 328c2ecf20Sopenharmony_ci * locked. (DaveM) 338c2ecf20Sopenharmony_ci * Ignore return value of dev_queue_xmit in __pppoe_xmit 348c2ecf20Sopenharmony_ci * or else we may kfree an SKB twice. (DaveM) 358c2ecf20Sopenharmony_ci * 190701 : When doing copies of skb's in __pppoe_xmit, always delete 368c2ecf20Sopenharmony_ci * the original skb that was passed in on success, never on 378c2ecf20Sopenharmony_ci * failure. Delete the copy of the skb on failure to avoid 388c2ecf20Sopenharmony_ci * a memory leak. 398c2ecf20Sopenharmony_ci * 081001 : Misc. cleanup (licence string, non-blocking, prevent 408c2ecf20Sopenharmony_ci * reference of device on close). 418c2ecf20Sopenharmony_ci * 121301 : New ppp channels interface; cannot unregister a channel 428c2ecf20Sopenharmony_ci * from interrupts. Thus, we mark the socket as a ZOMBIE 438c2ecf20Sopenharmony_ci * and do the unregistration later. 448c2ecf20Sopenharmony_ci * 081002 : seq_file support for proc stuff -acme 458c2ecf20Sopenharmony_ci * 111602 : Merge all 2.4 fixes into 2.5/2.6 tree. Label 2.5/2.6 468c2ecf20Sopenharmony_ci * as version 0.7. Spacing cleanup. 478c2ecf20Sopenharmony_ci * Author: Michal Ostrowski <mostrows@speakeasy.net> 488c2ecf20Sopenharmony_ci * Contributors: 498c2ecf20Sopenharmony_ci * Arnaldo Carvalho de Melo <acme@conectiva.com.br> 508c2ecf20Sopenharmony_ci * David S. Miller (davem@redhat.com) 518c2ecf20Sopenharmony_ci * 528c2ecf20Sopenharmony_ci * License: 538c2ecf20Sopenharmony_ci */ 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#include <linux/string.h> 568c2ecf20Sopenharmony_ci#include <linux/module.h> 578c2ecf20Sopenharmony_ci#include <linux/kernel.h> 588c2ecf20Sopenharmony_ci#include <linux/slab.h> 598c2ecf20Sopenharmony_ci#include <linux/errno.h> 608c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 618c2ecf20Sopenharmony_ci#include <linux/net.h> 628c2ecf20Sopenharmony_ci#include <linux/inetdevice.h> 638c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 648c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 658c2ecf20Sopenharmony_ci#include <linux/init.h> 668c2ecf20Sopenharmony_ci#include <linux/if_ether.h> 678c2ecf20Sopenharmony_ci#include <linux/if_pppox.h> 688c2ecf20Sopenharmony_ci#include <linux/ppp_channel.h> 698c2ecf20Sopenharmony_ci#include <linux/ppp_defs.h> 708c2ecf20Sopenharmony_ci#include <linux/ppp-ioctl.h> 718c2ecf20Sopenharmony_ci#include <linux/notifier.h> 728c2ecf20Sopenharmony_ci#include <linux/file.h> 738c2ecf20Sopenharmony_ci#include <linux/proc_fs.h> 748c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci#include <linux/nsproxy.h> 778c2ecf20Sopenharmony_ci#include <net/net_namespace.h> 788c2ecf20Sopenharmony_ci#include <net/netns/generic.h> 798c2ecf20Sopenharmony_ci#include <net/sock.h> 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci#define PPPOE_HASH_BITS 4 848c2ecf20Sopenharmony_ci#define PPPOE_HASH_SIZE (1 << PPPOE_HASH_BITS) 858c2ecf20Sopenharmony_ci#define PPPOE_HASH_MASK (PPPOE_HASH_SIZE - 1) 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic int __pppoe_xmit(struct sock *sk, struct sk_buff *skb); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic const struct proto_ops pppoe_ops; 908c2ecf20Sopenharmony_cistatic const struct ppp_channel_ops pppoe_chan_ops; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci/* per-net private data for this module */ 938c2ecf20Sopenharmony_cistatic unsigned int pppoe_net_id __read_mostly; 948c2ecf20Sopenharmony_cistruct pppoe_net { 958c2ecf20Sopenharmony_ci /* 968c2ecf20Sopenharmony_ci * we could use _single_ hash table for all 978c2ecf20Sopenharmony_ci * nets by injecting net id into the hash but 988c2ecf20Sopenharmony_ci * it would increase hash chains and add 998c2ecf20Sopenharmony_ci * a few additional math comparations messy 1008c2ecf20Sopenharmony_ci * as well, moreover in case of SMP less locking 1018c2ecf20Sopenharmony_ci * controversy here 1028c2ecf20Sopenharmony_ci */ 1038c2ecf20Sopenharmony_ci struct pppox_sock *hash_table[PPPOE_HASH_SIZE]; 1048c2ecf20Sopenharmony_ci rwlock_t hash_lock; 1058c2ecf20Sopenharmony_ci}; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci/* 1088c2ecf20Sopenharmony_ci * PPPoE could be in the following stages: 1098c2ecf20Sopenharmony_ci * 1) Discovery stage (to obtain remote MAC and Session ID) 1108c2ecf20Sopenharmony_ci * 2) Session stage (MAC and SID are known) 1118c2ecf20Sopenharmony_ci * 1128c2ecf20Sopenharmony_ci * Ethernet frames have a special tag for this but 1138c2ecf20Sopenharmony_ci * we use simpler approach based on session id 1148c2ecf20Sopenharmony_ci */ 1158c2ecf20Sopenharmony_cistatic inline bool stage_session(__be16 sid) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci return sid != 0; 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic inline struct pppoe_net *pppoe_pernet(struct net *net) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci return net_generic(net, pppoe_net_id); 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic inline int cmp_2_addr(struct pppoe_addr *a, struct pppoe_addr *b) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci return a->sid == b->sid && ether_addr_equal(a->remote, b->remote); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic inline int cmp_addr(struct pppoe_addr *a, __be16 sid, char *addr) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci return a->sid == sid && ether_addr_equal(a->remote, addr); 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci#if 8 % PPPOE_HASH_BITS 1368c2ecf20Sopenharmony_ci#error 8 must be a multiple of PPPOE_HASH_BITS 1378c2ecf20Sopenharmony_ci#endif 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic int hash_item(__be16 sid, unsigned char *addr) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci unsigned char hash = 0; 1428c2ecf20Sopenharmony_ci unsigned int i; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci for (i = 0; i < ETH_ALEN; i++) 1458c2ecf20Sopenharmony_ci hash ^= addr[i]; 1468c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(sid_t) * 8; i += 8) 1478c2ecf20Sopenharmony_ci hash ^= (__force __u32)sid >> i; 1488c2ecf20Sopenharmony_ci for (i = 8; (i >>= 1) >= PPPOE_HASH_BITS;) 1498c2ecf20Sopenharmony_ci hash ^= hash >> i; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci return hash & PPPOE_HASH_MASK; 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci/********************************************************************** 1558c2ecf20Sopenharmony_ci * 1568c2ecf20Sopenharmony_ci * Set/get/delete/rehash items (internal versions) 1578c2ecf20Sopenharmony_ci * 1588c2ecf20Sopenharmony_ci **********************************************************************/ 1598c2ecf20Sopenharmony_cistatic struct pppox_sock *__get_item(struct pppoe_net *pn, __be16 sid, 1608c2ecf20Sopenharmony_ci unsigned char *addr, int ifindex) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci int hash = hash_item(sid, addr); 1638c2ecf20Sopenharmony_ci struct pppox_sock *ret; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci ret = pn->hash_table[hash]; 1668c2ecf20Sopenharmony_ci while (ret) { 1678c2ecf20Sopenharmony_ci if (cmp_addr(&ret->pppoe_pa, sid, addr) && 1688c2ecf20Sopenharmony_ci ret->pppoe_ifindex == ifindex) 1698c2ecf20Sopenharmony_ci return ret; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci ret = ret->next; 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci return NULL; 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistatic int __set_item(struct pppoe_net *pn, struct pppox_sock *po) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci int hash = hash_item(po->pppoe_pa.sid, po->pppoe_pa.remote); 1808c2ecf20Sopenharmony_ci struct pppox_sock *ret; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci ret = pn->hash_table[hash]; 1838c2ecf20Sopenharmony_ci while (ret) { 1848c2ecf20Sopenharmony_ci if (cmp_2_addr(&ret->pppoe_pa, &po->pppoe_pa) && 1858c2ecf20Sopenharmony_ci ret->pppoe_ifindex == po->pppoe_ifindex) 1868c2ecf20Sopenharmony_ci return -EALREADY; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci ret = ret->next; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci po->next = pn->hash_table[hash]; 1928c2ecf20Sopenharmony_ci pn->hash_table[hash] = po; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci return 0; 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic void __delete_item(struct pppoe_net *pn, __be16 sid, 1988c2ecf20Sopenharmony_ci char *addr, int ifindex) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci int hash = hash_item(sid, addr); 2018c2ecf20Sopenharmony_ci struct pppox_sock *ret, **src; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci ret = pn->hash_table[hash]; 2048c2ecf20Sopenharmony_ci src = &pn->hash_table[hash]; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci while (ret) { 2078c2ecf20Sopenharmony_ci if (cmp_addr(&ret->pppoe_pa, sid, addr) && 2088c2ecf20Sopenharmony_ci ret->pppoe_ifindex == ifindex) { 2098c2ecf20Sopenharmony_ci *src = ret->next; 2108c2ecf20Sopenharmony_ci break; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci src = &ret->next; 2148c2ecf20Sopenharmony_ci ret = ret->next; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci/********************************************************************** 2198c2ecf20Sopenharmony_ci * 2208c2ecf20Sopenharmony_ci * Set/get/delete/rehash items 2218c2ecf20Sopenharmony_ci * 2228c2ecf20Sopenharmony_ci **********************************************************************/ 2238c2ecf20Sopenharmony_cistatic inline struct pppox_sock *get_item(struct pppoe_net *pn, __be16 sid, 2248c2ecf20Sopenharmony_ci unsigned char *addr, int ifindex) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci struct pppox_sock *po; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci read_lock_bh(&pn->hash_lock); 2298c2ecf20Sopenharmony_ci po = __get_item(pn, sid, addr, ifindex); 2308c2ecf20Sopenharmony_ci if (po) 2318c2ecf20Sopenharmony_ci sock_hold(sk_pppox(po)); 2328c2ecf20Sopenharmony_ci read_unlock_bh(&pn->hash_lock); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci return po; 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic inline struct pppox_sock *get_item_by_addr(struct net *net, 2388c2ecf20Sopenharmony_ci struct sockaddr_pppox *sp) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci struct net_device *dev; 2418c2ecf20Sopenharmony_ci struct pppoe_net *pn; 2428c2ecf20Sopenharmony_ci struct pppox_sock *pppox_sock = NULL; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci int ifindex; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci rcu_read_lock(); 2478c2ecf20Sopenharmony_ci dev = dev_get_by_name_rcu(net, sp->sa_addr.pppoe.dev); 2488c2ecf20Sopenharmony_ci if (dev) { 2498c2ecf20Sopenharmony_ci ifindex = dev->ifindex; 2508c2ecf20Sopenharmony_ci pn = pppoe_pernet(net); 2518c2ecf20Sopenharmony_ci pppox_sock = get_item(pn, sp->sa_addr.pppoe.sid, 2528c2ecf20Sopenharmony_ci sp->sa_addr.pppoe.remote, ifindex); 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci rcu_read_unlock(); 2558c2ecf20Sopenharmony_ci return pppox_sock; 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic inline void delete_item(struct pppoe_net *pn, __be16 sid, 2598c2ecf20Sopenharmony_ci char *addr, int ifindex) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci write_lock_bh(&pn->hash_lock); 2628c2ecf20Sopenharmony_ci __delete_item(pn, sid, addr, ifindex); 2638c2ecf20Sopenharmony_ci write_unlock_bh(&pn->hash_lock); 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci/*************************************************************************** 2678c2ecf20Sopenharmony_ci * 2688c2ecf20Sopenharmony_ci * Handler for device events. 2698c2ecf20Sopenharmony_ci * Certain device events require that sockets be unconnected. 2708c2ecf20Sopenharmony_ci * 2718c2ecf20Sopenharmony_ci **************************************************************************/ 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic void pppoe_flush_dev(struct net_device *dev) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci struct pppoe_net *pn; 2768c2ecf20Sopenharmony_ci int i; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci pn = pppoe_pernet(dev_net(dev)); 2798c2ecf20Sopenharmony_ci write_lock_bh(&pn->hash_lock); 2808c2ecf20Sopenharmony_ci for (i = 0; i < PPPOE_HASH_SIZE; i++) { 2818c2ecf20Sopenharmony_ci struct pppox_sock *po = pn->hash_table[i]; 2828c2ecf20Sopenharmony_ci struct sock *sk; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci while (po) { 2858c2ecf20Sopenharmony_ci while (po && po->pppoe_dev != dev) { 2868c2ecf20Sopenharmony_ci po = po->next; 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci if (!po) 2908c2ecf20Sopenharmony_ci break; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci sk = sk_pppox(po); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci /* We always grab the socket lock, followed by the 2958c2ecf20Sopenharmony_ci * hash_lock, in that order. Since we should hold the 2968c2ecf20Sopenharmony_ci * sock lock while doing any unbinding, we need to 2978c2ecf20Sopenharmony_ci * release the lock we're holding. Hold a reference to 2988c2ecf20Sopenharmony_ci * the sock so it doesn't disappear as we're jumping 2998c2ecf20Sopenharmony_ci * between locks. 3008c2ecf20Sopenharmony_ci */ 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci sock_hold(sk); 3038c2ecf20Sopenharmony_ci write_unlock_bh(&pn->hash_lock); 3048c2ecf20Sopenharmony_ci lock_sock(sk); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci if (po->pppoe_dev == dev && 3078c2ecf20Sopenharmony_ci sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)) { 3088c2ecf20Sopenharmony_ci pppox_unbind_sock(sk); 3098c2ecf20Sopenharmony_ci sk->sk_state_change(sk); 3108c2ecf20Sopenharmony_ci po->pppoe_dev = NULL; 3118c2ecf20Sopenharmony_ci dev_put(dev); 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci release_sock(sk); 3158c2ecf20Sopenharmony_ci sock_put(sk); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci /* Restart the process from the start of the current 3188c2ecf20Sopenharmony_ci * hash chain. We dropped locks so the world may have 3198c2ecf20Sopenharmony_ci * change from underneath us. 3208c2ecf20Sopenharmony_ci */ 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci BUG_ON(pppoe_pernet(dev_net(dev)) == NULL); 3238c2ecf20Sopenharmony_ci write_lock_bh(&pn->hash_lock); 3248c2ecf20Sopenharmony_ci po = pn->hash_table[i]; 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci write_unlock_bh(&pn->hash_lock); 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic int pppoe_device_event(struct notifier_block *this, 3318c2ecf20Sopenharmony_ci unsigned long event, void *ptr) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci struct net_device *dev = netdev_notifier_info_to_dev(ptr); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci /* Only look at sockets that are using this specific device. */ 3368c2ecf20Sopenharmony_ci switch (event) { 3378c2ecf20Sopenharmony_ci case NETDEV_CHANGEADDR: 3388c2ecf20Sopenharmony_ci case NETDEV_CHANGEMTU: 3398c2ecf20Sopenharmony_ci /* A change in mtu or address is a bad thing, requiring 3408c2ecf20Sopenharmony_ci * LCP re-negotiation. 3418c2ecf20Sopenharmony_ci */ 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci case NETDEV_GOING_DOWN: 3448c2ecf20Sopenharmony_ci case NETDEV_DOWN: 3458c2ecf20Sopenharmony_ci /* Find every socket on this device and kill it. */ 3468c2ecf20Sopenharmony_ci pppoe_flush_dev(dev); 3478c2ecf20Sopenharmony_ci break; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci default: 3508c2ecf20Sopenharmony_ci break; 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci return NOTIFY_DONE; 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic struct notifier_block pppoe_notifier = { 3578c2ecf20Sopenharmony_ci .notifier_call = pppoe_device_event, 3588c2ecf20Sopenharmony_ci}; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci/************************************************************************ 3618c2ecf20Sopenharmony_ci * 3628c2ecf20Sopenharmony_ci * Do the real work of receiving a PPPoE Session frame. 3638c2ecf20Sopenharmony_ci * 3648c2ecf20Sopenharmony_ci ***********************************************************************/ 3658c2ecf20Sopenharmony_cistatic int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci struct pppox_sock *po = pppox_sk(sk); 3688c2ecf20Sopenharmony_ci struct pppox_sock *relay_po; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci /* Backlog receive. Semantics of backlog rcv preclude any code from 3718c2ecf20Sopenharmony_ci * executing in lock_sock()/release_sock() bounds; meaning sk->sk_state 3728c2ecf20Sopenharmony_ci * can't change. 3738c2ecf20Sopenharmony_ci */ 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci if (skb->pkt_type == PACKET_OTHERHOST) 3768c2ecf20Sopenharmony_ci goto abort_kfree; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci if (sk->sk_state & PPPOX_BOUND) { 3798c2ecf20Sopenharmony_ci ppp_input(&po->chan, skb); 3808c2ecf20Sopenharmony_ci } else if (sk->sk_state & PPPOX_RELAY) { 3818c2ecf20Sopenharmony_ci relay_po = get_item_by_addr(sock_net(sk), 3828c2ecf20Sopenharmony_ci &po->pppoe_relay); 3838c2ecf20Sopenharmony_ci if (relay_po == NULL) 3848c2ecf20Sopenharmony_ci goto abort_kfree; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci if ((sk_pppox(relay_po)->sk_state & PPPOX_CONNECTED) == 0) 3878c2ecf20Sopenharmony_ci goto abort_put; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci if (!__pppoe_xmit(sk_pppox(relay_po), skb)) 3908c2ecf20Sopenharmony_ci goto abort_put; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci sock_put(sk_pppox(relay_po)); 3938c2ecf20Sopenharmony_ci } else { 3948c2ecf20Sopenharmony_ci if (sock_queue_rcv_skb(sk, skb)) 3958c2ecf20Sopenharmony_ci goto abort_kfree; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci return NET_RX_SUCCESS; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ciabort_put: 4018c2ecf20Sopenharmony_ci sock_put(sk_pppox(relay_po)); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ciabort_kfree: 4048c2ecf20Sopenharmony_ci kfree_skb(skb); 4058c2ecf20Sopenharmony_ci return NET_RX_DROP; 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci/************************************************************************ 4098c2ecf20Sopenharmony_ci * 4108c2ecf20Sopenharmony_ci * Receive wrapper called in BH context. 4118c2ecf20Sopenharmony_ci * 4128c2ecf20Sopenharmony_ci ***********************************************************************/ 4138c2ecf20Sopenharmony_cistatic int pppoe_rcv(struct sk_buff *skb, struct net_device *dev, 4148c2ecf20Sopenharmony_ci struct packet_type *pt, struct net_device *orig_dev) 4158c2ecf20Sopenharmony_ci{ 4168c2ecf20Sopenharmony_ci struct pppoe_hdr *ph; 4178c2ecf20Sopenharmony_ci struct pppox_sock *po; 4188c2ecf20Sopenharmony_ci struct pppoe_net *pn; 4198c2ecf20Sopenharmony_ci int len; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci skb = skb_share_check(skb, GFP_ATOMIC); 4228c2ecf20Sopenharmony_ci if (!skb) 4238c2ecf20Sopenharmony_ci goto out; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci if (skb_mac_header_len(skb) < ETH_HLEN) 4268c2ecf20Sopenharmony_ci goto drop; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr))) 4298c2ecf20Sopenharmony_ci goto drop; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci ph = pppoe_hdr(skb); 4328c2ecf20Sopenharmony_ci len = ntohs(ph->length); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci skb_pull_rcsum(skb, sizeof(*ph)); 4358c2ecf20Sopenharmony_ci if (skb->len < len) 4368c2ecf20Sopenharmony_ci goto drop; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci if (pskb_trim_rcsum(skb, len)) 4398c2ecf20Sopenharmony_ci goto drop; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci ph = pppoe_hdr(skb); 4428c2ecf20Sopenharmony_ci pn = pppoe_pernet(dev_net(dev)); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci /* Note that get_item does a sock_hold(), so sk_pppox(po) 4458c2ecf20Sopenharmony_ci * is known to be safe. 4468c2ecf20Sopenharmony_ci */ 4478c2ecf20Sopenharmony_ci po = get_item(pn, ph->sid, eth_hdr(skb)->h_source, dev->ifindex); 4488c2ecf20Sopenharmony_ci if (!po) 4498c2ecf20Sopenharmony_ci goto drop; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci return sk_receive_skb(sk_pppox(po), skb, 0); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_cidrop: 4548c2ecf20Sopenharmony_ci kfree_skb(skb); 4558c2ecf20Sopenharmony_ciout: 4568c2ecf20Sopenharmony_ci return NET_RX_DROP; 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_cistatic void pppoe_unbind_sock_work(struct work_struct *work) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci struct pppox_sock *po = container_of(work, struct pppox_sock, 4628c2ecf20Sopenharmony_ci proto.pppoe.padt_work); 4638c2ecf20Sopenharmony_ci struct sock *sk = sk_pppox(po); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci lock_sock(sk); 4668c2ecf20Sopenharmony_ci if (po->pppoe_dev) { 4678c2ecf20Sopenharmony_ci dev_put(po->pppoe_dev); 4688c2ecf20Sopenharmony_ci po->pppoe_dev = NULL; 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci pppox_unbind_sock(sk); 4718c2ecf20Sopenharmony_ci release_sock(sk); 4728c2ecf20Sopenharmony_ci sock_put(sk); 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci/************************************************************************ 4768c2ecf20Sopenharmony_ci * 4778c2ecf20Sopenharmony_ci * Receive a PPPoE Discovery frame. 4788c2ecf20Sopenharmony_ci * This is solely for detection of PADT frames 4798c2ecf20Sopenharmony_ci * 4808c2ecf20Sopenharmony_ci ***********************************************************************/ 4818c2ecf20Sopenharmony_cistatic int pppoe_disc_rcv(struct sk_buff *skb, struct net_device *dev, 4828c2ecf20Sopenharmony_ci struct packet_type *pt, struct net_device *orig_dev) 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci struct pppoe_hdr *ph; 4868c2ecf20Sopenharmony_ci struct pppox_sock *po; 4878c2ecf20Sopenharmony_ci struct pppoe_net *pn; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci skb = skb_share_check(skb, GFP_ATOMIC); 4908c2ecf20Sopenharmony_ci if (!skb) 4918c2ecf20Sopenharmony_ci goto out; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci if (skb->pkt_type != PACKET_HOST) 4948c2ecf20Sopenharmony_ci goto abort; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr))) 4978c2ecf20Sopenharmony_ci goto abort; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci ph = pppoe_hdr(skb); 5008c2ecf20Sopenharmony_ci if (ph->code != PADT_CODE) 5018c2ecf20Sopenharmony_ci goto abort; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci pn = pppoe_pernet(dev_net(dev)); 5048c2ecf20Sopenharmony_ci po = get_item(pn, ph->sid, eth_hdr(skb)->h_source, dev->ifindex); 5058c2ecf20Sopenharmony_ci if (po) 5068c2ecf20Sopenharmony_ci if (!schedule_work(&po->proto.pppoe.padt_work)) 5078c2ecf20Sopenharmony_ci sock_put(sk_pppox(po)); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ciabort: 5108c2ecf20Sopenharmony_ci kfree_skb(skb); 5118c2ecf20Sopenharmony_ciout: 5128c2ecf20Sopenharmony_ci return NET_RX_SUCCESS; /* Lies... :-) */ 5138c2ecf20Sopenharmony_ci} 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_cistatic struct packet_type pppoes_ptype __read_mostly = { 5168c2ecf20Sopenharmony_ci .type = cpu_to_be16(ETH_P_PPP_SES), 5178c2ecf20Sopenharmony_ci .func = pppoe_rcv, 5188c2ecf20Sopenharmony_ci}; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cistatic struct packet_type pppoed_ptype __read_mostly = { 5218c2ecf20Sopenharmony_ci .type = cpu_to_be16(ETH_P_PPP_DISC), 5228c2ecf20Sopenharmony_ci .func = pppoe_disc_rcv, 5238c2ecf20Sopenharmony_ci}; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_cistatic struct proto pppoe_sk_proto __read_mostly = { 5268c2ecf20Sopenharmony_ci .name = "PPPOE", 5278c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 5288c2ecf20Sopenharmony_ci .obj_size = sizeof(struct pppox_sock), 5298c2ecf20Sopenharmony_ci}; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci/*********************************************************************** 5328c2ecf20Sopenharmony_ci * 5338c2ecf20Sopenharmony_ci * Initialize a new struct sock. 5348c2ecf20Sopenharmony_ci * 5358c2ecf20Sopenharmony_ci **********************************************************************/ 5368c2ecf20Sopenharmony_cistatic int pppoe_create(struct net *net, struct socket *sock, int kern) 5378c2ecf20Sopenharmony_ci{ 5388c2ecf20Sopenharmony_ci struct sock *sk; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppoe_sk_proto, kern); 5418c2ecf20Sopenharmony_ci if (!sk) 5428c2ecf20Sopenharmony_ci return -ENOMEM; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci sock_init_data(sock, sk); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci sock->state = SS_UNCONNECTED; 5478c2ecf20Sopenharmony_ci sock->ops = &pppoe_ops; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci sk->sk_backlog_rcv = pppoe_rcv_core; 5508c2ecf20Sopenharmony_ci sk->sk_state = PPPOX_NONE; 5518c2ecf20Sopenharmony_ci sk->sk_type = SOCK_STREAM; 5528c2ecf20Sopenharmony_ci sk->sk_family = PF_PPPOX; 5538c2ecf20Sopenharmony_ci sk->sk_protocol = PX_PROTO_OE; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci INIT_WORK(&pppox_sk(sk)->proto.pppoe.padt_work, 5568c2ecf20Sopenharmony_ci pppoe_unbind_sock_work); 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci return 0; 5598c2ecf20Sopenharmony_ci} 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_cistatic int pppoe_release(struct socket *sock) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 5648c2ecf20Sopenharmony_ci struct pppox_sock *po; 5658c2ecf20Sopenharmony_ci struct pppoe_net *pn; 5668c2ecf20Sopenharmony_ci struct net *net = NULL; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci if (!sk) 5698c2ecf20Sopenharmony_ci return 0; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci lock_sock(sk); 5728c2ecf20Sopenharmony_ci if (sock_flag(sk, SOCK_DEAD)) { 5738c2ecf20Sopenharmony_ci release_sock(sk); 5748c2ecf20Sopenharmony_ci return -EBADF; 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci po = pppox_sk(sk); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci if (po->pppoe_dev) { 5808c2ecf20Sopenharmony_ci dev_put(po->pppoe_dev); 5818c2ecf20Sopenharmony_ci po->pppoe_dev = NULL; 5828c2ecf20Sopenharmony_ci } 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci pppox_unbind_sock(sk); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci /* Signal the death of the socket. */ 5878c2ecf20Sopenharmony_ci sk->sk_state = PPPOX_DEAD; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci net = sock_net(sk); 5908c2ecf20Sopenharmony_ci pn = pppoe_pernet(net); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci /* 5938c2ecf20Sopenharmony_ci * protect "po" from concurrent updates 5948c2ecf20Sopenharmony_ci * on pppoe_flush_dev 5958c2ecf20Sopenharmony_ci */ 5968c2ecf20Sopenharmony_ci delete_item(pn, po->pppoe_pa.sid, po->pppoe_pa.remote, 5978c2ecf20Sopenharmony_ci po->pppoe_ifindex); 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci sock_orphan(sk); 6008c2ecf20Sopenharmony_ci sock->sk = NULL; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci skb_queue_purge(&sk->sk_receive_queue); 6038c2ecf20Sopenharmony_ci release_sock(sk); 6048c2ecf20Sopenharmony_ci sock_put(sk); 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci return 0; 6078c2ecf20Sopenharmony_ci} 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_cistatic int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr, 6108c2ecf20Sopenharmony_ci int sockaddr_len, int flags) 6118c2ecf20Sopenharmony_ci{ 6128c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 6138c2ecf20Sopenharmony_ci struct sockaddr_pppox *sp = (struct sockaddr_pppox *)uservaddr; 6148c2ecf20Sopenharmony_ci struct pppox_sock *po = pppox_sk(sk); 6158c2ecf20Sopenharmony_ci struct net_device *dev = NULL; 6168c2ecf20Sopenharmony_ci struct pppoe_net *pn; 6178c2ecf20Sopenharmony_ci struct net *net = NULL; 6188c2ecf20Sopenharmony_ci int error; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci lock_sock(sk); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci error = -EINVAL; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci if (sockaddr_len != sizeof(struct sockaddr_pppox)) 6258c2ecf20Sopenharmony_ci goto end; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci if (sp->sa_protocol != PX_PROTO_OE) 6288c2ecf20Sopenharmony_ci goto end; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci /* Check for already bound sockets */ 6318c2ecf20Sopenharmony_ci error = -EBUSY; 6328c2ecf20Sopenharmony_ci if ((sk->sk_state & PPPOX_CONNECTED) && 6338c2ecf20Sopenharmony_ci stage_session(sp->sa_addr.pppoe.sid)) 6348c2ecf20Sopenharmony_ci goto end; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci /* Check for already disconnected sockets, on attempts to disconnect */ 6378c2ecf20Sopenharmony_ci error = -EALREADY; 6388c2ecf20Sopenharmony_ci if ((sk->sk_state & PPPOX_DEAD) && 6398c2ecf20Sopenharmony_ci !stage_session(sp->sa_addr.pppoe.sid)) 6408c2ecf20Sopenharmony_ci goto end; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci error = 0; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci /* Delete the old binding */ 6458c2ecf20Sopenharmony_ci if (stage_session(po->pppoe_pa.sid)) { 6468c2ecf20Sopenharmony_ci pppox_unbind_sock(sk); 6478c2ecf20Sopenharmony_ci pn = pppoe_pernet(sock_net(sk)); 6488c2ecf20Sopenharmony_ci delete_item(pn, po->pppoe_pa.sid, 6498c2ecf20Sopenharmony_ci po->pppoe_pa.remote, po->pppoe_ifindex); 6508c2ecf20Sopenharmony_ci if (po->pppoe_dev) { 6518c2ecf20Sopenharmony_ci dev_put(po->pppoe_dev); 6528c2ecf20Sopenharmony_ci po->pppoe_dev = NULL; 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci po->pppoe_ifindex = 0; 6568c2ecf20Sopenharmony_ci memset(&po->pppoe_pa, 0, sizeof(po->pppoe_pa)); 6578c2ecf20Sopenharmony_ci memset(&po->pppoe_relay, 0, sizeof(po->pppoe_relay)); 6588c2ecf20Sopenharmony_ci memset(&po->chan, 0, sizeof(po->chan)); 6598c2ecf20Sopenharmony_ci po->next = NULL; 6608c2ecf20Sopenharmony_ci po->num = 0; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci sk->sk_state = PPPOX_NONE; 6638c2ecf20Sopenharmony_ci } 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci /* Re-bind in session stage only */ 6668c2ecf20Sopenharmony_ci if (stage_session(sp->sa_addr.pppoe.sid)) { 6678c2ecf20Sopenharmony_ci error = -ENODEV; 6688c2ecf20Sopenharmony_ci net = sock_net(sk); 6698c2ecf20Sopenharmony_ci dev = dev_get_by_name(net, sp->sa_addr.pppoe.dev); 6708c2ecf20Sopenharmony_ci if (!dev) 6718c2ecf20Sopenharmony_ci goto err_put; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci po->pppoe_dev = dev; 6748c2ecf20Sopenharmony_ci po->pppoe_ifindex = dev->ifindex; 6758c2ecf20Sopenharmony_ci pn = pppoe_pernet(net); 6768c2ecf20Sopenharmony_ci if (!(dev->flags & IFF_UP)) { 6778c2ecf20Sopenharmony_ci goto err_put; 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci memcpy(&po->pppoe_pa, 6818c2ecf20Sopenharmony_ci &sp->sa_addr.pppoe, 6828c2ecf20Sopenharmony_ci sizeof(struct pppoe_addr)); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci write_lock_bh(&pn->hash_lock); 6858c2ecf20Sopenharmony_ci error = __set_item(pn, po); 6868c2ecf20Sopenharmony_ci write_unlock_bh(&pn->hash_lock); 6878c2ecf20Sopenharmony_ci if (error < 0) 6888c2ecf20Sopenharmony_ci goto err_put; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci po->chan.hdrlen = (sizeof(struct pppoe_hdr) + 6918c2ecf20Sopenharmony_ci dev->hard_header_len); 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci po->chan.mtu = dev->mtu - sizeof(struct pppoe_hdr) - 2; 6948c2ecf20Sopenharmony_ci po->chan.private = sk; 6958c2ecf20Sopenharmony_ci po->chan.ops = &pppoe_chan_ops; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci error = ppp_register_net_channel(dev_net(dev), &po->chan); 6988c2ecf20Sopenharmony_ci if (error) { 6998c2ecf20Sopenharmony_ci delete_item(pn, po->pppoe_pa.sid, 7008c2ecf20Sopenharmony_ci po->pppoe_pa.remote, po->pppoe_ifindex); 7018c2ecf20Sopenharmony_ci goto err_put; 7028c2ecf20Sopenharmony_ci } 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci sk->sk_state = PPPOX_CONNECTED; 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci po->num = sp->sa_addr.pppoe.sid; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ciend: 7108c2ecf20Sopenharmony_ci release_sock(sk); 7118c2ecf20Sopenharmony_ci return error; 7128c2ecf20Sopenharmony_cierr_put: 7138c2ecf20Sopenharmony_ci if (po->pppoe_dev) { 7148c2ecf20Sopenharmony_ci dev_put(po->pppoe_dev); 7158c2ecf20Sopenharmony_ci po->pppoe_dev = NULL; 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci goto end; 7188c2ecf20Sopenharmony_ci} 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_cistatic int pppoe_getname(struct socket *sock, struct sockaddr *uaddr, 7218c2ecf20Sopenharmony_ci int peer) 7228c2ecf20Sopenharmony_ci{ 7238c2ecf20Sopenharmony_ci int len = sizeof(struct sockaddr_pppox); 7248c2ecf20Sopenharmony_ci struct sockaddr_pppox sp; 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci sp.sa_family = AF_PPPOX; 7278c2ecf20Sopenharmony_ci sp.sa_protocol = PX_PROTO_OE; 7288c2ecf20Sopenharmony_ci memcpy(&sp.sa_addr.pppoe, &pppox_sk(sock->sk)->pppoe_pa, 7298c2ecf20Sopenharmony_ci sizeof(struct pppoe_addr)); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci memcpy(uaddr, &sp, len); 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci return len; 7348c2ecf20Sopenharmony_ci} 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_cistatic int pppoe_ioctl(struct socket *sock, unsigned int cmd, 7378c2ecf20Sopenharmony_ci unsigned long arg) 7388c2ecf20Sopenharmony_ci{ 7398c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 7408c2ecf20Sopenharmony_ci struct pppox_sock *po = pppox_sk(sk); 7418c2ecf20Sopenharmony_ci int val; 7428c2ecf20Sopenharmony_ci int err; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci switch (cmd) { 7458c2ecf20Sopenharmony_ci case PPPIOCGMRU: 7468c2ecf20Sopenharmony_ci err = -ENXIO; 7478c2ecf20Sopenharmony_ci if (!(sk->sk_state & PPPOX_CONNECTED)) 7488c2ecf20Sopenharmony_ci break; 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci err = -EFAULT; 7518c2ecf20Sopenharmony_ci if (put_user(po->pppoe_dev->mtu - 7528c2ecf20Sopenharmony_ci sizeof(struct pppoe_hdr) - 7538c2ecf20Sopenharmony_ci PPP_HDRLEN, 7548c2ecf20Sopenharmony_ci (int __user *)arg)) 7558c2ecf20Sopenharmony_ci break; 7568c2ecf20Sopenharmony_ci err = 0; 7578c2ecf20Sopenharmony_ci break; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci case PPPIOCSMRU: 7608c2ecf20Sopenharmony_ci err = -ENXIO; 7618c2ecf20Sopenharmony_ci if (!(sk->sk_state & PPPOX_CONNECTED)) 7628c2ecf20Sopenharmony_ci break; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci err = -EFAULT; 7658c2ecf20Sopenharmony_ci if (get_user(val, (int __user *)arg)) 7668c2ecf20Sopenharmony_ci break; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci if (val < (po->pppoe_dev->mtu 7698c2ecf20Sopenharmony_ci - sizeof(struct pppoe_hdr) 7708c2ecf20Sopenharmony_ci - PPP_HDRLEN)) 7718c2ecf20Sopenharmony_ci err = 0; 7728c2ecf20Sopenharmony_ci else 7738c2ecf20Sopenharmony_ci err = -EINVAL; 7748c2ecf20Sopenharmony_ci break; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci case PPPIOCSFLAGS: 7778c2ecf20Sopenharmony_ci err = -EFAULT; 7788c2ecf20Sopenharmony_ci if (get_user(val, (int __user *)arg)) 7798c2ecf20Sopenharmony_ci break; 7808c2ecf20Sopenharmony_ci err = 0; 7818c2ecf20Sopenharmony_ci break; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci case PPPOEIOCSFWD: 7848c2ecf20Sopenharmony_ci { 7858c2ecf20Sopenharmony_ci struct pppox_sock *relay_po; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci err = -EBUSY; 7888c2ecf20Sopenharmony_ci if (sk->sk_state & (PPPOX_BOUND | PPPOX_DEAD)) 7898c2ecf20Sopenharmony_ci break; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci err = -ENOTCONN; 7928c2ecf20Sopenharmony_ci if (!(sk->sk_state & PPPOX_CONNECTED)) 7938c2ecf20Sopenharmony_ci break; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci /* PPPoE address from the user specifies an outbound 7968c2ecf20Sopenharmony_ci PPPoE address which frames are forwarded to */ 7978c2ecf20Sopenharmony_ci err = -EFAULT; 7988c2ecf20Sopenharmony_ci if (copy_from_user(&po->pppoe_relay, 7998c2ecf20Sopenharmony_ci (void __user *)arg, 8008c2ecf20Sopenharmony_ci sizeof(struct sockaddr_pppox))) 8018c2ecf20Sopenharmony_ci break; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci err = -EINVAL; 8048c2ecf20Sopenharmony_ci if (po->pppoe_relay.sa_family != AF_PPPOX || 8058c2ecf20Sopenharmony_ci po->pppoe_relay.sa_protocol != PX_PROTO_OE) 8068c2ecf20Sopenharmony_ci break; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci /* Check that the socket referenced by the address 8098c2ecf20Sopenharmony_ci actually exists. */ 8108c2ecf20Sopenharmony_ci relay_po = get_item_by_addr(sock_net(sk), &po->pppoe_relay); 8118c2ecf20Sopenharmony_ci if (!relay_po) 8128c2ecf20Sopenharmony_ci break; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci sock_put(sk_pppox(relay_po)); 8158c2ecf20Sopenharmony_ci sk->sk_state |= PPPOX_RELAY; 8168c2ecf20Sopenharmony_ci err = 0; 8178c2ecf20Sopenharmony_ci break; 8188c2ecf20Sopenharmony_ci } 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci case PPPOEIOCDFWD: 8218c2ecf20Sopenharmony_ci err = -EALREADY; 8228c2ecf20Sopenharmony_ci if (!(sk->sk_state & PPPOX_RELAY)) 8238c2ecf20Sopenharmony_ci break; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci sk->sk_state &= ~PPPOX_RELAY; 8268c2ecf20Sopenharmony_ci err = 0; 8278c2ecf20Sopenharmony_ci break; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci default: 8308c2ecf20Sopenharmony_ci err = -ENOTTY; 8318c2ecf20Sopenharmony_ci } 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci return err; 8348c2ecf20Sopenharmony_ci} 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_cistatic int pppoe_sendmsg(struct socket *sock, struct msghdr *m, 8378c2ecf20Sopenharmony_ci size_t total_len) 8388c2ecf20Sopenharmony_ci{ 8398c2ecf20Sopenharmony_ci struct sk_buff *skb; 8408c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 8418c2ecf20Sopenharmony_ci struct pppox_sock *po = pppox_sk(sk); 8428c2ecf20Sopenharmony_ci int error; 8438c2ecf20Sopenharmony_ci struct pppoe_hdr hdr; 8448c2ecf20Sopenharmony_ci struct pppoe_hdr *ph; 8458c2ecf20Sopenharmony_ci struct net_device *dev; 8468c2ecf20Sopenharmony_ci char *start; 8478c2ecf20Sopenharmony_ci int hlen; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci lock_sock(sk); 8508c2ecf20Sopenharmony_ci if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) { 8518c2ecf20Sopenharmony_ci error = -ENOTCONN; 8528c2ecf20Sopenharmony_ci goto end; 8538c2ecf20Sopenharmony_ci } 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci hdr.ver = 1; 8568c2ecf20Sopenharmony_ci hdr.type = 1; 8578c2ecf20Sopenharmony_ci hdr.code = 0; 8588c2ecf20Sopenharmony_ci hdr.sid = po->num; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci dev = po->pppoe_dev; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci error = -EMSGSIZE; 8638c2ecf20Sopenharmony_ci if (total_len > (dev->mtu + dev->hard_header_len)) 8648c2ecf20Sopenharmony_ci goto end; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci hlen = LL_RESERVED_SPACE(dev); 8678c2ecf20Sopenharmony_ci skb = sock_wmalloc(sk, hlen + sizeof(*ph) + total_len + 8688c2ecf20Sopenharmony_ci dev->needed_tailroom, 0, GFP_KERNEL); 8698c2ecf20Sopenharmony_ci if (!skb) { 8708c2ecf20Sopenharmony_ci error = -ENOMEM; 8718c2ecf20Sopenharmony_ci goto end; 8728c2ecf20Sopenharmony_ci } 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci /* Reserve space for headers. */ 8758c2ecf20Sopenharmony_ci skb_reserve(skb, hlen); 8768c2ecf20Sopenharmony_ci skb_reset_network_header(skb); 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci skb->dev = dev; 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci skb->priority = sk->sk_priority; 8818c2ecf20Sopenharmony_ci skb->protocol = cpu_to_be16(ETH_P_PPP_SES); 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci ph = skb_put(skb, total_len + sizeof(struct pppoe_hdr)); 8848c2ecf20Sopenharmony_ci start = (char *)&ph->tag[0]; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci error = memcpy_from_msg(start, m, total_len); 8878c2ecf20Sopenharmony_ci if (error < 0) { 8888c2ecf20Sopenharmony_ci kfree_skb(skb); 8898c2ecf20Sopenharmony_ci goto end; 8908c2ecf20Sopenharmony_ci } 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci error = total_len; 8938c2ecf20Sopenharmony_ci dev_hard_header(skb, dev, ETH_P_PPP_SES, 8948c2ecf20Sopenharmony_ci po->pppoe_pa.remote, NULL, total_len); 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci memcpy(ph, &hdr, sizeof(struct pppoe_hdr)); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci ph->length = htons(total_len); 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci dev_queue_xmit(skb); 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ciend: 9038c2ecf20Sopenharmony_ci release_sock(sk); 9048c2ecf20Sopenharmony_ci return error; 9058c2ecf20Sopenharmony_ci} 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci/************************************************************************ 9088c2ecf20Sopenharmony_ci * 9098c2ecf20Sopenharmony_ci * xmit function for internal use. 9108c2ecf20Sopenharmony_ci * 9118c2ecf20Sopenharmony_ci ***********************************************************************/ 9128c2ecf20Sopenharmony_cistatic int __pppoe_xmit(struct sock *sk, struct sk_buff *skb) 9138c2ecf20Sopenharmony_ci{ 9148c2ecf20Sopenharmony_ci struct pppox_sock *po = pppox_sk(sk); 9158c2ecf20Sopenharmony_ci struct net_device *dev = po->pppoe_dev; 9168c2ecf20Sopenharmony_ci struct pppoe_hdr *ph; 9178c2ecf20Sopenharmony_ci int data_len = skb->len; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci /* The higher-level PPP code (ppp_unregister_channel()) ensures the PPP 9208c2ecf20Sopenharmony_ci * xmit operations conclude prior to an unregistration call. Thus 9218c2ecf20Sopenharmony_ci * sk->sk_state cannot change, so we don't need to do lock_sock(). 9228c2ecf20Sopenharmony_ci * But, we also can't do a lock_sock since that introduces a potential 9238c2ecf20Sopenharmony_ci * deadlock as we'd reverse the lock ordering used when calling 9248c2ecf20Sopenharmony_ci * ppp_unregister_channel(). 9258c2ecf20Sopenharmony_ci */ 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) 9288c2ecf20Sopenharmony_ci goto abort; 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci if (!dev) 9318c2ecf20Sopenharmony_ci goto abort; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci /* Copy the data if there is no space for the header or if it's 9348c2ecf20Sopenharmony_ci * read-only. 9358c2ecf20Sopenharmony_ci */ 9368c2ecf20Sopenharmony_ci if (skb_cow_head(skb, LL_RESERVED_SPACE(dev) + sizeof(*ph))) 9378c2ecf20Sopenharmony_ci goto abort; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci __skb_push(skb, sizeof(*ph)); 9408c2ecf20Sopenharmony_ci skb_reset_network_header(skb); 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci ph = pppoe_hdr(skb); 9438c2ecf20Sopenharmony_ci ph->ver = 1; 9448c2ecf20Sopenharmony_ci ph->type = 1; 9458c2ecf20Sopenharmony_ci ph->code = 0; 9468c2ecf20Sopenharmony_ci ph->sid = po->num; 9478c2ecf20Sopenharmony_ci ph->length = htons(data_len); 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci skb->protocol = cpu_to_be16(ETH_P_PPP_SES); 9508c2ecf20Sopenharmony_ci skb->dev = dev; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci dev_hard_header(skb, dev, ETH_P_PPP_SES, 9538c2ecf20Sopenharmony_ci po->pppoe_pa.remote, NULL, data_len); 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci dev_queue_xmit(skb); 9568c2ecf20Sopenharmony_ci return 1; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ciabort: 9598c2ecf20Sopenharmony_ci kfree_skb(skb); 9608c2ecf20Sopenharmony_ci return 1; 9618c2ecf20Sopenharmony_ci} 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci/************************************************************************ 9648c2ecf20Sopenharmony_ci * 9658c2ecf20Sopenharmony_ci * xmit function called by generic PPP driver 9668c2ecf20Sopenharmony_ci * sends PPP frame over PPPoE socket 9678c2ecf20Sopenharmony_ci * 9688c2ecf20Sopenharmony_ci ***********************************************************************/ 9698c2ecf20Sopenharmony_cistatic int pppoe_xmit(struct ppp_channel *chan, struct sk_buff *skb) 9708c2ecf20Sopenharmony_ci{ 9718c2ecf20Sopenharmony_ci struct sock *sk = (struct sock *)chan->private; 9728c2ecf20Sopenharmony_ci return __pppoe_xmit(sk, skb); 9738c2ecf20Sopenharmony_ci} 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_cistatic const struct ppp_channel_ops pppoe_chan_ops = { 9768c2ecf20Sopenharmony_ci .start_xmit = pppoe_xmit, 9778c2ecf20Sopenharmony_ci}; 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_cistatic int pppoe_recvmsg(struct socket *sock, struct msghdr *m, 9808c2ecf20Sopenharmony_ci size_t total_len, int flags) 9818c2ecf20Sopenharmony_ci{ 9828c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 9838c2ecf20Sopenharmony_ci struct sk_buff *skb; 9848c2ecf20Sopenharmony_ci int error = 0; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci if (sk->sk_state & PPPOX_BOUND) { 9878c2ecf20Sopenharmony_ci error = -EIO; 9888c2ecf20Sopenharmony_ci goto end; 9898c2ecf20Sopenharmony_ci } 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, 9928c2ecf20Sopenharmony_ci flags & MSG_DONTWAIT, &error); 9938c2ecf20Sopenharmony_ci if (error < 0) 9948c2ecf20Sopenharmony_ci goto end; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci if (skb) { 9978c2ecf20Sopenharmony_ci total_len = min_t(size_t, total_len, skb->len); 9988c2ecf20Sopenharmony_ci error = skb_copy_datagram_msg(skb, 0, m, total_len); 9998c2ecf20Sopenharmony_ci if (error == 0) { 10008c2ecf20Sopenharmony_ci consume_skb(skb); 10018c2ecf20Sopenharmony_ci return total_len; 10028c2ecf20Sopenharmony_ci } 10038c2ecf20Sopenharmony_ci } 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci kfree_skb(skb); 10068c2ecf20Sopenharmony_ciend: 10078c2ecf20Sopenharmony_ci return error; 10088c2ecf20Sopenharmony_ci} 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS 10118c2ecf20Sopenharmony_cistatic int pppoe_seq_show(struct seq_file *seq, void *v) 10128c2ecf20Sopenharmony_ci{ 10138c2ecf20Sopenharmony_ci struct pppox_sock *po; 10148c2ecf20Sopenharmony_ci char *dev_name; 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci if (v == SEQ_START_TOKEN) { 10178c2ecf20Sopenharmony_ci seq_puts(seq, "Id Address Device\n"); 10188c2ecf20Sopenharmony_ci goto out; 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci po = v; 10228c2ecf20Sopenharmony_ci dev_name = po->pppoe_pa.dev; 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci seq_printf(seq, "%08X %pM %8s\n", 10258c2ecf20Sopenharmony_ci po->pppoe_pa.sid, po->pppoe_pa.remote, dev_name); 10268c2ecf20Sopenharmony_ciout: 10278c2ecf20Sopenharmony_ci return 0; 10288c2ecf20Sopenharmony_ci} 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_cistatic inline struct pppox_sock *pppoe_get_idx(struct pppoe_net *pn, loff_t pos) 10318c2ecf20Sopenharmony_ci{ 10328c2ecf20Sopenharmony_ci struct pppox_sock *po; 10338c2ecf20Sopenharmony_ci int i; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci for (i = 0; i < PPPOE_HASH_SIZE; i++) { 10368c2ecf20Sopenharmony_ci po = pn->hash_table[i]; 10378c2ecf20Sopenharmony_ci while (po) { 10388c2ecf20Sopenharmony_ci if (!pos--) 10398c2ecf20Sopenharmony_ci goto out; 10408c2ecf20Sopenharmony_ci po = po->next; 10418c2ecf20Sopenharmony_ci } 10428c2ecf20Sopenharmony_ci } 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ciout: 10458c2ecf20Sopenharmony_ci return po; 10468c2ecf20Sopenharmony_ci} 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_cistatic void *pppoe_seq_start(struct seq_file *seq, loff_t *pos) 10498c2ecf20Sopenharmony_ci __acquires(pn->hash_lock) 10508c2ecf20Sopenharmony_ci{ 10518c2ecf20Sopenharmony_ci struct pppoe_net *pn = pppoe_pernet(seq_file_net(seq)); 10528c2ecf20Sopenharmony_ci loff_t l = *pos; 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci read_lock_bh(&pn->hash_lock); 10558c2ecf20Sopenharmony_ci return l ? pppoe_get_idx(pn, --l) : SEQ_START_TOKEN; 10568c2ecf20Sopenharmony_ci} 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_cistatic void *pppoe_seq_next(struct seq_file *seq, void *v, loff_t *pos) 10598c2ecf20Sopenharmony_ci{ 10608c2ecf20Sopenharmony_ci struct pppoe_net *pn = pppoe_pernet(seq_file_net(seq)); 10618c2ecf20Sopenharmony_ci struct pppox_sock *po; 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci ++*pos; 10648c2ecf20Sopenharmony_ci if (v == SEQ_START_TOKEN) { 10658c2ecf20Sopenharmony_ci po = pppoe_get_idx(pn, 0); 10668c2ecf20Sopenharmony_ci goto out; 10678c2ecf20Sopenharmony_ci } 10688c2ecf20Sopenharmony_ci po = v; 10698c2ecf20Sopenharmony_ci if (po->next) 10708c2ecf20Sopenharmony_ci po = po->next; 10718c2ecf20Sopenharmony_ci else { 10728c2ecf20Sopenharmony_ci int hash = hash_item(po->pppoe_pa.sid, po->pppoe_pa.remote); 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci po = NULL; 10758c2ecf20Sopenharmony_ci while (++hash < PPPOE_HASH_SIZE) { 10768c2ecf20Sopenharmony_ci po = pn->hash_table[hash]; 10778c2ecf20Sopenharmony_ci if (po) 10788c2ecf20Sopenharmony_ci break; 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci } 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ciout: 10838c2ecf20Sopenharmony_ci return po; 10848c2ecf20Sopenharmony_ci} 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_cistatic void pppoe_seq_stop(struct seq_file *seq, void *v) 10878c2ecf20Sopenharmony_ci __releases(pn->hash_lock) 10888c2ecf20Sopenharmony_ci{ 10898c2ecf20Sopenharmony_ci struct pppoe_net *pn = pppoe_pernet(seq_file_net(seq)); 10908c2ecf20Sopenharmony_ci read_unlock_bh(&pn->hash_lock); 10918c2ecf20Sopenharmony_ci} 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_cistatic const struct seq_operations pppoe_seq_ops = { 10948c2ecf20Sopenharmony_ci .start = pppoe_seq_start, 10958c2ecf20Sopenharmony_ci .next = pppoe_seq_next, 10968c2ecf20Sopenharmony_ci .stop = pppoe_seq_stop, 10978c2ecf20Sopenharmony_ci .show = pppoe_seq_show, 10988c2ecf20Sopenharmony_ci}; 10998c2ecf20Sopenharmony_ci#endif /* CONFIG_PROC_FS */ 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_cistatic const struct proto_ops pppoe_ops = { 11028c2ecf20Sopenharmony_ci .family = AF_PPPOX, 11038c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 11048c2ecf20Sopenharmony_ci .release = pppoe_release, 11058c2ecf20Sopenharmony_ci .bind = sock_no_bind, 11068c2ecf20Sopenharmony_ci .connect = pppoe_connect, 11078c2ecf20Sopenharmony_ci .socketpair = sock_no_socketpair, 11088c2ecf20Sopenharmony_ci .accept = sock_no_accept, 11098c2ecf20Sopenharmony_ci .getname = pppoe_getname, 11108c2ecf20Sopenharmony_ci .poll = datagram_poll, 11118c2ecf20Sopenharmony_ci .listen = sock_no_listen, 11128c2ecf20Sopenharmony_ci .shutdown = sock_no_shutdown, 11138c2ecf20Sopenharmony_ci .sendmsg = pppoe_sendmsg, 11148c2ecf20Sopenharmony_ci .recvmsg = pppoe_recvmsg, 11158c2ecf20Sopenharmony_ci .mmap = sock_no_mmap, 11168c2ecf20Sopenharmony_ci .ioctl = pppox_ioctl, 11178c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 11188c2ecf20Sopenharmony_ci .compat_ioctl = pppox_compat_ioctl, 11198c2ecf20Sopenharmony_ci#endif 11208c2ecf20Sopenharmony_ci}; 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_cistatic const struct pppox_proto pppoe_proto = { 11238c2ecf20Sopenharmony_ci .create = pppoe_create, 11248c2ecf20Sopenharmony_ci .ioctl = pppoe_ioctl, 11258c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 11268c2ecf20Sopenharmony_ci}; 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_cistatic __net_init int pppoe_init_net(struct net *net) 11298c2ecf20Sopenharmony_ci{ 11308c2ecf20Sopenharmony_ci struct pppoe_net *pn = pppoe_pernet(net); 11318c2ecf20Sopenharmony_ci struct proc_dir_entry *pde; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci rwlock_init(&pn->hash_lock); 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci pde = proc_create_net("pppoe", 0444, net->proc_net, 11368c2ecf20Sopenharmony_ci &pppoe_seq_ops, sizeof(struct seq_net_private)); 11378c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS 11388c2ecf20Sopenharmony_ci if (!pde) 11398c2ecf20Sopenharmony_ci return -ENOMEM; 11408c2ecf20Sopenharmony_ci#endif 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci return 0; 11438c2ecf20Sopenharmony_ci} 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_cistatic __net_exit void pppoe_exit_net(struct net *net) 11468c2ecf20Sopenharmony_ci{ 11478c2ecf20Sopenharmony_ci remove_proc_entry("pppoe", net->proc_net); 11488c2ecf20Sopenharmony_ci} 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_cistatic struct pernet_operations pppoe_net_ops = { 11518c2ecf20Sopenharmony_ci .init = pppoe_init_net, 11528c2ecf20Sopenharmony_ci .exit = pppoe_exit_net, 11538c2ecf20Sopenharmony_ci .id = &pppoe_net_id, 11548c2ecf20Sopenharmony_ci .size = sizeof(struct pppoe_net), 11558c2ecf20Sopenharmony_ci}; 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_cistatic int __init pppoe_init(void) 11588c2ecf20Sopenharmony_ci{ 11598c2ecf20Sopenharmony_ci int err; 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci err = register_pernet_device(&pppoe_net_ops); 11628c2ecf20Sopenharmony_ci if (err) 11638c2ecf20Sopenharmony_ci goto out; 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci err = proto_register(&pppoe_sk_proto, 0); 11668c2ecf20Sopenharmony_ci if (err) 11678c2ecf20Sopenharmony_ci goto out_unregister_net_ops; 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci err = register_pppox_proto(PX_PROTO_OE, &pppoe_proto); 11708c2ecf20Sopenharmony_ci if (err) 11718c2ecf20Sopenharmony_ci goto out_unregister_pppoe_proto; 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci dev_add_pack(&pppoes_ptype); 11748c2ecf20Sopenharmony_ci dev_add_pack(&pppoed_ptype); 11758c2ecf20Sopenharmony_ci register_netdevice_notifier(&pppoe_notifier); 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci return 0; 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ciout_unregister_pppoe_proto: 11808c2ecf20Sopenharmony_ci proto_unregister(&pppoe_sk_proto); 11818c2ecf20Sopenharmony_ciout_unregister_net_ops: 11828c2ecf20Sopenharmony_ci unregister_pernet_device(&pppoe_net_ops); 11838c2ecf20Sopenharmony_ciout: 11848c2ecf20Sopenharmony_ci return err; 11858c2ecf20Sopenharmony_ci} 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_cistatic void __exit pppoe_exit(void) 11888c2ecf20Sopenharmony_ci{ 11898c2ecf20Sopenharmony_ci unregister_netdevice_notifier(&pppoe_notifier); 11908c2ecf20Sopenharmony_ci dev_remove_pack(&pppoed_ptype); 11918c2ecf20Sopenharmony_ci dev_remove_pack(&pppoes_ptype); 11928c2ecf20Sopenharmony_ci unregister_pppox_proto(PX_PROTO_OE); 11938c2ecf20Sopenharmony_ci proto_unregister(&pppoe_sk_proto); 11948c2ecf20Sopenharmony_ci unregister_pernet_device(&pppoe_net_ops); 11958c2ecf20Sopenharmony_ci} 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_cimodule_init(pppoe_init); 11988c2ecf20Sopenharmony_cimodule_exit(pppoe_exit); 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ciMODULE_AUTHOR("Michal Ostrowski <mostrows@speakeasy.net>"); 12018c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("PPP over Ethernet driver"); 12028c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 12038c2ecf20Sopenharmony_ciMODULE_ALIAS_NET_PF_PROTO(PF_PPPOX, PX_PROTO_OE); 1204