xref: /OK3568_Linux_fs/kernel/net/decnet/dn_dev.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * DECnet       An implementation of the DECnet protocol suite for the LINUX
4*4882a593Smuzhiyun  *              operating system.  DECnet is implemented using the  BSD Socket
5*4882a593Smuzhiyun  *              interface as the means of communication with the user level.
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  *              DECnet Device Layer
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * Authors:     Steve Whitehouse <SteveW@ACM.org>
10*4882a593Smuzhiyun  *              Eduardo Marcelo Serrat <emserrat@geocities.com>
11*4882a593Smuzhiyun  *
12*4882a593Smuzhiyun  * Changes:
13*4882a593Smuzhiyun  *          Steve Whitehouse : Devices now see incoming frames so they
14*4882a593Smuzhiyun  *                             can mark on who it came from.
15*4882a593Smuzhiyun  *          Steve Whitehouse : Fixed bug in creating neighbours. Each neighbour
16*4882a593Smuzhiyun  *                             can now have a device specific setup func.
17*4882a593Smuzhiyun  *          Steve Whitehouse : Added /proc/sys/net/decnet/conf/<dev>/
18*4882a593Smuzhiyun  *          Steve Whitehouse : Fixed bug which sometimes killed timer
19*4882a593Smuzhiyun  *          Steve Whitehouse : Multiple ifaddr support
20*4882a593Smuzhiyun  *          Steve Whitehouse : SIOCGIFCONF is now a compile time option
21*4882a593Smuzhiyun  *          Steve Whitehouse : /proc/sys/net/decnet/conf/<sys>/forwarding
22*4882a593Smuzhiyun  *          Steve Whitehouse : Removed timer1 - it's a user space issue now
23*4882a593Smuzhiyun  *         Patrick Caulfield : Fixed router hello message format
24*4882a593Smuzhiyun  *          Steve Whitehouse : Got rid of constant sizes for blksize for
25*4882a593Smuzhiyun  *                             devices. All mtu based now.
26*4882a593Smuzhiyun  */
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #include <linux/capability.h>
29*4882a593Smuzhiyun #include <linux/module.h>
30*4882a593Smuzhiyun #include <linux/moduleparam.h>
31*4882a593Smuzhiyun #include <linux/init.h>
32*4882a593Smuzhiyun #include <linux/net.h>
33*4882a593Smuzhiyun #include <linux/netdevice.h>
34*4882a593Smuzhiyun #include <linux/proc_fs.h>
35*4882a593Smuzhiyun #include <linux/seq_file.h>
36*4882a593Smuzhiyun #include <linux/timer.h>
37*4882a593Smuzhiyun #include <linux/string.h>
38*4882a593Smuzhiyun #include <linux/if_addr.h>
39*4882a593Smuzhiyun #include <linux/if_arp.h>
40*4882a593Smuzhiyun #include <linux/if_ether.h>
41*4882a593Smuzhiyun #include <linux/skbuff.h>
42*4882a593Smuzhiyun #include <linux/sysctl.h>
43*4882a593Smuzhiyun #include <linux/notifier.h>
44*4882a593Smuzhiyun #include <linux/slab.h>
45*4882a593Smuzhiyun #include <linux/jiffies.h>
46*4882a593Smuzhiyun #include <linux/uaccess.h>
47*4882a593Smuzhiyun #include <net/net_namespace.h>
48*4882a593Smuzhiyun #include <net/neighbour.h>
49*4882a593Smuzhiyun #include <net/dst.h>
50*4882a593Smuzhiyun #include <net/flow.h>
51*4882a593Smuzhiyun #include <net/fib_rules.h>
52*4882a593Smuzhiyun #include <net/netlink.h>
53*4882a593Smuzhiyun #include <net/dn.h>
54*4882a593Smuzhiyun #include <net/dn_dev.h>
55*4882a593Smuzhiyun #include <net/dn_route.h>
56*4882a593Smuzhiyun #include <net/dn_neigh.h>
57*4882a593Smuzhiyun #include <net/dn_fib.h>
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun #define DN_IFREQ_SIZE (offsetof(struct ifreq, ifr_ifru) + sizeof(struct sockaddr_dn))
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun static char dn_rt_all_end_mcast[ETH_ALEN] = {0xAB,0x00,0x00,0x04,0x00,0x00};
62*4882a593Smuzhiyun static char dn_rt_all_rt_mcast[ETH_ALEN]  = {0xAB,0x00,0x00,0x03,0x00,0x00};
63*4882a593Smuzhiyun static char dn_hiord[ETH_ALEN]            = {0xAA,0x00,0x04,0x00,0x00,0x00};
64*4882a593Smuzhiyun static unsigned char dn_eco_version[3]    = {0x02,0x00,0x00};
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun extern struct neigh_table dn_neigh_table;
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun /*
69*4882a593Smuzhiyun  * decnet_address is kept in network order.
70*4882a593Smuzhiyun  */
71*4882a593Smuzhiyun __le16 decnet_address = 0;
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun static DEFINE_SPINLOCK(dndev_lock);
74*4882a593Smuzhiyun static struct net_device *decnet_default_device;
75*4882a593Smuzhiyun static BLOCKING_NOTIFIER_HEAD(dnaddr_chain);
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun static struct dn_dev *dn_dev_create(struct net_device *dev, int *err);
78*4882a593Smuzhiyun static void dn_dev_delete(struct net_device *dev);
79*4882a593Smuzhiyun static void dn_ifaddr_notify(int event, struct dn_ifaddr *ifa);
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun static int dn_eth_up(struct net_device *);
82*4882a593Smuzhiyun static void dn_eth_down(struct net_device *);
83*4882a593Smuzhiyun static void dn_send_brd_hello(struct net_device *dev, struct dn_ifaddr *ifa);
84*4882a593Smuzhiyun static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa);
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun static struct dn_dev_parms dn_dev_list[] =  {
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun 	.type =		ARPHRD_ETHER, /* Ethernet */
89*4882a593Smuzhiyun 	.mode =		DN_DEV_BCAST,
90*4882a593Smuzhiyun 	.state =	DN_DEV_S_RU,
91*4882a593Smuzhiyun 	.t2 =		1,
92*4882a593Smuzhiyun 	.t3 =		10,
93*4882a593Smuzhiyun 	.name =		"ethernet",
94*4882a593Smuzhiyun 	.up =		dn_eth_up,
95*4882a593Smuzhiyun 	.down = 	dn_eth_down,
96*4882a593Smuzhiyun 	.timer3 =	dn_send_brd_hello,
97*4882a593Smuzhiyun },
98*4882a593Smuzhiyun {
99*4882a593Smuzhiyun 	.type =		ARPHRD_IPGRE, /* DECnet tunneled over GRE in IP */
100*4882a593Smuzhiyun 	.mode =		DN_DEV_BCAST,
101*4882a593Smuzhiyun 	.state =	DN_DEV_S_RU,
102*4882a593Smuzhiyun 	.t2 =		1,
103*4882a593Smuzhiyun 	.t3 =		10,
104*4882a593Smuzhiyun 	.name =		"ipgre",
105*4882a593Smuzhiyun 	.timer3 =	dn_send_brd_hello,
106*4882a593Smuzhiyun },
107*4882a593Smuzhiyun #if 0
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun 	.type =		ARPHRD_X25, /* Bog standard X.25 */
110*4882a593Smuzhiyun 	.mode =		DN_DEV_UCAST,
111*4882a593Smuzhiyun 	.state =	DN_DEV_S_DS,
112*4882a593Smuzhiyun 	.t2 =		1,
113*4882a593Smuzhiyun 	.t3 =		120,
114*4882a593Smuzhiyun 	.name =		"x25",
115*4882a593Smuzhiyun 	.timer3 =	dn_send_ptp_hello,
116*4882a593Smuzhiyun },
117*4882a593Smuzhiyun #endif
118*4882a593Smuzhiyun #if 0
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun 	.type =		ARPHRD_PPP, /* DECnet over PPP */
121*4882a593Smuzhiyun 	.mode =		DN_DEV_BCAST,
122*4882a593Smuzhiyun 	.state =	DN_DEV_S_RU,
123*4882a593Smuzhiyun 	.t2 =		1,
124*4882a593Smuzhiyun 	.t3 =		10,
125*4882a593Smuzhiyun 	.name =		"ppp",
126*4882a593Smuzhiyun 	.timer3 =	dn_send_brd_hello,
127*4882a593Smuzhiyun },
128*4882a593Smuzhiyun #endif
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun 	.type =		ARPHRD_DDCMP, /* DECnet over DDCMP */
131*4882a593Smuzhiyun 	.mode =		DN_DEV_UCAST,
132*4882a593Smuzhiyun 	.state =	DN_DEV_S_DS,
133*4882a593Smuzhiyun 	.t2 =		1,
134*4882a593Smuzhiyun 	.t3 =		120,
135*4882a593Smuzhiyun 	.name =		"ddcmp",
136*4882a593Smuzhiyun 	.timer3 =	dn_send_ptp_hello,
137*4882a593Smuzhiyun },
138*4882a593Smuzhiyun {
139*4882a593Smuzhiyun 	.type =		ARPHRD_LOOPBACK, /* Loopback interface - always last */
140*4882a593Smuzhiyun 	.mode =		DN_DEV_BCAST,
141*4882a593Smuzhiyun 	.state =	DN_DEV_S_RU,
142*4882a593Smuzhiyun 	.t2 =		1,
143*4882a593Smuzhiyun 	.t3 =		10,
144*4882a593Smuzhiyun 	.name =		"loopback",
145*4882a593Smuzhiyun 	.timer3 =	dn_send_brd_hello,
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun };
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun #define DN_DEV_LIST_SIZE ARRAY_SIZE(dn_dev_list)
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun #define DN_DEV_PARMS_OFFSET(x) offsetof(struct dn_dev_parms, x)
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun #ifdef CONFIG_SYSCTL
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun static int min_t2[] = { 1 };
156*4882a593Smuzhiyun static int max_t2[] = { 60 }; /* No max specified, but this seems sensible */
157*4882a593Smuzhiyun static int min_t3[] = { 1 };
158*4882a593Smuzhiyun static int max_t3[] = { 8191 }; /* Must fit in 16 bits when multiplied by BCT3MULT or T3MULT */
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun static int min_priority[1];
161*4882a593Smuzhiyun static int max_priority[] = { 127 }; /* From DECnet spec */
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun static int dn_forwarding_proc(struct ctl_table *, int, void *, size_t *,
164*4882a593Smuzhiyun 		loff_t *);
165*4882a593Smuzhiyun static struct dn_dev_sysctl_table {
166*4882a593Smuzhiyun 	struct ctl_table_header *sysctl_header;
167*4882a593Smuzhiyun 	struct ctl_table dn_dev_vars[5];
168*4882a593Smuzhiyun } dn_dev_sysctl = {
169*4882a593Smuzhiyun 	NULL,
170*4882a593Smuzhiyun 	{
171*4882a593Smuzhiyun 	{
172*4882a593Smuzhiyun 		.procname = "forwarding",
173*4882a593Smuzhiyun 		.data = (void *)DN_DEV_PARMS_OFFSET(forwarding),
174*4882a593Smuzhiyun 		.maxlen = sizeof(int),
175*4882a593Smuzhiyun 		.mode = 0644,
176*4882a593Smuzhiyun 		.proc_handler = dn_forwarding_proc,
177*4882a593Smuzhiyun 	},
178*4882a593Smuzhiyun 	{
179*4882a593Smuzhiyun 		.procname = "priority",
180*4882a593Smuzhiyun 		.data = (void *)DN_DEV_PARMS_OFFSET(priority),
181*4882a593Smuzhiyun 		.maxlen = sizeof(int),
182*4882a593Smuzhiyun 		.mode = 0644,
183*4882a593Smuzhiyun 		.proc_handler = proc_dointvec_minmax,
184*4882a593Smuzhiyun 		.extra1 = &min_priority,
185*4882a593Smuzhiyun 		.extra2 = &max_priority
186*4882a593Smuzhiyun 	},
187*4882a593Smuzhiyun 	{
188*4882a593Smuzhiyun 		.procname = "t2",
189*4882a593Smuzhiyun 		.data = (void *)DN_DEV_PARMS_OFFSET(t2),
190*4882a593Smuzhiyun 		.maxlen = sizeof(int),
191*4882a593Smuzhiyun 		.mode = 0644,
192*4882a593Smuzhiyun 		.proc_handler = proc_dointvec_minmax,
193*4882a593Smuzhiyun 		.extra1 = &min_t2,
194*4882a593Smuzhiyun 		.extra2 = &max_t2
195*4882a593Smuzhiyun 	},
196*4882a593Smuzhiyun 	{
197*4882a593Smuzhiyun 		.procname = "t3",
198*4882a593Smuzhiyun 		.data = (void *)DN_DEV_PARMS_OFFSET(t3),
199*4882a593Smuzhiyun 		.maxlen = sizeof(int),
200*4882a593Smuzhiyun 		.mode = 0644,
201*4882a593Smuzhiyun 		.proc_handler = proc_dointvec_minmax,
202*4882a593Smuzhiyun 		.extra1 = &min_t3,
203*4882a593Smuzhiyun 		.extra2 = &max_t3
204*4882a593Smuzhiyun 	},
205*4882a593Smuzhiyun 	{ }
206*4882a593Smuzhiyun 	},
207*4882a593Smuzhiyun };
208*4882a593Smuzhiyun 
dn_dev_sysctl_register(struct net_device * dev,struct dn_dev_parms * parms)209*4882a593Smuzhiyun static void dn_dev_sysctl_register(struct net_device *dev, struct dn_dev_parms *parms)
210*4882a593Smuzhiyun {
211*4882a593Smuzhiyun 	struct dn_dev_sysctl_table *t;
212*4882a593Smuzhiyun 	int i;
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 	char path[sizeof("net/decnet/conf/") + IFNAMSIZ];
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	t = kmemdup(&dn_dev_sysctl, sizeof(*t), GFP_KERNEL);
217*4882a593Smuzhiyun 	if (t == NULL)
218*4882a593Smuzhiyun 		return;
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	for(i = 0; i < ARRAY_SIZE(t->dn_dev_vars) - 1; i++) {
221*4882a593Smuzhiyun 		long offset = (long)t->dn_dev_vars[i].data;
222*4882a593Smuzhiyun 		t->dn_dev_vars[i].data = ((char *)parms) + offset;
223*4882a593Smuzhiyun 	}
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	snprintf(path, sizeof(path), "net/decnet/conf/%s",
226*4882a593Smuzhiyun 		dev? dev->name : parms->name);
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	t->dn_dev_vars[0].extra1 = (void *)dev;
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	t->sysctl_header = register_net_sysctl(&init_net, path, t->dn_dev_vars);
231*4882a593Smuzhiyun 	if (t->sysctl_header == NULL)
232*4882a593Smuzhiyun 		kfree(t);
233*4882a593Smuzhiyun 	else
234*4882a593Smuzhiyun 		parms->sysctl = t;
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun 
dn_dev_sysctl_unregister(struct dn_dev_parms * parms)237*4882a593Smuzhiyun static void dn_dev_sysctl_unregister(struct dn_dev_parms *parms)
238*4882a593Smuzhiyun {
239*4882a593Smuzhiyun 	if (parms->sysctl) {
240*4882a593Smuzhiyun 		struct dn_dev_sysctl_table *t = parms->sysctl;
241*4882a593Smuzhiyun 		parms->sysctl = NULL;
242*4882a593Smuzhiyun 		unregister_net_sysctl_table(t->sysctl_header);
243*4882a593Smuzhiyun 		kfree(t);
244*4882a593Smuzhiyun 	}
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun 
dn_forwarding_proc(struct ctl_table * table,int write,void * buffer,size_t * lenp,loff_t * ppos)247*4882a593Smuzhiyun static int dn_forwarding_proc(struct ctl_table *table, int write,
248*4882a593Smuzhiyun 		void *buffer, size_t *lenp, loff_t *ppos)
249*4882a593Smuzhiyun {
250*4882a593Smuzhiyun #ifdef CONFIG_DECNET_ROUTER
251*4882a593Smuzhiyun 	struct net_device *dev = table->extra1;
252*4882a593Smuzhiyun 	struct dn_dev *dn_db;
253*4882a593Smuzhiyun 	int err;
254*4882a593Smuzhiyun 	int tmp, old;
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	if (table->extra1 == NULL)
257*4882a593Smuzhiyun 		return -EINVAL;
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	dn_db = rcu_dereference_raw(dev->dn_ptr);
260*4882a593Smuzhiyun 	old = dn_db->parms.forwarding;
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 	err = proc_dointvec(table, write, buffer, lenp, ppos);
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	if ((err >= 0) && write) {
265*4882a593Smuzhiyun 		if (dn_db->parms.forwarding < 0)
266*4882a593Smuzhiyun 			dn_db->parms.forwarding = 0;
267*4882a593Smuzhiyun 		if (dn_db->parms.forwarding > 2)
268*4882a593Smuzhiyun 			dn_db->parms.forwarding = 2;
269*4882a593Smuzhiyun 		/*
270*4882a593Smuzhiyun 		 * What an ugly hack this is... its works, just. It
271*4882a593Smuzhiyun 		 * would be nice if sysctl/proc were just that little
272*4882a593Smuzhiyun 		 * bit more flexible so I don't have to write a special
273*4882a593Smuzhiyun 		 * routine, or suffer hacks like this - SJW
274*4882a593Smuzhiyun 		 */
275*4882a593Smuzhiyun 		tmp = dn_db->parms.forwarding;
276*4882a593Smuzhiyun 		dn_db->parms.forwarding = old;
277*4882a593Smuzhiyun 		if (dn_db->parms.down)
278*4882a593Smuzhiyun 			dn_db->parms.down(dev);
279*4882a593Smuzhiyun 		dn_db->parms.forwarding = tmp;
280*4882a593Smuzhiyun 		if (dn_db->parms.up)
281*4882a593Smuzhiyun 			dn_db->parms.up(dev);
282*4882a593Smuzhiyun 	}
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	return err;
285*4882a593Smuzhiyun #else
286*4882a593Smuzhiyun 	return -EINVAL;
287*4882a593Smuzhiyun #endif
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun #else /* CONFIG_SYSCTL */
dn_dev_sysctl_unregister(struct dn_dev_parms * parms)291*4882a593Smuzhiyun static void dn_dev_sysctl_unregister(struct dn_dev_parms *parms)
292*4882a593Smuzhiyun {
293*4882a593Smuzhiyun }
dn_dev_sysctl_register(struct net_device * dev,struct dn_dev_parms * parms)294*4882a593Smuzhiyun static void dn_dev_sysctl_register(struct net_device *dev, struct dn_dev_parms *parms)
295*4882a593Smuzhiyun {
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun #endif /* CONFIG_SYSCTL */
299*4882a593Smuzhiyun 
mtu2blksize(struct net_device * dev)300*4882a593Smuzhiyun static inline __u16 mtu2blksize(struct net_device *dev)
301*4882a593Smuzhiyun {
302*4882a593Smuzhiyun 	u32 blksize = dev->mtu;
303*4882a593Smuzhiyun 	if (blksize > 0xffff)
304*4882a593Smuzhiyun 		blksize = 0xffff;
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	if (dev->type == ARPHRD_ETHER ||
307*4882a593Smuzhiyun 	    dev->type == ARPHRD_PPP ||
308*4882a593Smuzhiyun 	    dev->type == ARPHRD_IPGRE ||
309*4882a593Smuzhiyun 	    dev->type == ARPHRD_LOOPBACK)
310*4882a593Smuzhiyun 		blksize -= 2;
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	return (__u16)blksize;
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun 
dn_dev_alloc_ifa(void)315*4882a593Smuzhiyun static struct dn_ifaddr *dn_dev_alloc_ifa(void)
316*4882a593Smuzhiyun {
317*4882a593Smuzhiyun 	struct dn_ifaddr *ifa;
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun 	ifa = kzalloc(sizeof(*ifa), GFP_KERNEL);
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 	return ifa;
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun 
dn_dev_free_ifa(struct dn_ifaddr * ifa)324*4882a593Smuzhiyun static void dn_dev_free_ifa(struct dn_ifaddr *ifa)
325*4882a593Smuzhiyun {
326*4882a593Smuzhiyun 	kfree_rcu(ifa, rcu);
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun 
dn_dev_del_ifa(struct dn_dev * dn_db,struct dn_ifaddr __rcu ** ifap,int destroy)329*4882a593Smuzhiyun static void dn_dev_del_ifa(struct dn_dev *dn_db, struct dn_ifaddr __rcu **ifap, int destroy)
330*4882a593Smuzhiyun {
331*4882a593Smuzhiyun 	struct dn_ifaddr *ifa1 = rtnl_dereference(*ifap);
332*4882a593Smuzhiyun 	unsigned char mac_addr[6];
333*4882a593Smuzhiyun 	struct net_device *dev = dn_db->dev;
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	ASSERT_RTNL();
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	*ifap = ifa1->ifa_next;
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	if (dn_db->dev->type == ARPHRD_ETHER) {
340*4882a593Smuzhiyun 		if (ifa1->ifa_local != dn_eth2dn(dev->dev_addr)) {
341*4882a593Smuzhiyun 			dn_dn2eth(mac_addr, ifa1->ifa_local);
342*4882a593Smuzhiyun 			dev_mc_del(dev, mac_addr);
343*4882a593Smuzhiyun 		}
344*4882a593Smuzhiyun 	}
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 	dn_ifaddr_notify(RTM_DELADDR, ifa1);
347*4882a593Smuzhiyun 	blocking_notifier_call_chain(&dnaddr_chain, NETDEV_DOWN, ifa1);
348*4882a593Smuzhiyun 	if (destroy) {
349*4882a593Smuzhiyun 		dn_dev_free_ifa(ifa1);
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 		if (dn_db->ifa_list == NULL)
352*4882a593Smuzhiyun 			dn_dev_delete(dn_db->dev);
353*4882a593Smuzhiyun 	}
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun 
dn_dev_insert_ifa(struct dn_dev * dn_db,struct dn_ifaddr * ifa)356*4882a593Smuzhiyun static int dn_dev_insert_ifa(struct dn_dev *dn_db, struct dn_ifaddr *ifa)
357*4882a593Smuzhiyun {
358*4882a593Smuzhiyun 	struct net_device *dev = dn_db->dev;
359*4882a593Smuzhiyun 	struct dn_ifaddr *ifa1;
360*4882a593Smuzhiyun 	unsigned char mac_addr[6];
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 	ASSERT_RTNL();
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun 	/* Check for duplicates */
365*4882a593Smuzhiyun 	for (ifa1 = rtnl_dereference(dn_db->ifa_list);
366*4882a593Smuzhiyun 	     ifa1 != NULL;
367*4882a593Smuzhiyun 	     ifa1 = rtnl_dereference(ifa1->ifa_next)) {
368*4882a593Smuzhiyun 		if (ifa1->ifa_local == ifa->ifa_local)
369*4882a593Smuzhiyun 			return -EEXIST;
370*4882a593Smuzhiyun 	}
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	if (dev->type == ARPHRD_ETHER) {
373*4882a593Smuzhiyun 		if (ifa->ifa_local != dn_eth2dn(dev->dev_addr)) {
374*4882a593Smuzhiyun 			dn_dn2eth(mac_addr, ifa->ifa_local);
375*4882a593Smuzhiyun 			dev_mc_add(dev, mac_addr);
376*4882a593Smuzhiyun 		}
377*4882a593Smuzhiyun 	}
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	ifa->ifa_next = dn_db->ifa_list;
380*4882a593Smuzhiyun 	rcu_assign_pointer(dn_db->ifa_list, ifa);
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 	dn_ifaddr_notify(RTM_NEWADDR, ifa);
383*4882a593Smuzhiyun 	blocking_notifier_call_chain(&dnaddr_chain, NETDEV_UP, ifa);
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	return 0;
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun 
dn_dev_set_ifa(struct net_device * dev,struct dn_ifaddr * ifa)388*4882a593Smuzhiyun static int dn_dev_set_ifa(struct net_device *dev, struct dn_ifaddr *ifa)
389*4882a593Smuzhiyun {
390*4882a593Smuzhiyun 	struct dn_dev *dn_db = rtnl_dereference(dev->dn_ptr);
391*4882a593Smuzhiyun 	int rv;
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 	if (dn_db == NULL) {
394*4882a593Smuzhiyun 		int err;
395*4882a593Smuzhiyun 		dn_db = dn_dev_create(dev, &err);
396*4882a593Smuzhiyun 		if (dn_db == NULL)
397*4882a593Smuzhiyun 			return err;
398*4882a593Smuzhiyun 	}
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 	ifa->ifa_dev = dn_db;
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 	if (dev->flags & IFF_LOOPBACK)
403*4882a593Smuzhiyun 		ifa->ifa_scope = RT_SCOPE_HOST;
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 	rv = dn_dev_insert_ifa(dn_db, ifa);
406*4882a593Smuzhiyun 	if (rv)
407*4882a593Smuzhiyun 		dn_dev_free_ifa(ifa);
408*4882a593Smuzhiyun 	return rv;
409*4882a593Smuzhiyun }
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 
dn_dev_ioctl(unsigned int cmd,void __user * arg)412*4882a593Smuzhiyun int dn_dev_ioctl(unsigned int cmd, void __user *arg)
413*4882a593Smuzhiyun {
414*4882a593Smuzhiyun 	char buffer[DN_IFREQ_SIZE];
415*4882a593Smuzhiyun 	struct ifreq *ifr = (struct ifreq *)buffer;
416*4882a593Smuzhiyun 	struct sockaddr_dn *sdn = (struct sockaddr_dn *)&ifr->ifr_addr;
417*4882a593Smuzhiyun 	struct dn_dev *dn_db;
418*4882a593Smuzhiyun 	struct net_device *dev;
419*4882a593Smuzhiyun 	struct dn_ifaddr *ifa = NULL;
420*4882a593Smuzhiyun 	struct dn_ifaddr __rcu **ifap = NULL;
421*4882a593Smuzhiyun 	int ret = 0;
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	if (copy_from_user(ifr, arg, DN_IFREQ_SIZE))
424*4882a593Smuzhiyun 		return -EFAULT;
425*4882a593Smuzhiyun 	ifr->ifr_name[IFNAMSIZ-1] = 0;
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	dev_load(&init_net, ifr->ifr_name);
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun 	switch (cmd) {
430*4882a593Smuzhiyun 	case SIOCGIFADDR:
431*4882a593Smuzhiyun 		break;
432*4882a593Smuzhiyun 	case SIOCSIFADDR:
433*4882a593Smuzhiyun 		if (!capable(CAP_NET_ADMIN))
434*4882a593Smuzhiyun 			return -EACCES;
435*4882a593Smuzhiyun 		if (sdn->sdn_family != AF_DECnet)
436*4882a593Smuzhiyun 			return -EINVAL;
437*4882a593Smuzhiyun 		break;
438*4882a593Smuzhiyun 	default:
439*4882a593Smuzhiyun 		return -EINVAL;
440*4882a593Smuzhiyun 	}
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 	rtnl_lock();
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 	if ((dev = __dev_get_by_name(&init_net, ifr->ifr_name)) == NULL) {
445*4882a593Smuzhiyun 		ret = -ENODEV;
446*4882a593Smuzhiyun 		goto done;
447*4882a593Smuzhiyun 	}
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	if ((dn_db = rtnl_dereference(dev->dn_ptr)) != NULL) {
450*4882a593Smuzhiyun 		for (ifap = &dn_db->ifa_list;
451*4882a593Smuzhiyun 		     (ifa = rtnl_dereference(*ifap)) != NULL;
452*4882a593Smuzhiyun 		     ifap = &ifa->ifa_next)
453*4882a593Smuzhiyun 			if (strcmp(ifr->ifr_name, ifa->ifa_label) == 0)
454*4882a593Smuzhiyun 				break;
455*4882a593Smuzhiyun 	}
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 	if (ifa == NULL && cmd != SIOCSIFADDR) {
458*4882a593Smuzhiyun 		ret = -EADDRNOTAVAIL;
459*4882a593Smuzhiyun 		goto done;
460*4882a593Smuzhiyun 	}
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 	switch (cmd) {
463*4882a593Smuzhiyun 	case SIOCGIFADDR:
464*4882a593Smuzhiyun 		*((__le16 *)sdn->sdn_nodeaddr) = ifa->ifa_local;
465*4882a593Smuzhiyun 		if (copy_to_user(arg, ifr, DN_IFREQ_SIZE))
466*4882a593Smuzhiyun 			ret = -EFAULT;
467*4882a593Smuzhiyun 		break;
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun 	case SIOCSIFADDR:
470*4882a593Smuzhiyun 		if (!ifa) {
471*4882a593Smuzhiyun 			if ((ifa = dn_dev_alloc_ifa()) == NULL) {
472*4882a593Smuzhiyun 				ret = -ENOBUFS;
473*4882a593Smuzhiyun 				break;
474*4882a593Smuzhiyun 			}
475*4882a593Smuzhiyun 			memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
476*4882a593Smuzhiyun 		} else {
477*4882a593Smuzhiyun 			if (ifa->ifa_local == dn_saddr2dn(sdn))
478*4882a593Smuzhiyun 				break;
479*4882a593Smuzhiyun 			dn_dev_del_ifa(dn_db, ifap, 0);
480*4882a593Smuzhiyun 		}
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun 		ifa->ifa_local = ifa->ifa_address = dn_saddr2dn(sdn);
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun 		ret = dn_dev_set_ifa(dev, ifa);
485*4882a593Smuzhiyun 	}
486*4882a593Smuzhiyun done:
487*4882a593Smuzhiyun 	rtnl_unlock();
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	return ret;
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun 
dn_dev_get_default(void)492*4882a593Smuzhiyun struct net_device *dn_dev_get_default(void)
493*4882a593Smuzhiyun {
494*4882a593Smuzhiyun 	struct net_device *dev;
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun 	spin_lock(&dndev_lock);
497*4882a593Smuzhiyun 	dev = decnet_default_device;
498*4882a593Smuzhiyun 	if (dev) {
499*4882a593Smuzhiyun 		if (dev->dn_ptr)
500*4882a593Smuzhiyun 			dev_hold(dev);
501*4882a593Smuzhiyun 		else
502*4882a593Smuzhiyun 			dev = NULL;
503*4882a593Smuzhiyun 	}
504*4882a593Smuzhiyun 	spin_unlock(&dndev_lock);
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun 	return dev;
507*4882a593Smuzhiyun }
508*4882a593Smuzhiyun 
dn_dev_set_default(struct net_device * dev,int force)509*4882a593Smuzhiyun int dn_dev_set_default(struct net_device *dev, int force)
510*4882a593Smuzhiyun {
511*4882a593Smuzhiyun 	struct net_device *old = NULL;
512*4882a593Smuzhiyun 	int rv = -EBUSY;
513*4882a593Smuzhiyun 	if (!dev->dn_ptr)
514*4882a593Smuzhiyun 		return -ENODEV;
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun 	spin_lock(&dndev_lock);
517*4882a593Smuzhiyun 	if (force || decnet_default_device == NULL) {
518*4882a593Smuzhiyun 		old = decnet_default_device;
519*4882a593Smuzhiyun 		decnet_default_device = dev;
520*4882a593Smuzhiyun 		rv = 0;
521*4882a593Smuzhiyun 	}
522*4882a593Smuzhiyun 	spin_unlock(&dndev_lock);
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun 	if (old)
525*4882a593Smuzhiyun 		dev_put(old);
526*4882a593Smuzhiyun 	return rv;
527*4882a593Smuzhiyun }
528*4882a593Smuzhiyun 
dn_dev_check_default(struct net_device * dev)529*4882a593Smuzhiyun static void dn_dev_check_default(struct net_device *dev)
530*4882a593Smuzhiyun {
531*4882a593Smuzhiyun 	spin_lock(&dndev_lock);
532*4882a593Smuzhiyun 	if (dev == decnet_default_device) {
533*4882a593Smuzhiyun 		decnet_default_device = NULL;
534*4882a593Smuzhiyun 	} else {
535*4882a593Smuzhiyun 		dev = NULL;
536*4882a593Smuzhiyun 	}
537*4882a593Smuzhiyun 	spin_unlock(&dndev_lock);
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 	if (dev)
540*4882a593Smuzhiyun 		dev_put(dev);
541*4882a593Smuzhiyun }
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun /*
544*4882a593Smuzhiyun  * Called with RTNL
545*4882a593Smuzhiyun  */
dn_dev_by_index(int ifindex)546*4882a593Smuzhiyun static struct dn_dev *dn_dev_by_index(int ifindex)
547*4882a593Smuzhiyun {
548*4882a593Smuzhiyun 	struct net_device *dev;
549*4882a593Smuzhiyun 	struct dn_dev *dn_dev = NULL;
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun 	dev = __dev_get_by_index(&init_net, ifindex);
552*4882a593Smuzhiyun 	if (dev)
553*4882a593Smuzhiyun 		dn_dev = rtnl_dereference(dev->dn_ptr);
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun 	return dn_dev;
556*4882a593Smuzhiyun }
557*4882a593Smuzhiyun 
558*4882a593Smuzhiyun static const struct nla_policy dn_ifa_policy[IFA_MAX+1] = {
559*4882a593Smuzhiyun 	[IFA_ADDRESS]		= { .type = NLA_U16 },
560*4882a593Smuzhiyun 	[IFA_LOCAL]		= { .type = NLA_U16 },
561*4882a593Smuzhiyun 	[IFA_LABEL]		= { .type = NLA_STRING,
562*4882a593Smuzhiyun 				    .len = IFNAMSIZ - 1 },
563*4882a593Smuzhiyun 	[IFA_FLAGS]		= { .type = NLA_U32 },
564*4882a593Smuzhiyun };
565*4882a593Smuzhiyun 
dn_nl_deladdr(struct sk_buff * skb,struct nlmsghdr * nlh,struct netlink_ext_ack * extack)566*4882a593Smuzhiyun static int dn_nl_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh,
567*4882a593Smuzhiyun 			 struct netlink_ext_ack *extack)
568*4882a593Smuzhiyun {
569*4882a593Smuzhiyun 	struct net *net = sock_net(skb->sk);
570*4882a593Smuzhiyun 	struct nlattr *tb[IFA_MAX+1];
571*4882a593Smuzhiyun 	struct dn_dev *dn_db;
572*4882a593Smuzhiyun 	struct ifaddrmsg *ifm;
573*4882a593Smuzhiyun 	struct dn_ifaddr *ifa;
574*4882a593Smuzhiyun 	struct dn_ifaddr __rcu **ifap;
575*4882a593Smuzhiyun 	int err = -EINVAL;
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun 	if (!netlink_capable(skb, CAP_NET_ADMIN))
578*4882a593Smuzhiyun 		return -EPERM;
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun 	if (!net_eq(net, &init_net))
581*4882a593Smuzhiyun 		goto errout;
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun 	err = nlmsg_parse_deprecated(nlh, sizeof(*ifm), tb, IFA_MAX,
584*4882a593Smuzhiyun 				     dn_ifa_policy, extack);
585*4882a593Smuzhiyun 	if (err < 0)
586*4882a593Smuzhiyun 		goto errout;
587*4882a593Smuzhiyun 
588*4882a593Smuzhiyun 	err = -ENODEV;
589*4882a593Smuzhiyun 	ifm = nlmsg_data(nlh);
590*4882a593Smuzhiyun 	if ((dn_db = dn_dev_by_index(ifm->ifa_index)) == NULL)
591*4882a593Smuzhiyun 		goto errout;
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun 	err = -EADDRNOTAVAIL;
594*4882a593Smuzhiyun 	for (ifap = &dn_db->ifa_list;
595*4882a593Smuzhiyun 	     (ifa = rtnl_dereference(*ifap)) != NULL;
596*4882a593Smuzhiyun 	     ifap = &ifa->ifa_next) {
597*4882a593Smuzhiyun 		if (tb[IFA_LOCAL] &&
598*4882a593Smuzhiyun 		    nla_memcmp(tb[IFA_LOCAL], &ifa->ifa_local, 2))
599*4882a593Smuzhiyun 			continue;
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun 		if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
602*4882a593Smuzhiyun 			continue;
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun 		dn_dev_del_ifa(dn_db, ifap, 1);
605*4882a593Smuzhiyun 		return 0;
606*4882a593Smuzhiyun 	}
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun errout:
609*4882a593Smuzhiyun 	return err;
610*4882a593Smuzhiyun }
611*4882a593Smuzhiyun 
dn_nl_newaddr(struct sk_buff * skb,struct nlmsghdr * nlh,struct netlink_ext_ack * extack)612*4882a593Smuzhiyun static int dn_nl_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
613*4882a593Smuzhiyun 			 struct netlink_ext_ack *extack)
614*4882a593Smuzhiyun {
615*4882a593Smuzhiyun 	struct net *net = sock_net(skb->sk);
616*4882a593Smuzhiyun 	struct nlattr *tb[IFA_MAX+1];
617*4882a593Smuzhiyun 	struct net_device *dev;
618*4882a593Smuzhiyun 	struct dn_dev *dn_db;
619*4882a593Smuzhiyun 	struct ifaddrmsg *ifm;
620*4882a593Smuzhiyun 	struct dn_ifaddr *ifa;
621*4882a593Smuzhiyun 	int err;
622*4882a593Smuzhiyun 
623*4882a593Smuzhiyun 	if (!netlink_capable(skb, CAP_NET_ADMIN))
624*4882a593Smuzhiyun 		return -EPERM;
625*4882a593Smuzhiyun 
626*4882a593Smuzhiyun 	if (!net_eq(net, &init_net))
627*4882a593Smuzhiyun 		return -EINVAL;
628*4882a593Smuzhiyun 
629*4882a593Smuzhiyun 	err = nlmsg_parse_deprecated(nlh, sizeof(*ifm), tb, IFA_MAX,
630*4882a593Smuzhiyun 				     dn_ifa_policy, extack);
631*4882a593Smuzhiyun 	if (err < 0)
632*4882a593Smuzhiyun 		return err;
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 	if (tb[IFA_LOCAL] == NULL)
635*4882a593Smuzhiyun 		return -EINVAL;
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun 	ifm = nlmsg_data(nlh);
638*4882a593Smuzhiyun 	if ((dev = __dev_get_by_index(&init_net, ifm->ifa_index)) == NULL)
639*4882a593Smuzhiyun 		return -ENODEV;
640*4882a593Smuzhiyun 
641*4882a593Smuzhiyun 	if ((dn_db = rtnl_dereference(dev->dn_ptr)) == NULL) {
642*4882a593Smuzhiyun 		dn_db = dn_dev_create(dev, &err);
643*4882a593Smuzhiyun 		if (!dn_db)
644*4882a593Smuzhiyun 			return err;
645*4882a593Smuzhiyun 	}
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun 	if ((ifa = dn_dev_alloc_ifa()) == NULL)
648*4882a593Smuzhiyun 		return -ENOBUFS;
649*4882a593Smuzhiyun 
650*4882a593Smuzhiyun 	if (tb[IFA_ADDRESS] == NULL)
651*4882a593Smuzhiyun 		tb[IFA_ADDRESS] = tb[IFA_LOCAL];
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun 	ifa->ifa_local = nla_get_le16(tb[IFA_LOCAL]);
654*4882a593Smuzhiyun 	ifa->ifa_address = nla_get_le16(tb[IFA_ADDRESS]);
655*4882a593Smuzhiyun 	ifa->ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) :
656*4882a593Smuzhiyun 					 ifm->ifa_flags;
657*4882a593Smuzhiyun 	ifa->ifa_scope = ifm->ifa_scope;
658*4882a593Smuzhiyun 	ifa->ifa_dev = dn_db;
659*4882a593Smuzhiyun 
660*4882a593Smuzhiyun 	if (tb[IFA_LABEL])
661*4882a593Smuzhiyun 		nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
662*4882a593Smuzhiyun 	else
663*4882a593Smuzhiyun 		memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
664*4882a593Smuzhiyun 
665*4882a593Smuzhiyun 	err = dn_dev_insert_ifa(dn_db, ifa);
666*4882a593Smuzhiyun 	if (err)
667*4882a593Smuzhiyun 		dn_dev_free_ifa(ifa);
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun 	return err;
670*4882a593Smuzhiyun }
671*4882a593Smuzhiyun 
dn_ifaddr_nlmsg_size(void)672*4882a593Smuzhiyun static inline size_t dn_ifaddr_nlmsg_size(void)
673*4882a593Smuzhiyun {
674*4882a593Smuzhiyun 	return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
675*4882a593Smuzhiyun 	       + nla_total_size(IFNAMSIZ) /* IFA_LABEL */
676*4882a593Smuzhiyun 	       + nla_total_size(2) /* IFA_ADDRESS */
677*4882a593Smuzhiyun 	       + nla_total_size(2) /* IFA_LOCAL */
678*4882a593Smuzhiyun 	       + nla_total_size(4); /* IFA_FLAGS */
679*4882a593Smuzhiyun }
680*4882a593Smuzhiyun 
dn_nl_fill_ifaddr(struct sk_buff * skb,struct dn_ifaddr * ifa,u32 portid,u32 seq,int event,unsigned int flags)681*4882a593Smuzhiyun static int dn_nl_fill_ifaddr(struct sk_buff *skb, struct dn_ifaddr *ifa,
682*4882a593Smuzhiyun 			     u32 portid, u32 seq, int event, unsigned int flags)
683*4882a593Smuzhiyun {
684*4882a593Smuzhiyun 	struct ifaddrmsg *ifm;
685*4882a593Smuzhiyun 	struct nlmsghdr *nlh;
686*4882a593Smuzhiyun 	u32 ifa_flags = ifa->ifa_flags | IFA_F_PERMANENT;
687*4882a593Smuzhiyun 
688*4882a593Smuzhiyun 	nlh = nlmsg_put(skb, portid, seq, event, sizeof(*ifm), flags);
689*4882a593Smuzhiyun 	if (nlh == NULL)
690*4882a593Smuzhiyun 		return -EMSGSIZE;
691*4882a593Smuzhiyun 
692*4882a593Smuzhiyun 	ifm = nlmsg_data(nlh);
693*4882a593Smuzhiyun 	ifm->ifa_family = AF_DECnet;
694*4882a593Smuzhiyun 	ifm->ifa_prefixlen = 16;
695*4882a593Smuzhiyun 	ifm->ifa_flags = ifa_flags;
696*4882a593Smuzhiyun 	ifm->ifa_scope = ifa->ifa_scope;
697*4882a593Smuzhiyun 	ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun 	if ((ifa->ifa_address &&
700*4882a593Smuzhiyun 	     nla_put_le16(skb, IFA_ADDRESS, ifa->ifa_address)) ||
701*4882a593Smuzhiyun 	    (ifa->ifa_local &&
702*4882a593Smuzhiyun 	     nla_put_le16(skb, IFA_LOCAL, ifa->ifa_local)) ||
703*4882a593Smuzhiyun 	    (ifa->ifa_label[0] &&
704*4882a593Smuzhiyun 	     nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) ||
705*4882a593Smuzhiyun 	     nla_put_u32(skb, IFA_FLAGS, ifa_flags))
706*4882a593Smuzhiyun 		goto nla_put_failure;
707*4882a593Smuzhiyun 	nlmsg_end(skb, nlh);
708*4882a593Smuzhiyun 	return 0;
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun nla_put_failure:
711*4882a593Smuzhiyun 	nlmsg_cancel(skb, nlh);
712*4882a593Smuzhiyun 	return -EMSGSIZE;
713*4882a593Smuzhiyun }
714*4882a593Smuzhiyun 
dn_ifaddr_notify(int event,struct dn_ifaddr * ifa)715*4882a593Smuzhiyun static void dn_ifaddr_notify(int event, struct dn_ifaddr *ifa)
716*4882a593Smuzhiyun {
717*4882a593Smuzhiyun 	struct sk_buff *skb;
718*4882a593Smuzhiyun 	int err = -ENOBUFS;
719*4882a593Smuzhiyun 
720*4882a593Smuzhiyun 	skb = alloc_skb(dn_ifaddr_nlmsg_size(), GFP_KERNEL);
721*4882a593Smuzhiyun 	if (skb == NULL)
722*4882a593Smuzhiyun 		goto errout;
723*4882a593Smuzhiyun 
724*4882a593Smuzhiyun 	err = dn_nl_fill_ifaddr(skb, ifa, 0, 0, event, 0);
725*4882a593Smuzhiyun 	if (err < 0) {
726*4882a593Smuzhiyun 		/* -EMSGSIZE implies BUG in dn_ifaddr_nlmsg_size() */
727*4882a593Smuzhiyun 		WARN_ON(err == -EMSGSIZE);
728*4882a593Smuzhiyun 		kfree_skb(skb);
729*4882a593Smuzhiyun 		goto errout;
730*4882a593Smuzhiyun 	}
731*4882a593Smuzhiyun 	rtnl_notify(skb, &init_net, 0, RTNLGRP_DECnet_IFADDR, NULL, GFP_KERNEL);
732*4882a593Smuzhiyun 	return;
733*4882a593Smuzhiyun errout:
734*4882a593Smuzhiyun 	if (err < 0)
735*4882a593Smuzhiyun 		rtnl_set_sk_err(&init_net, RTNLGRP_DECnet_IFADDR, err);
736*4882a593Smuzhiyun }
737*4882a593Smuzhiyun 
dn_nl_dump_ifaddr(struct sk_buff * skb,struct netlink_callback * cb)738*4882a593Smuzhiyun static int dn_nl_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
739*4882a593Smuzhiyun {
740*4882a593Smuzhiyun 	struct net *net = sock_net(skb->sk);
741*4882a593Smuzhiyun 	int idx, dn_idx = 0, skip_ndevs, skip_naddr;
742*4882a593Smuzhiyun 	struct net_device *dev;
743*4882a593Smuzhiyun 	struct dn_dev *dn_db;
744*4882a593Smuzhiyun 	struct dn_ifaddr *ifa;
745*4882a593Smuzhiyun 
746*4882a593Smuzhiyun 	if (!net_eq(net, &init_net))
747*4882a593Smuzhiyun 		return 0;
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun 	skip_ndevs = cb->args[0];
750*4882a593Smuzhiyun 	skip_naddr = cb->args[1];
751*4882a593Smuzhiyun 
752*4882a593Smuzhiyun 	idx = 0;
753*4882a593Smuzhiyun 	rcu_read_lock();
754*4882a593Smuzhiyun 	for_each_netdev_rcu(&init_net, dev) {
755*4882a593Smuzhiyun 		if (idx < skip_ndevs)
756*4882a593Smuzhiyun 			goto cont;
757*4882a593Smuzhiyun 		else if (idx > skip_ndevs) {
758*4882a593Smuzhiyun 			/* Only skip over addresses for first dev dumped
759*4882a593Smuzhiyun 			 * in this iteration (idx == skip_ndevs) */
760*4882a593Smuzhiyun 			skip_naddr = 0;
761*4882a593Smuzhiyun 		}
762*4882a593Smuzhiyun 
763*4882a593Smuzhiyun 		if ((dn_db = rcu_dereference(dev->dn_ptr)) == NULL)
764*4882a593Smuzhiyun 			goto cont;
765*4882a593Smuzhiyun 
766*4882a593Smuzhiyun 		for (ifa = rcu_dereference(dn_db->ifa_list), dn_idx = 0; ifa;
767*4882a593Smuzhiyun 		     ifa = rcu_dereference(ifa->ifa_next), dn_idx++) {
768*4882a593Smuzhiyun 			if (dn_idx < skip_naddr)
769*4882a593Smuzhiyun 				continue;
770*4882a593Smuzhiyun 
771*4882a593Smuzhiyun 			if (dn_nl_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).portid,
772*4882a593Smuzhiyun 					      cb->nlh->nlmsg_seq, RTM_NEWADDR,
773*4882a593Smuzhiyun 					      NLM_F_MULTI) < 0)
774*4882a593Smuzhiyun 				goto done;
775*4882a593Smuzhiyun 		}
776*4882a593Smuzhiyun cont:
777*4882a593Smuzhiyun 		idx++;
778*4882a593Smuzhiyun 	}
779*4882a593Smuzhiyun done:
780*4882a593Smuzhiyun 	rcu_read_unlock();
781*4882a593Smuzhiyun 	cb->args[0] = idx;
782*4882a593Smuzhiyun 	cb->args[1] = dn_idx;
783*4882a593Smuzhiyun 
784*4882a593Smuzhiyun 	return skb->len;
785*4882a593Smuzhiyun }
786*4882a593Smuzhiyun 
dn_dev_get_first(struct net_device * dev,__le16 * addr)787*4882a593Smuzhiyun static int dn_dev_get_first(struct net_device *dev, __le16 *addr)
788*4882a593Smuzhiyun {
789*4882a593Smuzhiyun 	struct dn_dev *dn_db;
790*4882a593Smuzhiyun 	struct dn_ifaddr *ifa;
791*4882a593Smuzhiyun 	int rv = -ENODEV;
792*4882a593Smuzhiyun 
793*4882a593Smuzhiyun 	rcu_read_lock();
794*4882a593Smuzhiyun 	dn_db = rcu_dereference(dev->dn_ptr);
795*4882a593Smuzhiyun 	if (dn_db == NULL)
796*4882a593Smuzhiyun 		goto out;
797*4882a593Smuzhiyun 
798*4882a593Smuzhiyun 	ifa = rcu_dereference(dn_db->ifa_list);
799*4882a593Smuzhiyun 	if (ifa != NULL) {
800*4882a593Smuzhiyun 		*addr = ifa->ifa_local;
801*4882a593Smuzhiyun 		rv = 0;
802*4882a593Smuzhiyun 	}
803*4882a593Smuzhiyun out:
804*4882a593Smuzhiyun 	rcu_read_unlock();
805*4882a593Smuzhiyun 	return rv;
806*4882a593Smuzhiyun }
807*4882a593Smuzhiyun 
808*4882a593Smuzhiyun /*
809*4882a593Smuzhiyun  * Find a default address to bind to.
810*4882a593Smuzhiyun  *
811*4882a593Smuzhiyun  * This is one of those areas where the initial VMS concepts don't really
812*4882a593Smuzhiyun  * map onto the Linux concepts, and since we introduced multiple addresses
813*4882a593Smuzhiyun  * per interface we have to cope with slightly odd ways of finding out what
814*4882a593Smuzhiyun  * "our address" really is. Mostly it's not a problem; for this we just guess
815*4882a593Smuzhiyun  * a sensible default. Eventually the routing code will take care of all the
816*4882a593Smuzhiyun  * nasties for us I hope.
817*4882a593Smuzhiyun  */
dn_dev_bind_default(__le16 * addr)818*4882a593Smuzhiyun int dn_dev_bind_default(__le16 *addr)
819*4882a593Smuzhiyun {
820*4882a593Smuzhiyun 	struct net_device *dev;
821*4882a593Smuzhiyun 	int rv;
822*4882a593Smuzhiyun 	dev = dn_dev_get_default();
823*4882a593Smuzhiyun last_chance:
824*4882a593Smuzhiyun 	if (dev) {
825*4882a593Smuzhiyun 		rv = dn_dev_get_first(dev, addr);
826*4882a593Smuzhiyun 		dev_put(dev);
827*4882a593Smuzhiyun 		if (rv == 0 || dev == init_net.loopback_dev)
828*4882a593Smuzhiyun 			return rv;
829*4882a593Smuzhiyun 	}
830*4882a593Smuzhiyun 	dev = init_net.loopback_dev;
831*4882a593Smuzhiyun 	dev_hold(dev);
832*4882a593Smuzhiyun 	goto last_chance;
833*4882a593Smuzhiyun }
834*4882a593Smuzhiyun 
dn_send_endnode_hello(struct net_device * dev,struct dn_ifaddr * ifa)835*4882a593Smuzhiyun static void dn_send_endnode_hello(struct net_device *dev, struct dn_ifaddr *ifa)
836*4882a593Smuzhiyun {
837*4882a593Smuzhiyun 	struct endnode_hello_message *msg;
838*4882a593Smuzhiyun 	struct sk_buff *skb = NULL;
839*4882a593Smuzhiyun 	__le16 *pktlen;
840*4882a593Smuzhiyun 	struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr);
841*4882a593Smuzhiyun 
842*4882a593Smuzhiyun 	if ((skb = dn_alloc_skb(NULL, sizeof(*msg), GFP_ATOMIC)) == NULL)
843*4882a593Smuzhiyun 		return;
844*4882a593Smuzhiyun 
845*4882a593Smuzhiyun 	skb->dev = dev;
846*4882a593Smuzhiyun 
847*4882a593Smuzhiyun 	msg = skb_put(skb, sizeof(*msg));
848*4882a593Smuzhiyun 
849*4882a593Smuzhiyun 	msg->msgflg  = 0x0D;
850*4882a593Smuzhiyun 	memcpy(msg->tiver, dn_eco_version, 3);
851*4882a593Smuzhiyun 	dn_dn2eth(msg->id, ifa->ifa_local);
852*4882a593Smuzhiyun 	msg->iinfo   = DN_RT_INFO_ENDN;
853*4882a593Smuzhiyun 	msg->blksize = cpu_to_le16(mtu2blksize(dev));
854*4882a593Smuzhiyun 	msg->area    = 0x00;
855*4882a593Smuzhiyun 	memset(msg->seed, 0, 8);
856*4882a593Smuzhiyun 	memcpy(msg->neighbor, dn_hiord, ETH_ALEN);
857*4882a593Smuzhiyun 
858*4882a593Smuzhiyun 	if (dn_db->router) {
859*4882a593Smuzhiyun 		struct dn_neigh *dn = (struct dn_neigh *)dn_db->router;
860*4882a593Smuzhiyun 		dn_dn2eth(msg->neighbor, dn->addr);
861*4882a593Smuzhiyun 	}
862*4882a593Smuzhiyun 
863*4882a593Smuzhiyun 	msg->timer   = cpu_to_le16((unsigned short)dn_db->parms.t3);
864*4882a593Smuzhiyun 	msg->mpd     = 0x00;
865*4882a593Smuzhiyun 	msg->datalen = 0x02;
866*4882a593Smuzhiyun 	memset(msg->data, 0xAA, 2);
867*4882a593Smuzhiyun 
868*4882a593Smuzhiyun 	pktlen = skb_push(skb, 2);
869*4882a593Smuzhiyun 	*pktlen = cpu_to_le16(skb->len - 2);
870*4882a593Smuzhiyun 
871*4882a593Smuzhiyun 	skb_reset_network_header(skb);
872*4882a593Smuzhiyun 
873*4882a593Smuzhiyun 	dn_rt_finish_output(skb, dn_rt_all_rt_mcast, msg->id);
874*4882a593Smuzhiyun }
875*4882a593Smuzhiyun 
876*4882a593Smuzhiyun 
877*4882a593Smuzhiyun #define DRDELAY (5 * HZ)
878*4882a593Smuzhiyun 
dn_am_i_a_router(struct dn_neigh * dn,struct dn_dev * dn_db,struct dn_ifaddr * ifa)879*4882a593Smuzhiyun static int dn_am_i_a_router(struct dn_neigh *dn, struct dn_dev *dn_db, struct dn_ifaddr *ifa)
880*4882a593Smuzhiyun {
881*4882a593Smuzhiyun 	/* First check time since device went up */
882*4882a593Smuzhiyun 	if (time_before(jiffies, dn_db->uptime + DRDELAY))
883*4882a593Smuzhiyun 		return 0;
884*4882a593Smuzhiyun 
885*4882a593Smuzhiyun 	/* If there is no router, then yes... */
886*4882a593Smuzhiyun 	if (!dn_db->router)
887*4882a593Smuzhiyun 		return 1;
888*4882a593Smuzhiyun 
889*4882a593Smuzhiyun 	/* otherwise only if we have a higher priority or.. */
890*4882a593Smuzhiyun 	if (dn->priority < dn_db->parms.priority)
891*4882a593Smuzhiyun 		return 1;
892*4882a593Smuzhiyun 
893*4882a593Smuzhiyun 	/* if we have equal priority and a higher node number */
894*4882a593Smuzhiyun 	if (dn->priority != dn_db->parms.priority)
895*4882a593Smuzhiyun 		return 0;
896*4882a593Smuzhiyun 
897*4882a593Smuzhiyun 	if (le16_to_cpu(dn->addr) < le16_to_cpu(ifa->ifa_local))
898*4882a593Smuzhiyun 		return 1;
899*4882a593Smuzhiyun 
900*4882a593Smuzhiyun 	return 0;
901*4882a593Smuzhiyun }
902*4882a593Smuzhiyun 
dn_send_router_hello(struct net_device * dev,struct dn_ifaddr * ifa)903*4882a593Smuzhiyun static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa)
904*4882a593Smuzhiyun {
905*4882a593Smuzhiyun 	int n;
906*4882a593Smuzhiyun 	struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr);
907*4882a593Smuzhiyun 	struct dn_neigh *dn = (struct dn_neigh *)dn_db->router;
908*4882a593Smuzhiyun 	struct sk_buff *skb;
909*4882a593Smuzhiyun 	size_t size;
910*4882a593Smuzhiyun 	unsigned char *ptr;
911*4882a593Smuzhiyun 	unsigned char *i1, *i2;
912*4882a593Smuzhiyun 	__le16 *pktlen;
913*4882a593Smuzhiyun 	char *src;
914*4882a593Smuzhiyun 
915*4882a593Smuzhiyun 	if (mtu2blksize(dev) < (26 + 7))
916*4882a593Smuzhiyun 		return;
917*4882a593Smuzhiyun 
918*4882a593Smuzhiyun 	n = mtu2blksize(dev) - 26;
919*4882a593Smuzhiyun 	n /= 7;
920*4882a593Smuzhiyun 
921*4882a593Smuzhiyun 	if (n > 32)
922*4882a593Smuzhiyun 		n = 32;
923*4882a593Smuzhiyun 
924*4882a593Smuzhiyun 	size = 2 + 26 + 7 * n;
925*4882a593Smuzhiyun 
926*4882a593Smuzhiyun 	if ((skb = dn_alloc_skb(NULL, size, GFP_ATOMIC)) == NULL)
927*4882a593Smuzhiyun 		return;
928*4882a593Smuzhiyun 
929*4882a593Smuzhiyun 	skb->dev = dev;
930*4882a593Smuzhiyun 	ptr = skb_put(skb, size);
931*4882a593Smuzhiyun 
932*4882a593Smuzhiyun 	*ptr++ = DN_RT_PKT_CNTL | DN_RT_PKT_ERTH;
933*4882a593Smuzhiyun 	*ptr++ = 2; /* ECO */
934*4882a593Smuzhiyun 	*ptr++ = 0;
935*4882a593Smuzhiyun 	*ptr++ = 0;
936*4882a593Smuzhiyun 	dn_dn2eth(ptr, ifa->ifa_local);
937*4882a593Smuzhiyun 	src = ptr;
938*4882a593Smuzhiyun 	ptr += ETH_ALEN;
939*4882a593Smuzhiyun 	*ptr++ = dn_db->parms.forwarding == 1 ?
940*4882a593Smuzhiyun 			DN_RT_INFO_L1RT : DN_RT_INFO_L2RT;
941*4882a593Smuzhiyun 	*((__le16 *)ptr) = cpu_to_le16(mtu2blksize(dev));
942*4882a593Smuzhiyun 	ptr += 2;
943*4882a593Smuzhiyun 	*ptr++ = dn_db->parms.priority; /* Priority */
944*4882a593Smuzhiyun 	*ptr++ = 0; /* Area: Reserved */
945*4882a593Smuzhiyun 	*((__le16 *)ptr) = cpu_to_le16((unsigned short)dn_db->parms.t3);
946*4882a593Smuzhiyun 	ptr += 2;
947*4882a593Smuzhiyun 	*ptr++ = 0; /* MPD: Reserved */
948*4882a593Smuzhiyun 	i1 = ptr++;
949*4882a593Smuzhiyun 	memset(ptr, 0, 7); /* Name: Reserved */
950*4882a593Smuzhiyun 	ptr += 7;
951*4882a593Smuzhiyun 	i2 = ptr++;
952*4882a593Smuzhiyun 
953*4882a593Smuzhiyun 	n = dn_neigh_elist(dev, ptr, n);
954*4882a593Smuzhiyun 
955*4882a593Smuzhiyun 	*i2 = 7 * n;
956*4882a593Smuzhiyun 	*i1 = 8 + *i2;
957*4882a593Smuzhiyun 
958*4882a593Smuzhiyun 	skb_trim(skb, (27 + *i2));
959*4882a593Smuzhiyun 
960*4882a593Smuzhiyun 	pktlen = skb_push(skb, 2);
961*4882a593Smuzhiyun 	*pktlen = cpu_to_le16(skb->len - 2);
962*4882a593Smuzhiyun 
963*4882a593Smuzhiyun 	skb_reset_network_header(skb);
964*4882a593Smuzhiyun 
965*4882a593Smuzhiyun 	if (dn_am_i_a_router(dn, dn_db, ifa)) {
966*4882a593Smuzhiyun 		struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
967*4882a593Smuzhiyun 		if (skb2) {
968*4882a593Smuzhiyun 			dn_rt_finish_output(skb2, dn_rt_all_end_mcast, src);
969*4882a593Smuzhiyun 		}
970*4882a593Smuzhiyun 	}
971*4882a593Smuzhiyun 
972*4882a593Smuzhiyun 	dn_rt_finish_output(skb, dn_rt_all_rt_mcast, src);
973*4882a593Smuzhiyun }
974*4882a593Smuzhiyun 
dn_send_brd_hello(struct net_device * dev,struct dn_ifaddr * ifa)975*4882a593Smuzhiyun static void dn_send_brd_hello(struct net_device *dev, struct dn_ifaddr *ifa)
976*4882a593Smuzhiyun {
977*4882a593Smuzhiyun 	struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr);
978*4882a593Smuzhiyun 
979*4882a593Smuzhiyun 	if (dn_db->parms.forwarding == 0)
980*4882a593Smuzhiyun 		dn_send_endnode_hello(dev, ifa);
981*4882a593Smuzhiyun 	else
982*4882a593Smuzhiyun 		dn_send_router_hello(dev, ifa);
983*4882a593Smuzhiyun }
984*4882a593Smuzhiyun 
dn_send_ptp_hello(struct net_device * dev,struct dn_ifaddr * ifa)985*4882a593Smuzhiyun static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa)
986*4882a593Smuzhiyun {
987*4882a593Smuzhiyun 	int tdlen = 16;
988*4882a593Smuzhiyun 	int size = dev->hard_header_len + 2 + 4 + tdlen;
989*4882a593Smuzhiyun 	struct sk_buff *skb = dn_alloc_skb(NULL, size, GFP_ATOMIC);
990*4882a593Smuzhiyun 	int i;
991*4882a593Smuzhiyun 	unsigned char *ptr;
992*4882a593Smuzhiyun 	char src[ETH_ALEN];
993*4882a593Smuzhiyun 
994*4882a593Smuzhiyun 	if (skb == NULL)
995*4882a593Smuzhiyun 		return ;
996*4882a593Smuzhiyun 
997*4882a593Smuzhiyun 	skb->dev = dev;
998*4882a593Smuzhiyun 	skb_push(skb, dev->hard_header_len);
999*4882a593Smuzhiyun 	ptr = skb_put(skb, 2 + 4 + tdlen);
1000*4882a593Smuzhiyun 
1001*4882a593Smuzhiyun 	*ptr++ = DN_RT_PKT_HELO;
1002*4882a593Smuzhiyun 	*((__le16 *)ptr) = ifa->ifa_local;
1003*4882a593Smuzhiyun 	ptr += 2;
1004*4882a593Smuzhiyun 	*ptr++ = tdlen;
1005*4882a593Smuzhiyun 
1006*4882a593Smuzhiyun 	for(i = 0; i < tdlen; i++)
1007*4882a593Smuzhiyun 		*ptr++ = 0252;
1008*4882a593Smuzhiyun 
1009*4882a593Smuzhiyun 	dn_dn2eth(src, ifa->ifa_local);
1010*4882a593Smuzhiyun 	dn_rt_finish_output(skb, dn_rt_all_rt_mcast, src);
1011*4882a593Smuzhiyun }
1012*4882a593Smuzhiyun 
dn_eth_up(struct net_device * dev)1013*4882a593Smuzhiyun static int dn_eth_up(struct net_device *dev)
1014*4882a593Smuzhiyun {
1015*4882a593Smuzhiyun 	struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr);
1016*4882a593Smuzhiyun 
1017*4882a593Smuzhiyun 	if (dn_db->parms.forwarding == 0)
1018*4882a593Smuzhiyun 		dev_mc_add(dev, dn_rt_all_end_mcast);
1019*4882a593Smuzhiyun 	else
1020*4882a593Smuzhiyun 		dev_mc_add(dev, dn_rt_all_rt_mcast);
1021*4882a593Smuzhiyun 
1022*4882a593Smuzhiyun 	dn_db->use_long = 1;
1023*4882a593Smuzhiyun 
1024*4882a593Smuzhiyun 	return 0;
1025*4882a593Smuzhiyun }
1026*4882a593Smuzhiyun 
dn_eth_down(struct net_device * dev)1027*4882a593Smuzhiyun static void dn_eth_down(struct net_device *dev)
1028*4882a593Smuzhiyun {
1029*4882a593Smuzhiyun 	struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr);
1030*4882a593Smuzhiyun 
1031*4882a593Smuzhiyun 	if (dn_db->parms.forwarding == 0)
1032*4882a593Smuzhiyun 		dev_mc_del(dev, dn_rt_all_end_mcast);
1033*4882a593Smuzhiyun 	else
1034*4882a593Smuzhiyun 		dev_mc_del(dev, dn_rt_all_rt_mcast);
1035*4882a593Smuzhiyun }
1036*4882a593Smuzhiyun 
1037*4882a593Smuzhiyun static void dn_dev_set_timer(struct net_device *dev);
1038*4882a593Smuzhiyun 
dn_dev_timer_func(struct timer_list * t)1039*4882a593Smuzhiyun static void dn_dev_timer_func(struct timer_list *t)
1040*4882a593Smuzhiyun {
1041*4882a593Smuzhiyun 	struct dn_dev *dn_db = from_timer(dn_db, t, timer);
1042*4882a593Smuzhiyun 	struct net_device *dev;
1043*4882a593Smuzhiyun 	struct dn_ifaddr *ifa;
1044*4882a593Smuzhiyun 
1045*4882a593Smuzhiyun 	rcu_read_lock();
1046*4882a593Smuzhiyun 	dev = dn_db->dev;
1047*4882a593Smuzhiyun 	if (dn_db->t3 <= dn_db->parms.t2) {
1048*4882a593Smuzhiyun 		if (dn_db->parms.timer3) {
1049*4882a593Smuzhiyun 			for (ifa = rcu_dereference(dn_db->ifa_list);
1050*4882a593Smuzhiyun 			     ifa;
1051*4882a593Smuzhiyun 			     ifa = rcu_dereference(ifa->ifa_next)) {
1052*4882a593Smuzhiyun 				if (!(ifa->ifa_flags & IFA_F_SECONDARY))
1053*4882a593Smuzhiyun 					dn_db->parms.timer3(dev, ifa);
1054*4882a593Smuzhiyun 			}
1055*4882a593Smuzhiyun 		}
1056*4882a593Smuzhiyun 		dn_db->t3 = dn_db->parms.t3;
1057*4882a593Smuzhiyun 	} else {
1058*4882a593Smuzhiyun 		dn_db->t3 -= dn_db->parms.t2;
1059*4882a593Smuzhiyun 	}
1060*4882a593Smuzhiyun 	rcu_read_unlock();
1061*4882a593Smuzhiyun 	dn_dev_set_timer(dev);
1062*4882a593Smuzhiyun }
1063*4882a593Smuzhiyun 
dn_dev_set_timer(struct net_device * dev)1064*4882a593Smuzhiyun static void dn_dev_set_timer(struct net_device *dev)
1065*4882a593Smuzhiyun {
1066*4882a593Smuzhiyun 	struct dn_dev *dn_db = rcu_dereference_raw(dev->dn_ptr);
1067*4882a593Smuzhiyun 
1068*4882a593Smuzhiyun 	if (dn_db->parms.t2 > dn_db->parms.t3)
1069*4882a593Smuzhiyun 		dn_db->parms.t2 = dn_db->parms.t3;
1070*4882a593Smuzhiyun 
1071*4882a593Smuzhiyun 	dn_db->timer.expires = jiffies + (dn_db->parms.t2 * HZ);
1072*4882a593Smuzhiyun 
1073*4882a593Smuzhiyun 	add_timer(&dn_db->timer);
1074*4882a593Smuzhiyun }
1075*4882a593Smuzhiyun 
dn_dev_create(struct net_device * dev,int * err)1076*4882a593Smuzhiyun static struct dn_dev *dn_dev_create(struct net_device *dev, int *err)
1077*4882a593Smuzhiyun {
1078*4882a593Smuzhiyun 	int i;
1079*4882a593Smuzhiyun 	struct dn_dev_parms *p = dn_dev_list;
1080*4882a593Smuzhiyun 	struct dn_dev *dn_db;
1081*4882a593Smuzhiyun 
1082*4882a593Smuzhiyun 	for(i = 0; i < DN_DEV_LIST_SIZE; i++, p++) {
1083*4882a593Smuzhiyun 		if (p->type == dev->type)
1084*4882a593Smuzhiyun 			break;
1085*4882a593Smuzhiyun 	}
1086*4882a593Smuzhiyun 
1087*4882a593Smuzhiyun 	*err = -ENODEV;
1088*4882a593Smuzhiyun 	if (i == DN_DEV_LIST_SIZE)
1089*4882a593Smuzhiyun 		return NULL;
1090*4882a593Smuzhiyun 
1091*4882a593Smuzhiyun 	*err = -ENOBUFS;
1092*4882a593Smuzhiyun 	if ((dn_db = kzalloc(sizeof(struct dn_dev), GFP_ATOMIC)) == NULL)
1093*4882a593Smuzhiyun 		return NULL;
1094*4882a593Smuzhiyun 
1095*4882a593Smuzhiyun 	memcpy(&dn_db->parms, p, sizeof(struct dn_dev_parms));
1096*4882a593Smuzhiyun 
1097*4882a593Smuzhiyun 	rcu_assign_pointer(dev->dn_ptr, dn_db);
1098*4882a593Smuzhiyun 	dn_db->dev = dev;
1099*4882a593Smuzhiyun 	timer_setup(&dn_db->timer, dn_dev_timer_func, 0);
1100*4882a593Smuzhiyun 
1101*4882a593Smuzhiyun 	dn_db->uptime = jiffies;
1102*4882a593Smuzhiyun 
1103*4882a593Smuzhiyun 	dn_db->neigh_parms = neigh_parms_alloc(dev, &dn_neigh_table);
1104*4882a593Smuzhiyun 	if (!dn_db->neigh_parms) {
1105*4882a593Smuzhiyun 		RCU_INIT_POINTER(dev->dn_ptr, NULL);
1106*4882a593Smuzhiyun 		kfree(dn_db);
1107*4882a593Smuzhiyun 		return NULL;
1108*4882a593Smuzhiyun 	}
1109*4882a593Smuzhiyun 
1110*4882a593Smuzhiyun 	if (dn_db->parms.up) {
1111*4882a593Smuzhiyun 		if (dn_db->parms.up(dev) < 0) {
1112*4882a593Smuzhiyun 			neigh_parms_release(&dn_neigh_table, dn_db->neigh_parms);
1113*4882a593Smuzhiyun 			dev->dn_ptr = NULL;
1114*4882a593Smuzhiyun 			kfree(dn_db);
1115*4882a593Smuzhiyun 			return NULL;
1116*4882a593Smuzhiyun 		}
1117*4882a593Smuzhiyun 	}
1118*4882a593Smuzhiyun 
1119*4882a593Smuzhiyun 	dn_dev_sysctl_register(dev, &dn_db->parms);
1120*4882a593Smuzhiyun 
1121*4882a593Smuzhiyun 	dn_dev_set_timer(dev);
1122*4882a593Smuzhiyun 
1123*4882a593Smuzhiyun 	*err = 0;
1124*4882a593Smuzhiyun 	return dn_db;
1125*4882a593Smuzhiyun }
1126*4882a593Smuzhiyun 
1127*4882a593Smuzhiyun 
1128*4882a593Smuzhiyun /*
1129*4882a593Smuzhiyun  * This processes a device up event. We only start up
1130*4882a593Smuzhiyun  * the loopback device & ethernet devices with correct
1131*4882a593Smuzhiyun  * MAC addresses automatically. Others must be started
1132*4882a593Smuzhiyun  * specifically.
1133*4882a593Smuzhiyun  *
1134*4882a593Smuzhiyun  * FIXME: How should we configure the loopback address ? If we could dispense
1135*4882a593Smuzhiyun  * with using decnet_address here and for autobind, it will be one less thing
1136*4882a593Smuzhiyun  * for users to worry about setting up.
1137*4882a593Smuzhiyun  */
1138*4882a593Smuzhiyun 
dn_dev_up(struct net_device * dev)1139*4882a593Smuzhiyun void dn_dev_up(struct net_device *dev)
1140*4882a593Smuzhiyun {
1141*4882a593Smuzhiyun 	struct dn_ifaddr *ifa;
1142*4882a593Smuzhiyun 	__le16 addr = decnet_address;
1143*4882a593Smuzhiyun 	int maybe_default = 0;
1144*4882a593Smuzhiyun 	struct dn_dev *dn_db = rtnl_dereference(dev->dn_ptr);
1145*4882a593Smuzhiyun 
1146*4882a593Smuzhiyun 	if ((dev->type != ARPHRD_ETHER) && (dev->type != ARPHRD_LOOPBACK))
1147*4882a593Smuzhiyun 		return;
1148*4882a593Smuzhiyun 
1149*4882a593Smuzhiyun 	/*
1150*4882a593Smuzhiyun 	 * Need to ensure that loopback device has a dn_db attached to it
1151*4882a593Smuzhiyun 	 * to allow creation of neighbours against it, even though it might
1152*4882a593Smuzhiyun 	 * not have a local address of its own. Might as well do the same for
1153*4882a593Smuzhiyun 	 * all autoconfigured interfaces.
1154*4882a593Smuzhiyun 	 */
1155*4882a593Smuzhiyun 	if (dn_db == NULL) {
1156*4882a593Smuzhiyun 		int err;
1157*4882a593Smuzhiyun 		dn_db = dn_dev_create(dev, &err);
1158*4882a593Smuzhiyun 		if (dn_db == NULL)
1159*4882a593Smuzhiyun 			return;
1160*4882a593Smuzhiyun 	}
1161*4882a593Smuzhiyun 
1162*4882a593Smuzhiyun 	if (dev->type == ARPHRD_ETHER) {
1163*4882a593Smuzhiyun 		if (memcmp(dev->dev_addr, dn_hiord, 4) != 0)
1164*4882a593Smuzhiyun 			return;
1165*4882a593Smuzhiyun 		addr = dn_eth2dn(dev->dev_addr);
1166*4882a593Smuzhiyun 		maybe_default = 1;
1167*4882a593Smuzhiyun 	}
1168*4882a593Smuzhiyun 
1169*4882a593Smuzhiyun 	if (addr == 0)
1170*4882a593Smuzhiyun 		return;
1171*4882a593Smuzhiyun 
1172*4882a593Smuzhiyun 	if ((ifa = dn_dev_alloc_ifa()) == NULL)
1173*4882a593Smuzhiyun 		return;
1174*4882a593Smuzhiyun 
1175*4882a593Smuzhiyun 	ifa->ifa_local = ifa->ifa_address = addr;
1176*4882a593Smuzhiyun 	ifa->ifa_flags = 0;
1177*4882a593Smuzhiyun 	ifa->ifa_scope = RT_SCOPE_UNIVERSE;
1178*4882a593Smuzhiyun 	strcpy(ifa->ifa_label, dev->name);
1179*4882a593Smuzhiyun 
1180*4882a593Smuzhiyun 	dn_dev_set_ifa(dev, ifa);
1181*4882a593Smuzhiyun 
1182*4882a593Smuzhiyun 	/*
1183*4882a593Smuzhiyun 	 * Automagically set the default device to the first automatically
1184*4882a593Smuzhiyun 	 * configured ethernet card in the system.
1185*4882a593Smuzhiyun 	 */
1186*4882a593Smuzhiyun 	if (maybe_default) {
1187*4882a593Smuzhiyun 		dev_hold(dev);
1188*4882a593Smuzhiyun 		if (dn_dev_set_default(dev, 0))
1189*4882a593Smuzhiyun 			dev_put(dev);
1190*4882a593Smuzhiyun 	}
1191*4882a593Smuzhiyun }
1192*4882a593Smuzhiyun 
dn_dev_delete(struct net_device * dev)1193*4882a593Smuzhiyun static void dn_dev_delete(struct net_device *dev)
1194*4882a593Smuzhiyun {
1195*4882a593Smuzhiyun 	struct dn_dev *dn_db = rtnl_dereference(dev->dn_ptr);
1196*4882a593Smuzhiyun 
1197*4882a593Smuzhiyun 	if (dn_db == NULL)
1198*4882a593Smuzhiyun 		return;
1199*4882a593Smuzhiyun 
1200*4882a593Smuzhiyun 	del_timer_sync(&dn_db->timer);
1201*4882a593Smuzhiyun 	dn_dev_sysctl_unregister(&dn_db->parms);
1202*4882a593Smuzhiyun 	dn_dev_check_default(dev);
1203*4882a593Smuzhiyun 	neigh_ifdown(&dn_neigh_table, dev);
1204*4882a593Smuzhiyun 
1205*4882a593Smuzhiyun 	if (dn_db->parms.down)
1206*4882a593Smuzhiyun 		dn_db->parms.down(dev);
1207*4882a593Smuzhiyun 
1208*4882a593Smuzhiyun 	dev->dn_ptr = NULL;
1209*4882a593Smuzhiyun 
1210*4882a593Smuzhiyun 	neigh_parms_release(&dn_neigh_table, dn_db->neigh_parms);
1211*4882a593Smuzhiyun 	neigh_ifdown(&dn_neigh_table, dev);
1212*4882a593Smuzhiyun 
1213*4882a593Smuzhiyun 	if (dn_db->router)
1214*4882a593Smuzhiyun 		neigh_release(dn_db->router);
1215*4882a593Smuzhiyun 	if (dn_db->peer)
1216*4882a593Smuzhiyun 		neigh_release(dn_db->peer);
1217*4882a593Smuzhiyun 
1218*4882a593Smuzhiyun 	kfree(dn_db);
1219*4882a593Smuzhiyun }
1220*4882a593Smuzhiyun 
dn_dev_down(struct net_device * dev)1221*4882a593Smuzhiyun void dn_dev_down(struct net_device *dev)
1222*4882a593Smuzhiyun {
1223*4882a593Smuzhiyun 	struct dn_dev *dn_db = rtnl_dereference(dev->dn_ptr);
1224*4882a593Smuzhiyun 	struct dn_ifaddr *ifa;
1225*4882a593Smuzhiyun 
1226*4882a593Smuzhiyun 	if (dn_db == NULL)
1227*4882a593Smuzhiyun 		return;
1228*4882a593Smuzhiyun 
1229*4882a593Smuzhiyun 	while ((ifa = rtnl_dereference(dn_db->ifa_list)) != NULL) {
1230*4882a593Smuzhiyun 		dn_dev_del_ifa(dn_db, &dn_db->ifa_list, 0);
1231*4882a593Smuzhiyun 		dn_dev_free_ifa(ifa);
1232*4882a593Smuzhiyun 	}
1233*4882a593Smuzhiyun 
1234*4882a593Smuzhiyun 	dn_dev_delete(dev);
1235*4882a593Smuzhiyun }
1236*4882a593Smuzhiyun 
dn_dev_init_pkt(struct sk_buff * skb)1237*4882a593Smuzhiyun void dn_dev_init_pkt(struct sk_buff *skb)
1238*4882a593Smuzhiyun {
1239*4882a593Smuzhiyun }
1240*4882a593Smuzhiyun 
dn_dev_veri_pkt(struct sk_buff * skb)1241*4882a593Smuzhiyun void dn_dev_veri_pkt(struct sk_buff *skb)
1242*4882a593Smuzhiyun {
1243*4882a593Smuzhiyun }
1244*4882a593Smuzhiyun 
dn_dev_hello(struct sk_buff * skb)1245*4882a593Smuzhiyun void dn_dev_hello(struct sk_buff *skb)
1246*4882a593Smuzhiyun {
1247*4882a593Smuzhiyun }
1248*4882a593Smuzhiyun 
dn_dev_devices_off(void)1249*4882a593Smuzhiyun void dn_dev_devices_off(void)
1250*4882a593Smuzhiyun {
1251*4882a593Smuzhiyun 	struct net_device *dev;
1252*4882a593Smuzhiyun 
1253*4882a593Smuzhiyun 	rtnl_lock();
1254*4882a593Smuzhiyun 	for_each_netdev(&init_net, dev)
1255*4882a593Smuzhiyun 		dn_dev_down(dev);
1256*4882a593Smuzhiyun 	rtnl_unlock();
1257*4882a593Smuzhiyun 
1258*4882a593Smuzhiyun }
1259*4882a593Smuzhiyun 
dn_dev_devices_on(void)1260*4882a593Smuzhiyun void dn_dev_devices_on(void)
1261*4882a593Smuzhiyun {
1262*4882a593Smuzhiyun 	struct net_device *dev;
1263*4882a593Smuzhiyun 
1264*4882a593Smuzhiyun 	rtnl_lock();
1265*4882a593Smuzhiyun 	for_each_netdev(&init_net, dev) {
1266*4882a593Smuzhiyun 		if (dev->flags & IFF_UP)
1267*4882a593Smuzhiyun 			dn_dev_up(dev);
1268*4882a593Smuzhiyun 	}
1269*4882a593Smuzhiyun 	rtnl_unlock();
1270*4882a593Smuzhiyun }
1271*4882a593Smuzhiyun 
register_dnaddr_notifier(struct notifier_block * nb)1272*4882a593Smuzhiyun int register_dnaddr_notifier(struct notifier_block *nb)
1273*4882a593Smuzhiyun {
1274*4882a593Smuzhiyun 	return blocking_notifier_chain_register(&dnaddr_chain, nb);
1275*4882a593Smuzhiyun }
1276*4882a593Smuzhiyun 
unregister_dnaddr_notifier(struct notifier_block * nb)1277*4882a593Smuzhiyun int unregister_dnaddr_notifier(struct notifier_block *nb)
1278*4882a593Smuzhiyun {
1279*4882a593Smuzhiyun 	return blocking_notifier_chain_unregister(&dnaddr_chain, nb);
1280*4882a593Smuzhiyun }
1281*4882a593Smuzhiyun 
1282*4882a593Smuzhiyun #ifdef CONFIG_PROC_FS
is_dn_dev(struct net_device * dev)1283*4882a593Smuzhiyun static inline int is_dn_dev(struct net_device *dev)
1284*4882a593Smuzhiyun {
1285*4882a593Smuzhiyun 	return dev->dn_ptr != NULL;
1286*4882a593Smuzhiyun }
1287*4882a593Smuzhiyun 
dn_dev_seq_start(struct seq_file * seq,loff_t * pos)1288*4882a593Smuzhiyun static void *dn_dev_seq_start(struct seq_file *seq, loff_t *pos)
1289*4882a593Smuzhiyun 	__acquires(RCU)
1290*4882a593Smuzhiyun {
1291*4882a593Smuzhiyun 	int i;
1292*4882a593Smuzhiyun 	struct net_device *dev;
1293*4882a593Smuzhiyun 
1294*4882a593Smuzhiyun 	rcu_read_lock();
1295*4882a593Smuzhiyun 
1296*4882a593Smuzhiyun 	if (*pos == 0)
1297*4882a593Smuzhiyun 		return SEQ_START_TOKEN;
1298*4882a593Smuzhiyun 
1299*4882a593Smuzhiyun 	i = 1;
1300*4882a593Smuzhiyun 	for_each_netdev_rcu(&init_net, dev) {
1301*4882a593Smuzhiyun 		if (!is_dn_dev(dev))
1302*4882a593Smuzhiyun 			continue;
1303*4882a593Smuzhiyun 
1304*4882a593Smuzhiyun 		if (i++ == *pos)
1305*4882a593Smuzhiyun 			return dev;
1306*4882a593Smuzhiyun 	}
1307*4882a593Smuzhiyun 
1308*4882a593Smuzhiyun 	return NULL;
1309*4882a593Smuzhiyun }
1310*4882a593Smuzhiyun 
dn_dev_seq_next(struct seq_file * seq,void * v,loff_t * pos)1311*4882a593Smuzhiyun static void *dn_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
1312*4882a593Smuzhiyun {
1313*4882a593Smuzhiyun 	struct net_device *dev;
1314*4882a593Smuzhiyun 
1315*4882a593Smuzhiyun 	++*pos;
1316*4882a593Smuzhiyun 
1317*4882a593Smuzhiyun 	dev = v;
1318*4882a593Smuzhiyun 	if (v == SEQ_START_TOKEN)
1319*4882a593Smuzhiyun 		dev = net_device_entry(&init_net.dev_base_head);
1320*4882a593Smuzhiyun 
1321*4882a593Smuzhiyun 	for_each_netdev_continue_rcu(&init_net, dev) {
1322*4882a593Smuzhiyun 		if (!is_dn_dev(dev))
1323*4882a593Smuzhiyun 			continue;
1324*4882a593Smuzhiyun 
1325*4882a593Smuzhiyun 		return dev;
1326*4882a593Smuzhiyun 	}
1327*4882a593Smuzhiyun 
1328*4882a593Smuzhiyun 	return NULL;
1329*4882a593Smuzhiyun }
1330*4882a593Smuzhiyun 
dn_dev_seq_stop(struct seq_file * seq,void * v)1331*4882a593Smuzhiyun static void dn_dev_seq_stop(struct seq_file *seq, void *v)
1332*4882a593Smuzhiyun 	__releases(RCU)
1333*4882a593Smuzhiyun {
1334*4882a593Smuzhiyun 	rcu_read_unlock();
1335*4882a593Smuzhiyun }
1336*4882a593Smuzhiyun 
dn_type2asc(char type)1337*4882a593Smuzhiyun static char *dn_type2asc(char type)
1338*4882a593Smuzhiyun {
1339*4882a593Smuzhiyun 	switch (type) {
1340*4882a593Smuzhiyun 	case DN_DEV_BCAST:
1341*4882a593Smuzhiyun 		return "B";
1342*4882a593Smuzhiyun 	case DN_DEV_UCAST:
1343*4882a593Smuzhiyun 		return "U";
1344*4882a593Smuzhiyun 	case DN_DEV_MPOINT:
1345*4882a593Smuzhiyun 		return "M";
1346*4882a593Smuzhiyun 	}
1347*4882a593Smuzhiyun 
1348*4882a593Smuzhiyun 	return "?";
1349*4882a593Smuzhiyun }
1350*4882a593Smuzhiyun 
dn_dev_seq_show(struct seq_file * seq,void * v)1351*4882a593Smuzhiyun static int dn_dev_seq_show(struct seq_file *seq, void *v)
1352*4882a593Smuzhiyun {
1353*4882a593Smuzhiyun 	if (v == SEQ_START_TOKEN)
1354*4882a593Smuzhiyun 		seq_puts(seq, "Name     Flags T1   Timer1 T3   Timer3 BlkSize Pri State DevType    Router Peer\n");
1355*4882a593Smuzhiyun 	else {
1356*4882a593Smuzhiyun 		struct net_device *dev = v;
1357*4882a593Smuzhiyun 		char peer_buf[DN_ASCBUF_LEN];
1358*4882a593Smuzhiyun 		char router_buf[DN_ASCBUF_LEN];
1359*4882a593Smuzhiyun 		struct dn_dev *dn_db = rcu_dereference(dev->dn_ptr);
1360*4882a593Smuzhiyun 
1361*4882a593Smuzhiyun 		seq_printf(seq, "%-8s %1s     %04u %04u   %04lu %04lu"
1362*4882a593Smuzhiyun 				"   %04hu    %03d %02x    %-10s %-7s %-7s\n",
1363*4882a593Smuzhiyun 				dev->name,
1364*4882a593Smuzhiyun 				dn_type2asc(dn_db->parms.mode),
1365*4882a593Smuzhiyun 				0, 0,
1366*4882a593Smuzhiyun 				dn_db->t3, dn_db->parms.t3,
1367*4882a593Smuzhiyun 				mtu2blksize(dev),
1368*4882a593Smuzhiyun 				dn_db->parms.priority,
1369*4882a593Smuzhiyun 				dn_db->parms.state, dn_db->parms.name,
1370*4882a593Smuzhiyun 				dn_db->router ? dn_addr2asc(le16_to_cpu(*(__le16 *)dn_db->router->primary_key), router_buf) : "",
1371*4882a593Smuzhiyun 				dn_db->peer ? dn_addr2asc(le16_to_cpu(*(__le16 *)dn_db->peer->primary_key), peer_buf) : "");
1372*4882a593Smuzhiyun 	}
1373*4882a593Smuzhiyun 	return 0;
1374*4882a593Smuzhiyun }
1375*4882a593Smuzhiyun 
1376*4882a593Smuzhiyun static const struct seq_operations dn_dev_seq_ops = {
1377*4882a593Smuzhiyun 	.start	= dn_dev_seq_start,
1378*4882a593Smuzhiyun 	.next	= dn_dev_seq_next,
1379*4882a593Smuzhiyun 	.stop	= dn_dev_seq_stop,
1380*4882a593Smuzhiyun 	.show	= dn_dev_seq_show,
1381*4882a593Smuzhiyun };
1382*4882a593Smuzhiyun #endif /* CONFIG_PROC_FS */
1383*4882a593Smuzhiyun 
1384*4882a593Smuzhiyun static int addr[2];
1385*4882a593Smuzhiyun module_param_array(addr, int, NULL, 0444);
1386*4882a593Smuzhiyun MODULE_PARM_DESC(addr, "The DECnet address of this machine: area,node");
1387*4882a593Smuzhiyun 
dn_dev_init(void)1388*4882a593Smuzhiyun void __init dn_dev_init(void)
1389*4882a593Smuzhiyun {
1390*4882a593Smuzhiyun 	if (addr[0] > 63 || addr[0] < 0) {
1391*4882a593Smuzhiyun 		printk(KERN_ERR "DECnet: Area must be between 0 and 63");
1392*4882a593Smuzhiyun 		return;
1393*4882a593Smuzhiyun 	}
1394*4882a593Smuzhiyun 
1395*4882a593Smuzhiyun 	if (addr[1] > 1023 || addr[1] < 0) {
1396*4882a593Smuzhiyun 		printk(KERN_ERR "DECnet: Node must be between 0 and 1023");
1397*4882a593Smuzhiyun 		return;
1398*4882a593Smuzhiyun 	}
1399*4882a593Smuzhiyun 
1400*4882a593Smuzhiyun 	decnet_address = cpu_to_le16((addr[0] << 10) | addr[1]);
1401*4882a593Smuzhiyun 
1402*4882a593Smuzhiyun 	dn_dev_devices_on();
1403*4882a593Smuzhiyun 
1404*4882a593Smuzhiyun 	rtnl_register_module(THIS_MODULE, PF_DECnet, RTM_NEWADDR,
1405*4882a593Smuzhiyun 			     dn_nl_newaddr, NULL, 0);
1406*4882a593Smuzhiyun 	rtnl_register_module(THIS_MODULE, PF_DECnet, RTM_DELADDR,
1407*4882a593Smuzhiyun 			     dn_nl_deladdr, NULL, 0);
1408*4882a593Smuzhiyun 	rtnl_register_module(THIS_MODULE, PF_DECnet, RTM_GETADDR,
1409*4882a593Smuzhiyun 			     NULL, dn_nl_dump_ifaddr, 0);
1410*4882a593Smuzhiyun 
1411*4882a593Smuzhiyun 	proc_create_seq("decnet_dev", 0444, init_net.proc_net, &dn_dev_seq_ops);
1412*4882a593Smuzhiyun 
1413*4882a593Smuzhiyun #ifdef CONFIG_SYSCTL
1414*4882a593Smuzhiyun 	{
1415*4882a593Smuzhiyun 		int i;
1416*4882a593Smuzhiyun 		for(i = 0; i < DN_DEV_LIST_SIZE; i++)
1417*4882a593Smuzhiyun 			dn_dev_sysctl_register(NULL, &dn_dev_list[i]);
1418*4882a593Smuzhiyun 	}
1419*4882a593Smuzhiyun #endif /* CONFIG_SYSCTL */
1420*4882a593Smuzhiyun }
1421*4882a593Smuzhiyun 
dn_dev_cleanup(void)1422*4882a593Smuzhiyun void __exit dn_dev_cleanup(void)
1423*4882a593Smuzhiyun {
1424*4882a593Smuzhiyun #ifdef CONFIG_SYSCTL
1425*4882a593Smuzhiyun 	{
1426*4882a593Smuzhiyun 		int i;
1427*4882a593Smuzhiyun 		for(i = 0; i < DN_DEV_LIST_SIZE; i++)
1428*4882a593Smuzhiyun 			dn_dev_sysctl_unregister(&dn_dev_list[i]);
1429*4882a593Smuzhiyun 	}
1430*4882a593Smuzhiyun #endif /* CONFIG_SYSCTL */
1431*4882a593Smuzhiyun 
1432*4882a593Smuzhiyun 	remove_proc_entry("decnet_dev", init_net.proc_net);
1433*4882a593Smuzhiyun 
1434*4882a593Smuzhiyun 	dn_dev_devices_off();
1435*4882a593Smuzhiyun }
1436