diff options
Diffstat (limited to 'kernel/drivers/net/ppp')
-rw-r--r-- | kernel/drivers/net/ppp/ppp_generic.c | 103 | ||||
-rw-r--r-- | kernel/drivers/net/ppp/pppoe.c | 23 | ||||
-rw-r--r-- | kernel/drivers/net/ppp/pppox.c | 2 | ||||
-rw-r--r-- | kernel/drivers/net/ppp/pptp.c | 53 |
4 files changed, 113 insertions, 68 deletions
diff --git a/kernel/drivers/net/ppp/ppp_generic.c b/kernel/drivers/net/ppp/ppp_generic.c index 9d1556652..9a863c6a6 100644 --- a/kernel/drivers/net/ppp/ppp_generic.c +++ b/kernel/drivers/net/ppp/ppp_generic.c @@ -269,9 +269,9 @@ static void ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound); static void ppp_ccp_closed(struct ppp *ppp); static struct compressor *find_compressor(int type); static void ppp_get_stats(struct ppp *ppp, struct ppp_stats *st); -static struct ppp *ppp_create_interface(struct net *net, int unit, int *retp); +static struct ppp *ppp_create_interface(struct net *net, int unit, + struct file *file, int *retp); static void init_ppp_file(struct ppp_file *pf, int kind); -static void ppp_shutdown_interface(struct ppp *ppp); static void ppp_destroy_interface(struct ppp *ppp); static struct ppp *ppp_find_unit(struct ppp_net *pn, int unit); static struct channel *ppp_find_channel(struct ppp_net *pn, int unit); @@ -283,6 +283,8 @@ static int unit_set(struct idr *p, void *ptr, int n); static void unit_put(struct idr *p, int n); static void *unit_find(struct idr *p, int n); +static const struct net_device_ops ppp_netdev_ops; + static struct class *ppp_class; /* per net-namespace data */ @@ -392,8 +394,10 @@ static int ppp_release(struct inode *unused, struct file *file) file->private_data = NULL; if (pf->kind == INTERFACE) { ppp = PF_TO_PPP(pf); + rtnl_lock(); if (file == ppp->owner) - ppp_shutdown_interface(ppp); + unregister_netdevice(ppp->dev); + rtnl_unlock(); } if (atomic_dec_and_test(&pf->refcnt)) { switch (pf->kind) { @@ -593,8 +597,10 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) mutex_lock(&ppp_mutex); if (pf->kind == INTERFACE) { ppp = PF_TO_PPP(pf); + rtnl_lock(); if (file == ppp->owner) - ppp_shutdown_interface(ppp); + unregister_netdevice(ppp->dev); + rtnl_unlock(); } if (atomic_long_read(&file->f_count) < 2) { ppp_release(NULL, file); @@ -715,10 +721,8 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) val &= 0xffff; } vj = slhc_init(val2+1, val+1); - if (!vj) { - netdev_err(ppp->dev, - "PPP: no memory (VJ compressor)\n"); - err = -ENOMEM; + if (IS_ERR(vj)) { + err = PTR_ERR(vj); break; } ppp_lock(ppp); @@ -838,11 +842,10 @@ static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf, /* Create a new ppp unit */ if (get_user(unit, p)) break; - ppp = ppp_create_interface(net, unit, &err); + ppp = ppp_create_interface(net, unit, file, &err); if (!ppp) break; file->private_data = &ppp->file; - ppp->owner = file; err = -EFAULT; if (put_user(ppp->file.index, p)) break; @@ -916,6 +919,25 @@ static __net_init int ppp_init_net(struct net *net) static __net_exit void ppp_exit_net(struct net *net) { struct ppp_net *pn = net_generic(net, ppp_net_id); + struct net_device *dev; + struct net_device *aux; + struct ppp *ppp; + LIST_HEAD(list); + int id; + + rtnl_lock(); + for_each_netdev_safe(net, dev, aux) { + if (dev->netdev_ops == &ppp_netdev_ops) + unregister_netdevice_queue(dev, &list); + } + + idr_for_each_entry(&pn->units_idr, ppp, id) + /* Skip devices already unregistered by previous loop */ + if (!net_eq(dev_net(ppp->dev), net)) + unregister_netdevice_queue(ppp->dev, &list); + + unregister_netdevice_many(&list); + rtnl_unlock(); idr_destroy(&pn->units_idr); } @@ -1004,6 +1026,7 @@ ppp_start_xmit(struct sk_buff *skb, struct net_device *dev) proto = npindex_to_proto[npi]; put_unaligned_be16(proto, pp); + skb_scrub_packet(skb, !net_eq(ppp->ppp_net, dev_net(dev))); skb_queue_tail(&ppp->file.xq, skb); ppp_xmit_process(ppp); return NETDEV_TX_OK; @@ -1088,8 +1111,28 @@ static int ppp_dev_init(struct net_device *dev) return 0; } +static void ppp_dev_uninit(struct net_device *dev) +{ + struct ppp *ppp = netdev_priv(dev); + struct ppp_net *pn = ppp_pernet(ppp->ppp_net); + + ppp_lock(ppp); + ppp->closing = 1; + ppp_unlock(ppp); + + mutex_lock(&pn->all_ppp_mutex); + unit_put(&pn->units_idr, ppp->file.index); + mutex_unlock(&pn->all_ppp_mutex); + + ppp->owner = NULL; + + ppp->file.dead = 1; + wake_up_interruptible(&ppp->file.rwait); +} + static const struct net_device_ops ppp_netdev_ops = { .ndo_init = ppp_dev_init, + .ndo_uninit = ppp_dev_uninit, .ndo_start_xmit = ppp_start_xmit, .ndo_do_ioctl = ppp_net_ioctl, .ndo_get_stats64 = ppp_get_stats64, @@ -1104,7 +1147,6 @@ static void ppp_setup(struct net_device *dev) dev->tx_queue_len = 3; dev->type = ARPHRD_PPP; dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; - dev->features |= NETIF_F_NETNS_LOCAL; netif_keep_dst(dev); } @@ -1867,6 +1909,8 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) skb->dev = ppp->dev; skb->protocol = htons(npindex_to_ethertype[npi]); skb_reset_mac_header(skb); + skb_scrub_packet(skb, !net_eq(ppp->ppp_net, + dev_net(ppp->dev))); netif_rx(skb); } } @@ -2667,8 +2711,8 @@ ppp_get_stats(struct ppp *ppp, struct ppp_stats *st) * or if there is already a unit with the requested number. * unit == -1 means allocate a new number. */ -static struct ppp * -ppp_create_interface(struct net *net, int unit, int *retp) +static struct ppp *ppp_create_interface(struct net *net, int unit, + struct file *file, int *retp) { struct ppp *ppp; struct ppp_net *pn; @@ -2688,6 +2732,7 @@ ppp_create_interface(struct net *net, int unit, int *retp) ppp->mru = PPP_MRU; init_ppp_file(&ppp->file, INTERFACE); ppp->file.hdrlen = PPP_HDRLEN - 2; /* don't count proto bytes */ + ppp->owner = file; for (i = 0; i < NUM_NP; ++i) ppp->npmode[i] = NPMODE_PASS; INIT_LIST_HEAD(&ppp->channels); @@ -2708,6 +2753,7 @@ ppp_create_interface(struct net *net, int unit, int *retp) */ dev_net_set(dev, net); + rtnl_lock(); mutex_lock(&pn->all_ppp_mutex); if (unit < 0) { @@ -2738,7 +2784,7 @@ ppp_create_interface(struct net *net, int unit, int *retp) ppp->file.index = unit; sprintf(dev->name, "ppp%d", unit); - ret = register_netdev(dev); + ret = register_netdevice(dev); if (ret != 0) { unit_put(&pn->units_idr, unit); netdev_err(ppp->dev, "PPP: couldn't register device %s (%d)\n", @@ -2750,6 +2796,7 @@ ppp_create_interface(struct net *net, int unit, int *retp) atomic_inc(&ppp_unit_count); mutex_unlock(&pn->all_ppp_mutex); + rtnl_unlock(); *retp = 0; return ppp; @@ -2776,34 +2823,6 @@ init_ppp_file(struct ppp_file *pf, int kind) } /* - * Take down a ppp interface unit - called when the owning file - * (the one that created the unit) is closed or detached. - */ -static void ppp_shutdown_interface(struct ppp *ppp) -{ - struct ppp_net *pn; - - pn = ppp_pernet(ppp->ppp_net); - mutex_lock(&pn->all_ppp_mutex); - - /* This will call dev_close() for us. */ - ppp_lock(ppp); - if (!ppp->closing) { - ppp->closing = 1; - ppp_unlock(ppp); - unregister_netdev(ppp->dev); - unit_put(&pn->units_idr, ppp->file.index); - } else - ppp_unlock(ppp); - - ppp->file.dead = 1; - ppp->owner = NULL; - wake_up_interruptible(&ppp->file.rwait); - - mutex_unlock(&pn->all_ppp_mutex); -} - -/* * Free the memory used by a ppp unit. This is only called once * there are no channels connected to the unit and no file structs * that reference the unit. diff --git a/kernel/drivers/net/ppp/pppoe.c b/kernel/drivers/net/ppp/pppoe.c index b62a5e3a1..4e0068e77 100644 --- a/kernel/drivers/net/ppp/pppoe.c +++ b/kernel/drivers/net/ppp/pppoe.c @@ -313,7 +313,6 @@ static void pppoe_flush_dev(struct net_device *dev) if (po->pppoe_dev == dev && sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND | PPPOX_ZOMBIE)) { pppox_unbind_sock(sk); - sk->sk_state = PPPOX_ZOMBIE; sk->sk_state_change(sk); po->pppoe_dev = NULL; dev_put(dev); @@ -396,6 +395,8 @@ static int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb) 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; @@ -550,11 +551,11 @@ static struct proto pppoe_sk_proto __read_mostly = { * 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; @@ -569,6 +570,9 @@ static int pppoe_create(struct net *net, struct socket *sock) 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; } @@ -590,7 +594,7 @@ static int pppoe_release(struct socket *sock) po = pppox_sk(sk); - if (sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND | PPPOX_ZOMBIE)) { + if (po->pppoe_dev) { dev_put(po->pppoe_dev); po->pppoe_dev = NULL; } @@ -633,8 +637,6 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr, lock_sock(sk); - INIT_WORK(&po->proto.pppoe.padt_work, pppoe_unbind_sock_work); - error = -EINVAL; if (sp->sa_protocol != PX_PROTO_OE) goto end; @@ -664,8 +666,13 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr, 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; } diff --git a/kernel/drivers/net/ppp/pppox.c b/kernel/drivers/net/ppp/pppox.c index 2940e9fe3..0e1b30622 100644 --- a/kernel/drivers/net/ppp/pppox.c +++ b/kernel/drivers/net/ppp/pppox.c @@ -118,7 +118,7 @@ static int pppox_create(struct net *net, struct socket *sock, int protocol, !try_module_get(pppox_protos[protocol]->owner)) goto out; - rc = pppox_protos[protocol]->create(net, sock); + rc = pppox_protos[protocol]->create(net, sock, kern); module_put(pppox_protos[protocol]->owner); out: diff --git a/kernel/drivers/net/ppp/pptp.c b/kernel/drivers/net/ppp/pptp.c index e3bfbd4d0..f7e8c7934 100644 --- a/kernel/drivers/net/ppp/pptp.c +++ b/kernel/drivers/net/ppp/pptp.c @@ -28,8 +28,6 @@ #include <linux/file.h> #include <linux/in.h> #include <linux/ip.h> -#include <linux/netfilter.h> -#include <linux/netfilter_ipv4.h> #include <linux/rcupdate.h> #include <linux/spinlock.h> @@ -131,24 +129,27 @@ static int lookup_chan_dst(u16 call_id, __be32 d_addr) return i < MAX_CALLID; } -static int add_chan(struct pppox_sock *sock) +static int add_chan(struct pppox_sock *sock, + struct pptp_addr *sa) { static int call_id; spin_lock(&chan_lock); - if (!sock->proto.pptp.src_addr.call_id) { + if (!sa->call_id) { call_id = find_next_zero_bit(callid_bitmap, MAX_CALLID, call_id + 1); if (call_id == MAX_CALLID) { call_id = find_next_zero_bit(callid_bitmap, MAX_CALLID, 1); if (call_id == MAX_CALLID) goto out_err; } - sock->proto.pptp.src_addr.call_id = call_id; - } else if (test_bit(sock->proto.pptp.src_addr.call_id, callid_bitmap)) + sa->call_id = call_id; + } else if (test_bit(sa->call_id, callid_bitmap)) { goto out_err; + } - set_bit(sock->proto.pptp.src_addr.call_id, callid_bitmap); - rcu_assign_pointer(callid_sock[sock->proto.pptp.src_addr.call_id], sock); + sock->proto.pptp.src_addr = *sa; + set_bit(sa->call_id, callid_bitmap); + rcu_assign_pointer(callid_sock[sa->call_id], sock); spin_unlock(&chan_lock); return 0; @@ -171,6 +172,7 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb) { struct sock *sk = (struct sock *) chan->private; struct pppox_sock *po = pppox_sk(sk); + struct net *net = sock_net(sk); struct pptp_opt *opt = &po->proto.pptp; struct pptp_gre_header *hdr; unsigned int header_len = sizeof(*hdr); @@ -189,7 +191,7 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb) if (sk_pppox(po)->sk_state & PPPOX_DEAD) goto tx_error; - rt = ip_route_output_ports(sock_net(sk), &fl4, NULL, + rt = ip_route_output_ports(net, &fl4, NULL, opt->dst_addr.sin_addr.s_addr, opt->src_addr.sin_addr.s_addr, 0, 0, IPPROTO_GRE, @@ -281,10 +283,10 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb) nf_reset(skb); skb->ip_summed = CHECKSUM_NONE; - ip_select_ident(sock_net(sk), skb, NULL); + ip_select_ident(net, skb, NULL); ip_send_check(iph); - ip_local_out(skb); + ip_local_out(net, skb->sk, skb); return 1; tx_error: @@ -417,15 +419,29 @@ static int pptp_bind(struct socket *sock, struct sockaddr *uservaddr, struct sock *sk = sock->sk; struct sockaddr_pppox *sp = (struct sockaddr_pppox *) uservaddr; struct pppox_sock *po = pppox_sk(sk); - struct pptp_opt *opt = &po->proto.pptp; int error = 0; + if (sockaddr_len < sizeof(struct sockaddr_pppox)) + return -EINVAL; + lock_sock(sk); - opt->src_addr = sp->sa_addr.pptp; - if (add_chan(po)) + if (sk->sk_state & PPPOX_DEAD) { + error = -EALREADY; + goto out; + } + + if (sk->sk_state & PPPOX_BOUND) { error = -EBUSY; + goto out; + } + + if (add_chan(po, &sp->sa_addr.pptp)) + error = -EBUSY; + else + sk->sk_state |= PPPOX_BOUND; +out: release_sock(sk); return error; } @@ -441,6 +457,9 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr, struct flowi4 fl4; int error = 0; + if (sockaddr_len < sizeof(struct sockaddr_pppox)) + return -EINVAL; + if (sp->sa_protocol != PX_PROTO_PPTP) return -EINVAL; @@ -493,7 +512,7 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr, } opt->dst_addr = sp->sa_addr.pptp; - sk->sk_state = PPPOX_CONNECTED; + sk->sk_state |= PPPOX_CONNECTED; end: release_sock(sk); @@ -561,14 +580,14 @@ static void pptp_sock_destruct(struct sock *sk) skb_queue_purge(&sk->sk_receive_queue); } -static int pptp_create(struct net *net, struct socket *sock) +static int pptp_create(struct net *net, struct socket *sock, int kern) { int error = -ENOMEM; struct sock *sk; struct pppox_sock *po; struct pptp_opt *opt; - sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pptp_sk_proto); + sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pptp_sk_proto, kern); if (!sk) goto out; |