orinoco: fix unsafe locking in orinoco_cs_resume
[safe/jmp/linux-2.6] / net / sched / sch_atm.c
index 19c0007..43d3725 100644 (file)
@@ -160,9 +160,9 @@ static void atm_tc_put(struct Qdisc *sch, unsigned long cl)
        *prev = flow->next;
        pr_debug("atm_tc_put: qdisc %p\n", flow->q);
        qdisc_destroy(flow->q);
-       tcf_destroy_chain(flow->filter_list);
+       tcf_destroy_chain(&flow->filter_list);
        if (flow->sock) {
-               pr_debug("atm_tc_put: f_count %d\n",
+               pr_debug("atm_tc_put: f_count %ld\n",
                        file_count(flow->sock->file));
                flow->vcc->pop = flow->old_pop;
                sockfd_put(flow->sock);
@@ -195,6 +195,11 @@ static const u8 llc_oui_ip[] = {
        0x08, 0x00
 };                             /* Ethertype IP (0800) */
 
+static const struct nla_policy atm_policy[TCA_ATM_MAX + 1] = {
+       [TCA_ATM_FD]            = { .type = NLA_U32 },
+       [TCA_ATM_EXCESS]        = { .type = NLA_U32 },
+};
+
 static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent,
                         struct nlattr **tca, unsigned long *arg)
 {
@@ -225,13 +230,14 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent,
                return -EBUSY;
        if (opt == NULL)
                return -EINVAL;
-       error = nla_parse_nested(tb, TCA_ATM_MAX, opt, NULL);
+
+       error = nla_parse_nested(tb, TCA_ATM_MAX, opt, atm_policy);
        if (error < 0)
                return error;
 
-       if (!tb[TCA_ATM_FD] || nla_len(tb[TCA_ATM_FD]) < sizeof(fd))
+       if (!tb[TCA_ATM_FD])
                return -EINVAL;
-       fd = *(int *)nla_data(tb[TCA_ATM_FD]);
+       fd = nla_get_u32(tb[TCA_ATM_FD]);
        pr_debug("atm_tc_change: fd %d\n", fd);
        if (tb[TCA_ATM_HDR]) {
                hdr_len = nla_len(tb[TCA_ATM_HDR]);
@@ -243,10 +249,8 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent,
        if (!tb[TCA_ATM_EXCESS])
                excess = NULL;
        else {
-               if (nla_len(tb[TCA_ATM_EXCESS]) != sizeof(u32))
-                       return -EINVAL;
                excess = (struct atm_flow_data *)
-                       atm_tc_get(sch, *(u32 *)nla_data(tb[TCA_ATM_EXCESS]));
+                       atm_tc_get(sch, nla_get_u32(tb[TCA_ATM_EXCESS]));
                if (!excess)
                        return -ENOENT;
        }
@@ -255,7 +259,7 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent,
        sock = sockfd_lookup(fd, &error);
        if (!sock)
                return error;   /* f_count++ */
-       pr_debug("atm_tc_change: f_count %d\n", file_count(sock->file));
+       pr_debug("atm_tc_change: f_count %ld\n", file_count(sock->file));
        if (sock->ops->family != PF_ATMSVC && sock->ops->family != PF_ATMPVC) {
                error = -EPROTOTYPE;
                goto err_out;
@@ -292,7 +296,8 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent,
                goto err_out;
        }
        flow->filter_list = NULL;
-       flow->q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, classid);
+       flow->q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
+                                   &pfifo_qdisc_ops, classid);
        if (!flow->q)
                flow->q = &noop_qdisc;
        pr_debug("atm_tc_change: qdisc %p\n", flow->q);
@@ -410,7 +415,7 @@ static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                case TC_ACT_QUEUED:
                case TC_ACT_STOLEN:
                        kfree_skb(skb);
-                       return NET_XMIT_SUCCESS;
+                       return NET_XMIT_SUCCESS | __NET_XMIT_STOLEN;
                case TC_ACT_SHOT:
                        kfree_skb(skb);
                        goto drop;
@@ -424,17 +429,19 @@ static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 #endif
        }
 
-       ret = flow->q->enqueue(skb, flow->q);
+       ret = qdisc_enqueue(skb, flow->q);
        if (ret != 0) {
 drop: __maybe_unused
-               sch->qstats.drops++;
-               if (flow)
-                       flow->qstats.drops++;
+               if (net_xmit_drop_count(ret)) {
+                       sch->qstats.drops++;
+                       if (flow)
+                               flow->qstats.drops++;
+               }
                return ret;
        }
-       sch->bstats.bytes += skb->len;
+       sch->bstats.bytes += qdisc_pkt_len(skb);
        sch->bstats.packets++;
-       flow->bstats.bytes += skb->len;
+       flow->bstats.bytes += qdisc_pkt_len(skb);
        flow->bstats.packets++;
        /*
         * Okay, this may seem weird. We pretend we've dropped the packet if
@@ -450,7 +457,7 @@ drop: __maybe_unused
                return 0;
        }
        tasklet_schedule(&p->task);
-       return NET_XMIT_BYPASS;
+       return NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
 }
 
 /*
@@ -525,7 +532,7 @@ static int atm_tc_requeue(struct sk_buff *skb, struct Qdisc *sch)
        if (!ret) {
                sch->q.qlen++;
                sch->qstats.requeues++;
-       } else {
+       } else if (net_xmit_drop_count(ret)) {
                sch->qstats.drops++;
                p->link.qstats.drops++;
        }
@@ -551,7 +558,8 @@ static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt)
 
        pr_debug("atm_tc_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt);
        p->flows = &p->link;
-       p->link.q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, sch->handle);
+       p->link.q = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
+                                     &pfifo_qdisc_ops, sch->handle);
        if (!p->link.q)
                p->link.q = &noop_qdisc;
        pr_debug("atm_tc_init: link (%p) qdisc %p\n", &p->link, p->link.q);
@@ -582,10 +590,11 @@ static void atm_tc_destroy(struct Qdisc *sch)
        struct atm_flow_data *flow;
 
        pr_debug("atm_tc_destroy(sch %p,[qdisc %p])\n", sch, p);
+       for (flow = p->flows; flow; flow = flow->next)
+               tcf_destroy_chain(&flow->filter_list);
+
        /* races ? */
        while ((flow = p->flows)) {
-               tcf_destroy_chain(flow->filter_list);
-               flow->filter_list = NULL;
                if (flow->ref > 1)
                        printk(KERN_ERR "atm_destroy: %p->ref = %d\n", flow,
                               flow->ref);
@@ -629,14 +638,12 @@ static int atm_tc_dump_class(struct Qdisc *sch, unsigned long cl,
                pvc.sap_addr.vci = flow->vcc->vci;
                NLA_PUT(skb, TCA_ATM_ADDR, sizeof(pvc), &pvc);
                state = ATM_VF2VS(flow->vcc->flags);
-               NLA_PUT(skb, TCA_ATM_STATE, sizeof(state), &state);
+               NLA_PUT_U32(skb, TCA_ATM_STATE, state);
        }
        if (flow->excess)
-               NLA_PUT(skb, TCA_ATM_EXCESS, sizeof(u32), &flow->classid);
+               NLA_PUT_U32(skb, TCA_ATM_EXCESS, flow->classid);
        else {
-               static u32 zero;
-
-               NLA_PUT(skb, TCA_ATM_EXCESS, sizeof(zero), &zero);
+               NLA_PUT_U32(skb, TCA_ATM_EXCESS, 0);
        }
 
        nla_nest_end(skb, nest);