--- zzzz-none-000/linux-3.10.107/drivers/net/ppp/pppoe.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/net/ppp/pppoe.c 2021-02-04 17:41:59.000000000 +0000 @@ -1,3 +1,19 @@ +/* + ************************************************************************** + * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ************************************************************************** + */ + /** -*- linux-c -*- *********************************************************** * Linux PPP over Ethernet (PPPoX/PPPoE) Sockets * @@ -67,6 +83,7 @@ #include #include #include +#include #include #include #include @@ -92,7 +109,7 @@ static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb); static const struct proto_ops pppoe_ops; -static const struct ppp_channel_ops pppoe_chan_ops; +static const struct pppoe_channel_ops pppoe_chan_ops; /* per-net private data for this module */ static int pppoe_net_id __read_mostly; @@ -131,12 +148,12 @@ static inline int cmp_2_addr(struct pppoe_addr *a, struct pppoe_addr *b) { - return a->sid == b->sid && !memcmp(a->remote, b->remote, ETH_ALEN); + return a->sid == b->sid && ether_addr_equal(a->remote, b->remote); } static inline int cmp_addr(struct pppoe_addr *a, __be16 sid, char *addr) { - return a->sid == sid && !memcmp(a->remote, addr, ETH_ALEN); + return a->sid == sid && ether_addr_equal(a->remote, addr); } #if 8 % PPPOE_HASH_BITS @@ -337,7 +354,7 @@ static int pppoe_device_event(struct notifier_block *this, unsigned long event, void *ptr) { - struct net_device *dev = (struct net_device *)ptr; + struct net_device *dev = netdev_notifier_info_to_dev(ptr); /* Only look at sockets that are using this specific device. */ switch (event) { @@ -379,6 +396,9 @@ * can't change. */ + if (skb->pkt_type == PACKET_OTHERHOST) + goto abort_kfree; + if (sk->sk_state & PPPOX_BOUND) { ppp_input(&po->chan, skb); } else if (sk->sk_state & PPPOX_RELAY) { @@ -392,6 +412,8 @@ if (!__pppoe_xmit(sk_pppox(relay_po), skb)) goto abort_put; + + sock_put(sk_pppox(relay_po)); } else { if (sock_queue_rcv_skb(sk, skb)) goto abort_kfree; @@ -454,6 +476,22 @@ return NET_RX_DROP; } +static void pppoe_unbind_sock_work(struct work_struct *work) +{ + struct pppox_sock *po = container_of(work, struct pppox_sock, + proto.pppoe.padt_work); + struct sock *sk = sk_pppox(po); + + lock_sock(sk); + if (po->pppoe_dev) { + dev_put(po->pppoe_dev); + po->pppoe_dev = NULL; + } + pppox_unbind_sock(sk); + release_sock(sk); + sock_put(sk); +} + /************************************************************************ * * Receive a PPPoE Discovery frame. @@ -499,7 +537,8 @@ } bh_unlock_sock(sk); - sock_put(sk); + if (!schedule_work(&po->proto.pppoe.padt_work)) + sock_put(sk); } abort: @@ -529,11 +568,11 @@ * Initialize a new struct sock. * **********************************************************************/ -static int pppoe_create(struct net *net, struct socket *sock) +static int pppoe_create(struct net *net, struct socket *sock, int kern) { struct sock *sk; - sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppoe_sk_proto); + sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppoe_sk_proto, kern); if (!sk) return -ENOMEM; @@ -548,6 +587,9 @@ sk->sk_family = PF_PPPOX; sk->sk_protocol = PX_PROTO_OE; + INIT_WORK(&pppox_sk(sk)->proto.pppoe.padt_work, + pppoe_unbind_sock_work); + return 0; } @@ -634,6 +676,7 @@ if (stage_session(po->pppoe_pa.sid)) { pppox_unbind_sock(sk); pn = pppoe_pernet(sock_net(sk)); + delete_item(pn, po->pppoe_pa.sid, po->pppoe_pa.remote, po->pppoe_ifindex); if (po->pppoe_dev) { @@ -641,8 +684,13 @@ po->pppoe_dev = NULL; } - memset(sk_pppox(po) + 1, 0, - sizeof(struct pppox_sock) - sizeof(struct sock)); + po->pppoe_ifindex = 0; + memset(&po->pppoe_pa, 0, sizeof(po->pppoe_pa)); + memset(&po->pppoe_relay, 0, sizeof(po->pppoe_relay)); + memset(&po->chan, 0, sizeof(po->chan)); + po->next = NULL; + po->num = 0; + sk->sk_state = PPPOX_NONE; } @@ -676,7 +724,7 @@ po->chan.mtu = dev->mtu - sizeof(struct pppoe_hdr) - 2; po->chan.private = sk; - po->chan.ops = &pppoe_chan_ops; + po->chan.ops = (struct ppp_channel_ops *)&pppoe_chan_ops; error = ppp_register_net_channel(dev_net(dev), &po->chan); if (error) { @@ -819,8 +867,8 @@ return err; } -static int pppoe_sendmsg(struct kiocb *iocb, struct socket *sock, - struct msghdr *m, size_t total_len) +static int pppoe_sendmsg(struct socket *sock, struct msghdr *m, + size_t total_len) { struct sk_buff *skb; struct sock *sk = sock->sk; @@ -849,7 +897,7 @@ goto end; - skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32, + skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32 + NET_SKB_PAD, 0, GFP_KERNEL); if (!skb) { error = -ENOMEM; @@ -857,7 +905,7 @@ } /* Reserve space for headers. */ - skb_reserve(skb, dev->hard_header_len); + skb_reserve(skb, dev->hard_header_len + NET_SKB_PAD); skb_reset_network_header(skb); skb->dev = dev; @@ -868,7 +916,7 @@ ph = (struct pppoe_hdr *)skb_put(skb, total_len + sizeof(struct pppoe_hdr)); start = (char *)&ph->tag[0]; - error = memcpy_fromiovec(start, m->msg_iov, total_len); + error = memcpy_from_msg(start, m, total_len); if (error < 0) { kfree_skb(skb); goto end; @@ -957,12 +1005,79 @@ return __pppoe_xmit(sk, skb); } -static const struct ppp_channel_ops pppoe_chan_ops = { - .start_xmit = pppoe_xmit, +/************************************************************************ + * + * function called by generic PPP driver to hold channel + * + ***********************************************************************/ +static void pppoe_hold_chan(struct ppp_channel *chan) +{ + struct sock *sk = (struct sock *)chan->private; + + sock_hold(sk); +} + +/************************************************************************ + * + * function called by generic PPP driver to release channel + * + ***********************************************************************/ +static void pppoe_release_chan(struct ppp_channel *chan) +{ + struct sock *sk = (struct sock *)chan->private; + + sock_put(sk); +} + +/************************************************************************ + * + * function called to get the channel protocol type + * + ***********************************************************************/ +static int pppoe_get_channel_protocol(struct ppp_channel *chan) +{ + return PX_PROTO_OE; +} + +/************************************************************************ + * + * function called to get the PPPoE channel addressing + * NOTE: This function returns a HOLD to the netdevice + * + ***********************************************************************/ +static void pppoe_get_addressing(struct ppp_channel *chan, + struct pppoe_opt *addressing) +{ + struct sock *sk = (struct sock *)chan->private; + struct pppox_sock *po = pppox_sk(sk); + + *addressing = po->proto.pppoe; + if (addressing->dev) + dev_hold(addressing->dev); +} + +/* pppoe_channel_addressing_get() + * Return PPPoE channel specific addressing information. + */ +void pppoe_channel_addressing_get(struct ppp_channel *chan, + struct pppoe_opt *addressing) +{ + pppoe_get_addressing(chan, addressing); +} +EXPORT_SYMBOL(pppoe_channel_addressing_get); + +static const struct pppoe_channel_ops pppoe_chan_ops = { + /* PPPoE specific channel ops */ + .get_addressing = pppoe_get_addressing, + /* General ppp channel ops */ + .ops.start_xmit = pppoe_xmit, + .ops.get_channel_protocol = pppoe_get_channel_protocol, + .ops.hold = pppoe_hold_chan, + .ops.release = pppoe_release_chan, }; -static int pppoe_recvmsg(struct kiocb *iocb, struct socket *sock, - struct msghdr *m, size_t total_len, int flags) +static int pppoe_recvmsg(struct socket *sock, struct msghdr *m, + size_t total_len, int flags) { struct sock *sk = sock->sk; struct sk_buff *skb; @@ -980,7 +1095,7 @@ if (skb) { total_len = min_t(size_t, total_len, skb->len); - error = skb_copy_datagram_iovec(skb, 0, m->msg_iov, total_len); + error = skb_copy_datagram_msg(skb, 0, m, total_len); if (error == 0) { consume_skb(skb); return total_len;