^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /* net/sched/sch_atm.c - ATM VC selection "queueing discipline" */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) /* Written 1998-2000 by Werner Almesberger, EPFL ICA */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/skbuff.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/atmdev.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/atmclip.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/rtnetlink.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/file.h> /* for fput */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <net/netlink.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <net/pkt_sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <net/pkt_cls.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * The ATM queuing discipline provides a framework for invoking classifiers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * (aka "filters"), which in turn select classes of this queuing discipline.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * Each class maps the flow(s) it is handling to a given VC. Multiple classes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * may share the same VC.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * When creating a class, VCs are specified by passing the number of the open
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * socket descriptor by which the calling process references the VC. The kernel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * keeps the VC open at least until all classes using it are removed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * In this file, most functions are named atm_tc_* to avoid confusion with all
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * the atm_* in net/atm. This naming convention differs from what's used in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * rest of net/sched.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * Known bugs:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * - sometimes messes up the IP stack
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * - any manipulations besides the few operations described in the README, are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * untested and likely to crash the system
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * - should lock the flow while there is data in the queue (?)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define VCC2FLOW(vcc) ((struct atm_flow_data *) ((vcc)->user_back))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) struct atm_flow_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) struct Qdisc_class_common common;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) struct Qdisc *q; /* FIFO, TBF, etc. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) struct tcf_proto __rcu *filter_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) struct tcf_block *block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) struct atm_vcc *vcc; /* VCC; NULL if VCC is closed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) void (*old_pop)(struct atm_vcc *vcc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) struct sk_buff *skb); /* chaining */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) struct atm_qdisc_data *parent; /* parent qdisc */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) struct socket *sock; /* for closing */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) int ref; /* reference count */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) struct gnet_stats_basic_packed bstats;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) struct gnet_stats_queue qstats;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) struct list_head list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) struct atm_flow_data *excess; /* flow for excess traffic;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) NULL to set CLP instead */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) int hdr_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) unsigned char hdr[]; /* header data; MUST BE LAST */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) struct atm_qdisc_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) struct atm_flow_data link; /* unclassified skbs go here */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) struct list_head flows; /* NB: "link" is also on this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) list */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) struct tasklet_struct task; /* dequeue tasklet */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) /* ------------------------- Class/flow operations ------------------------- */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) static inline struct atm_flow_data *lookup_flow(struct Qdisc *sch, u32 classid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) struct atm_qdisc_data *p = qdisc_priv(sch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) struct atm_flow_data *flow;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) list_for_each_entry(flow, &p->flows, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) if (flow->common.classid == classid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) return flow;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) static int atm_tc_graft(struct Qdisc *sch, unsigned long arg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) struct Qdisc *new, struct Qdisc **old,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) struct netlink_ext_ack *extack)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) struct atm_qdisc_data *p = qdisc_priv(sch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) struct atm_flow_data *flow = (struct atm_flow_data *)arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) pr_debug("atm_tc_graft(sch %p,[qdisc %p],flow %p,new %p,old %p)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) sch, p, flow, new, old);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) if (list_empty(&flow->list))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) if (!new)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) new = &noop_qdisc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) *old = flow->q;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) flow->q = new;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) if (*old)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) qdisc_reset(*old);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) static struct Qdisc *atm_tc_leaf(struct Qdisc *sch, unsigned long cl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) struct atm_flow_data *flow = (struct atm_flow_data *)cl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) pr_debug("atm_tc_leaf(sch %p,flow %p)\n", sch, flow);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) return flow ? flow->q : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) static unsigned long atm_tc_find(struct Qdisc *sch, u32 classid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) struct atm_qdisc_data *p __maybe_unused = qdisc_priv(sch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) struct atm_flow_data *flow;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) pr_debug("%s(sch %p,[qdisc %p],classid %x)\n", __func__, sch, p, classid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) flow = lookup_flow(sch, classid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) pr_debug("%s: flow %p\n", __func__, flow);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) return (unsigned long)flow;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) static unsigned long atm_tc_bind_filter(struct Qdisc *sch,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) unsigned long parent, u32 classid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) struct atm_qdisc_data *p __maybe_unused = qdisc_priv(sch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) struct atm_flow_data *flow;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) pr_debug("%s(sch %p,[qdisc %p],classid %x)\n", __func__, sch, p, classid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) flow = lookup_flow(sch, classid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) if (flow)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) flow->ref++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) pr_debug("%s: flow %p\n", __func__, flow);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) return (unsigned long)flow;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) * atm_tc_put handles all destructions, including the ones that are explicitly
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) * requested (atm_tc_destroy, etc.). The assumption here is that we never drop
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) * anything that still seems to be in use.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) static void atm_tc_put(struct Qdisc *sch, unsigned long cl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) struct atm_qdisc_data *p = qdisc_priv(sch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) struct atm_flow_data *flow = (struct atm_flow_data *)cl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) pr_debug("atm_tc_put(sch %p,[qdisc %p],flow %p)\n", sch, p, flow);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) if (--flow->ref)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) pr_debug("atm_tc_put: destroying\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) list_del_init(&flow->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) pr_debug("atm_tc_put: qdisc %p\n", flow->q);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) qdisc_put(flow->q);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) tcf_block_put(flow->block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) if (flow->sock) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) pr_debug("atm_tc_put: f_count %ld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) file_count(flow->sock->file));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) flow->vcc->pop = flow->old_pop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) sockfd_put(flow->sock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) if (flow->excess)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) atm_tc_put(sch, (unsigned long)flow->excess);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) if (flow != &p->link)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) kfree(flow);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) * If flow == &p->link, the qdisc no longer works at this point and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) * needs to be removed. (By the caller of atm_tc_put.)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) static void sch_atm_pop(struct atm_vcc *vcc, struct sk_buff *skb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) struct atm_qdisc_data *p = VCC2FLOW(vcc)->parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) pr_debug("sch_atm_pop(vcc %p,skb %p,[qdisc %p])\n", vcc, skb, p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) VCC2FLOW(vcc)->old_pop(vcc, skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) tasklet_schedule(&p->task);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) static const u8 llc_oui_ip[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 0xaa, /* DSAP: non-ISO */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 0xaa, /* SSAP: non-ISO */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 0x03, /* Ctrl: Unnumbered Information Command PDU */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 0x00, /* OUI: EtherType */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 0x00, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 0x08, 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) }; /* Ethertype IP (0800) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) static const struct nla_policy atm_policy[TCA_ATM_MAX + 1] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) [TCA_ATM_FD] = { .type = NLA_U32 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) [TCA_ATM_EXCESS] = { .type = NLA_U32 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) struct nlattr **tca, unsigned long *arg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) struct netlink_ext_ack *extack)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) struct atm_qdisc_data *p = qdisc_priv(sch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) struct atm_flow_data *flow = (struct atm_flow_data *)*arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) struct atm_flow_data *excess = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) struct nlattr *opt = tca[TCA_OPTIONS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) struct nlattr *tb[TCA_ATM_MAX + 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) struct socket *sock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) int fd, error, hdr_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) void *hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) pr_debug("atm_tc_change(sch %p,[qdisc %p],classid %x,parent %x,"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) "flow %p,opt %p)\n", sch, p, classid, parent, flow, opt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) * The concept of parents doesn't apply for this qdisc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) if (parent && parent != TC_H_ROOT && parent != sch->handle)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) * ATM classes cannot be changed. In order to change properties of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) * ATM connection, that socket needs to be modified directly (via the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) * native ATM API. In order to send a flow to a different VC, the old
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) * class needs to be removed and a new one added. (This may be changed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) * later.)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) if (flow)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) if (opt == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) error = nla_parse_nested_deprecated(tb, TCA_ATM_MAX, opt, atm_policy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) if (error < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) if (!tb[TCA_ATM_FD])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) fd = nla_get_u32(tb[TCA_ATM_FD]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) pr_debug("atm_tc_change: fd %d\n", fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) if (tb[TCA_ATM_HDR]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) hdr_len = nla_len(tb[TCA_ATM_HDR]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) hdr = nla_data(tb[TCA_ATM_HDR]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) hdr_len = RFC1483LLC_LEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) hdr = NULL; /* default LLC/SNAP for IP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) if (!tb[TCA_ATM_EXCESS])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) excess = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) excess = (struct atm_flow_data *)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) atm_tc_find(sch, nla_get_u32(tb[TCA_ATM_EXCESS]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) if (!excess)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) pr_debug("atm_tc_change: type %d, payload %d, hdr_len %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) opt->nla_type, nla_len(opt), hdr_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) sock = sockfd_lookup(fd, &error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) if (!sock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) return error; /* f_count++ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) pr_debug("atm_tc_change: f_count %ld\n", file_count(sock->file));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) if (sock->ops->family != PF_ATMSVC && sock->ops->family != PF_ATMPVC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) error = -EPROTOTYPE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) goto err_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) /* @@@ should check if the socket is really operational or we'll crash
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) on vcc->send */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) if (classid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) if (TC_H_MAJ(classid ^ sch->handle)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) pr_debug("atm_tc_change: classid mismatch\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) error = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) goto err_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) unsigned long cl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) for (i = 1; i < 0x8000; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) classid = TC_H_MAKE(sch->handle, 0x8000 | i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) cl = atm_tc_find(sch, classid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) if (!cl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) pr_debug("atm_tc_change: new id %x\n", classid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) flow = kzalloc(sizeof(struct atm_flow_data) + hdr_len, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) pr_debug("atm_tc_change: flow %p\n", flow);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) if (!flow) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) error = -ENOBUFS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) goto err_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) error = tcf_block_get(&flow->block, &flow->filter_list, sch,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) extack);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) kfree(flow);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) goto err_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) flow->q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, classid,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) extack);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) if (!flow->q)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) flow->q = &noop_qdisc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) pr_debug("atm_tc_change: qdisc %p\n", flow->q);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) flow->sock = sock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) flow->vcc = ATM_SD(sock); /* speedup */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) flow->vcc->user_back = flow;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) pr_debug("atm_tc_change: vcc %p\n", flow->vcc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) flow->old_pop = flow->vcc->pop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) flow->parent = p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) flow->vcc->pop = sch_atm_pop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) flow->common.classid = classid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) flow->ref = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) flow->excess = excess;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) list_add(&flow->list, &p->link.list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) flow->hdr_len = hdr_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) if (hdr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) memcpy(flow->hdr, hdr, hdr_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) memcpy(flow->hdr, llc_oui_ip, sizeof(llc_oui_ip));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) *arg = (unsigned long)flow;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) err_out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) sockfd_put(sock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) static int atm_tc_delete(struct Qdisc *sch, unsigned long arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) struct atm_qdisc_data *p = qdisc_priv(sch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) struct atm_flow_data *flow = (struct atm_flow_data *)arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) pr_debug("atm_tc_delete(sch %p,[qdisc %p],flow %p)\n", sch, p, flow);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) if (list_empty(&flow->list))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) if (rcu_access_pointer(flow->filter_list) || flow == &p->link)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) * Reference count must be 2: one for "keepalive" (set at class
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) * creation), and one for the reference held when calling delete.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) if (flow->ref < 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) pr_err("atm_tc_delete: flow->ref == %d\n", flow->ref);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) if (flow->ref > 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) return -EBUSY; /* catch references via excess, etc. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) atm_tc_put(sch, arg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) static void atm_tc_walk(struct Qdisc *sch, struct qdisc_walker *walker)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) struct atm_qdisc_data *p = qdisc_priv(sch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) struct atm_flow_data *flow;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) pr_debug("atm_tc_walk(sch %p,[qdisc %p],walker %p)\n", sch, p, walker);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) if (walker->stop)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) list_for_each_entry(flow, &p->flows, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) if (walker->count >= walker->skip &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) walker->fn(sch, (unsigned long)flow, walker) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) walker->stop = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) walker->count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) static struct tcf_block *atm_tc_tcf_block(struct Qdisc *sch, unsigned long cl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) struct netlink_ext_ack *extack)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) struct atm_qdisc_data *p = qdisc_priv(sch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) struct atm_flow_data *flow = (struct atm_flow_data *)cl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) pr_debug("atm_tc_find_tcf(sch %p,[qdisc %p],flow %p)\n", sch, p, flow);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) return flow ? flow->block : p->link.block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) /* --------------------------- Qdisc operations ---------------------------- */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) struct sk_buff **to_free)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) struct atm_qdisc_data *p = qdisc_priv(sch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) struct atm_flow_data *flow;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) struct tcf_result res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) int ret = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) pr_debug("atm_tc_enqueue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) result = TC_ACT_OK; /* be nice to gcc */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) flow = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) if (TC_H_MAJ(skb->priority) != sch->handle ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) !(flow = (struct atm_flow_data *)atm_tc_find(sch, skb->priority))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) struct tcf_proto *fl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) list_for_each_entry(flow, &p->flows, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) fl = rcu_dereference_bh(flow->filter_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) if (fl) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) result = tcf_classify(skb, fl, &res, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) if (result < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) flow = (struct atm_flow_data *)res.class;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) if (!flow)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) flow = lookup_flow(sch, res.classid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) goto done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) flow = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) done:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) if (!flow) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) flow = &p->link;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) if (flow->vcc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) ATM_SKB(skb)->atm_options = flow->vcc->atm_options;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) /*@@@ looks good ... but it's not supposed to work :-) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) #ifdef CONFIG_NET_CLS_ACT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) switch (result) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) case TC_ACT_QUEUED:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) case TC_ACT_STOLEN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) case TC_ACT_TRAP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) __qdisc_drop(skb, to_free);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) return NET_XMIT_SUCCESS | __NET_XMIT_STOLEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) case TC_ACT_SHOT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) __qdisc_drop(skb, to_free);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) goto drop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) case TC_ACT_RECLASSIFY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) if (flow->excess)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) flow = flow->excess;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) ATM_SKB(skb)->atm_options |= ATM_ATMOPT_CLP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) ret = qdisc_enqueue(skb, flow->q, to_free);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) if (ret != NET_XMIT_SUCCESS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) drop: __maybe_unused
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) if (net_xmit_drop_count(ret)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) qdisc_qstats_drop(sch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) if (flow)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) flow->qstats.drops++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) * Okay, this may seem weird. We pretend we've dropped the packet if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) * it goes via ATM. The reason for this is that the outer qdisc
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) * expects to be able to q->dequeue the packet later on if we return
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) * success at this place. Also, sch->q.qdisc needs to reflect whether
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) * there is a packet egligible for dequeuing or not. Note that the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) * statistics of the outer qdisc are necessarily wrong because of all
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) * this. There's currently no correct solution for this.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) if (flow == &p->link) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) sch->q.qlen++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) return NET_XMIT_SUCCESS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) tasklet_schedule(&p->task);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) return NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) * Dequeue packets and send them over ATM. Note that we quite deliberately
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) * avoid checking net_device's flow control here, simply because sch_atm
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) * uses its own channels, which have nothing to do with any CLIP/LANE/or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) * non-ATM interfaces.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) static void sch_atm_dequeue(unsigned long data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) struct Qdisc *sch = (struct Qdisc *)data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) struct atm_qdisc_data *p = qdisc_priv(sch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) struct atm_flow_data *flow;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) struct sk_buff *skb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) pr_debug("sch_atm_dequeue(sch %p,[qdisc %p])\n", sch, p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) list_for_each_entry(flow, &p->flows, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) if (flow == &p->link)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) * If traffic is properly shaped, this won't generate nasty
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) * little bursts. Otherwise, it may ... (but that's okay)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) while ((skb = flow->q->ops->peek(flow->q))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) if (!atm_may_send(flow->vcc, skb->truesize))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) skb = qdisc_dequeue_peeked(flow->q);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) if (unlikely(!skb))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) qdisc_bstats_update(sch, skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) bstats_update(&flow->bstats, skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) pr_debug("atm_tc_dequeue: sending on class %p\n", flow);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) /* remove any LL header somebody else has attached */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) skb_pull(skb, skb_network_offset(skb));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) if (skb_headroom(skb) < flow->hdr_len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) struct sk_buff *new;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) new = skb_realloc_headroom(skb, flow->hdr_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) dev_kfree_skb(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) if (!new)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) skb = new;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) pr_debug("sch_atm_dequeue: ip %p, data %p\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) skb_network_header(skb), skb->data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) ATM_SKB(skb)->vcc = flow->vcc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) memcpy(skb_push(skb, flow->hdr_len), flow->hdr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) flow->hdr_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) refcount_add(skb->truesize,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) &sk_atm(flow->vcc)->sk_wmem_alloc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) /* atm.atm_options are already set by atm_tc_enqueue */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) flow->vcc->send(flow->vcc, skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) static struct sk_buff *atm_tc_dequeue(struct Qdisc *sch)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) struct atm_qdisc_data *p = qdisc_priv(sch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) struct sk_buff *skb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) pr_debug("atm_tc_dequeue(sch %p,[qdisc %p])\n", sch, p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) tasklet_schedule(&p->task);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) skb = qdisc_dequeue_peeked(p->link.q);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) if (skb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) sch->q.qlen--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) return skb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) static struct sk_buff *atm_tc_peek(struct Qdisc *sch)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) struct atm_qdisc_data *p = qdisc_priv(sch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) pr_debug("atm_tc_peek(sch %p,[qdisc %p])\n", sch, p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) return p->link.q->ops->peek(p->link.q);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) struct netlink_ext_ack *extack)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) struct atm_qdisc_data *p = qdisc_priv(sch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) pr_debug("atm_tc_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) INIT_LIST_HEAD(&p->flows);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) INIT_LIST_HEAD(&p->link.list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) list_add(&p->link.list, &p->flows);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) p->link.q = qdisc_create_dflt(sch->dev_queue,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) &pfifo_qdisc_ops, sch->handle, extack);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) if (!p->link.q)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) p->link.q = &noop_qdisc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) pr_debug("atm_tc_init: link (%p) qdisc %p\n", &p->link, p->link.q);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) p->link.vcc = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) p->link.sock = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) p->link.common.classid = sch->handle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) p->link.ref = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) err = tcf_block_get(&p->link.block, &p->link.filter_list, sch,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) extack);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) tasklet_init(&p->task, sch_atm_dequeue, (unsigned long)sch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) static void atm_tc_reset(struct Qdisc *sch)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) struct atm_qdisc_data *p = qdisc_priv(sch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) struct atm_flow_data *flow;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) pr_debug("atm_tc_reset(sch %p,[qdisc %p])\n", sch, p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) list_for_each_entry(flow, &p->flows, list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) qdisc_reset(flow->q);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) sch->q.qlen = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) static void atm_tc_destroy(struct Qdisc *sch)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) struct atm_qdisc_data *p = qdisc_priv(sch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) struct atm_flow_data *flow, *tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) pr_debug("atm_tc_destroy(sch %p,[qdisc %p])\n", sch, p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) list_for_each_entry(flow, &p->flows, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) tcf_block_put(flow->block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) flow->block = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) list_for_each_entry_safe(flow, tmp, &p->flows, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) if (flow->ref > 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) pr_err("atm_destroy: %p->ref = %d\n", flow, flow->ref);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) atm_tc_put(sch, (unsigned long)flow);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) tasklet_kill(&p->task);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) static int atm_tc_dump_class(struct Qdisc *sch, unsigned long cl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) struct sk_buff *skb, struct tcmsg *tcm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) struct atm_qdisc_data *p = qdisc_priv(sch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) struct atm_flow_data *flow = (struct atm_flow_data *)cl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) struct nlattr *nest;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) pr_debug("atm_tc_dump_class(sch %p,[qdisc %p],flow %p,skb %p,tcm %p)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) sch, p, flow, skb, tcm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) if (list_empty(&flow->list))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) tcm->tcm_handle = flow->common.classid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) tcm->tcm_info = flow->q->handle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) nest = nla_nest_start_noflag(skb, TCA_OPTIONS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) if (nest == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) goto nla_put_failure;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) if (nla_put(skb, TCA_ATM_HDR, flow->hdr_len, flow->hdr))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) goto nla_put_failure;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) if (flow->vcc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) struct sockaddr_atmpvc pvc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) int state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) memset(&pvc, 0, sizeof(pvc));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) pvc.sap_family = AF_ATMPVC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) pvc.sap_addr.itf = flow->vcc->dev ? flow->vcc->dev->number : -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) pvc.sap_addr.vpi = flow->vcc->vpi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) pvc.sap_addr.vci = flow->vcc->vci;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) if (nla_put(skb, TCA_ATM_ADDR, sizeof(pvc), &pvc))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) goto nla_put_failure;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) state = ATM_VF2VS(flow->vcc->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) if (nla_put_u32(skb, TCA_ATM_STATE, state))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) goto nla_put_failure;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) if (flow->excess) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) if (nla_put_u32(skb, TCA_ATM_EXCESS, flow->common.classid))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) goto nla_put_failure;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) if (nla_put_u32(skb, TCA_ATM_EXCESS, 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) goto nla_put_failure;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) return nla_nest_end(skb, nest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) nla_put_failure:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) nla_nest_cancel(skb, nest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) atm_tc_dump_class_stats(struct Qdisc *sch, unsigned long arg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) struct gnet_dump *d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) struct atm_flow_data *flow = (struct atm_flow_data *)arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) if (gnet_stats_copy_basic(qdisc_root_sleeping_running(sch),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) d, NULL, &flow->bstats) < 0 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) gnet_stats_copy_queue(d, NULL, &flow->qstats, flow->q->q.qlen) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) static int atm_tc_dump(struct Qdisc *sch, struct sk_buff *skb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) static const struct Qdisc_class_ops atm_class_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) .graft = atm_tc_graft,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) .leaf = atm_tc_leaf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) .find = atm_tc_find,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) .change = atm_tc_change,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) .delete = atm_tc_delete,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) .walk = atm_tc_walk,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) .tcf_block = atm_tc_tcf_block,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) .bind_tcf = atm_tc_bind_filter,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) .unbind_tcf = atm_tc_put,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) .dump = atm_tc_dump_class,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) .dump_stats = atm_tc_dump_class_stats,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) static struct Qdisc_ops atm_qdisc_ops __read_mostly = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) .cl_ops = &atm_class_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) .id = "atm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) .priv_size = sizeof(struct atm_qdisc_data),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) .enqueue = atm_tc_enqueue,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) .dequeue = atm_tc_dequeue,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) .peek = atm_tc_peek,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) .init = atm_tc_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) .reset = atm_tc_reset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) .destroy = atm_tc_destroy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) .dump = atm_tc_dump,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) static int __init atm_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) return register_qdisc(&atm_qdisc_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) static void __exit atm_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) unregister_qdisc(&atm_qdisc_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) module_init(atm_init)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) module_exit(atm_exit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) MODULE_LICENSE("GPL");