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