clip.c 24.1 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
2
3
4
/* net/atm/clip.c - RFC1577 Classical IP over ATM */

/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */

5
6
#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__

Linus Torvalds's avatar
Linus Torvalds committed
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/kernel.h> /* for UINT_MAX */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/wait.h>
#include <linux/timer.h>
#include <linux/if_arp.h> /* for some manifest constants */
#include <linux/notifier.h>
#include <linux/atm.h>
#include <linux/atmdev.h>
#include <linux/atmclip.h>
#include <linux/atmarp.h>
22
#include <linux/capability.h>
Linus Torvalds's avatar
Linus Torvalds committed
23
24
25
26
27
#include <linux/ip.h> /* for net/route.h */
#include <linux/in.h> /* for struct sockaddr_in */
#include <linux/if.h> /* for IFF_UP */
#include <linux/inetdevice.h>
#include <linux/bitops.h>
Randy Dunlap's avatar
Randy Dunlap committed
28
#include <linux/poison.h>
Linus Torvalds's avatar
Linus Torvalds committed
29
30
31
32
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/rcupdate.h>
#include <linux/jhash.h>
33
#include <linux/slab.h>
Linus Torvalds's avatar
Linus Torvalds committed
34
35
#include <net/route.h> /* for struct rtable and routing */
#include <net/icmp.h> /* icmp_send */
36
37
#include <linux/param.h> /* for HZ */
#include <linux/uaccess.h>
Linus Torvalds's avatar
Linus Torvalds committed
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <asm/byteorder.h> /* for htons etc. */
#include <asm/system.h> /* save/restore_flags */
#include <asm/atomic.h>

#include "common.h"
#include "resources.h"
#include <net/atmclip.h>

static struct net_device *clip_devs;
static struct atm_vcc *atmarpd;
static struct neigh_table clip_tbl;
static struct timer_list idle_timer;

Al Viro's avatar
Al Viro committed
51
static int to_atmarpd(enum atmarp_ctrl_type type, int itf, __be32 ip)
Linus Torvalds's avatar
Linus Torvalds committed
52
53
54
55
56
{
	struct sock *sk;
	struct atmarp_ctrl *ctrl;
	struct sk_buff *skb;

57
	pr_debug("(%d)\n", type);
58
59
	if (!atmarpd)
		return -EUNATCH;
60
	skb = alloc_skb(sizeof(struct atmarp_ctrl), GFP_ATOMIC);
61
62
	if (!skb)
		return -ENOMEM;
63
	ctrl = (struct atmarp_ctrl *)skb_put(skb, sizeof(struct atmarp_ctrl));
Linus Torvalds's avatar
Linus Torvalds committed
64
65
66
	ctrl->type = type;
	ctrl->itf_num = itf;
	ctrl->ip = ip;
67
	atm_force_charge(atmarpd, skb->truesize);
Linus Torvalds's avatar
Linus Torvalds committed
68
69
70
71
72
73
74

	sk = sk_atm(atmarpd);
	skb_queue_tail(&sk->sk_receive_queue, skb);
	sk->sk_data_ready(sk, skb->len);
	return 0;
}

75
static void link_vcc(struct clip_vcc *clip_vcc, struct atmarp_entry *entry)
Linus Torvalds's avatar
Linus Torvalds committed
76
{
77
	pr_debug("%p to entry %p (neigh %p)\n", clip_vcc, entry, entry->neigh);
Linus Torvalds's avatar
Linus Torvalds committed
78
	clip_vcc->entry = entry;
79
	clip_vcc->xoff = 0;	/* @@@ may overrun buffer by one packet */
Linus Torvalds's avatar
Linus Torvalds committed
80
81
82
83
84
85
86
87
88
89
90
	clip_vcc->next = entry->vccs;
	entry->vccs = clip_vcc;
	entry->neigh->used = jiffies;
}

static void unlink_clip_vcc(struct clip_vcc *clip_vcc)
{
	struct atmarp_entry *entry = clip_vcc->entry;
	struct clip_vcc **walk;

	if (!entry) {
91
		pr_crit("!clip_vcc->entry (clip_vcc %p)\n", clip_vcc);
Linus Torvalds's avatar
Linus Torvalds committed
92
93
		return;
	}
Herbert Xu's avatar
Herbert Xu committed
94
	netif_tx_lock_bh(entry->neigh->dev);	/* block clip_start_xmit() */
Linus Torvalds's avatar
Linus Torvalds committed
95
96
97
98
99
	entry->neigh->used = jiffies;
	for (walk = &entry->vccs; *walk; walk = &(*walk)->next)
		if (*walk == clip_vcc) {
			int error;

100
			*walk = clip_vcc->next;	/* atomic */
Linus Torvalds's avatar
Linus Torvalds committed
101
102
103
104
105
			clip_vcc->entry = NULL;
			if (clip_vcc->xoff)
				netif_wake_queue(entry->neigh->dev);
			if (entry->vccs)
				goto out;
106
107
			entry->expires = jiffies - 1;
			/* force resolution or expiration */
Linus Torvalds's avatar
Linus Torvalds committed
108
109
110
			error = neigh_update(entry->neigh, NULL, NUD_NONE,
					     NEIGH_UPDATE_F_ADMIN);
			if (error)
111
				pr_crit("neigh_update failed with %d\n", error);
Linus Torvalds's avatar
Linus Torvalds committed
112
113
			goto out;
		}
114
	pr_crit("ATMARP: failed (entry %p, vcc 0x%p)\n", entry, clip_vcc);
115
out:
Herbert Xu's avatar
Herbert Xu committed
116
	netif_tx_unlock_bh(entry->neigh->dev);
Linus Torvalds's avatar
Linus Torvalds committed
117
118
119
120
121
122
123
124
125
126
127
128
}

/* The neighbour entry n->lock is held. */
static int neigh_check_cb(struct neighbour *n)
{
	struct atmarp_entry *entry = NEIGH2ENTRY(n);
	struct clip_vcc *cv;

	for (cv = entry->vccs; cv; cv = cv->next) {
		unsigned long exp = cv->last_use + cv->idle_timeout;

		if (cv->idle_timeout && time_after(jiffies, exp)) {
129
			pr_debug("releasing vcc %p->%p of entry %p\n",
130
				 cv, cv->vcc, entry);
Linus Torvalds's avatar
Linus Torvalds committed
131
132
133
134
135
136
137
138
139
140
			vcc_release_async(cv->vcc, -ETIMEDOUT);
		}
	}

	if (entry->vccs || time_before(jiffies, entry->expires))
		return 0;

	if (atomic_read(&n->refcnt) > 1) {
		struct sk_buff *skb;

141
		pr_debug("destruction postponed with ref %d\n",
142
			 atomic_read(&n->refcnt));
Linus Torvalds's avatar
Linus Torvalds committed
143

144
		while ((skb = skb_dequeue(&n->arp_queue)) != NULL)
Linus Torvalds's avatar
Linus Torvalds committed
145
146
147
148
149
			dev_kfree_skb(skb);

		return 0;
	}

150
	pr_debug("expired neigh %p\n", n);
Linus Torvalds's avatar
Linus Torvalds committed
151
152
153
154
155
156
157
	return 1;
}

static void idle_timer_check(unsigned long dummy)
{
	write_lock(&clip_tbl.lock);
	__neigh_for_each_release(&clip_tbl, neigh_check_cb);
158
	mod_timer(&idle_timer, jiffies + CLIP_CHECK_INTERVAL * HZ);
Linus Torvalds's avatar
Linus Torvalds committed
159
160
161
162
163
164
165
	write_unlock(&clip_tbl.lock);
}

static int clip_arp_rcv(struct sk_buff *skb)
{
	struct atm_vcc *vcc;

166
	pr_debug("\n");
Linus Torvalds's avatar
Linus Torvalds committed
167
	vcc = ATM_SKB(skb)->vcc;
168
	if (!vcc || !atm_charge(vcc, skb->truesize)) {
Linus Torvalds's avatar
Linus Torvalds committed
169
170
171
		dev_kfree_skb_any(skb);
		return 0;
	}
172
173
	pr_debug("pushing to %p\n", vcc);
	pr_debug("using %p\n", CLIP_VCC(vcc)->old_push);
174
	CLIP_VCC(vcc)->old_push(vcc, skb);
Linus Torvalds's avatar
Linus Torvalds committed
175
176
177
178
179
180
181
182
183
	return 0;
}

static const unsigned char llc_oui[] = {
	0xaa,	/* DSAP: non-ISO */
	0xaa,	/* SSAP: non-ISO */
	0x03,	/* Ctrl: Unnumbered Information Command PDU */
	0x00,	/* OUI: EtherType */
	0x00,
184
185
	0x00
};
Linus Torvalds's avatar
Linus Torvalds committed
186

187
static void clip_push(struct atm_vcc *vcc, struct sk_buff *skb)
Linus Torvalds's avatar
Linus Torvalds committed
188
189
190
{
	struct clip_vcc *clip_vcc = CLIP_VCC(vcc);

191
	pr_debug("\n");
Linus Torvalds's avatar
Linus Torvalds committed
192
	if (!skb) {
193
		pr_debug("removing VCC %p\n", clip_vcc);
194
195
196
		if (clip_vcc->entry)
			unlink_clip_vcc(clip_vcc);
		clip_vcc->old_push(vcc, NULL);	/* pass on the bad news */
Linus Torvalds's avatar
Linus Torvalds committed
197
198
199
		kfree(clip_vcc);
		return;
	}
200
	atm_return(vcc, skb->truesize);
Linus Torvalds's avatar
Linus Torvalds committed
201
	skb->dev = clip_vcc->entry ? clip_vcc->entry->neigh->dev : clip_devs;
202
	/* clip_vcc->entry == NULL if we don't have an IP address yet */
Linus Torvalds's avatar
Linus Torvalds committed
203
204
205
206
207
	if (!skb->dev) {
		dev_kfree_skb_any(skb);
		return;
	}
	ATM_SKB(skb)->vcc = vcc;
208
	skb_reset_mac_header(skb);
209
210
211
	if (!clip_vcc->encap ||
	    skb->len < RFC1483LLC_LEN ||
	    memcmp(skb->data, llc_oui, sizeof(llc_oui)))
212
		skb->protocol = htons(ETH_P_IP);
Linus Torvalds's avatar
Linus Torvalds committed
213
	else {
214
		skb->protocol = ((__be16 *)skb->data)[3];
215
		skb_pull(skb, RFC1483LLC_LEN);
Linus Torvalds's avatar
Linus Torvalds committed
216
		if (skb->protocol == htons(ETH_P_ARP)) {
217
218
			skb->dev->stats.rx_packets++;
			skb->dev->stats.rx_bytes += skb->len;
Linus Torvalds's avatar
Linus Torvalds committed
219
220
221
222
223
			clip_arp_rcv(skb);
			return;
		}
	}
	clip_vcc->last_use = jiffies;
224
225
	skb->dev->stats.rx_packets++;
	skb->dev->stats.rx_bytes += skb->len;
Linus Torvalds's avatar
Linus Torvalds committed
226
227
228
229
230
231
232
233
234
	memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data));
	netif_rx(skb);
}

/*
 * Note: these spinlocks _must_not_ block on non-SMP. The only goal is that
 * clip_pop is atomic with respect to the critical section in clip_start_xmit.
 */

235
static void clip_pop(struct atm_vcc *vcc, struct sk_buff *skb)
Linus Torvalds's avatar
Linus Torvalds committed
236
237
238
239
240
241
{
	struct clip_vcc *clip_vcc = CLIP_VCC(vcc);
	struct net_device *dev = skb->dev;
	int old;
	unsigned long flags;

242
	pr_debug("(vcc %p)\n", vcc);
243
	clip_vcc->old_pop(vcc, skb);
Linus Torvalds's avatar
Linus Torvalds committed
244
	/* skb->dev == NULL in outbound ARP packets */
245
246
247
248
249
250
251
	if (!dev)
		return;
	spin_lock_irqsave(&PRIV(dev)->xoff_lock, flags);
	if (atm_may_send(vcc, 0)) {
		old = xchg(&clip_vcc->xoff, 0);
		if (old)
			netif_wake_queue(dev);
Linus Torvalds's avatar
Linus Torvalds committed
252
	}
253
	spin_unlock_irqrestore(&PRIV(dev)->xoff_lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
254
255
}

256
static void clip_neigh_solicit(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds's avatar
Linus Torvalds committed
257
{
258
	pr_debug("(neigh %p, skb %p)\n", neigh, skb);
259
	to_atmarpd(act_need, PRIV(neigh->dev)->number, NEIGH2ENTRY(neigh)->ip);
Linus Torvalds's avatar
Linus Torvalds committed
260
261
}

262
static void clip_neigh_error(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds's avatar
Linus Torvalds committed
263
264
{
#ifndef CONFIG_ATM_CLIP_NO_ICMP
265
	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0);
Linus Torvalds's avatar
Linus Torvalds committed
266
267
268
269
#endif
	kfree_skb(skb);
}

270
static const struct neigh_ops clip_neigh_ops = {
Linus Torvalds's avatar
Linus Torvalds committed
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
	.family =		AF_INET,
	.solicit =		clip_neigh_solicit,
	.error_report =		clip_neigh_error,
	.output =		dev_queue_xmit,
	.connected_output =	dev_queue_xmit,
	.hh_output =		dev_queue_xmit,
	.queue_xmit =		dev_queue_xmit,
};

static int clip_constructor(struct neighbour *neigh)
{
	struct atmarp_entry *entry = NEIGH2ENTRY(neigh);
	struct net_device *dev = neigh->dev;
	struct in_device *in_dev;
	struct neigh_parms *parms;

287
	pr_debug("(neigh %p, entry %p)\n", neigh, entry);
288
	neigh->type = inet_addr_type(&init_net, entry->ip);
289
290
	if (neigh->type != RTN_UNICAST)
		return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
291
292

	rcu_read_lock();
293
	in_dev = __in_dev_get_rcu(dev);
Linus Torvalds's avatar
Linus Torvalds committed
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
	if (!in_dev) {
		rcu_read_unlock();
		return -EINVAL;
	}

	parms = in_dev->arp_parms;
	__neigh_parms_put(neigh->parms);
	neigh->parms = neigh_parms_clone(parms);
	rcu_read_unlock();

	neigh->ops = &clip_neigh_ops;
	neigh->output = neigh->nud_state & NUD_VALID ?
	    neigh->ops->connected_output : neigh->ops->output;
	entry->neigh = neigh;
	entry->vccs = NULL;
309
	entry->expires = jiffies - 1;
Linus Torvalds's avatar
Linus Torvalds committed
310
311
312
	return 0;
}

313
static u32 clip_hash(const void *pkey, const struct net_device *dev, __u32 rnd)
Linus Torvalds's avatar
Linus Torvalds committed
314
{
315
	return jhash_2words(*(u32 *) pkey, dev->ifindex, rnd);
Linus Torvalds's avatar
Linus Torvalds committed
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
}

static struct neigh_table clip_tbl = {
	.family 	= AF_INET,
	.entry_size 	= sizeof(struct neighbour)+sizeof(struct atmarp_entry),
	.key_len 	= 4,
	.hash 		= clip_hash,
	.constructor 	= clip_constructor,
	.id 		= "clip_arp_cache",

	/* parameters are copied from ARP ... */
	.parms = {
		.tbl 			= &clip_tbl,
		.base_reachable_time 	= 30 * HZ,
		.retrans_time 		= 1 * HZ,
		.gc_staletime 		= 60 * HZ,
		.reachable_time 	= 30 * HZ,
		.delay_probe_time 	= 5 * HZ,
		.queue_len 		= 3,
		.ucast_probes 		= 3,
		.mcast_probes 		= 3,
		.anycast_delay 		= 1 * HZ,
		.proxy_delay 		= (8 * HZ) / 10,
		.proxy_qlen 		= 64,
		.locktime 		= 1 * HZ,
	},
	.gc_interval 	= 30 * HZ,
	.gc_thresh1 	= 128,
	.gc_thresh2 	= 512,
	.gc_thresh3 	= 1024,
};

/* @@@ copy bh locking from arp.c -- need to bh-enable atm code before */

/*
 * We play with the resolve flag: 0 and 1 have the usual meaning, but -1 means
 * to allocate the neighbour entry but not to ask atmarpd for resolution. Also,
 * don't increment the usage count. This is used to create entries in
 * clip_setentry.
 */

357
static int clip_encap(struct atm_vcc *vcc, int mode)
Linus Torvalds's avatar
Linus Torvalds committed
358
359
360
361
362
{
	CLIP_VCC(vcc)->encap = mode;
	return 0;
}

363
364
static netdev_tx_t clip_start_xmit(struct sk_buff *skb,
				   struct net_device *dev)
Linus Torvalds's avatar
Linus Torvalds committed
365
366
367
368
369
370
371
{
	struct clip_priv *clip_priv = PRIV(dev);
	struct atmarp_entry *entry;
	struct atm_vcc *vcc;
	int old;
	unsigned long flags;

372
	pr_debug("(skb %p)\n", skb);
Eric Dumazet's avatar
Eric Dumazet committed
373
	if (!skb_dst(skb)) {
374
		pr_err("skb_dst(skb) == NULL\n");
Linus Torvalds's avatar
Linus Torvalds committed
375
		dev_kfree_skb(skb);
376
		dev->stats.tx_dropped++;
377
		return NETDEV_TX_OK;
Linus Torvalds's avatar
Linus Torvalds committed
378
	}
Eric Dumazet's avatar
Eric Dumazet committed
379
	if (!skb_dst(skb)->neighbour) {
Linus Torvalds's avatar
Linus Torvalds committed
380
#if 0
Eric Dumazet's avatar
Eric Dumazet committed
381
382
		skb_dst(skb)->neighbour = clip_find_neighbour(skb_dst(skb), 1);
		if (!skb_dst(skb)->neighbour) {
383
			dev_kfree_skb(skb);	/* lost that one */
384
			dev->stats.tx_dropped++;
Linus Torvalds's avatar
Linus Torvalds committed
385
386
387
			return 0;
		}
#endif
388
		pr_err("NO NEIGHBOUR !\n");
Linus Torvalds's avatar
Linus Torvalds committed
389
		dev_kfree_skb(skb);
390
		dev->stats.tx_dropped++;
391
		return NETDEV_TX_OK;
Linus Torvalds's avatar
Linus Torvalds committed
392
	}
Eric Dumazet's avatar
Eric Dumazet committed
393
	entry = NEIGH2ENTRY(skb_dst(skb)->neighbour);
Linus Torvalds's avatar
Linus Torvalds committed
394
395
396
	if (!entry->vccs) {
		if (time_after(jiffies, entry->expires)) {
			/* should be resolved */
397
398
			entry->expires = jiffies + ATMARP_RETRY_DELAY * HZ;
			to_atmarpd(act_need, PRIV(dev)->number, entry->ip);
Linus Torvalds's avatar
Linus Torvalds committed
399
400
		}
		if (entry->neigh->arp_queue.qlen < ATMARP_MAX_UNRES_PACKETS)
401
			skb_queue_tail(&entry->neigh->arp_queue, skb);
Linus Torvalds's avatar
Linus Torvalds committed
402
403
		else {
			dev_kfree_skb(skb);
404
			dev->stats.tx_dropped++;
Linus Torvalds's avatar
Linus Torvalds committed
405
		}
406
		return NETDEV_TX_OK;
Linus Torvalds's avatar
Linus Torvalds committed
407
	}
408
	pr_debug("neigh %p, vccs %p\n", entry, entry->vccs);
Linus Torvalds's avatar
Linus Torvalds committed
409
	ATM_SKB(skb)->vcc = vcc = entry->vccs->vcc;
Eric Dumazet's avatar
Eric Dumazet committed
410
	pr_debug("using neighbour %p, vcc %p\n", skb_dst(skb)->neighbour, vcc);
Linus Torvalds's avatar
Linus Torvalds committed
411
412
413
	if (entry->vccs->encap) {
		void *here;

414
415
		here = skb_push(skb, RFC1483LLC_LEN);
		memcpy(here, llc_oui, sizeof(llc_oui));
Al Viro's avatar
Al Viro committed
416
		((__be16 *) here)[3] = skb->protocol;
Linus Torvalds's avatar
Linus Torvalds committed
417
418
419
420
	}
	atomic_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
	ATM_SKB(skb)->atm_options = vcc->atm_options;
	entry->vccs->last_use = jiffies;
421
	pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, vcc, vcc->dev);
422
	old = xchg(&entry->vccs->xoff, 1);	/* assume XOFF ... */
Linus Torvalds's avatar
Linus Torvalds committed
423
	if (old) {
424
		pr_warning("XOFF->XOFF transition\n");
425
		return NETDEV_TX_OK;
Linus Torvalds's avatar
Linus Torvalds committed
426
	}
427
428
	dev->stats.tx_packets++;
	dev->stats.tx_bytes += skb->len;
429
	vcc->send(vcc, skb);
430
	if (atm_may_send(vcc, 0)) {
Linus Torvalds's avatar
Linus Torvalds committed
431
		entry->vccs->xoff = 0;
432
		return NETDEV_TX_OK;
Linus Torvalds's avatar
Linus Torvalds committed
433
	}
434
435
	spin_lock_irqsave(&clip_priv->xoff_lock, flags);
	netif_stop_queue(dev);	/* XOFF -> throttle immediately */
Linus Torvalds's avatar
Linus Torvalds committed
436
437
438
	barrier();
	if (!entry->vccs->xoff)
		netif_start_queue(dev);
439
440
441
442
443
	/* Oh, we just raced with clip_pop. netif_start_queue should be
	   good enough, because nothing should really be asleep because
	   of the brief netif_stop_queue. If this isn't true or if it
	   changes, use netif_wake_queue instead. */
	spin_unlock_irqrestore(&clip_priv->xoff_lock, flags);
444
	return NETDEV_TX_OK;
Linus Torvalds's avatar
Linus Torvalds committed
445
446
}

447
static int clip_mkip(struct atm_vcc *vcc, int timeout)
Linus Torvalds's avatar
Linus Torvalds committed
448
{
449
	struct sk_buff_head *rq, queue;
Linus Torvalds's avatar
Linus Torvalds committed
450
	struct clip_vcc *clip_vcc;
451
	struct sk_buff *skb, *tmp;
David S. Miller's avatar
David S. Miller committed
452
	unsigned long flags;
Linus Torvalds's avatar
Linus Torvalds committed
453

454
455
456
457
458
	if (!vcc->push)
		return -EBADFD;
	clip_vcc = kmalloc(sizeof(struct clip_vcc), GFP_KERNEL);
	if (!clip_vcc)
		return -ENOMEM;
459
	pr_debug("%p vcc %p\n", clip_vcc, vcc);
Linus Torvalds's avatar
Linus Torvalds committed
460
461
462
463
464
465
466
	clip_vcc->vcc = vcc;
	vcc->user_back = clip_vcc;
	set_bit(ATM_VF_IS_CLIP, &vcc->flags);
	clip_vcc->entry = NULL;
	clip_vcc->xoff = 0;
	clip_vcc->encap = 1;
	clip_vcc->last_use = jiffies;
467
	clip_vcc->idle_timeout = timeout * HZ;
Linus Torvalds's avatar
Linus Torvalds committed
468
469
470
471
	clip_vcc->old_push = vcc->push;
	clip_vcc->old_pop = vcc->pop;
	vcc->push = clip_push;
	vcc->pop = clip_pop;
David S. Miller's avatar
David S. Miller committed
472

473
	__skb_queue_head_init(&queue);
David S. Miller's avatar
David S. Miller committed
474
475
476
	rq = &sk_atm(vcc)->sk_receive_queue;

	spin_lock_irqsave(&rq->lock, flags);
477
	skb_queue_splice_init(rq, &queue);
David S. Miller's avatar
David S. Miller committed
478
479
	spin_unlock_irqrestore(&rq->lock, flags);

Linus Torvalds's avatar
Linus Torvalds committed
480
	/* re-process everything received between connection setup and MKIP */
481
	skb_queue_walk_safe(&queue, skb, tmp) {
Linus Torvalds's avatar
Linus Torvalds committed
482
		if (!clip_devs) {
483
			atm_return(vcc, skb->truesize);
Linus Torvalds's avatar
Linus Torvalds committed
484
			kfree_skb(skb);
485
		} else {
486
			struct net_device *dev = skb->dev;
Linus Torvalds's avatar
Linus Torvalds committed
487
488
			unsigned int len = skb->len;

489
			skb_get(skb);
490
			clip_push(vcc, skb);
491
492
			dev->stats.rx_packets--;
			dev->stats.rx_bytes -= len;
493
			kfree_skb(skb);
Linus Torvalds's avatar
Linus Torvalds committed
494
		}
David S. Miller's avatar
David S. Miller committed
495
	}
Linus Torvalds's avatar
Linus Torvalds committed
496
497
498
	return 0;
}

Al Viro's avatar
Al Viro committed
499
static int clip_setentry(struct atm_vcc *vcc, __be32 ip)
Linus Torvalds's avatar
Linus Torvalds committed
500
501
502
503
504
{
	struct neighbour *neigh;
	struct atmarp_entry *entry;
	int error;
	struct clip_vcc *clip_vcc;
505
506
	struct flowi fl = { .fl4_dst = ip,
			    .fl4_tos = 1 };
Linus Torvalds's avatar
Linus Torvalds committed
507
508
509
	struct rtable *rt;

	if (vcc->push != clip_push) {
510
		pr_warning("non-CLIP VCC\n");
Linus Torvalds's avatar
Linus Torvalds committed
511
512
513
514
515
		return -EBADF;
	}
	clip_vcc = CLIP_VCC(vcc);
	if (!ip) {
		if (!clip_vcc->entry) {
516
			pr_err("hiding hidden ATMARP entry\n");
Linus Torvalds's avatar
Linus Torvalds committed
517
518
			return 0;
		}
519
		pr_debug("remove\n");
Linus Torvalds's avatar
Linus Torvalds committed
520
521
522
		unlink_clip_vcc(clip_vcc);
		return 0;
	}
523
524
525
	rt = ip_route_output_key(&init_net, &fl);
	if (IS_ERR(rt))
		return PTR_ERR(rt);
526
	neigh = __neigh_lookup(&clip_tbl, &ip, rt->dst.dev, 1);
Linus Torvalds's avatar
Linus Torvalds committed
527
528
529
530
531
	ip_rt_put(rt);
	if (!neigh)
		return -ENOMEM;
	entry = NEIGH2ENTRY(neigh);
	if (entry != clip_vcc->entry) {
532
		if (!clip_vcc->entry)
533
			pr_debug("add\n");
Linus Torvalds's avatar
Linus Torvalds committed
534
		else {
535
			pr_debug("update\n");
Linus Torvalds's avatar
Linus Torvalds committed
536
537
			unlink_clip_vcc(clip_vcc);
		}
538
		link_vcc(clip_vcc, entry);
Linus Torvalds's avatar
Linus Torvalds committed
539
	}
540
541
	error = neigh_update(neigh, llc_oui, NUD_PERMANENT,
			     NEIGH_UPDATE_F_OVERRIDE | NEIGH_UPDATE_F_ADMIN);
Linus Torvalds's avatar
Linus Torvalds committed
542
543
544
545
	neigh_release(neigh);
	return error;
}

546
547
548
549
static const struct net_device_ops clip_netdev_ops = {
	.ndo_start_xmit = clip_start_xmit,
};

Linus Torvalds's avatar
Linus Torvalds committed
550
551
static void clip_setup(struct net_device *dev)
{
552
	dev->netdev_ops = &clip_netdev_ops;
Linus Torvalds's avatar
Linus Torvalds committed
553
554
555
	dev->type = ARPHRD_ATM;
	dev->hard_header_len = RFC1483LLC_LEN;
	dev->mtu = RFC1626_MTU;
556
557
558
559
560
561
	dev->tx_queue_len = 100;	/* "normal" queue (packets) */
	/* When using a "real" qdisc, the qdisc determines the queue */
	/* length. tx_queue_len is only used for the default case, */
	/* without any more elaborate queuing. 100 is a reasonable */
	/* compromise between decent burst-tolerance and protection */
	/* against memory hogs. */
562
	dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
Linus Torvalds's avatar
Linus Torvalds committed
563
564
565
566
567
568
569
570
571
572
}

static int clip_create(int number)
{
	struct net_device *dev;
	struct clip_priv *clip_priv;
	int error;

	if (number != -1) {
		for (dev = clip_devs; dev; dev = PRIV(dev)->next)
573
574
575
			if (PRIV(dev)->number == number)
				return -EEXIST;
	} else {
Linus Torvalds's avatar
Linus Torvalds committed
576
577
578
		number = 0;
		for (dev = clip_devs; dev; dev = PRIV(dev)->next)
			if (PRIV(dev)->number >= number)
579
				number = PRIV(dev)->number + 1;
Linus Torvalds's avatar
Linus Torvalds committed
580
581
582
583
584
	}
	dev = alloc_netdev(sizeof(struct clip_priv), "", clip_setup);
	if (!dev)
		return -ENOMEM;
	clip_priv = PRIV(dev);
585
	sprintf(dev->name, "atm%d", number);
Linus Torvalds's avatar
Linus Torvalds committed
586
587
588
589
590
591
592
593
594
	spin_lock_init(&clip_priv->xoff_lock);
	clip_priv->number = number;
	error = register_netdev(dev);
	if (error) {
		free_netdev(dev);
		return error;
	}
	clip_priv->next = clip_devs;
	clip_devs = dev;
595
	pr_debug("registered (net:%s)\n", dev->name);
Linus Torvalds's avatar
Linus Torvalds committed
596
597
598
	return number;
}

599
static int clip_device_event(struct notifier_block *this, unsigned long event,
600
			     void *arg)
Linus Torvalds's avatar
Linus Torvalds committed
601
{
602
603
	struct net_device *dev = arg;

604
	if (!net_eq(dev_net(dev), &init_net))
605
606
		return NOTIFY_DONE;

607
608
609
610
611
	if (event == NETDEV_UNREGISTER) {
		neigh_ifdown(&clip_tbl, dev);
		return NOTIFY_DONE;
	}

Linus Torvalds's avatar
Linus Torvalds committed
612
	/* ignore non-CLIP devices */
613
	if (dev->type != ARPHRD_ATM || dev->netdev_ops != &clip_netdev_ops)
Linus Torvalds's avatar
Linus Torvalds committed
614
		return NOTIFY_DONE;
615

Linus Torvalds's avatar
Linus Torvalds committed
616
	switch (event) {
617
	case NETDEV_UP:
618
		pr_debug("NETDEV_UP\n");
619
		to_atmarpd(act_up, PRIV(dev)->number, 0);
620
621
		break;
	case NETDEV_GOING_DOWN:
622
		pr_debug("NETDEV_DOWN\n");
623
		to_atmarpd(act_down, PRIV(dev)->number, 0);
624
625
626
		break;
	case NETDEV_CHANGE:
	case NETDEV_CHANGEMTU:
627
		pr_debug("NETDEV_CHANGE*\n");
628
		to_atmarpd(act_change, PRIV(dev)->number, 0);
629
		break;
Linus Torvalds's avatar
Linus Torvalds committed
630
631
632
633
	}
	return NOTIFY_DONE;
}

634
635
static int clip_inet_event(struct notifier_block *this, unsigned long event,
			   void *ifa)
Linus Torvalds's avatar
Linus Torvalds committed
636
637
638
{
	struct in_device *in_dev;

639
	in_dev = ((struct in_ifaddr *)ifa)->ifa_dev;
Linus Torvalds's avatar
Linus Torvalds committed
640
641
642
643
	/*
	 * Transitions are of the down-change-up type, so it's sufficient to
	 * handle the change on up.
	 */
644
645
646
	if (event != NETDEV_UP)
		return NOTIFY_DONE;
	return clip_device_event(this, NETDEV_CHANGE, in_dev->dev);
Linus Torvalds's avatar
Linus Torvalds committed
647
648
649
}

static struct notifier_block clip_dev_notifier = {
650
	.notifier_call = clip_device_event,
Linus Torvalds's avatar
Linus Torvalds committed
651
652
653
654
655
};



static struct notifier_block clip_inet_notifier = {
656
	.notifier_call = clip_inet_event,
Linus Torvalds's avatar
Linus Torvalds committed
657
658
659
660
661
662
};



static void atmarpd_close(struct atm_vcc *vcc)
{
663
	pr_debug("\n");
664
665
666

	rtnl_lock();
	atmarpd = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
667
	skb_queue_purge(&sk_atm(vcc)->sk_receive_queue);
668
669
	rtnl_unlock();

670
	pr_debug("(done)\n");
Linus Torvalds's avatar
Linus Torvalds committed
671
672
673
674
675
676
677
678
679
680
681
682
	module_put(THIS_MODULE);
}

static struct atmdev_ops atmarpd_dev_ops = {
	.close = atmarpd_close
};


static struct atm_dev atmarpd_dev = {
	.ops =			&atmarpd_dev_ops,
	.type =			"arpd",
	.number = 		999,
683
	.lock =			__SPIN_LOCK_UNLOCKED(atmarpd_dev.lock)
Linus Torvalds's avatar
Linus Torvalds committed
684
685
686
687
688
};


static int atm_init_atmarp(struct atm_vcc *vcc)
{
689
690
691
692
693
694
	rtnl_lock();
	if (atmarpd) {
		rtnl_unlock();
		return -EADDRINUSE;
	}

695
	mod_timer(&idle_timer, jiffies + CLIP_CHECK_INTERVAL * HZ);
Stephen Hemminger's avatar
Stephen Hemminger committed
696

Linus Torvalds's avatar
Linus Torvalds committed
697
	atmarpd = vcc;
698
699
	set_bit(ATM_VF_META, &vcc->flags);
	set_bit(ATM_VF_READY, &vcc->flags);
Linus Torvalds's avatar
Linus Torvalds committed
700
701
702
703
704
705
	    /* allow replies and avoid getting closed if signaling dies */
	vcc->dev = &atmarpd_dev;
	vcc_insert_socket(sk_atm(vcc));
	vcc->push = NULL;
	vcc->pop = NULL; /* crash */
	vcc->push_oam = NULL; /* crash */
706
	rtnl_unlock();
Linus Torvalds's avatar
Linus Torvalds committed
707
708
709
710
711
712
713
714
715
	return 0;
}

static int clip_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
	struct atm_vcc *vcc = ATM_SD(sock);
	int err = 0;

	switch (cmd) {
716
717
718
719
720
721
722
723
724
725
	case SIOCMKCLIP:
	case ATMARPD_CTRL:
	case ATMARP_MKIP:
	case ATMARP_SETENTRY:
	case ATMARP_ENCAP:
		if (!capable(CAP_NET_ADMIN))
			return -EPERM;
		break;
	default:
		return -ENOIOCTLCMD;
Linus Torvalds's avatar
Linus Torvalds committed
726
727
728
	}

	switch (cmd) {
729
730
731
732
733
734
735
736
737
738
739
740
741
742
	case SIOCMKCLIP:
		err = clip_create(arg);
		break;
	case ATMARPD_CTRL:
		err = atm_init_atmarp(vcc);
		if (!err) {
			sock->state = SS_CONNECTED;
			__module_get(THIS_MODULE);
		}
		break;
	case ATMARP_MKIP:
		err = clip_mkip(vcc, arg);
		break;
	case ATMARP_SETENTRY:
Al Viro's avatar
Al Viro committed
743
		err = clip_setentry(vcc, (__force __be32)arg);
744
745
746
747
		break;
	case ATMARP_ENCAP:
		err = clip_encap(vcc, arg);
		break;
Linus Torvalds's avatar
Linus Torvalds committed
748
749
750
751
752
	}
	return err;
}

static struct atm_ioctl clip_ioctl_ops = {
753
754
	.owner = THIS_MODULE,
	.ioctl = clip_ioctl,
Linus Torvalds's avatar
Linus Torvalds committed
755
756
757
758
759
760
};

#ifdef CONFIG_PROC_FS

static void svc_addr(struct seq_file *seq, struct sockaddr_atmsvc *addr)
{
761
762
	static int code[] = { 1, 2, 10, 6, 1, 0 };
	static int e164[] = { 1, 8, 4, 6, 1, 0 };
Linus Torvalds's avatar
Linus Torvalds committed
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780

	if (*addr->sas_addr.pub) {
		seq_printf(seq, "%s", addr->sas_addr.pub);
		if (*addr->sas_addr.prv)
			seq_putc(seq, '+');
	} else if (!*addr->sas_addr.prv) {
		seq_printf(seq, "%s", "(none)");
		return;
	}
	if (*addr->sas_addr.prv) {
		unsigned char *prv = addr->sas_addr.prv;
		int *fields;
		int i, j;

		fields = *prv == ATM_AFI_E164 ? e164 : code;
		for (i = 0; fields[i]; i++) {
			for (j = fields[i]; j; j--)
				seq_printf(seq, "%02X", *prv++);
781
			if (fields[i + 1])
Linus Torvalds's avatar
Linus Torvalds committed
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
				seq_putc(seq, '.');
		}
	}
}

/* This means the neighbour entry has no attached VCC objects. */
#define SEQ_NO_VCC_TOKEN	((void *) 2)

static void atmarp_info(struct seq_file *seq, struct net_device *dev,
			struct atmarp_entry *entry, struct clip_vcc *clip_vcc)
{
	unsigned long exp;
	char buf[17];
	int svc, llc, off;

	svc = ((clip_vcc == SEQ_NO_VCC_TOKEN) ||
	       (sk_atm(clip_vcc->vcc)->sk_family == AF_ATMSVC));

800
	llc = ((clip_vcc == SEQ_NO_VCC_TOKEN) || clip_vcc->encap);
Linus Torvalds's avatar
Linus Torvalds committed
801
802
803
804
805
806
807
808
809

	if (clip_vcc == SEQ_NO_VCC_TOKEN)
		exp = entry->neigh->used;
	else
		exp = clip_vcc->last_use;

	exp = (jiffies - exp) / HZ;

	seq_printf(seq, "%-6s%-4s%-4s%5ld ",
810
		   dev->name, svc ? "SVC" : "PVC", llc ? "LLC" : "NULL", exp);
Linus Torvalds's avatar
Linus Torvalds committed
811

812
813
	off = scnprintf(buf, sizeof(buf) - 1, "%pI4",
			&entry->ip);
Linus Torvalds's avatar
Linus Torvalds committed
814
815
816
817
818
819
820
821
822
823
824
825
826
827
	while (off < 16)
		buf[off++] = ' ';
	buf[off] = '\0';
	seq_printf(seq, "%s", buf);

	if (clip_vcc == SEQ_NO_VCC_TOKEN) {
		if (time_before(jiffies, entry->expires))
			seq_printf(seq, "(resolving)\n");
		else
			seq_printf(seq, "(expired, ref %d)\n",
				   atomic_read(&entry->neigh->refcnt));
	} else if (!svc) {
		seq_printf(seq, "%d.%d.%d\n",
			   clip_vcc->vcc->dev->number,
828
			   clip_vcc->vcc->vpi, clip_vcc->vcc->vci);
Linus Torvalds's avatar
Linus Torvalds committed
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
	} else {
		svc_addr(seq, &clip_vcc->vcc->remote);
		seq_putc(seq, '\n');
	}
}

struct clip_seq_state {
	/* This member must be first. */
	struct neigh_seq_state ns;

	/* Local to clip specific iteration. */
	struct clip_vcc *vcc;
};

static struct clip_vcc *clip_seq_next_vcc(struct atmarp_entry *e,
					  struct clip_vcc *curr)
{
	if (!curr) {
		curr = e->vccs;
		if (!curr)
			return SEQ_NO_VCC_TOKEN;
		return curr;
	}
	if (curr == SEQ_NO_VCC_TOKEN)
		return NULL;

	curr = curr->next;

	return curr;
}

static void *clip_seq_vcc_walk(struct clip_seq_state *state,
861
			       struct atmarp_entry *e, loff_t * pos)
Linus Torvalds's avatar
Linus Torvalds committed
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
{
	struct clip_vcc *vcc = state->vcc;

	vcc = clip_seq_next_vcc(e, vcc);
	if (vcc && pos != NULL) {
		while (*pos) {
			vcc = clip_seq_next_vcc(e, vcc);
			if (!vcc)
				break;
			--(*pos);
		}
	}
	state->vcc = vcc;

	return vcc;
}
878

Linus Torvalds's avatar
Linus Torvalds committed
879
static void *clip_seq_sub_iter(struct neigh_seq_state *_state,
880
			       struct neighbour *n, loff_t * pos)
Linus Torvalds's avatar
Linus Torvalds committed
881
{
882
	struct clip_seq_state *state = (struct clip_seq_state *)_state;
Linus Torvalds's avatar
Linus Torvalds committed
883
884
885
886

	return clip_seq_vcc_walk(state, NEIGH2ENTRY(n), pos);
}

887
static void *clip_seq_start(struct seq_file *seq, loff_t * pos)
Linus Torvalds's avatar
Linus Torvalds committed
888
{
889
890
	struct clip_seq_state *state = seq->private;
	state->ns.neigh_sub_iter = clip_seq_sub_iter;
Linus Torvalds's avatar
Linus Torvalds committed
891
892
893
894
895
	return neigh_seq_start(seq, pos, &clip_tbl, NEIGH_SEQ_NEIGH_ONLY);
}

static int clip_seq_show(struct seq_file *seq, void *v)
{
896
897
	static char atm_arp_banner[] =
	    "IPitf TypeEncp Idle IP address      ATM address\n";
Linus Torvalds's avatar
Linus Torvalds committed
898
899
900
901
902
903
904
905
906
907

	if (v == SEQ_START_TOKEN) {
		seq_puts(seq, atm_arp_banner);
	} else {
		struct clip_seq_state *state = seq->private;
		struct neighbour *n = v;
		struct clip_vcc *vcc = state->vcc;

		atmarp_info(seq, n->dev, NEIGH2ENTRY(n), vcc);
	}
908
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
909
910
}

911
static const struct seq_operations arp_seq_ops = {
Linus Torvalds's avatar
Linus Torvalds committed
912
913
914
915
916
917
918
919
	.start	= clip_seq_start,
	.next	= neigh_seq_next,
	.stop	= neigh_seq_stop,
	.show	= clip_seq_show,
};

static int arp_seq_open(struct inode *inode, struct file *file)
{
920
921
	return seq_open_net(inode, file, &arp_seq_ops,
			    sizeof(struct clip_seq_state));
922
923
}

924
static const struct file_operations arp_seq_fops = {
Linus Torvalds's avatar
Linus Torvalds committed
925
926
927
	.open		= arp_seq_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
928
	.release	= seq_release_net,
Linus Torvalds's avatar
Linus Torvalds committed
929
930
931
932
	.owner		= THIS_MODULE
};
#endif

933
934
static void atm_clip_exit_noproc(void);

Linus Torvalds's avatar
Linus Torvalds committed
935
936
static int __init atm_clip_init(void)
{
937
	neigh_table_init_no_netlink(&clip_tbl);
Linus Torvalds's avatar
Linus Torvalds committed
938
939
940

	clip_tbl_hook = &clip_tbl;
	register_atm_ioctl(&clip_ioctl_ops);
941
942
	register_netdevice_notifier(&clip_dev_notifier);
	register_inetaddr_notifier(&clip_inet_notifier);
Linus Torvalds's avatar
Linus Torvalds committed
943

Stephen Hemminger's avatar
Stephen Hemminger committed
944
945
	setup_timer(&idle_timer, idle_timer_check, 0);

946
947
948
949
#ifdef CONFIG_PROC_FS
	{
		struct proc_dir_entry *p;

950
		p = proc_create("arp", S_IRUGO, atm_proc_root, &arp_seq_fops);
951
		if (!p) {
952
			pr_err("Unable to initialize /proc/net/atm/arp\n");
953
954
955
			atm_clip_exit_noproc();
			return -ENOMEM;
		}
956
957
	}
#endif
Linus Torvalds's avatar
Linus Torvalds committed
958
959
960
961

	return 0;
}

962
static void atm_clip_exit_noproc(void)
Linus Torvalds's avatar
Linus Torvalds committed
963
964
965
{
	struct net_device *dev, *next;

966
967
968
	unregister_inetaddr_notifier(&clip_inet_notifier);
	unregister_netdevice_notifier(&clip_dev_notifier);

Linus Torvalds's avatar
Linus Torvalds committed
969
970
971
972
973
	deregister_atm_ioctl(&clip_ioctl_ops);

	/* First, stop the idle timer, so it stops banging
	 * on the table.
	 */
Stephen Hemminger's avatar
Stephen Hemminger committed
974
	del_timer_sync(&idle_timer);
Linus Torvalds's avatar
Linus Torvalds committed
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995

	/* Next, purge the table, so that the device
	 * unregister loop below does not hang due to
	 * device references remaining in the table.
	 */
	neigh_ifdown(&clip_tbl, NULL);

	dev = clip_devs;
	while (dev) {
		next = PRIV(dev)->next;
		unregister_netdev(dev);
		free_netdev(dev);
		dev = next;
	}

	/* Now it is safe to fully shutdown whole table. */
	neigh_table_clear(&clip_tbl);

	clip_tbl_hook = NULL;
}

996
997
998
999
1000
1001
1002
static void __exit atm_clip_exit(void)
{
	remove_proc_entry("arp", atm_proc_root);

	atm_clip_exit_noproc();
}

Linus Torvalds's avatar
Linus Torvalds committed
1003
1004
module_init(atm_clip_init);
module_exit(atm_clip_exit);
1005
1006
MODULE_AUTHOR("Werner Almesberger");
MODULE_DESCRIPTION("Classical/IP over ATM interface");
Linus Torvalds's avatar
Linus Torvalds committed
1007
MODULE_LICENSE("GPL");