X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fnet%2Fppp_generic.c;h=06b448285eb5d0783c104383c12b0e4add6309ea;hb=6dd014808f91ad99d4d794cf7c7c69610c10f904;hp=16a59cafb8d346bde82f8a416fb91c737a764b0b;hpb=8ab5e4c15b53e147c08031a959d9f776823dbe73;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 16a59ca..06b4482 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -22,13 +22,12 @@ * ==FILEVERSION 20041108== */ -#include #include #include #include #include #include -#include +#include #include #include #include @@ -41,8 +40,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -85,13 +84,11 @@ struct ppp_file { int dead; /* unit/channel has been shut down */ }; -#define PF_TO_X(pf, X) ((X *)((char *)(pf) - offsetof(X, file))) +#define PF_TO_X(pf, X) container_of(pf, X, file) #define PF_TO_PPP(pf) PF_TO_X(pf, struct ppp) #define PF_TO_CHANNEL(pf) PF_TO_X(pf, struct channel) -#define ROUNDUP(n, x) (((n) + (x) - 1) / (x)) - /* * Data structure describing one ppp unit. * A ppp unit corresponds to a ppp network interface device @@ -120,6 +117,7 @@ struct ppp { unsigned long last_xmit; /* jiffies when last pkt sent 9c */ unsigned long last_recv; /* jiffies when last pkt rcvd a0 */ struct net_device *dev; /* network interface device a4 */ + int closing; /* is device closing down? a8 */ #ifdef CONFIG_PPP_MULTILINK int nxchan; /* next channel to send something on */ u32 nxseq; /* next sequence number to send */ @@ -128,7 +126,6 @@ struct ppp { u32 minseq; /* MP: min of most recent seqnos */ struct sk_buff_head mrq; /* MP: receive reconstruction queue */ #endif /* CONFIG_PPP_MULTILINK */ - struct net_device_stats stats; /* statistics */ #ifdef CONFIG_PPP_FILTER struct sock_filter *pass_filter; /* filter for packets to pass */ struct sock_filter *active_filter;/* filter for pkts to reset idle */ @@ -177,35 +174,13 @@ struct channel { */ /* - * A cardmap represents a mapping from unsigned integers to pointers, - * and provides a fast "find lowest unused number" operation. - * It uses a broad (32-way) tree with a bitmap at each level. - * It is designed to be space-efficient for small numbers of entries - * and time-efficient for large numbers of entries. - */ -#define CARDMAP_ORDER 5 -#define CARDMAP_WIDTH (1U << CARDMAP_ORDER) -#define CARDMAP_MASK (CARDMAP_WIDTH - 1) - -struct cardmap { - int shift; - unsigned long inuse; - struct cardmap *parent; - void *ptr[CARDMAP_WIDTH]; -}; -static void *cardmap_get(struct cardmap *map, unsigned int nr); -static void cardmap_set(struct cardmap **map, unsigned int nr, void *ptr); -static unsigned int cardmap_find_first_free(struct cardmap *map); -static void cardmap_destroy(struct cardmap **map); - -/* * all_ppp_mutex protects the all_ppp_units mapping. * It also ensures that finding a ppp unit in the all_ppp_units map * and updating its file.refcnt field is atomic. */ static DEFINE_MUTEX(all_ppp_mutex); -static struct cardmap *all_ppp_units; static atomic_t ppp_unit_count = ATOMIC_INIT(0); +static DEFINE_IDR(ppp_units_idr); /* * all_channels_lock protects all_channels and last_channel_index, @@ -274,6 +249,9 @@ static struct channel *ppp_find_channel(int unit); static int ppp_connect_channel(struct channel *pch, int unit); static int ppp_disconnect_channel(struct channel *pch); static void ppp_destroy_channel(struct channel *pch); +static int unit_get(struct idr *p, void *ptr); +static void unit_put(struct idr *p, int n); +static void *unit_find(struct idr *p, int n); static struct class *ppp_class; @@ -306,7 +284,7 @@ static const int npindex_to_proto[NUM_NP] = { PPP_MPLS_UC, PPP_MPLS_MC, }; - + /* Translates an ethertype into an NP index */ static inline int ethertype_to_npindex(int ethertype) { @@ -359,6 +337,7 @@ static const int npindex_to_ethertype[NUM_NP] = { */ static int ppp_open(struct inode *inode, struct file *file) { + cycle_kernel_lock(); /* * This could (should?) be enforced by the permissions on /dev/ppp. */ @@ -367,12 +346,12 @@ static int ppp_open(struct inode *inode, struct file *file) return 0; } -static int ppp_release(struct inode *inode, struct file *file) +static int ppp_release(struct inode *unused, struct file *file) { struct ppp_file *pf = file->private_data; struct ppp *ppp; - if (pf != 0) { + if (pf) { file->private_data = NULL; if (pf->kind == INTERFACE) { ppp = PF_TO_PPP(pf); @@ -403,7 +382,7 @@ static ssize_t ppp_read(struct file *file, char __user *buf, ret = count; - if (pf == 0) + if (!pf) return -ENXIO; add_wait_queue(&pf->rwait, &wait); for (;;) { @@ -436,7 +415,7 @@ static ssize_t ppp_read(struct file *file, char __user *buf, set_current_state(TASK_RUNNING); remove_wait_queue(&pf->rwait, &wait); - if (skb == 0) + if (!skb) goto out; ret = -EOVERFLOW; @@ -460,11 +439,11 @@ static ssize_t ppp_write(struct file *file, const char __user *buf, struct sk_buff *skb; ssize_t ret; - if (pf == 0) + if (!pf) return -ENXIO; ret = -ENOMEM; skb = alloc_skb(count + pf->hdrlen, GFP_KERNEL); - if (skb == 0) + if (!skb) goto out; skb_reserve(skb, pf->hdrlen); ret = -EFAULT; @@ -496,11 +475,11 @@ static unsigned int ppp_poll(struct file *file, poll_table *wait) struct ppp_file *pf = file->private_data; unsigned int mask; - if (pf == 0) + if (!pf) return 0; poll_wait(file, &pf->rwait, wait); mask = POLLOUT | POLLWRNORM; - if (skb_peek(&pf->rq) != 0) + if (skb_peek(&pf->rq)) mask |= POLLIN | POLLRDNORM; if (pf->dead) mask |= POLLHUP; @@ -551,8 +530,7 @@ static int get_filter(void __user *arg, struct sock_filter **p) } #endif /* CONFIG_PPP_FILTER */ -static int ppp_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct ppp_file *pf = file->private_data; struct ppp *ppp; @@ -564,7 +542,7 @@ static int ppp_ioctl(struct inode *inode, struct file *file, void __user *argp = (void __user *)arg; int __user *p = argp; - if (pf == 0) + if (!pf) return ppp_unattached_ioctl(pf, file, cmd, arg); if (cmd == PPPIOCDETACH) { @@ -580,24 +558,29 @@ static int ppp_ioctl(struct inode *inode, struct file *file, * this fd and reopening /dev/ppp. */ err = -EINVAL; + lock_kernel(); if (pf->kind == INTERFACE) { ppp = PF_TO_PPP(pf); if (file == ppp->owner) ppp_shutdown_interface(ppp); } - if (atomic_read(&file->f_count) <= 2) { - ppp_release(inode, file); + if (atomic_long_read(&file->f_count) <= 2) { + ppp_release(NULL, file); err = 0; } else - printk(KERN_DEBUG "PPPIOCDETACH file->f_count=%d\n", - atomic_read(&file->f_count)); + printk(KERN_DEBUG "PPPIOCDETACH file->f_count=%ld\n", + atomic_long_read(&file->f_count)); + unlock_kernel(); return err; } if (pf->kind == CHANNEL) { - struct channel *pch = PF_TO_CHANNEL(pf); + struct channel *pch; struct ppp_channel *chan; + lock_kernel(); + pch = PF_TO_CHANNEL(pf); + switch (cmd) { case PPPIOCCONNECT: if (get_user(unit, p)) @@ -617,6 +600,7 @@ static int ppp_ioctl(struct inode *inode, struct file *file, err = chan->ops->ioctl(chan, cmd, arg); up_read(&pch->chan_sem); } + unlock_kernel(); return err; } @@ -626,6 +610,7 @@ static int ppp_ioctl(struct inode *inode, struct file *file, return -EINVAL; } + lock_kernel(); ppp = PF_TO_PPP(pf); switch (cmd) { case PPPIOCSMRU: @@ -694,13 +679,13 @@ static int ppp_ioctl(struct inode *inode, struct file *file, val &= 0xffff; } vj = slhc_init(val2+1, val+1); - if (vj == 0) { + if (!vj) { printk(KERN_ERR "PPP: no memory (VJ compressor)\n"); err = -ENOMEM; break; } ppp_lock(ppp); - if (ppp->vj != 0) + if (ppp->vj) slhc_free(ppp->vj); ppp->vj = vj; ppp_unlock(ppp); @@ -773,7 +758,7 @@ static int ppp_ioctl(struct inode *inode, struct file *file, default: err = -ENOTTY; } - + unlock_kernel(); return err; } @@ -785,13 +770,14 @@ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file, struct channel *chan; int __user *p = (int __user *)arg; + lock_kernel(); switch (cmd) { case PPPIOCNEWUNIT: /* Create a new ppp unit */ if (get_user(unit, p)) break; ppp = ppp_create_interface(unit, &err); - if (ppp == 0) + if (!ppp) break; file->private_data = &ppp->file; ppp->owner = file; @@ -808,7 +794,7 @@ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file, mutex_lock(&all_ppp_mutex); err = -ENXIO; ppp = ppp_find_unit(unit); - if (ppp != 0) { + if (ppp) { atomic_inc(&ppp->file.refcnt); file->private_data = &ppp->file; err = 0; @@ -822,7 +808,7 @@ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file, spin_lock_bh(&all_channels_lock); err = -ENXIO; chan = ppp_find_channel(unit); - if (chan != 0) { + if (chan) { atomic_inc(&chan->file.refcnt); file->private_data = &chan->file; err = 0; @@ -833,15 +819,16 @@ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file, default: err = -ENOTTY; } + unlock_kernel(); return err; } -static struct file_operations ppp_device_fops = { +static const struct file_operations ppp_device_fops = { .owner = THIS_MODULE, .read = ppp_read, .write = ppp_write, .poll = ppp_poll, - .ioctl = ppp_ioctl, + .unlocked_ioctl = ppp_ioctl, .open = ppp_open, .release = ppp_release }; @@ -862,7 +849,8 @@ static int __init ppp_init(void) err = PTR_ERR(ppp_class); goto out_chrdev; } - class_device_create(ppp_class, NULL, MKDEV(PPP_MAJOR, 0), NULL, "ppp"); + device_create(ppp_class, NULL, MKDEV(PPP_MAJOR, 0), NULL, + "ppp"); } out: @@ -881,7 +869,7 @@ out_chrdev: static int ppp_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct ppp *ppp = (struct ppp *) dev->priv; + struct ppp *ppp = netdev_priv(dev); int npi, proto; unsigned char *pp; @@ -904,17 +892,9 @@ ppp_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Put the 2-byte PPP protocol number on the front, making sure there is room for the address and control fields. */ - if (skb_headroom(skb) < PPP_HDRLEN) { - struct sk_buff *ns; - - ns = alloc_skb(skb->len + dev->hard_header_len, GFP_ATOMIC); - if (ns == 0) - goto outf; - skb_reserve(ns, dev->hard_header_len); - skb_copy_bits(skb, 0, skb_put(ns, skb->len), skb->len); - kfree_skb(skb); - skb = ns; - } + if (skb_cow_head(skb, PPP_HDRLEN)) + goto outf; + pp = skb_push(skb, 2); proto = npindex_to_proto[npi]; pp[0] = proto >> 8; @@ -927,22 +907,14 @@ ppp_start_xmit(struct sk_buff *skb, struct net_device *dev) outf: kfree_skb(skb); - ++ppp->stats.tx_dropped; + ++ppp->dev->stats.tx_dropped; return 0; } -static struct net_device_stats * -ppp_net_stats(struct net_device *dev) -{ - struct ppp *ppp = (struct ppp *) dev->priv; - - return &ppp->stats; -} - static int ppp_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - struct ppp *ppp = dev->priv; + struct ppp *ppp = netdev_priv(dev); int err = -EFAULT; void __user *addr = (void __user *) ifr->ifr_ifru.ifru_data; struct ppp_stats stats; @@ -959,9 +931,9 @@ ppp_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) case SIOCGPPPCSTATS: memset(&cstats, 0, sizeof(cstats)); - if (ppp->xc_state != 0) + if (ppp->xc_state) ppp->xcomp->comp_stat(ppp->xc_state, &cstats.c); - if (ppp->rc_state != 0) + if (ppp->rc_state) ppp->rcomp->decomp_stat(ppp->rc_state, &cstats.d); if (copy_to_user(addr, &cstats, sizeof(cstats))) break; @@ -982,8 +954,14 @@ ppp_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return err; } +static const struct net_device_ops ppp_netdev_ops = { + .ndo_start_xmit = ppp_start_xmit, + .ndo_do_ioctl = ppp_net_ioctl, +}; + static void ppp_setup(struct net_device *dev) { + dev->netdev_ops = &ppp_netdev_ops; dev->hard_header_len = PPP_HDRLEN; dev->mtu = PPP_MTU; dev->addr_len = 0; @@ -1006,14 +984,14 @@ ppp_xmit_process(struct ppp *ppp) struct sk_buff *skb; ppp_xmit_lock(ppp); - if (ppp->dev != 0) { + if (!ppp->closing) { ppp_push(ppp); - while (ppp->xmit_pending == 0 - && (skb = skb_dequeue(&ppp->file.xq)) != 0) + while (!ppp->xmit_pending + && (skb = skb_dequeue(&ppp->file.xq))) ppp_send_frame(ppp, skb); /* If there's no work left to do, tell the core net code that we can accept some more. */ - if (ppp->xmit_pending == 0 && skb_peek(&ppp->file.xq) == 0) + if (!ppp->xmit_pending && !skb_peek(&ppp->file.xq)) netif_wake_queue(ppp->dev); } ppp_xmit_unlock(ppp); @@ -1108,17 +1086,17 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb) #endif /* CONFIG_PPP_FILTER */ } - ++ppp->stats.tx_packets; - ppp->stats.tx_bytes += skb->len - 2; + ++ppp->dev->stats.tx_packets; + ppp->dev->stats.tx_bytes += skb->len - 2; switch (proto) { case PPP_IP: - if (ppp->vj == 0 || (ppp->flags & SC_COMP_TCP) == 0) + if (!ppp->vj || (ppp->flags & SC_COMP_TCP) == 0) break; /* try to do VJ TCP header compression */ new_skb = alloc_skb(skb->len + ppp->dev->hard_header_len - 2, GFP_ATOMIC); - if (new_skb == 0) { + if (!new_skb) { printk(KERN_ERR "PPP: no memory (VJ comp pkt)\n"); goto drop; } @@ -1153,7 +1131,7 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb) } /* try to do packet compression */ - if ((ppp->xstate & SC_COMP_RUN) && ppp->xc_state != 0 + if ((ppp->xstate & SC_COMP_RUN) && ppp->xc_state && proto != PPP_LCP && proto != PPP_CCP) { if (!(ppp->flags & SC_CCP_UP) && (ppp->flags & SC_MUST_COMP)) { if (net_ratelimit()) @@ -1184,7 +1162,7 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb) drop: if (skb) kfree_skb(skb); - ++ppp->stats.tx_errors; + ++ppp->dev->stats.tx_errors; } /* @@ -1198,7 +1176,7 @@ ppp_push(struct ppp *ppp) struct channel *pch; struct sk_buff *skb = ppp->xmit_pending; - if (skb == 0) + if (!skb) return; list = &ppp->channels; @@ -1299,7 +1277,7 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) */ fragsize = len; if (nfree > 1) - fragsize = ROUNDUP(fragsize, nfree); + fragsize = DIV_ROUND_UP(fragsize, nfree); /* nbigger channels get fragsize bytes, the rest get fragsize-1, except if nbigger==0, then they all get fragsize. */ nbigger = len % nfree; @@ -1368,7 +1346,7 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) if (flen == len && nfree == 0) bits |= E; frag = alloc_skb(flen + hdrlen + (flen == 0), GFP_ATOMIC); - if (frag == 0) + if (!frag) goto noskb; q = skb_put(frag, flen + hdrlen); @@ -1422,7 +1400,7 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) spin_unlock_bh(&pch->downl); if (ppp->debug & 1) printk(KERN_ERR "PPP: no memory (fragment)\n"); - ++ppp->stats.tx_errors; + ++ppp->dev->stats.tx_errors; ++ppp->nxseq; return 1; /* abandon the frame */ } @@ -1438,7 +1416,7 @@ ppp_channel_push(struct channel *pch) struct ppp *ppp; spin_lock_bh(&pch->downl); - if (pch->chan != 0) { + if (pch->chan) { while (!skb_queue_empty(&pch->file.xq)) { skb = skb_dequeue(&pch->file.xq); if (!pch->chan->ops->start_xmit(pch->chan, skb)) { @@ -1456,7 +1434,7 @@ ppp_channel_push(struct channel *pch) if (skb_queue_empty(&pch->file.xq)) { read_lock_bh(&pch->upl); ppp = pch->ppp; - if (ppp != 0) + if (ppp) ppp_xmit_process(ppp); read_unlock_bh(&pch->upl); } @@ -1474,8 +1452,7 @@ static inline void ppp_do_recv(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) { ppp_recv_lock(ppp); - /* ppp->dev == 0 means interface is closing down */ - if (ppp->dev != 0) + if (!ppp->closing) ppp_receive_frame(ppp, skb, pch); else kfree_skb(skb); @@ -1488,19 +1465,19 @@ ppp_input(struct ppp_channel *chan, struct sk_buff *skb) struct channel *pch = chan->ppp; int proto; - if (pch == 0 || skb->len == 0) { + if (!pch || skb->len == 0) { kfree_skb(skb); return; } proto = PPP_PROTO(skb); read_lock_bh(&pch->upl); - if (pch->ppp == 0 || proto >= 0xc000 || proto == PPP_CCPFRAG) { + if (!pch->ppp || proto >= 0xc000 || proto == PPP_CCPFRAG) { /* put it on the channel queue */ skb_queue_tail(&pch->file.rq, skb); /* drop old frames if queue too long */ while (pch->file.rq.qlen > PPP_MAX_RQLEN - && (skb = skb_dequeue(&pch->file.rq)) != 0) + && (skb = skb_dequeue(&pch->file.rq))) kfree_skb(skb); wake_up_interruptible(&pch->file.rwait); } else { @@ -1516,13 +1493,13 @@ ppp_input_error(struct ppp_channel *chan, int code) struct channel *pch = chan->ppp; struct sk_buff *skb; - if (pch == 0) + if (!pch) return; read_lock_bh(&pch->upl); - if (pch->ppp != 0) { + if (pch->ppp) { skb = alloc_skb(0, GFP_ATOMIC); - if (skb != 0) { + if (skb) { skb->len = 0; /* probably unnecessary */ skb->cb[0] = code; ppp_do_recv(pch->ppp, skb, pch); @@ -1538,7 +1515,7 @@ ppp_input_error(struct ppp_channel *chan, int code) static void ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) { - if (skb->len >= 2) { + if (pskb_may_pull(skb, 2)) { #ifdef CONFIG_PPP_MULTILINK /* XXX do channel-level decompression here */ if (PPP_PROTO(skb) == PPP_MP) @@ -1551,7 +1528,7 @@ ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) if (skb->len > 0) /* note: a 0-length skb is used as an error indication */ - ++ppp->stats.rx_length_errors; + ++ppp->dev->stats.rx_length_errors; kfree_skb(skb); ppp_receive_error(ppp); @@ -1560,8 +1537,8 @@ ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) static void ppp_receive_error(struct ppp *ppp) { - ++ppp->stats.rx_errors; - if (ppp->vj != 0) + ++ppp->dev->stats.rx_errors; + if (ppp->vj) slhc_toss(ppp->vj); } @@ -1576,7 +1553,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) * Note that some decompressors need to see uncompressed frames * that come in as well as compressed frames. */ - if (ppp->rc_state != 0 && (ppp->rstate & SC_DECOMP_RUN) + if (ppp->rc_state && (ppp->rstate & SC_DECOMP_RUN) && (ppp->rstate & (SC_DC_FERROR | SC_DC_ERROR)) == 0) skb = ppp_decompress_frame(ppp, skb); @@ -1587,13 +1564,13 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) switch (proto) { case PPP_VJC_COMP: /* decompress VJ compressed packets */ - if (ppp->vj == 0 || (ppp->flags & SC_REJ_COMP_TCP)) + if (!ppp->vj || (ppp->flags & SC_REJ_COMP_TCP)) goto err; - if (skb_tailroom(skb) < 124) { + if (skb_tailroom(skb) < 124 || skb_cloned(skb)) { /* copy to a new sk_buff with more tailroom */ ns = dev_alloc_skb(skb->len + 128); - if (ns == 0) { + if (!ns) { printk(KERN_ERR"PPP: no memory (VJ decomp)\n"); goto err; } @@ -1619,13 +1596,13 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) break; case PPP_VJC_UNCOMP: - if (ppp->vj == 0 || (ppp->flags & SC_REJ_COMP_TCP)) + if (!ppp->vj || (ppp->flags & SC_REJ_COMP_TCP)) goto err; - + /* Until we fix the decompressor need to make sure * data portion is linear. */ - if (!pskb_may_pull(skb, skb->len)) + if (!pskb_may_pull(skb, skb->len)) goto err; if (slhc_remember(ppp->vj, skb->data + 2, skb->len - 2) <= 0) { @@ -1640,8 +1617,8 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) break; } - ++ppp->stats.rx_packets; - ppp->stats.rx_bytes += skb->len - 2; + ++ppp->dev->stats.rx_packets; + ppp->dev->stats.rx_bytes += skb->len - 2; npi = proto_to_npindex(proto); if (npi < 0) { @@ -1649,7 +1626,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) skb_queue_tail(&ppp->file.rq, skb); /* limit queue length by dropping old frames */ while (ppp->file.rq.qlen > PPP_MAX_RQLEN - && (skb = skb_dequeue(&ppp->file.rq)) != 0) + && (skb = skb_dequeue(&ppp->file.rq))) kfree_skb(skb); /* wake up any process polling or blocking on read */ wake_up_interruptible(&ppp->file.rwait); @@ -1661,23 +1638,29 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) /* check if the packet passes the pass and active filters */ /* the filter instructions are constructed assuming a four-byte PPP header on each packet */ - *skb_push(skb, 2) = 0; - if (ppp->pass_filter - && sk_run_filter(skb, ppp->pass_filter, - ppp->pass_len) == 0) { - if (ppp->debug & 1) - printk(KERN_DEBUG "PPP: inbound frame not passed\n"); - kfree_skb(skb); - return; - } - if (!(ppp->active_filter - && sk_run_filter(skb, ppp->active_filter, - ppp->active_len) == 0)) - ppp->last_recv = jiffies; - skb_pull(skb, 2); -#else - ppp->last_recv = jiffies; + if (ppp->pass_filter || ppp->active_filter) { + if (skb_cloned(skb) && + pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) + goto err; + + *skb_push(skb, 2) = 0; + if (ppp->pass_filter + && sk_run_filter(skb, ppp->pass_filter, + ppp->pass_len) == 0) { + if (ppp->debug & 1) + printk(KERN_DEBUG "PPP: inbound frame " + "not passed\n"); + kfree_skb(skb); + return; + } + if (!(ppp->active_filter + && sk_run_filter(skb, ppp->active_filter, + ppp->active_len) == 0)) + ppp->last_recv = jiffies; + __skb_pull(skb, 2); + } else #endif /* CONFIG_PPP_FILTER */ + ppp->last_recv = jiffies; if ((ppp->dev->flags & IFF_UP) == 0 || ppp->npmode[npi] != NPMODE_PASS) { @@ -1687,9 +1670,8 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) skb_pull_rcsum(skb, 2); skb->dev = ppp->dev; skb->protocol = htons(npindex_to_ethertype[npi]); - skb->mac.raw = skb->data; + skb_reset_mac_header(skb); netif_rx(skb); - ppp->dev->last_rx = jiffies; } } return; @@ -1713,14 +1695,25 @@ ppp_decompress_frame(struct ppp *ppp, struct sk_buff *skb) goto err; if (proto == PPP_COMP) { - ns = dev_alloc_skb(ppp->mru + PPP_HDRLEN); - if (ns == 0) { + int obuff_size; + + switch(ppp->rcomp->compress_proto) { + case CI_MPPE: + obuff_size = ppp->mru + PPP_HDRLEN + 1; + break; + default: + obuff_size = ppp->mru + PPP_HDRLEN; + break; + } + + ns = dev_alloc_skb(obuff_size); + if (!ns) { printk(KERN_ERR "ppp_decompress_frame: no memory\n"); goto err; } /* the decompressor still expects the A/C bytes in the hdr */ len = ppp->rcomp->decompress(ppp->rc_state, skb->data - 2, - skb->len + 2, ns->data, ppp->mru + PPP_HDRLEN); + skb->len + 2, ns->data, obuff_size); if (len < 0) { /* Pass the compressed frame to pppd as an error indication. */ @@ -1764,7 +1757,7 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) struct channel *ch; int mphdrlen = (ppp->flags & SC_MP_SHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN; - if (!pskb_may_pull(skb, mphdrlen) || ppp->mrru == 0) + if (!pskb_may_pull(skb, mphdrlen + 1) || ppp->mrru == 0) goto err; /* no good, throw it away */ /* Decode sequence number and begin/end bits */ @@ -1802,7 +1795,7 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) */ if (seq_before(seq, ppp->nextseq)) { kfree_skb(skb); - ++ppp->stats.rx_dropped; + ++ppp->dev->stats.rx_dropped; ppp_receive_error(ppp); return; } @@ -1827,12 +1820,14 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch) /* If the queue is getting long, don't wait any longer for packets before the start of the queue. */ - if (skb_queue_len(&ppp->mrq) >= PPP_MP_MAX_QLEN - && seq_before(ppp->minseq, ppp->mrq.next->sequence)) - ppp->minseq = ppp->mrq.next->sequence; + if (skb_queue_len(&ppp->mrq) >= PPP_MP_MAX_QLEN) { + struct sk_buff *skb = skb_peek(&ppp->mrq); + if (seq_before(ppp->minseq, skb->sequence)) + ppp->minseq = skb->sequence; + } /* Pull completed packets off the queue and receive them. */ - while ((skb = ppp_mp_reconstruct(ppp)) != 0) + while ((skb = ppp_mp_reconstruct(ppp))) ppp_receive_nonmp_frame(ppp, skb); return; @@ -1855,10 +1850,11 @@ ppp_mp_insert(struct ppp *ppp, struct sk_buff *skb) /* N.B. we don't need to lock the list lock because we have the ppp unit receive-side lock. */ - for (p = list->next; p != (struct sk_buff *)list; p = p->next) + skb_queue_walk(list, p) { if (seq_before(seq, p->sequence)) break; - __skb_insert(skb, p->prev, p, list); + } + __skb_queue_before(list, p, skb); } /* @@ -1867,7 +1863,7 @@ ppp_mp_insert(struct ppp *ppp, struct sk_buff *skb) * complete packet, or we get to the sequence number for a fragment * which hasn't arrived but might still do so. */ -struct sk_buff * +static struct sk_buff * ppp_mp_reconstruct(struct ppp *ppp) { u32 seq = ppp->nextseq; @@ -1924,7 +1920,7 @@ ppp_mp_reconstruct(struct ppp *ppp) /* Got a complete packet yet? */ if (lost == 0 && (p->BEbits & E) && (head->BEbits & B)) { if (len > ppp->mrru + 2) { - ++ppp->stats.rx_length_errors; + ++ppp->dev->stats.rx_length_errors; printk(KERN_DEBUG "PPP: reconstructed packet" " is too long (%d)\n", len); } else if (p == head) { @@ -1933,7 +1929,7 @@ ppp_mp_reconstruct(struct ppp *ppp) skb = skb_get(p); break; } else if ((skb = dev_alloc_skb(len)) == NULL) { - ++ppp->stats.rx_missed_errors; + ++ppp->dev->stats.rx_missed_errors; printk(KERN_DEBUG "PPP: no memory for " "reconstructed packet"); } else { @@ -1962,7 +1958,7 @@ ppp_mp_reconstruct(struct ppp *ppp) if (ppp->debug & 1) printk(KERN_DEBUG " missed pkts %u..%u\n", ppp->nextseq, head->sequence-1); - ++ppp->stats.rx_dropped; + ++ppp->dev->stats.rx_dropped; ppp_receive_error(ppp); } @@ -1997,10 +1993,9 @@ ppp_register_channel(struct ppp_channel *chan) { struct channel *pch; - pch = kmalloc(sizeof(struct channel), GFP_KERNEL); - if (pch == 0) + pch = kzalloc(sizeof(struct channel), GFP_KERNEL); + if (!pch) return -ENOMEM; - memset(pch, 0, sizeof(struct channel)); pch->ppp = NULL; pch->chan = chan; chan->ppp = pch; @@ -2027,7 +2022,7 @@ int ppp_channel_index(struct ppp_channel *chan) { struct channel *pch = chan->ppp; - if (pch != 0) + if (pch) return pch->file.index; return -1; } @@ -2040,9 +2035,9 @@ int ppp_unit_number(struct ppp_channel *chan) struct channel *pch = chan->ppp; int unit = -1; - if (pch != 0) { + if (pch) { read_lock_bh(&pch->upl); - if (pch->ppp != 0) + if (pch->ppp) unit = pch->ppp->file.index; read_unlock_bh(&pch->upl); } @@ -2058,7 +2053,7 @@ ppp_unregister_channel(struct ppp_channel *chan) { struct channel *pch = chan->ppp; - if (pch == 0) + if (!pch) return; /* should never happen */ chan->ppp = NULL; @@ -2090,7 +2085,7 @@ ppp_output_wakeup(struct ppp_channel *chan) { struct channel *pch = chan->ppp; - if (pch == 0) + if (!pch) return; ppp_channel_push(pch); } @@ -2119,20 +2114,16 @@ ppp_set_compress(struct ppp *ppp, unsigned long arg) || ccp_option[1] < 2 || ccp_option[1] > data.length) goto out; - cp = find_compressor(ccp_option[0]); -#ifdef CONFIG_KMOD - if (cp == 0) { - request_module("ppp-compress-%d", ccp_option[0]); - cp = find_compressor(ccp_option[0]); - } -#endif /* CONFIG_KMOD */ - if (cp == 0) + cp = try_then_request_module( + find_compressor(ccp_option[0]), + "ppp-compress-%d", ccp_option[0]); + if (!cp) goto out; err = -ENOBUFS; if (data.transmit) { state = cp->comp_alloc(ccp_option, data.length); - if (state != 0) { + if (state) { ppp_xmit_lock(ppp); ppp->xstate &= ~SC_COMP_RUN; ocomp = ppp->xcomp; @@ -2140,7 +2131,7 @@ ppp_set_compress(struct ppp *ppp, unsigned long arg) ppp->xcomp = cp; ppp->xc_state = state; ppp_xmit_unlock(ppp); - if (ostate != 0) { + if (ostate) { ocomp->comp_free(ostate); module_put(ocomp->owner); } @@ -2150,7 +2141,7 @@ ppp_set_compress(struct ppp *ppp, unsigned long arg) } else { state = cp->decomp_alloc(ccp_option, data.length); - if (state != 0) { + if (state) { ppp_recv_lock(ppp); ppp->rstate &= ~SC_DECOMP_RUN; ocomp = ppp->rcomp; @@ -2158,7 +2149,7 @@ ppp_set_compress(struct ppp *ppp, unsigned long arg) ppp->rcomp = cp; ppp->rc_state = state; ppp_recv_unlock(ppp); - if (ostate != 0) { + if (ostate) { ocomp->decomp_free(ostate); module_put(ocomp->owner); } @@ -2188,7 +2179,7 @@ ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound) switch (CCP_CODE(dp)) { case CCP_CONFREQ: - /* A ConfReq starts negotiation of compression + /* A ConfReq starts negotiation of compression * in one direction of transmission, * and hence brings it down...but which way? * @@ -2198,16 +2189,16 @@ ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound) if(inbound) /* He is proposing what I should send */ ppp->xstate &= ~SC_COMP_RUN; - else + else /* I am proposing to what he should send */ ppp->rstate &= ~SC_DECOMP_RUN; - + break; - + case CCP_TERMREQ: case CCP_TERMACK: /* - * CCP is going down, both directions of transmission + * CCP is going down, both directions of transmission */ ppp->rstate &= ~SC_DECOMP_RUN; ppp->xstate &= ~SC_COMP_RUN; @@ -2225,7 +2216,7 @@ ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound) break; if (inbound) { /* we will start receiving compressed packets */ - if (ppp->rc_state == 0) + if (!ppp->rc_state) break; if (ppp->rcomp->decomp_init(ppp->rc_state, dp, len, ppp->file.index, 0, ppp->mru, ppp->debug)) { @@ -2234,7 +2225,7 @@ ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound) } } else { /* we will soon start sending compressed packets */ - if (ppp->xc_state == 0) + if (!ppp->xc_state) break; if (ppp->xcomp->comp_init(ppp->xc_state, dp, len, ppp->file.index, 0, ppp->debug)) @@ -2317,11 +2308,11 @@ ppp_register_compressor(struct compressor *cp) int ret; spin_lock(&compressor_list_lock); ret = -EEXIST; - if (find_comp_entry(cp->compress_proto) != 0) + if (find_comp_entry(cp->compress_proto)) goto out; ret = -ENOMEM; ce = kmalloc(sizeof(struct compressor_entry), GFP_ATOMIC); - if (ce == 0) + if (!ce) goto out; ret = 0; ce->comp = cp; @@ -2339,7 +2330,7 @@ ppp_unregister_compressor(struct compressor *cp) spin_lock(&compressor_list_lock); ce = find_comp_entry(cp->compress_proto); - if (ce != 0 && ce->comp == cp) { + if (ce && ce->comp == cp) { list_del(&ce->list); kfree(ce); } @@ -2355,7 +2346,7 @@ find_compressor(int type) spin_lock(&compressor_list_lock); ce = find_comp_entry(type); - if (ce != 0) { + if (ce) { cp = ce->comp; if (!try_module_get(cp->owner)) cp = NULL; @@ -2374,13 +2365,13 @@ ppp_get_stats(struct ppp *ppp, struct ppp_stats *st) struct slcompress *vj = ppp->vj; memset(st, 0, sizeof(*st)); - st->p.ppp_ipackets = ppp->stats.rx_packets; - st->p.ppp_ierrors = ppp->stats.rx_errors; - st->p.ppp_ibytes = ppp->stats.rx_bytes; - st->p.ppp_opackets = ppp->stats.tx_packets; - st->p.ppp_oerrors = ppp->stats.tx_errors; - st->p.ppp_obytes = ppp->stats.tx_bytes; - if (vj == 0) + st->p.ppp_ipackets = ppp->dev->stats.rx_packets; + st->p.ppp_ierrors = ppp->dev->stats.rx_errors; + st->p.ppp_ibytes = ppp->dev->stats.rx_bytes; + st->p.ppp_opackets = ppp->dev->stats.tx_packets; + st->p.ppp_oerrors = ppp->dev->stats.tx_errors; + st->p.ppp_obytes = ppp->dev->stats.tx_bytes; + if (!vj) return; st->vj.vjs_packets = vj->sls_o_compressed + vj->sls_o_uncompressed; st->vj.vjs_compressed = vj->sls_o_compressed; @@ -2410,14 +2401,12 @@ ppp_create_interface(int unit, int *retp) int ret = -ENOMEM; int i; - ppp = kmalloc(sizeof(struct ppp), GFP_KERNEL); - if (!ppp) - goto out; - dev = alloc_netdev(0, "", ppp_setup); + dev = alloc_netdev(sizeof(struct ppp), "", ppp_setup); if (!dev) goto out1; - memset(ppp, 0, sizeof(struct ppp)); + ppp = netdev_priv(dev); + ppp->dev = dev; ppp->mru = PPP_MRU; init_ppp_file(&ppp->file, INTERFACE); ppp->file.hdrlen = PPP_HDRLEN - 2; /* don't count proto bytes */ @@ -2430,19 +2419,25 @@ ppp_create_interface(int unit, int *retp) ppp->minseq = -1; skb_queue_head_init(&ppp->mrq); #endif /* CONFIG_PPP_MULTILINK */ - ppp->dev = dev; - dev->priv = ppp; - - dev->hard_start_xmit = ppp_start_xmit; - dev->get_stats = ppp_net_stats; - dev->do_ioctl = ppp_net_ioctl; ret = -EEXIST; mutex_lock(&all_ppp_mutex); - if (unit < 0) - unit = cardmap_find_first_free(all_ppp_units); - else if (cardmap_get(all_ppp_units, unit) != NULL) - goto out2; /* unit already exists */ + + if (unit < 0) { + unit = unit_get(&ppp_units_idr, ppp); + if (unit < 0) { + *retp = unit; + goto out2; + } + } else { + if (unit_find(&ppp_units_idr, unit)) + goto out2; /* unit already exists */ + else { + /* darn, someone is cheating us? */ + *retp = -EINVAL; + goto out2; + } + } /* Initialize the new ppp unit */ ppp->file.index = unit; @@ -2450,14 +2445,15 @@ ppp_create_interface(int unit, int *retp) ret = register_netdev(dev); if (ret != 0) { + unit_put(&ppp_units_idr, unit); printk(KERN_ERR "PPP: couldn't register device %s (%d)\n", dev->name, ret); goto out2; } atomic_inc(&ppp_unit_count); - cardmap_set(&all_ppp_units, unit, ppp); mutex_unlock(&all_ppp_mutex); + *retp = 0; return ppp; @@ -2465,8 +2461,6 @@ out2: mutex_unlock(&all_ppp_mutex); free_netdev(dev); out1: - kfree(ppp); -out: *retp = ret; return NULL; } @@ -2490,19 +2484,17 @@ init_ppp_file(struct ppp_file *pf, int kind) */ static void ppp_shutdown_interface(struct ppp *ppp) { - struct net_device *dev; - mutex_lock(&all_ppp_mutex); - ppp_lock(ppp); - dev = ppp->dev; - ppp->dev = NULL; - ppp_unlock(ppp); /* This will call dev_close() for us. */ - if (dev) { - unregister_netdev(dev); - free_netdev(dev); - } - cardmap_set(&all_ppp_units, ppp->file.index, NULL); + ppp_lock(ppp); + if (!ppp->closing) { + ppp->closing = 1; + ppp_unlock(ppp); + unregister_netdev(ppp->dev); + } else + ppp_unlock(ppp); + + unit_put(&ppp_units_idr, ppp->file.index); ppp->file.dead = 1; ppp->owner = NULL; wake_up_interruptible(&ppp->file.rwait); @@ -2543,7 +2535,10 @@ static void ppp_destroy_interface(struct ppp *ppp) ppp->active_filter = NULL; #endif /* CONFIG_PPP_FILTER */ - kfree(ppp); + if (ppp->xmit_pending) + kfree_skb(ppp->xmit_pending); + + free_netdev(ppp->dev); } /* @@ -2553,7 +2548,7 @@ static void ppp_destroy_interface(struct ppp *ppp) static struct ppp * ppp_find_unit(int unit) { - return cardmap_get(all_ppp_units, unit); + return unit_find(&ppp_units_idr, unit); } /* @@ -2594,18 +2589,18 @@ ppp_connect_channel(struct channel *pch, int unit) mutex_lock(&all_ppp_mutex); ppp = ppp_find_unit(unit); - if (ppp == 0) + if (!ppp) goto out; write_lock_bh(&pch->upl); ret = -EINVAL; - if (pch->ppp != 0) + if (pch->ppp) goto outl; ppp_lock(ppp); if (pch->file.hdrlen > ppp->file.hdrlen) ppp->file.hdrlen = pch->file.hdrlen; hdrlen = pch->file.hdrlen + 2; /* for protocol bytes */ - if (ppp->dev && hdrlen > ppp->dev->hard_header_len) + if (hdrlen > ppp->dev->hard_header_len) ppp->dev->hard_header_len = hdrlen; list_add_tail(&pch->clist, &ppp->channels); ++ppp->n_channels; @@ -2634,7 +2629,7 @@ ppp_disconnect_channel(struct channel *pch) ppp = pch->ppp; pch->ppp = NULL; write_unlock_bh(&pch->upl); - if (ppp != 0) { + if (ppp) { /* remove it from the ppp unit's list */ ppp_lock(ppp); list_del(&pch->clist); @@ -2671,119 +2666,45 @@ static void __exit ppp_cleanup(void) /* should never happen */ if (atomic_read(&ppp_unit_count) || atomic_read(&channel_count)) printk(KERN_ERR "PPP: removing module but units remain!\n"); - cardmap_destroy(&all_ppp_units); - if (unregister_chrdev(PPP_MAJOR, "ppp") != 0) - printk(KERN_ERR "PPP: failed to unregister PPP device\n"); - class_device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0)); + unregister_chrdev(PPP_MAJOR, "ppp"); + device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0)); class_destroy(ppp_class); + idr_destroy(&ppp_units_idr); } /* - * Cardmap implementation. + * Units handling. Caller must protect concurrent access + * by holding all_ppp_mutex */ -static void *cardmap_get(struct cardmap *map, unsigned int nr) + +/* get new free unit number and associate pointer with it */ +static int unit_get(struct idr *p, void *ptr) { - struct cardmap *p; - int i; + int unit, err; - for (p = map; p != NULL; ) { - if ((i = nr >> p->shift) >= CARDMAP_WIDTH) - return NULL; - if (p->shift == 0) - return p->ptr[i]; - nr &= ~(CARDMAP_MASK << p->shift); - p = p->ptr[i]; +again: + if (idr_pre_get(p, GFP_KERNEL) == 0) { + printk(KERN_ERR "Out of memory expanding drawable idr\n"); + return -ENOMEM; } - return NULL; -} -static void cardmap_set(struct cardmap **pmap, unsigned int nr, void *ptr) -{ - struct cardmap *p; - int i; + err = idr_get_new_above(p, ptr, 0, &unit); + if (err == -EAGAIN) + goto again; - p = *pmap; - if (p == NULL || (nr >> p->shift) >= CARDMAP_WIDTH) { - do { - /* need a new top level */ - struct cardmap *np = kmalloc(sizeof(*np), GFP_KERNEL); - memset(np, 0, sizeof(*np)); - np->ptr[0] = p; - if (p != NULL) { - np->shift = p->shift + CARDMAP_ORDER; - p->parent = np; - } else - np->shift = 0; - p = np; - } while ((nr >> p->shift) >= CARDMAP_WIDTH); - *pmap = p; - } - while (p->shift > 0) { - i = (nr >> p->shift) & CARDMAP_MASK; - if (p->ptr[i] == NULL) { - struct cardmap *np = kmalloc(sizeof(*np), GFP_KERNEL); - memset(np, 0, sizeof(*np)); - np->shift = p->shift - CARDMAP_ORDER; - np->parent = p; - p->ptr[i] = np; - } - if (ptr == NULL) - clear_bit(i, &p->inuse); - p = p->ptr[i]; - } - i = nr & CARDMAP_MASK; - p->ptr[i] = ptr; - if (ptr != NULL) - set_bit(i, &p->inuse); - else - clear_bit(i, &p->inuse); + return unit; } -static unsigned int cardmap_find_first_free(struct cardmap *map) +/* put unit number back to a pool */ +static void unit_put(struct idr *p, int n) { - struct cardmap *p; - unsigned int nr = 0; - int i; - - if ((p = map) == NULL) - return 0; - for (;;) { - i = find_first_zero_bit(&p->inuse, CARDMAP_WIDTH); - if (i >= CARDMAP_WIDTH) { - if (p->parent == NULL) - return CARDMAP_WIDTH << p->shift; - p = p->parent; - i = (nr >> p->shift) & CARDMAP_MASK; - set_bit(i, &p->inuse); - continue; - } - nr = (nr & (~CARDMAP_MASK << p->shift)) | (i << p->shift); - if (p->shift == 0 || p->ptr[i] == NULL) - return nr; - p = p->ptr[i]; - } + idr_remove(p, n); } -static void cardmap_destroy(struct cardmap **pmap) +/* get pointer associated with the number */ +static void *unit_find(struct idr *p, int n) { - struct cardmap *p, *np; - int i; - - for (p = *pmap; p != NULL; p = np) { - if (p->shift != 0) { - for (i = 0; i < CARDMAP_WIDTH; ++i) - if (p->ptr[i] != NULL) - break; - if (i < CARDMAP_WIDTH) { - np = p->ptr[i]; - p->ptr[i] = NULL; - continue; - } - } - np = p->parent; - kfree(p); - } - *pmap = NULL; + return idr_find(p, n); } /* Module/initialization stuff */