Blame view

net/decnet/dn_dev.c 32.1 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  /*
   * DECnet       An implementation of the DECnet protocol suite for the LINUX
   *              operating system.  DECnet is implemented using the  BSD Socket
   *              interface as the means of communication with the user level.
   *
   *              DECnet Device Layer
   *
   * Authors:     Steve Whitehouse <SteveW@ACM.org>
   *              Eduardo Marcelo Serrat <emserrat@geocities.com>
   *
   * Changes:
   *          Steve Whitehouse : Devices now see incoming frames so they
   *                             can mark on who it came from.
   *          Steve Whitehouse : Fixed bug in creating neighbours. Each neighbour
   *                             can now have a device specific setup func.
   *          Steve Whitehouse : Added /proc/sys/net/decnet/conf/<dev>/
   *          Steve Whitehouse : Fixed bug which sometimes killed timer
   *          Steve Whitehouse : Multiple ifaddr support
   *          Steve Whitehouse : SIOCGIFCONF is now a compile time option
   *          Steve Whitehouse : /proc/sys/net/decnet/conf/<sys>/forwarding
   *          Steve Whitehouse : Removed timer1 - it's a user space issue now
   *         Patrick Caulfield : Fixed router hello message format
   *          Steve Whitehouse : Got rid of constant sizes for blksize for
   *                             devices. All mtu based now.
   */
4fc268d24   Randy Dunlap   [PATCH] capable/c...
26
  #include <linux/capability.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
29
30
31
32
33
34
35
  #include <linux/module.h>
  #include <linux/moduleparam.h>
  #include <linux/init.h>
  #include <linux/net.h>
  #include <linux/netdevice.h>
  #include <linux/proc_fs.h>
  #include <linux/seq_file.h>
  #include <linux/timer.h>
  #include <linux/string.h>
1823730fb   Thomas Graf   [IPv4]: Move inte...
36
  #include <linux/if_addr.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
38
39
  #include <linux/if_arp.h>
  #include <linux/if_ether.h>
  #include <linux/skbuff.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
41
  #include <linux/sysctl.h>
  #include <linux/notifier.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
42
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
  #include <asm/uaccess.h>
  #include <asm/system.h>
457c4cbc5   Eric W. Biederman   [NET]: Make /proc...
45
  #include <net/net_namespace.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
48
  #include <net/neighbour.h>
  #include <net/dst.h>
  #include <net/flow.h>
a8731cbf6   Steven Whitehouse   [DECNET]: Covert ...
49
  #include <net/fib_rules.h>
a6f01cace   Thomas Graf   [DECNET] address:...
50
  #include <net/netlink.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
  #include <net/dn.h>
  #include <net/dn_dev.h>
  #include <net/dn_route.h>
  #include <net/dn_neigh.h>
  #include <net/dn_fib.h>
  
  #define DN_IFREQ_SIZE (sizeof(struct ifreq) - sizeof(struct sockaddr) + sizeof(struct sockaddr_dn))
  
  static char dn_rt_all_end_mcast[ETH_ALEN] = {0xAB,0x00,0x00,0x04,0x00,0x00};
  static char dn_rt_all_rt_mcast[ETH_ALEN]  = {0xAB,0x00,0x00,0x03,0x00,0x00};
  static char dn_hiord[ETH_ALEN]            = {0xAA,0x00,0x04,0x00,0x00,0x00};
  static unsigned char dn_eco_version[3]    = {0x02,0x00,0x00};
  
  extern struct neigh_table dn_neigh_table;
  
  /*
   * decnet_address is kept in network order.
   */
c4ea94ab3   Steven Whitehouse   [DECnet]: Endian ...
69
  __le16 decnet_address = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70

e5c140a34   stephen hemminger   decnet: convert d...
71
  static DEFINE_SPINLOCK(dndev_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
  static struct net_device *decnet_default_device;
e041c6834   Alan Stern   [PATCH] Notifier ...
73
  static BLOCKING_NOTIFIER_HEAD(dnaddr_chain);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
75
76
  
  static struct dn_dev *dn_dev_create(struct net_device *dev, int *err);
  static void dn_dev_delete(struct net_device *dev);
b020b942c   Thomas Graf   [DECNET] address:...
77
  static void dn_ifaddr_notify(int event, struct dn_ifaddr *ifa);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78
79
80
81
82
83
84
85
86
87
88
89
90
91
  
  static int dn_eth_up(struct net_device *);
  static void dn_eth_down(struct net_device *);
  static void dn_send_brd_hello(struct net_device *dev, struct dn_ifaddr *ifa);
  static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa);
  
  static struct dn_dev_parms dn_dev_list[] =  {
  {
  	.type =		ARPHRD_ETHER, /* Ethernet */
  	.mode =		DN_DEV_BCAST,
  	.state =	DN_DEV_S_RU,
  	.t2 =		1,
  	.t3 =		10,
  	.name =		"ethernet",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
93
94
95
96
97
98
99
100
101
102
  	.up =		dn_eth_up,
  	.down = 	dn_eth_down,
  	.timer3 =	dn_send_brd_hello,
  },
  {
  	.type =		ARPHRD_IPGRE, /* DECnet tunneled over GRE in IP */
  	.mode =		DN_DEV_BCAST,
  	.state =	DN_DEV_S_RU,
  	.t2 =		1,
  	.t3 =		10,
  	.name =		"ipgre",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
104
105
106
107
108
109
110
111
112
  	.timer3 =	dn_send_brd_hello,
  },
  #if 0
  {
  	.type =		ARPHRD_X25, /* Bog standard X.25 */
  	.mode =		DN_DEV_UCAST,
  	.state =	DN_DEV_S_DS,
  	.t2 =		1,
  	.t3 =		120,
  	.name =		"x25",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
114
115
116
117
118
119
120
121
122
123
  	.timer3 =	dn_send_ptp_hello,
  },
  #endif
  #if 0
  {
  	.type =		ARPHRD_PPP, /* DECnet over PPP */
  	.mode =		DN_DEV_BCAST,
  	.state =	DN_DEV_S_RU,
  	.t2 =		1,
  	.t3 =		10,
  	.name =		"ppp",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
125
126
127
128
129
130
131
132
133
  	.timer3 =	dn_send_brd_hello,
  },
  #endif
  {
  	.type =		ARPHRD_DDCMP, /* DECnet over DDCMP */
  	.mode =		DN_DEV_UCAST,
  	.state =	DN_DEV_S_DS,
  	.t2 =		1,
  	.t3 =		120,
  	.name =		"ddcmp",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
135
136
137
138
139
140
141
142
  	.timer3 =	dn_send_ptp_hello,
  },
  {
  	.type =		ARPHRD_LOOPBACK, /* Loopback interface - always last */
  	.mode =		DN_DEV_BCAST,
  	.state =	DN_DEV_S_RU,
  	.t2 =		1,
  	.t3 =		10,
  	.name =		"loopback",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
144
145
  	.timer3 =	dn_send_brd_hello,
  }
  };
8b14a5367   Denis Cheng   [NET]: all net/ c...
146
  #define DN_DEV_LIST_SIZE ARRAY_SIZE(dn_dev_list)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147

8fa0b315f   David S. Miller   decnet: Fix compi...
148
  #define DN_DEV_PARMS_OFFSET(x) offsetof(struct dn_dev_parms, x)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
150
151
152
153
154
155
156
157
158
  
  #ifdef CONFIG_SYSCTL
  
  static int min_t2[] = { 1 };
  static int max_t2[] = { 60 }; /* No max specified, but this seems sensible */
  static int min_t3[] = { 1 };
  static int max_t3[] = { 8191 }; /* Must fit in 16 bits when multiplied by BCT3MULT or T3MULT */
  
  static int min_priority[1];
  static int max_priority[] = { 127 }; /* From DECnet spec */
8d65af789   Alexey Dobriyan   sysctl: remove "s...
159
  static int dn_forwarding_proc(ctl_table *, int,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
  			void __user *, size_t *, loff_t *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
162
163
  static struct dn_dev_sysctl_table {
  	struct ctl_table_header *sysctl_header;
  	ctl_table dn_dev_vars[5];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
165
166
167
  } dn_dev_sysctl = {
  	NULL,
  	{
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
169
170
171
172
  		.procname = "forwarding",
  		.data = (void *)DN_DEV_PARMS_OFFSET(forwarding),
  		.maxlen = sizeof(int),
  		.mode = 0644,
  		.proc_handler = dn_forwarding_proc,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
174
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
176
177
178
179
  		.procname = "priority",
  		.data = (void *)DN_DEV_PARMS_OFFSET(priority),
  		.maxlen = sizeof(int),
  		.mode = 0644,
  		.proc_handler = proc_dointvec_minmax,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
181
182
183
  		.extra1 = &min_priority,
  		.extra2 = &max_priority
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184
185
186
187
188
  		.procname = "t2",
  		.data = (void *)DN_DEV_PARMS_OFFSET(t2),
  		.maxlen = sizeof(int),
  		.mode = 0644,
  		.proc_handler = proc_dointvec_minmax,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
190
191
192
  		.extra1 = &min_t2,
  		.extra2 = &max_t2
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
194
195
196
197
  		.procname = "t3",
  		.data = (void *)DN_DEV_PARMS_OFFSET(t3),
  		.maxlen = sizeof(int),
  		.mode = 0644,
  		.proc_handler = proc_dointvec_minmax,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
199
200
201
202
  		.extra1 = &min_t3,
  		.extra2 = &max_t3
  	},
  	{0}
  	},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203
204
205
206
207
208
  };
  
  static void dn_dev_sysctl_register(struct net_device *dev, struct dn_dev_parms *parms)
  {
  	struct dn_dev_sysctl_table *t;
  	int i;
3151a9ab0   Pavel Emelyanov   [DECNET]: Switch ...
209
210
211
  #define DN_CTL_PATH_DEV	3
  
  	struct ctl_path dn_ctl_path[] = {
f8572d8f2   Eric W. Biederman   sysctl net: Remov...
212
213
214
  		{ .procname = "net",  },
  		{ .procname = "decnet",  },
  		{ .procname = "conf",  },
3151a9ab0   Pavel Emelyanov   [DECNET]: Switch ...
215
216
217
  		{ /* to be set */ },
  		{ },
  	};
c66b721a5   Arnaldo Carvalho de Melo   [DECNET]: Use kme...
218
  	t = kmemdup(&dn_dev_sysctl, sizeof(*t), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
220
  	if (t == NULL)
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
222
223
  	for(i = 0; i < ARRAY_SIZE(t->dn_dev_vars) - 1; i++) {
  		long offset = (long)t->dn_dev_vars[i].data;
  		t->dn_dev_vars[i].data = ((char *)parms) + offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
224
225
226
  	}
  
  	if (dev) {
3151a9ab0   Pavel Emelyanov   [DECNET]: Switch ...
227
  		dn_ctl_path[DN_CTL_PATH_DEV].procname = dev->name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228
  	} else {
3151a9ab0   Pavel Emelyanov   [DECNET]: Switch ...
229
  		dn_ctl_path[DN_CTL_PATH_DEV].procname = parms->name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231
  	t->dn_dev_vars[0].extra1 = (void *)dev;
3151a9ab0   Pavel Emelyanov   [DECNET]: Switch ...
232
  	t->sysctl_header = register_sysctl_paths(dn_ctl_path, t->dn_dev_vars);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
  	if (t->sysctl_header == NULL)
  		kfree(t);
  	else
  		parms->sysctl = t;
  }
  
  static void dn_dev_sysctl_unregister(struct dn_dev_parms *parms)
  {
  	if (parms->sysctl) {
  		struct dn_dev_sysctl_table *t = parms->sysctl;
  		parms->sysctl = NULL;
  		unregister_sysctl_table(t->sysctl_header);
  		kfree(t);
  	}
  }
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
248
  static int dn_forwarding_proc(ctl_table *table, int write,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
250
251
252
253
254
255
256
257
258
259
  				void __user *buffer,
  				size_t *lenp, loff_t *ppos)
  {
  #ifdef CONFIG_DECNET_ROUTER
  	struct net_device *dev = table->extra1;
  	struct dn_dev *dn_db;
  	int err;
  	int tmp, old;
  
  	if (table->extra1 == NULL)
  		return -EINVAL;
fc766e4c4   Eric Dumazet   decnet: RCU conve...
260
  	dn_db = rcu_dereference_raw(dev->dn_ptr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261
  	old = dn_db->parms.forwarding;
8d65af789   Alexey Dobriyan   sysctl: remove "s...
262
  	err = proc_dointvec(table, write, buffer, lenp, ppos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
  
  	if ((err >= 0) && write) {
  		if (dn_db->parms.forwarding < 0)
  			dn_db->parms.forwarding = 0;
  		if (dn_db->parms.forwarding > 2)
  			dn_db->parms.forwarding = 2;
  		/*
  		 * What an ugly hack this is... its works, just. It
  		 * would be nice if sysctl/proc were just that little
  		 * bit more flexible so I don't have to write a special
  		 * routine, or suffer hacks like this - SJW
  		 */
  		tmp = dn_db->parms.forwarding;
  		dn_db->parms.forwarding = old;
  		if (dn_db->parms.down)
  			dn_db->parms.down(dev);
  		dn_db->parms.forwarding = tmp;
  		if (dn_db->parms.up)
  			dn_db->parms.up(dev);
  	}
  
  	return err;
  #else
  	return -EINVAL;
  #endif
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
  #else /* CONFIG_SYSCTL */
  static void dn_dev_sysctl_unregister(struct dn_dev_parms *parms)
  {
  }
  static void dn_dev_sysctl_register(struct net_device *dev, struct dn_dev_parms *parms)
  {
  }
  
  #endif /* CONFIG_SYSCTL */
  
  static inline __u16 mtu2blksize(struct net_device *dev)
  {
  	u32 blksize = dev->mtu;
  	if (blksize > 0xffff)
  		blksize = 0xffff;
  
  	if (dev->type == ARPHRD_ETHER ||
  	    dev->type == ARPHRD_PPP ||
  	    dev->type == ARPHRD_IPGRE ||
  	    dev->type == ARPHRD_LOOPBACK)
  		blksize -= 2;
  
  	return (__u16)blksize;
  }
  
  static struct dn_ifaddr *dn_dev_alloc_ifa(void)
  {
  	struct dn_ifaddr *ifa;
0da974f4f   Panagiotis Issaris   [NET]: Conversion...
317
  	ifa = kzalloc(sizeof(*ifa), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318
319
320
  
  	return ifa;
  }
fc766e4c4   Eric Dumazet   decnet: RCU conve...
321
  static void dn_dev_free_ifa(struct dn_ifaddr *ifa)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
322
  {
1e547757e   Lai Jiangshan   net,rcu: convert ...
323
  	kfree_rcu(ifa, rcu);
fc766e4c4   Eric Dumazet   decnet: RCU conve...
324
325
326
327
328
  }
  
  static void dn_dev_del_ifa(struct dn_dev *dn_db, struct dn_ifaddr __rcu **ifap, int destroy)
  {
  	struct dn_ifaddr *ifa1 = rtnl_dereference(*ifap);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329
330
331
332
333
334
335
336
  	unsigned char mac_addr[6];
  	struct net_device *dev = dn_db->dev;
  
  	ASSERT_RTNL();
  
  	*ifap = ifa1->ifa_next;
  
  	if (dn_db->dev->type == ARPHRD_ETHER) {
c4ea94ab3   Steven Whitehouse   [DECnet]: Endian ...
337
  		if (ifa1->ifa_local != dn_eth2dn(dev->dev_addr)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
338
  			dn_dn2eth(mac_addr, ifa1->ifa_local);
22bedad3c   Jiri Pirko   net: convert mult...
339
  			dev_mc_del(dev, mac_addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340
341
  		}
  	}
b020b942c   Thomas Graf   [DECNET] address:...
342
  	dn_ifaddr_notify(RTM_DELADDR, ifa1);
e041c6834   Alan Stern   [PATCH] Notifier ...
343
  	blocking_notifier_call_chain(&dnaddr_chain, NETDEV_DOWN, ifa1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
  	if (destroy) {
  		dn_dev_free_ifa(ifa1);
  
  		if (dn_db->ifa_list == NULL)
  			dn_dev_delete(dn_db->dev);
  	}
  }
  
  static int dn_dev_insert_ifa(struct dn_dev *dn_db, struct dn_ifaddr *ifa)
  {
  	struct net_device *dev = dn_db->dev;
  	struct dn_ifaddr *ifa1;
  	unsigned char mac_addr[6];
  
  	ASSERT_RTNL();
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
359
  	/* Check for duplicates */
fc766e4c4   Eric Dumazet   decnet: RCU conve...
360
361
362
  	for (ifa1 = rtnl_dereference(dn_db->ifa_list);
  	     ifa1 != NULL;
  	     ifa1 = rtnl_dereference(ifa1->ifa_next)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363
364
365
366
367
  		if (ifa1->ifa_local == ifa->ifa_local)
  			return -EEXIST;
  	}
  
  	if (dev->type == ARPHRD_ETHER) {
c4ea94ab3   Steven Whitehouse   [DECnet]: Endian ...
368
  		if (ifa->ifa_local != dn_eth2dn(dev->dev_addr)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
  			dn_dn2eth(mac_addr, ifa->ifa_local);
22bedad3c   Jiri Pirko   net: convert mult...
370
  			dev_mc_add(dev, mac_addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
372
373
374
  		}
  	}
  
  	ifa->ifa_next = dn_db->ifa_list;
cf778b00e   Eric Dumazet   net: reintroduce ...
375
  	rcu_assign_pointer(dn_db->ifa_list, ifa);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376

b020b942c   Thomas Graf   [DECNET] address:...
377
  	dn_ifaddr_notify(RTM_NEWADDR, ifa);
e041c6834   Alan Stern   [PATCH] Notifier ...
378
  	blocking_notifier_call_chain(&dnaddr_chain, NETDEV_UP, ifa);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
379
380
381
382
383
384
  
  	return 0;
  }
  
  static int dn_dev_set_ifa(struct net_device *dev, struct dn_ifaddr *ifa)
  {
fc766e4c4   Eric Dumazet   decnet: RCU conve...
385
  	struct dn_dev *dn_db = rtnl_dereference(dev->dn_ptr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
  	int rv;
  
  	if (dn_db == NULL) {
  		int err;
  		dn_db = dn_dev_create(dev, &err);
  		if (dn_db == NULL)
  			return err;
  	}
  
  	ifa->ifa_dev = dn_db;
  
  	if (dev->flags & IFF_LOOPBACK)
  		ifa->ifa_scope = RT_SCOPE_HOST;
  
  	rv = dn_dev_insert_ifa(dn_db, ifa);
  	if (rv)
  		dn_dev_free_ifa(ifa);
  	return rv;
  }
  
  
  int dn_dev_ioctl(unsigned int cmd, void __user *arg)
  {
  	char buffer[DN_IFREQ_SIZE];
  	struct ifreq *ifr = (struct ifreq *)buffer;
  	struct sockaddr_dn *sdn = (struct sockaddr_dn *)&ifr->ifr_addr;
  	struct dn_dev *dn_db;
  	struct net_device *dev;
fc766e4c4   Eric Dumazet   decnet: RCU conve...
414
415
  	struct dn_ifaddr *ifa = NULL;
  	struct dn_ifaddr __rcu **ifap = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
416
417
418
419
420
  	int ret = 0;
  
  	if (copy_from_user(ifr, arg, DN_IFREQ_SIZE))
  		return -EFAULT;
  	ifr->ifr_name[IFNAMSIZ-1] = 0;
881d966b4   Eric W. Biederman   [NET]: Make the d...
421
  	dev_load(&init_net, ifr->ifr_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422

06f8fe11b   Joe Perches   decnet: Reduce sw...
423
424
425
426
427
428
429
  	switch (cmd) {
  	case SIOCGIFADDR:
  		break;
  	case SIOCSIFADDR:
  		if (!capable(CAP_NET_ADMIN))
  			return -EACCES;
  		if (sdn->sdn_family != AF_DECnet)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
  			return -EINVAL;
06f8fe11b   Joe Perches   decnet: Reduce sw...
431
432
433
  		break;
  	default:
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
434
435
436
  	}
  
  	rtnl_lock();
881d966b4   Eric W. Biederman   [NET]: Make the d...
437
  	if ((dev = __dev_get_by_name(&init_net, ifr->ifr_name)) == NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
438
439
440
  		ret = -ENODEV;
  		goto done;
  	}
fc766e4c4   Eric Dumazet   decnet: RCU conve...
441
442
443
444
  	if ((dn_db = rtnl_dereference(dev->dn_ptr)) != NULL) {
  		for (ifap = &dn_db->ifa_list;
  		     (ifa = rtnl_dereference(*ifap)) != NULL;
  		     ifap = &ifa->ifa_next)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
446
447
448
449
450
451
452
  			if (strcmp(ifr->ifr_name, ifa->ifa_label) == 0)
  				break;
  	}
  
  	if (ifa == NULL && cmd != SIOCSIFADDR) {
  		ret = -EADDRNOTAVAIL;
  		goto done;
  	}
06f8fe11b   Joe Perches   decnet: Reduce sw...
453
454
455
456
457
458
459
460
461
462
  	switch (cmd) {
  	case SIOCGIFADDR:
  		*((__le16 *)sdn->sdn_nodeaddr) = ifa->ifa_local;
  		goto rarok;
  
  	case SIOCSIFADDR:
  		if (!ifa) {
  			if ((ifa = dn_dev_alloc_ifa()) == NULL) {
  				ret = -ENOBUFS;
  				break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
463
  			}
06f8fe11b   Joe Perches   decnet: Reduce sw...
464
465
466
467
468
469
  			memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
  		} else {
  			if (ifa->ifa_local == dn_saddr2dn(sdn))
  				break;
  			dn_dev_del_ifa(dn_db, ifap, 0);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470

06f8fe11b   Joe Perches   decnet: Reduce sw...
471
  		ifa->ifa_local = ifa->ifa_address = dn_saddr2dn(sdn);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472

06f8fe11b   Joe Perches   decnet: Reduce sw...
473
  		ret = dn_dev_set_ifa(dev, ifa);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
475
476
477
478
479
480
481
482
483
484
485
486
487
  	}
  done:
  	rtnl_unlock();
  
  	return ret;
  rarok:
  	if (copy_to_user(arg, ifr, DN_IFREQ_SIZE))
  		ret = -EFAULT;
  	goto done;
  }
  
  struct net_device *dn_dev_get_default(void)
  {
  	struct net_device *dev;
e5c140a34   stephen hemminger   decnet: convert d...
488
489
  
  	spin_lock(&dndev_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490
491
492
493
494
495
496
  	dev = decnet_default_device;
  	if (dev) {
  		if (dev->dn_ptr)
  			dev_hold(dev);
  		else
  			dev = NULL;
  	}
e5c140a34   stephen hemminger   decnet: convert d...
497
  	spin_unlock(&dndev_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
498
499
500
501
502
503
504
505
506
  	return dev;
  }
  
  int dn_dev_set_default(struct net_device *dev, int force)
  {
  	struct net_device *old = NULL;
  	int rv = -EBUSY;
  	if (!dev->dn_ptr)
  		return -ENODEV;
e5c140a34   stephen hemminger   decnet: convert d...
507
508
  
  	spin_lock(&dndev_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
510
511
512
513
  	if (force || decnet_default_device == NULL) {
  		old = decnet_default_device;
  		decnet_default_device = dev;
  		rv = 0;
  	}
e5c140a34   stephen hemminger   decnet: convert d...
514
  	spin_unlock(&dndev_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
515
  	if (old)
6a57b2ee4   Patrick Caulfield   [DECNET]: Fix ref...
516
  		dev_put(old);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517
518
519
520
521
  	return rv;
  }
  
  static void dn_dev_check_default(struct net_device *dev)
  {
e5c140a34   stephen hemminger   decnet: convert d...
522
  	spin_lock(&dndev_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523
524
525
526
527
  	if (dev == decnet_default_device) {
  		decnet_default_device = NULL;
  	} else {
  		dev = NULL;
  	}
e5c140a34   stephen hemminger   decnet: convert d...
528
  	spin_unlock(&dndev_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529
530
531
  	if (dev)
  		dev_put(dev);
  }
b4d745db1   Eric Dumazet   decnet: avoid tou...
532
533
534
  /*
   * Called with RTNL
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
536
537
538
  static struct dn_dev *dn_dev_by_index(int ifindex)
  {
  	struct net_device *dev;
  	struct dn_dev *dn_dev = NULL;
b4d745db1   Eric Dumazet   decnet: avoid tou...
539
540
541
  
  	dev = __dev_get_by_index(&init_net, ifindex);
  	if (dev)
fc766e4c4   Eric Dumazet   decnet: RCU conve...
542
  		dn_dev = rtnl_dereference(dev->dn_ptr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
543
544
545
  
  	return dn_dev;
  }
ef7c79ed6   Patrick McHardy   [NETLINK]: Mark n...
546
  static const struct nla_policy dn_ifa_policy[IFA_MAX+1] = {
4a89c2562   Thomas Graf   [DECNET] address:...
547
548
549
550
551
552
553
  	[IFA_ADDRESS]		= { .type = NLA_U16 },
  	[IFA_LOCAL]		= { .type = NLA_U16 },
  	[IFA_LABEL]		= { .type = NLA_STRING,
  				    .len = IFNAMSIZ - 1 },
  };
  
  static int dn_nl_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
554
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
555
  	struct net *net = sock_net(skb->sk);
4a89c2562   Thomas Graf   [DECNET] address:...
556
  	struct nlattr *tb[IFA_MAX+1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
557
  	struct dn_dev *dn_db;
4a89c2562   Thomas Graf   [DECNET] address:...
558
  	struct ifaddrmsg *ifm;
fc766e4c4   Eric Dumazet   decnet: RCU conve...
559
560
  	struct dn_ifaddr *ifa;
  	struct dn_ifaddr __rcu **ifap;
b854272b3   Denis V. Lunev   [NET]: Modify all...
561
  	int err = -EINVAL;
09ad9bc75   Octavian Purdila   net: use net_eq t...
562
  	if (!net_eq(net, &init_net))
b854272b3   Denis V. Lunev   [NET]: Modify all...
563
  		goto errout;
4a89c2562   Thomas Graf   [DECNET] address:...
564
565
566
567
  
  	err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, dn_ifa_policy);
  	if (err < 0)
  		goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568

3ccd86241   Pavel Emelyanov   [DECNET]: dn_nl_d...
569
  	err = -ENODEV;
4a89c2562   Thomas Graf   [DECNET] address:...
570
  	ifm = nlmsg_data(nlh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571
  	if ((dn_db = dn_dev_by_index(ifm->ifa_index)) == NULL)
4a89c2562   Thomas Graf   [DECNET] address:...
572
  		goto errout;
3ccd86241   Pavel Emelyanov   [DECNET]: dn_nl_d...
573
  	err = -EADDRNOTAVAIL;
fc766e4c4   Eric Dumazet   decnet: RCU conve...
574
575
576
  	for (ifap = &dn_db->ifa_list;
  	     (ifa = rtnl_dereference(*ifap)) != NULL;
  	     ifap = &ifa->ifa_next) {
4a89c2562   Thomas Graf   [DECNET] address:...
577
578
579
  		if (tb[IFA_LOCAL] &&
  		    nla_memcmp(tb[IFA_LOCAL], &ifa->ifa_local, 2))
  			continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580

4a89c2562   Thomas Graf   [DECNET] address:...
581
  		if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582
583
584
585
586
  			continue;
  
  		dn_dev_del_ifa(dn_db, ifap, 1);
  		return 0;
  	}
4a89c2562   Thomas Graf   [DECNET] address:...
587
588
  errout:
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589
  }
4a89c2562   Thomas Graf   [DECNET] address:...
590
  static int dn_nl_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
591
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
592
  	struct net *net = sock_net(skb->sk);
4a89c2562   Thomas Graf   [DECNET] address:...
593
  	struct nlattr *tb[IFA_MAX+1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594
595
  	struct net_device *dev;
  	struct dn_dev *dn_db;
4a89c2562   Thomas Graf   [DECNET] address:...
596
  	struct ifaddrmsg *ifm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
597
  	struct dn_ifaddr *ifa;
4a89c2562   Thomas Graf   [DECNET] address:...
598
  	int err;
09ad9bc75   Octavian Purdila   net: use net_eq t...
599
  	if (!net_eq(net, &init_net))
b854272b3   Denis V. Lunev   [NET]: Modify all...
600
  		return -EINVAL;
4a89c2562   Thomas Graf   [DECNET] address:...
601
602
603
  	err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, dn_ifa_policy);
  	if (err < 0)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
604

4a89c2562   Thomas Graf   [DECNET] address:...
605
  	if (tb[IFA_LOCAL] == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606
  		return -EINVAL;
4a89c2562   Thomas Graf   [DECNET] address:...
607
  	ifm = nlmsg_data(nlh);
881d966b4   Eric W. Biederman   [NET]: Make the d...
608
  	if ((dev = __dev_get_by_index(&init_net, ifm->ifa_index)) == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
609
  		return -ENODEV;
fc766e4c4   Eric Dumazet   decnet: RCU conve...
610
  	if ((dn_db = rtnl_dereference(dev->dn_ptr)) == NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
611
612
613
614
  		dn_db = dn_dev_create(dev, &err);
  		if (!dn_db)
  			return err;
  	}
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
615

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
616
617
  	if ((ifa = dn_dev_alloc_ifa()) == NULL)
  		return -ENOBUFS;
4a89c2562   Thomas Graf   [DECNET] address:...
618
619
620
621
622
  	if (tb[IFA_ADDRESS] == NULL)
  		tb[IFA_ADDRESS] = tb[IFA_LOCAL];
  
  	ifa->ifa_local = nla_get_le16(tb[IFA_LOCAL]);
  	ifa->ifa_address = nla_get_le16(tb[IFA_ADDRESS]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
623
624
625
  	ifa->ifa_flags = ifm->ifa_flags;
  	ifa->ifa_scope = ifm->ifa_scope;
  	ifa->ifa_dev = dn_db;
4a89c2562   Thomas Graf   [DECNET] address:...
626
627
628
  
  	if (tb[IFA_LABEL])
  		nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
629
630
  	else
  		memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
4a89c2562   Thomas Graf   [DECNET] address:...
631
632
  	err = dn_dev_insert_ifa(dn_db, ifa);
  	if (err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
633
  		dn_dev_free_ifa(ifa);
4a89c2562   Thomas Graf   [DECNET] address:...
634
635
  
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636
  }
a6f01cace   Thomas Graf   [DECNET] address:...
637
638
639
640
641
642
643
  static inline size_t dn_ifaddr_nlmsg_size(void)
  {
  	return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
  	       + nla_total_size(IFNAMSIZ) /* IFA_LABEL */
  	       + nla_total_size(2) /* IFA_ADDRESS */
  	       + nla_total_size(2); /* IFA_LOCAL */
  }
4a89c2562   Thomas Graf   [DECNET] address:...
644
645
  static int dn_nl_fill_ifaddr(struct sk_buff *skb, struct dn_ifaddr *ifa,
  			     u32 pid, u32 seq, int event, unsigned int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
646
647
648
  {
  	struct ifaddrmsg *ifm;
  	struct nlmsghdr *nlh;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
649

4a89c2562   Thomas Graf   [DECNET] address:...
650
651
  	nlh = nlmsg_put(skb, pid, seq, event, sizeof(*ifm), flags);
  	if (nlh == NULL)
26932566a   Patrick McHardy   [NETLINK]: Don't ...
652
  		return -EMSGSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
653

4a89c2562   Thomas Graf   [DECNET] address:...
654
  	ifm = nlmsg_data(nlh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
655
656
657
658
659
  	ifm->ifa_family = AF_DECnet;
  	ifm->ifa_prefixlen = 16;
  	ifm->ifa_flags = ifa->ifa_flags | IFA_F_PERMANENT;
  	ifm->ifa_scope = ifa->ifa_scope;
  	ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
4a89c2562   Thomas Graf   [DECNET] address:...
660

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
661
  	if (ifa->ifa_address)
4a89c2562   Thomas Graf   [DECNET] address:...
662
  		NLA_PUT_LE16(skb, IFA_ADDRESS, ifa->ifa_address);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
663
  	if (ifa->ifa_local)
4a89c2562   Thomas Graf   [DECNET] address:...
664
  		NLA_PUT_LE16(skb, IFA_LOCAL, ifa->ifa_local);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
665
  	if (ifa->ifa_label[0])
4a89c2562   Thomas Graf   [DECNET] address:...
666
  		NLA_PUT_STRING(skb, IFA_LABEL, ifa->ifa_label);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
667

4a89c2562   Thomas Graf   [DECNET] address:...
668
669
670
  	return nlmsg_end(skb, nlh);
  
  nla_put_failure:
26932566a   Patrick McHardy   [NETLINK]: Don't ...
671
672
  	nlmsg_cancel(skb, nlh);
  	return -EMSGSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
673
  }
b020b942c   Thomas Graf   [DECNET] address:...
674
  static void dn_ifaddr_notify(int event, struct dn_ifaddr *ifa)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
675
676
  {
  	struct sk_buff *skb;
dc738dd83   Thomas Graf   [DECNET]: Convert...
677
  	int err = -ENOBUFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
678

a6f01cace   Thomas Graf   [DECNET] address:...
679
  	skb = alloc_skb(dn_ifaddr_nlmsg_size(), GFP_KERNEL);
dc738dd83   Thomas Graf   [DECNET]: Convert...
680
681
  	if (skb == NULL)
  		goto errout;
4a89c2562   Thomas Graf   [DECNET] address:...
682
  	err = dn_nl_fill_ifaddr(skb, ifa, 0, 0, event, 0);
26932566a   Patrick McHardy   [NETLINK]: Don't ...
683
684
685
686
687
688
  	if (err < 0) {
  		/* -EMSGSIZE implies BUG in dn_ifaddr_nlmsg_size() */
  		WARN_ON(err == -EMSGSIZE);
  		kfree_skb(skb);
  		goto errout;
  	}
1ce85fe40   Pablo Neira Ayuso   netlink: change n...
689
690
  	rtnl_notify(skb, &init_net, 0, RTNLGRP_DECnet_IFADDR, NULL, GFP_KERNEL);
  	return;
dc738dd83   Thomas Graf   [DECNET]: Convert...
691
692
  errout:
  	if (err < 0)
97c53cacf   Denis V. Lunev   [NET]: Make rtnet...
693
  		rtnl_set_sk_err(&init_net, RTNLGRP_DECnet_IFADDR, err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
694
  }
4a89c2562   Thomas Graf   [DECNET] address:...
695
  static int dn_nl_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
696
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
697
  	struct net *net = sock_net(skb->sk);
4a89c2562   Thomas Graf   [DECNET] address:...
698
  	int idx, dn_idx = 0, skip_ndevs, skip_naddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
699
700
701
  	struct net_device *dev;
  	struct dn_dev *dn_db;
  	struct dn_ifaddr *ifa;
09ad9bc75   Octavian Purdila   net: use net_eq t...
702
  	if (!net_eq(net, &init_net))
b854272b3   Denis V. Lunev   [NET]: Modify all...
703
  		return 0;
4a89c2562   Thomas Graf   [DECNET] address:...
704
705
  	skip_ndevs = cb->args[0];
  	skip_naddr = cb->args[1];
7562f876c   Pavel Emelianov   [NET]: Rework dev...
706
  	idx = 0;
e67f88dd1   Eric Dumazet   net: dont hold rt...
707
708
  	rcu_read_lock();
  	for_each_netdev_rcu(&init_net, dev) {
4a89c2562   Thomas Graf   [DECNET] address:...
709
  		if (idx < skip_ndevs)
7562f876c   Pavel Emelianov   [NET]: Rework dev...
710
  			goto cont;
4a89c2562   Thomas Graf   [DECNET] address:...
711
712
713
714
715
  		else if (idx > skip_ndevs) {
  			/* Only skip over addresses for first dev dumped
  			 * in this iteration (idx == skip_ndevs) */
  			skip_naddr = 0;
  		}
e67f88dd1   Eric Dumazet   net: dont hold rt...
716
  		if ((dn_db = rcu_dereference(dev->dn_ptr)) == NULL)
7562f876c   Pavel Emelianov   [NET]: Rework dev...
717
  			goto cont;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
718

e67f88dd1   Eric Dumazet   net: dont hold rt...
719
720
  		for (ifa = rcu_dereference(dn_db->ifa_list), dn_idx = 0; ifa;
  		     ifa = rcu_dereference(ifa->ifa_next), dn_idx++) {
4a89c2562   Thomas Graf   [DECNET] address:...
721
  			if (dn_idx < skip_naddr)
a2221f308   Patrick McHardy   [DECNET]: Fix int...
722
  				continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
723

4a89c2562   Thomas Graf   [DECNET] address:...
724
725
726
  			if (dn_nl_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid,
  					      cb->nlh->nlmsg_seq, RTM_NEWADDR,
  					      NLM_F_MULTI) < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
727
728
  				goto done;
  		}
7562f876c   Pavel Emelianov   [NET]: Rework dev...
729
730
  cont:
  		idx++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
731
732
  	}
  done:
e67f88dd1   Eric Dumazet   net: dont hold rt...
733
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
734
735
736
737
738
  	cb->args[0] = idx;
  	cb->args[1] = dn_idx;
  
  	return skb->len;
  }
c4ea94ab3   Steven Whitehouse   [DECnet]: Endian ...
739
  static int dn_dev_get_first(struct net_device *dev, __le16 *addr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
  {
fc766e4c4   Eric Dumazet   decnet: RCU conve...
741
  	struct dn_dev *dn_db;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
742
743
  	struct dn_ifaddr *ifa;
  	int rv = -ENODEV;
41bdecf17   stephen hemminger   decnet: add RTNL ...
744

fc766e4c4   Eric Dumazet   decnet: RCU conve...
745
746
  	rcu_read_lock();
  	dn_db = rcu_dereference(dev->dn_ptr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747
748
  	if (dn_db == NULL)
  		goto out;
41bdecf17   stephen hemminger   decnet: add RTNL ...
749

fc766e4c4   Eric Dumazet   decnet: RCU conve...
750
  	ifa = rcu_dereference(dn_db->ifa_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
751
752
753
754
755
  	if (ifa != NULL) {
  		*addr = ifa->ifa_local;
  		rv = 0;
  	}
  out:
fc766e4c4   Eric Dumazet   decnet: RCU conve...
756
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
757
758
  	return rv;
  }
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
759
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
760
761
762
763
764
765
766
767
768
   * Find a default address to bind to.
   *
   * This is one of those areas where the initial VMS concepts don't really
   * map onto the Linux concepts, and since we introduced multiple addresses
   * per interface we have to cope with slightly odd ways of finding out what
   * "our address" really is. Mostly it's not a problem; for this we just guess
   * a sensible default. Eventually the routing code will take care of all the
   * nasties for us I hope.
   */
c4ea94ab3   Steven Whitehouse   [DECnet]: Endian ...
769
  int dn_dev_bind_default(__le16 *addr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
770
771
772
773
774
775
  {
  	struct net_device *dev;
  	int rv;
  	dev = dn_dev_get_default();
  last_chance:
  	if (dev) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
776
  		rv = dn_dev_get_first(dev, addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
777
  		dev_put(dev);
2774c7aba   Eric W. Biederman   [NET]: Make the l...
778
  		if (rv == 0 || dev == init_net.loopback_dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
779
780
  			return rv;
  	}
2774c7aba   Eric W. Biederman   [NET]: Make the l...
781
  	dev = init_net.loopback_dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
782
783
784
785
786
787
  	dev_hold(dev);
  	goto last_chance;
  }
  
  static void dn_send_endnode_hello(struct net_device *dev, struct dn_ifaddr *ifa)
  {
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
788
789
790
  	struct endnode_hello_message *msg;
  	struct sk_buff *skb = NULL;
  	__le16 *pktlen;
fc766e4c4   Eric Dumazet   decnet: RCU conve...
791
  	struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
792

429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
793
  	if ((skb = dn_alloc_skb(NULL, sizeof(*msg), GFP_ATOMIC)) == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
794
  		return;
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
795
  	skb->dev = dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
796

429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
797
  	msg = (struct endnode_hello_message *)skb_put(skb,sizeof(*msg));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
798

429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
799
800
  	msg->msgflg  = 0x0D;
  	memcpy(msg->tiver, dn_eco_version, 3);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
801
  	dn_dn2eth(msg->id, ifa->ifa_local);
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
802
  	msg->iinfo   = DN_RT_INFO_ENDN;
c4106aa88   Harvey Harrison   decnet: remove pr...
803
  	msg->blksize = cpu_to_le16(mtu2blksize(dev));
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
804
805
806
  	msg->area    = 0x00;
  	memset(msg->seed, 0, 8);
  	memcpy(msg->neighbor, dn_hiord, ETH_ALEN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
807
808
809
810
811
  
  	if (dn_db->router) {
  		struct dn_neigh *dn = (struct dn_neigh *)dn_db->router;
  		dn_dn2eth(msg->neighbor, dn->addr);
  	}
c4106aa88   Harvey Harrison   decnet: remove pr...
812
  	msg->timer   = cpu_to_le16((unsigned short)dn_db->parms.t3);
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
813
814
815
816
817
  	msg->mpd     = 0x00;
  	msg->datalen = 0x02;
  	memset(msg->data, 0xAA, 2);
  
  	pktlen = (__le16 *)skb_push(skb,2);
c4106aa88   Harvey Harrison   decnet: remove pr...
818
  	*pktlen = cpu_to_le16(skb->len - 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
819

c1d2bbe1c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
820
  	skb_reset_network_header(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
  
  	dn_rt_finish_output(skb, dn_rt_all_rt_mcast, msg->id);
  }
  
  
  #define DRDELAY (5 * HZ)
  
  static int dn_am_i_a_router(struct dn_neigh *dn, struct dn_dev *dn_db, struct dn_ifaddr *ifa)
  {
  	/* First check time since device went up */
  	if ((jiffies - dn_db->uptime) < DRDELAY)
  		return 0;
  
  	/* If there is no router, then yes... */
  	if (!dn_db->router)
  		return 1;
  
  	/* otherwise only if we have a higher priority or.. */
  	if (dn->priority < dn_db->parms.priority)
  		return 1;
  
  	/* if we have equal priority and a higher node number */
  	if (dn->priority != dn_db->parms.priority)
  		return 0;
c4106aa88   Harvey Harrison   decnet: remove pr...
845
  	if (le16_to_cpu(dn->addr) < le16_to_cpu(ifa->ifa_local))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
846
847
848
849
850
851
852
853
  		return 1;
  
  	return 0;
  }
  
  static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa)
  {
  	int n;
fc766e4c4   Eric Dumazet   decnet: RCU conve...
854
  	struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
855
856
857
858
859
  	struct dn_neigh *dn = (struct dn_neigh *)dn_db->router;
  	struct sk_buff *skb;
  	size_t size;
  	unsigned char *ptr;
  	unsigned char *i1, *i2;
c4ea94ab3   Steven Whitehouse   [DECnet]: Endian ...
860
  	__le16 *pktlen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
  	char *src;
  
  	if (mtu2blksize(dev) < (26 + 7))
  		return;
  
  	n = mtu2blksize(dev) - 26;
  	n /= 7;
  
  	if (n > 32)
  		n = 32;
  
  	size = 2 + 26 + 7 * n;
  
  	if ((skb = dn_alloc_skb(NULL, size, GFP_ATOMIC)) == NULL)
  		return;
  
  	skb->dev = dev;
  	ptr = skb_put(skb, size);
  
  	*ptr++ = DN_RT_PKT_CNTL | DN_RT_PKT_ERTH;
  	*ptr++ = 2; /* ECO */
  	*ptr++ = 0;
  	*ptr++ = 0;
  	dn_dn2eth(ptr, ifa->ifa_local);
  	src = ptr;
  	ptr += ETH_ALEN;
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
887
  	*ptr++ = dn_db->parms.forwarding == 1 ?
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
888
  			DN_RT_INFO_L1RT : DN_RT_INFO_L2RT;
c4106aa88   Harvey Harrison   decnet: remove pr...
889
  	*((__le16 *)ptr) = cpu_to_le16(mtu2blksize(dev));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
890
  	ptr += 2;
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
891
  	*ptr++ = dn_db->parms.priority; /* Priority */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
892
  	*ptr++ = 0; /* Area: Reserved */
c4106aa88   Harvey Harrison   decnet: remove pr...
893
  	*((__le16 *)ptr) = cpu_to_le16((unsigned short)dn_db->parms.t3);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
894
895
896
897
898
899
900
901
902
903
904
905
906
  	ptr += 2;
  	*ptr++ = 0; /* MPD: Reserved */
  	i1 = ptr++;
  	memset(ptr, 0, 7); /* Name: Reserved */
  	ptr += 7;
  	i2 = ptr++;
  
  	n = dn_neigh_elist(dev, ptr, n);
  
  	*i2 = 7 * n;
  	*i1 = 8 + *i2;
  
  	skb_trim(skb, (27 + *i2));
c4ea94ab3   Steven Whitehouse   [DECnet]: Endian ...
907
  	pktlen = (__le16 *)skb_push(skb, 2);
c4106aa88   Harvey Harrison   decnet: remove pr...
908
  	*pktlen = cpu_to_le16(skb->len - 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
909

c1d2bbe1c   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
910
  	skb_reset_network_header(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
911
912
913
914
915
916
917
918
919
920
921
922
923
  
  	if (dn_am_i_a_router(dn, dn_db, ifa)) {
  		struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
  		if (skb2) {
  			dn_rt_finish_output(skb2, dn_rt_all_end_mcast, src);
  		}
  	}
  
  	dn_rt_finish_output(skb, dn_rt_all_rt_mcast, src);
  }
  
  static void dn_send_brd_hello(struct net_device *dev, struct dn_ifaddr *ifa)
  {
fc766e4c4   Eric Dumazet   decnet: RCU conve...
924
  	struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
  
  	if (dn_db->parms.forwarding == 0)
  		dn_send_endnode_hello(dev, ifa);
  	else
  		dn_send_router_hello(dev, ifa);
  }
  
  static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa)
  {
  	int tdlen = 16;
  	int size = dev->hard_header_len + 2 + 4 + tdlen;
  	struct sk_buff *skb = dn_alloc_skb(NULL, size, GFP_ATOMIC);
  	int i;
  	unsigned char *ptr;
  	char src[ETH_ALEN];
  
  	if (skb == NULL)
  		return ;
  
  	skb->dev = dev;
  	skb_push(skb, dev->hard_header_len);
  	ptr = skb_put(skb, 2 + 4 + tdlen);
  
  	*ptr++ = DN_RT_PKT_HELO;
c4ea94ab3   Steven Whitehouse   [DECnet]: Endian ...
949
  	*((__le16 *)ptr) = ifa->ifa_local;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
950
951
952
953
954
955
956
957
958
959
960
961
  	ptr += 2;
  	*ptr++ = tdlen;
  
  	for(i = 0; i < tdlen; i++)
  		*ptr++ = 0252;
  
  	dn_dn2eth(src, ifa->ifa_local);
  	dn_rt_finish_output(skb, dn_rt_all_rt_mcast, src);
  }
  
  static int dn_eth_up(struct net_device *dev)
  {
fc766e4c4   Eric Dumazet   decnet: RCU conve...
962
  	struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
963
964
  
  	if (dn_db->parms.forwarding == 0)
22bedad3c   Jiri Pirko   net: convert mult...
965
  		dev_mc_add(dev, dn_rt_all_end_mcast);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
966
  	else
22bedad3c   Jiri Pirko   net: convert mult...
967
  		dev_mc_add(dev, dn_rt_all_rt_mcast);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
968

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
969
970
971
972
973
974
975
  	dn_db->use_long = 1;
  
  	return 0;
  }
  
  static void dn_eth_down(struct net_device *dev)
  {
fc766e4c4   Eric Dumazet   decnet: RCU conve...
976
  	struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
977
978
  
  	if (dn_db->parms.forwarding == 0)
22bedad3c   Jiri Pirko   net: convert mult...
979
  		dev_mc_del(dev, dn_rt_all_end_mcast);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
980
  	else
22bedad3c   Jiri Pirko   net: convert mult...
981
  		dev_mc_del(dev, dn_rt_all_rt_mcast);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
982
983
984
985
986
987
988
  }
  
  static void dn_dev_set_timer(struct net_device *dev);
  
  static void dn_dev_timer_func(unsigned long arg)
  {
  	struct net_device *dev = (struct net_device *)arg;
fc766e4c4   Eric Dumazet   decnet: RCU conve...
989
  	struct dn_dev *dn_db;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
990
  	struct dn_ifaddr *ifa;
fc766e4c4   Eric Dumazet   decnet: RCU conve...
991
992
  	rcu_read_lock();
  	dn_db = rcu_dereference(dev->dn_ptr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
993
994
  	if (dn_db->t3 <= dn_db->parms.t2) {
  		if (dn_db->parms.timer3) {
fc766e4c4   Eric Dumazet   decnet: RCU conve...
995
996
997
  			for (ifa = rcu_dereference(dn_db->ifa_list);
  			     ifa;
  			     ifa = rcu_dereference(ifa->ifa_next)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
998
999
1000
1001
1002
1003
1004
1005
  				if (!(ifa->ifa_flags & IFA_F_SECONDARY))
  					dn_db->parms.timer3(dev, ifa);
  			}
  		}
  		dn_db->t3 = dn_db->parms.t3;
  	} else {
  		dn_db->t3 -= dn_db->parms.t2;
  	}
fc766e4c4   Eric Dumazet   decnet: RCU conve...
1006
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1007
1008
1009
1010
1011
  	dn_dev_set_timer(dev);
  }
  
  static void dn_dev_set_timer(struct net_device *dev)
  {
fc766e4c4   Eric Dumazet   decnet: RCU conve...
1012
  	struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
  
  	if (dn_db->parms.t2 > dn_db->parms.t3)
  		dn_db->parms.t2 = dn_db->parms.t3;
  
  	dn_db->timer.data = (unsigned long)dev;
  	dn_db->timer.function = dn_dev_timer_func;
  	dn_db->timer.expires = jiffies + (dn_db->parms.t2 * HZ);
  
  	add_timer(&dn_db->timer);
  }
5eaa65b24   Roel Kluin   net: Make static
1023
  static struct dn_dev *dn_dev_create(struct net_device *dev, int *err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
  {
  	int i;
  	struct dn_dev_parms *p = dn_dev_list;
  	struct dn_dev *dn_db;
  
  	for(i = 0; i < DN_DEV_LIST_SIZE; i++, p++) {
  		if (p->type == dev->type)
  			break;
  	}
  
  	*err = -ENODEV;
  	if (i == DN_DEV_LIST_SIZE)
  		return NULL;
  
  	*err = -ENOBUFS;
0da974f4f   Panagiotis Issaris   [NET]: Conversion...
1039
  	if ((dn_db = kzalloc(sizeof(struct dn_dev), GFP_ATOMIC)) == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1040
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1041
  	memcpy(&dn_db->parms, p, sizeof(struct dn_dev_parms));
fc766e4c4   Eric Dumazet   decnet: RCU conve...
1042

cf778b00e   Eric Dumazet   net: reintroduce ...
1043
  	rcu_assign_pointer(dev->dn_ptr, dn_db);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1044
1045
1046
1047
  	dn_db->dev = dev;
  	init_timer(&dn_db->timer);
  
  	dn_db->uptime = jiffies;
95743deb3   Eric W. Biederman   [DECNET]: Handle ...
1048
1049
1050
  
  	dn_db->neigh_parms = neigh_parms_alloc(dev, &dn_neigh_table);
  	if (!dn_db->neigh_parms) {
a9b3cd7f3   Stephen Hemminger   rcu: convert uses...
1051
  		RCU_INIT_POINTER(dev->dn_ptr, NULL);
95743deb3   Eric W. Biederman   [DECNET]: Handle ...
1052
1053
1054
  		kfree(dn_db);
  		return NULL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1055
1056
  	if (dn_db->parms.up) {
  		if (dn_db->parms.up(dev) < 0) {
95743deb3   Eric W. Biederman   [DECNET]: Handle ...
1057
  			neigh_parms_release(&dn_neigh_table, dn_db->neigh_parms);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1058
1059
1060
1061
1062
  			dev->dn_ptr = NULL;
  			kfree(dn_db);
  			return NULL;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
  	dn_dev_sysctl_register(dev, &dn_db->parms);
  
  	dn_dev_set_timer(dev);
  
  	*err = 0;
  	return dn_db;
  }
  
  
  /*
   * This processes a device up event. We only start up
   * the loopback device & ethernet devices with correct
b595076a1   Uwe Kleine-König   tree-wide: fix co...
1075
   * MAC addresses automatically. Others must be started
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
   * specifically.
   *
   * FIXME: How should we configure the loopback address ? If we could dispense
   * with using decnet_address here and for autobind, it will be one less thing
   * for users to worry about setting up.
   */
  
  void dn_dev_up(struct net_device *dev)
  {
  	struct dn_ifaddr *ifa;
c4ea94ab3   Steven Whitehouse   [DECnet]: Endian ...
1086
  	__le16 addr = decnet_address;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1087
  	int maybe_default = 0;
fc766e4c4   Eric Dumazet   decnet: RCU conve...
1088
  	struct dn_dev *dn_db = rtnl_dereference(dev->dn_ptr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
  
  	if ((dev->type != ARPHRD_ETHER) && (dev->type != ARPHRD_LOOPBACK))
  		return;
  
  	/*
  	 * Need to ensure that loopback device has a dn_db attached to it
  	 * to allow creation of neighbours against it, even though it might
  	 * not have a local address of its own. Might as well do the same for
  	 * all autoconfigured interfaces.
  	 */
  	if (dn_db == NULL) {
  		int err;
  		dn_db = dn_dev_create(dev, &err);
  		if (dn_db == NULL)
  			return;
  	}
  
  	if (dev->type == ARPHRD_ETHER) {
  		if (memcmp(dev->dev_addr, dn_hiord, 4) != 0)
  			return;
c4ea94ab3   Steven Whitehouse   [DECnet]: Endian ...
1109
  		addr = dn_eth2dn(dev->dev_addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
  		maybe_default = 1;
  	}
  
  	if (addr == 0)
  		return;
  
  	if ((ifa = dn_dev_alloc_ifa()) == NULL)
  		return;
  
  	ifa->ifa_local = ifa->ifa_address = addr;
  	ifa->ifa_flags = 0;
  	ifa->ifa_scope = RT_SCOPE_UNIVERSE;
  	strcpy(ifa->ifa_label, dev->name);
  
  	dn_dev_set_ifa(dev, ifa);
  
  	/*
  	 * Automagically set the default device to the first automatically
  	 * configured ethernet card in the system.
  	 */
  	if (maybe_default) {
  		dev_hold(dev);
  		if (dn_dev_set_default(dev, 0))
  			dev_put(dev);
  	}
  }
  
  static void dn_dev_delete(struct net_device *dev)
  {
fc766e4c4   Eric Dumazet   decnet: RCU conve...
1139
  	struct dn_dev *dn_db = rtnl_dereference(dev->dn_ptr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
  
  	if (dn_db == NULL)
  		return;
  
  	del_timer_sync(&dn_db->timer);
  	dn_dev_sysctl_unregister(&dn_db->parms);
  	dn_dev_check_default(dev);
  	neigh_ifdown(&dn_neigh_table, dev);
  
  	if (dn_db->parms.down)
  		dn_db->parms.down(dev);
  
  	dev->dn_ptr = NULL;
  
  	neigh_parms_release(&dn_neigh_table, dn_db->neigh_parms);
  	neigh_ifdown(&dn_neigh_table, dev);
  
  	if (dn_db->router)
  		neigh_release(dn_db->router);
  	if (dn_db->peer)
  		neigh_release(dn_db->peer);
  
  	kfree(dn_db);
  }
  
  void dn_dev_down(struct net_device *dev)
  {
fc766e4c4   Eric Dumazet   decnet: RCU conve...
1167
  	struct dn_dev *dn_db = rtnl_dereference(dev->dn_ptr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1168
1169
1170
1171
  	struct dn_ifaddr *ifa;
  
  	if (dn_db == NULL)
  		return;
fc766e4c4   Eric Dumazet   decnet: RCU conve...
1172
  	while ((ifa = rtnl_dereference(dn_db->ifa_list)) != NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1173
1174
1175
1176
1177
1178
1179
1180
1181
  		dn_dev_del_ifa(dn_db, &dn_db->ifa_list, 0);
  		dn_dev_free_ifa(ifa);
  	}
  
  	dn_dev_delete(dev);
  }
  
  void dn_dev_init_pkt(struct sk_buff *skb)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1182
1183
1184
1185
  }
  
  void dn_dev_veri_pkt(struct sk_buff *skb)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1186
1187
1188
1189
  }
  
  void dn_dev_hello(struct sk_buff *skb)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1190
1191
1192
1193
1194
1195
1196
  }
  
  void dn_dev_devices_off(void)
  {
  	struct net_device *dev;
  
  	rtnl_lock();
881d966b4   Eric W. Biederman   [NET]: Make the d...
1197
  	for_each_netdev(&init_net, dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
  		dn_dev_down(dev);
  	rtnl_unlock();
  
  }
  
  void dn_dev_devices_on(void)
  {
  	struct net_device *dev;
  
  	rtnl_lock();
881d966b4   Eric W. Biederman   [NET]: Make the d...
1208
  	for_each_netdev(&init_net, dev) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1209
1210
1211
1212
1213
1214
1215
1216
  		if (dev->flags & IFF_UP)
  			dn_dev_up(dev);
  	}
  	rtnl_unlock();
  }
  
  int register_dnaddr_notifier(struct notifier_block *nb)
  {
e041c6834   Alan Stern   [PATCH] Notifier ...
1217
  	return blocking_notifier_chain_register(&dnaddr_chain, nb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1218
1219
1220
1221
  }
  
  int unregister_dnaddr_notifier(struct notifier_block *nb)
  {
e041c6834   Alan Stern   [PATCH] Notifier ...
1222
  	return blocking_notifier_chain_unregister(&dnaddr_chain, nb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1223
1224
1225
  }
  
  #ifdef CONFIG_PROC_FS
7562f876c   Pavel Emelianov   [NET]: Rework dev...
1226
  static inline int is_dn_dev(struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1227
  {
7562f876c   Pavel Emelianov   [NET]: Rework dev...
1228
  	return dev->dn_ptr != NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1229
  }
7562f876c   Pavel Emelianov   [NET]: Rework dev...
1230
  static void *dn_dev_seq_start(struct seq_file *seq, loff_t *pos)
fc766e4c4   Eric Dumazet   decnet: RCU conve...
1231
  	__acquires(RCU)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1232
  {
7562f876c   Pavel Emelianov   [NET]: Rework dev...
1233
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1234
  	struct net_device *dev;
fa918602b   stephen hemminger   decnet: use RCU t...
1235
  	rcu_read_lock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1236

7562f876c   Pavel Emelianov   [NET]: Rework dev...
1237
1238
1239
1240
  	if (*pos == 0)
  		return SEQ_START_TOKEN;
  
  	i = 1;
fa918602b   stephen hemminger   decnet: use RCU t...
1241
  	for_each_netdev_rcu(&init_net, dev) {
7562f876c   Pavel Emelianov   [NET]: Rework dev...
1242
1243
1244
1245
1246
  		if (!is_dn_dev(dev))
  			continue;
  
  		if (i++ == *pos)
  			return dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1247
  	}
7562f876c   Pavel Emelianov   [NET]: Rework dev...
1248
1249
  
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1250
1251
1252
1253
  }
  
  static void *dn_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
  {
7562f876c   Pavel Emelianov   [NET]: Rework dev...
1254
  	struct net_device *dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1255

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1256
  	++*pos;
7562f876c   Pavel Emelianov   [NET]: Rework dev...
1257

ea1107338   Joe Perches   net: Remove casts...
1258
  	dev = v;
7562f876c   Pavel Emelianov   [NET]: Rework dev...
1259
  	if (v == SEQ_START_TOKEN)
881d966b4   Eric W. Biederman   [NET]: Make the d...
1260
  		dev = net_device_entry(&init_net.dev_base_head);
7562f876c   Pavel Emelianov   [NET]: Rework dev...
1261

fa918602b   stephen hemminger   decnet: use RCU t...
1262
  	for_each_netdev_continue_rcu(&init_net, dev) {
7562f876c   Pavel Emelianov   [NET]: Rework dev...
1263
1264
1265
1266
1267
1268
1269
  		if (!is_dn_dev(dev))
  			continue;
  
  		return dev;
  	}
  
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1270
1271
1272
  }
  
  static void dn_dev_seq_stop(struct seq_file *seq, void *v)
fc766e4c4   Eric Dumazet   decnet: RCU conve...
1273
  	__releases(RCU)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1274
  {
fa918602b   stephen hemminger   decnet: use RCU t...
1275
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1276
1277
1278
1279
  }
  
  static char *dn_type2asc(char type)
  {
06f8fe11b   Joe Perches   decnet: Reduce sw...
1280
1281
1282
1283
1284
1285
1286
  	switch (type) {
  	case DN_DEV_BCAST:
  		return "B";
  	case DN_DEV_UCAST:
  		return "U";
  	case DN_DEV_MPOINT:
  		return "M";
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1287
1288
1289
1290
1291
1292
1293
1294
  	}
  
  	return "?";
  }
  
  static int dn_dev_seq_show(struct seq_file *seq, void *v)
  {
  	if (v == SEQ_START_TOKEN)
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
1295
1296
  		seq_puts(seq, "Name     Flags T1   Timer1 T3   Timer3 BlkSize Pri State DevType    Router Peer
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1297
1298
1299
1300
  	else {
  		struct net_device *dev = v;
  		char peer_buf[DN_ASCBUF_LEN];
  		char router_buf[DN_ASCBUF_LEN];
fc766e4c4   Eric Dumazet   decnet: RCU conve...
1301
  		struct dn_dev *dn_db = rcu_dereference(dev->dn_ptr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1302

429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
1303
  		seq_printf(seq, "%-8s %1s     %04u %04u   %04lu %04lu"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1304
1305
  				"   %04hu    %03d %02x    %-10s %-7s %-7s
  ",
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
1306
1307
1308
  				dev->name ? dev->name : "???",
  				dn_type2asc(dn_db->parms.mode),
  				0, 0,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1309
1310
1311
1312
  				dn_db->t3, dn_db->parms.t3,
  				mtu2blksize(dev),
  				dn_db->parms.priority,
  				dn_db->parms.state, dn_db->parms.name,
c4106aa88   Harvey Harrison   decnet: remove pr...
1313
1314
  				dn_db->router ? dn_addr2asc(le16_to_cpu(*(__le16 *)dn_db->router->primary_key), router_buf) : "",
  				dn_db->peer ? dn_addr2asc(le16_to_cpu(*(__le16 *)dn_db->peer->primary_key), peer_buf) : "");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1315
1316
1317
  	}
  	return 0;
  }
56b3d975b   Philippe De Muyter   [NET]: Make all i...
1318
  static const struct seq_operations dn_dev_seq_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
  	.start	= dn_dev_seq_start,
  	.next	= dn_dev_seq_next,
  	.stop	= dn_dev_seq_stop,
  	.show	= dn_dev_seq_show,
  };
  
  static int dn_dev_seq_open(struct inode *inode, struct file *file)
  {
  	return seq_open(file, &dn_dev_seq_ops);
  }
9a32144e9   Arjan van de Ven   [PATCH] mark stru...
1329
  static const struct file_operations dn_dev_seq_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1330
1331
1332
1333
1334
1335
1336
1337
  	.owner	 = THIS_MODULE,
  	.open	 = dn_dev_seq_open,
  	.read	 = seq_read,
  	.llseek	 = seq_lseek,
  	.release = seq_release,
  };
  
  #endif /* CONFIG_PROC_FS */
4e058063f   Alexey Dobriyan   [DECNET]: "addr" ...
1338
  static int addr[2];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1339
1340
1341
1342
1343
  module_param_array(addr, int, NULL, 0444);
  MODULE_PARM_DESC(addr, "The DECnet address of this machine: area,node");
  
  void __init dn_dev_init(void)
  {
429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
1344
1345
1346
1347
  	if (addr[0] > 63 || addr[0] < 0) {
  		printk(KERN_ERR "DECnet: Area must be between 0 and 63");
  		return;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1348

429eb0fae   YOSHIFUJI Hideaki   [NET] DECNET: Fix...
1349
1350
1351
1352
  	if (addr[1] > 1023 || addr[1] < 0) {
  		printk(KERN_ERR "DECnet: Node must be between 0 and 1023");
  		return;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1353

c4106aa88   Harvey Harrison   decnet: remove pr...
1354
  	decnet_address = cpu_to_le16((addr[0] << 10) | addr[1]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1355
1356
  
  	dn_dev_devices_on();
c7ac8679b   Greg Rose   rtnetlink: Comput...
1357
1358
1359
  	rtnl_register(PF_DECnet, RTM_NEWADDR, dn_nl_newaddr, NULL, NULL);
  	rtnl_register(PF_DECnet, RTM_DELADDR, dn_nl_deladdr, NULL, NULL);
  	rtnl_register(PF_DECnet, RTM_GETADDR, NULL, dn_nl_dump_ifaddr, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1360

457c4cbc5   Eric W. Biederman   [NET]: Make /proc...
1361
  	proc_net_fops_create(&init_net, "decnet_dev", S_IRUGO, &dn_dev_seq_fops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
  
  #ifdef CONFIG_SYSCTL
  	{
  		int i;
  		for(i = 0; i < DN_DEV_LIST_SIZE; i++)
  			dn_dev_sysctl_register(NULL, &dn_dev_list[i]);
  	}
  #endif /* CONFIG_SYSCTL */
  }
  
  void __exit dn_dev_cleanup(void)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1374
1375
1376
1377
1378
1379
1380
  #ifdef CONFIG_SYSCTL
  	{
  		int i;
  		for(i = 0; i < DN_DEV_LIST_SIZE; i++)
  			dn_dev_sysctl_unregister(&dn_dev_list[i]);
  	}
  #endif /* CONFIG_SYSCTL */
457c4cbc5   Eric W. Biederman   [NET]: Make /proc...
1381
  	proc_net_remove(&init_net, "decnet_dev");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1382
1383
1384
  
  	dn_dev_devices_off();
  }