diff options
Diffstat (limited to 'net/decnet/dn_dev.c')
-rw-r--r-- | net/decnet/dn_dev.c | 118 |
1 files changed, 35 insertions, 83 deletions
diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index 6e1f085db06a..cead68eb254c 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <linux/skbuff.h> | 40 | #include <linux/skbuff.h> |
41 | #include <linux/sysctl.h> | 41 | #include <linux/sysctl.h> |
42 | #include <linux/notifier.h> | 42 | #include <linux/notifier.h> |
43 | #include <linux/slab.h> | ||
43 | #include <asm/uaccess.h> | 44 | #include <asm/uaccess.h> |
44 | #include <asm/system.h> | 45 | #include <asm/system.h> |
45 | #include <net/net_namespace.h> | 46 | #include <net/net_namespace.h> |
@@ -68,7 +69,7 @@ extern struct neigh_table dn_neigh_table; | |||
68 | */ | 69 | */ |
69 | __le16 decnet_address = 0; | 70 | __le16 decnet_address = 0; |
70 | 71 | ||
71 | static DEFINE_RWLOCK(dndev_lock); | 72 | static DEFINE_SPINLOCK(dndev_lock); |
72 | static struct net_device *decnet_default_device; | 73 | static struct net_device *decnet_default_device; |
73 | static BLOCKING_NOTIFIER_HEAD(dnaddr_chain); | 74 | static BLOCKING_NOTIFIER_HEAD(dnaddr_chain); |
74 | 75 | ||
@@ -89,7 +90,6 @@ static struct dn_dev_parms dn_dev_list[] = { | |||
89 | .t2 = 1, | 90 | .t2 = 1, |
90 | .t3 = 10, | 91 | .t3 = 10, |
91 | .name = "ethernet", | 92 | .name = "ethernet", |
92 | .ctl_name = NET_DECNET_CONF_ETHER, | ||
93 | .up = dn_eth_up, | 93 | .up = dn_eth_up, |
94 | .down = dn_eth_down, | 94 | .down = dn_eth_down, |
95 | .timer3 = dn_send_brd_hello, | 95 | .timer3 = dn_send_brd_hello, |
@@ -101,7 +101,6 @@ static struct dn_dev_parms dn_dev_list[] = { | |||
101 | .t2 = 1, | 101 | .t2 = 1, |
102 | .t3 = 10, | 102 | .t3 = 10, |
103 | .name = "ipgre", | 103 | .name = "ipgre", |
104 | .ctl_name = NET_DECNET_CONF_GRE, | ||
105 | .timer3 = dn_send_brd_hello, | 104 | .timer3 = dn_send_brd_hello, |
106 | }, | 105 | }, |
107 | #if 0 | 106 | #if 0 |
@@ -112,7 +111,6 @@ static struct dn_dev_parms dn_dev_list[] = { | |||
112 | .t2 = 1, | 111 | .t2 = 1, |
113 | .t3 = 120, | 112 | .t3 = 120, |
114 | .name = "x25", | 113 | .name = "x25", |
115 | .ctl_name = NET_DECNET_CONF_X25, | ||
116 | .timer3 = dn_send_ptp_hello, | 114 | .timer3 = dn_send_ptp_hello, |
117 | }, | 115 | }, |
118 | #endif | 116 | #endif |
@@ -124,7 +122,6 @@ static struct dn_dev_parms dn_dev_list[] = { | |||
124 | .t2 = 1, | 122 | .t2 = 1, |
125 | .t3 = 10, | 123 | .t3 = 10, |
126 | .name = "ppp", | 124 | .name = "ppp", |
127 | .ctl_name = NET_DECNET_CONF_PPP, | ||
128 | .timer3 = dn_send_brd_hello, | 125 | .timer3 = dn_send_brd_hello, |
129 | }, | 126 | }, |
130 | #endif | 127 | #endif |
@@ -135,7 +132,6 @@ static struct dn_dev_parms dn_dev_list[] = { | |||
135 | .t2 = 1, | 132 | .t2 = 1, |
136 | .t3 = 120, | 133 | .t3 = 120, |
137 | .name = "ddcmp", | 134 | .name = "ddcmp", |
138 | .ctl_name = NET_DECNET_CONF_DDCMP, | ||
139 | .timer3 = dn_send_ptp_hello, | 135 | .timer3 = dn_send_ptp_hello, |
140 | }, | 136 | }, |
141 | { | 137 | { |
@@ -145,7 +141,6 @@ static struct dn_dev_parms dn_dev_list[] = { | |||
145 | .t2 = 1, | 141 | .t2 = 1, |
146 | .t3 = 10, | 142 | .t3 = 10, |
147 | .name = "loopback", | 143 | .name = "loopback", |
148 | .ctl_name = NET_DECNET_CONF_LOOPBACK, | ||
149 | .timer3 = dn_send_brd_hello, | 144 | .timer3 = dn_send_brd_hello, |
150 | } | 145 | } |
151 | }; | 146 | }; |
@@ -166,10 +161,6 @@ static int max_priority[] = { 127 }; /* From DECnet spec */ | |||
166 | 161 | ||
167 | static int dn_forwarding_proc(ctl_table *, int, | 162 | static int dn_forwarding_proc(ctl_table *, int, |
168 | void __user *, size_t *, loff_t *); | 163 | void __user *, size_t *, loff_t *); |
169 | static int dn_forwarding_sysctl(ctl_table *table, | ||
170 | void __user *oldval, size_t __user *oldlenp, | ||
171 | void __user *newval, size_t newlen); | ||
172 | |||
173 | static struct dn_dev_sysctl_table { | 164 | static struct dn_dev_sysctl_table { |
174 | struct ctl_table_header *sysctl_header; | 165 | struct ctl_table_header *sysctl_header; |
175 | ctl_table dn_dev_vars[5]; | 166 | ctl_table dn_dev_vars[5]; |
@@ -177,44 +168,36 @@ static struct dn_dev_sysctl_table { | |||
177 | NULL, | 168 | NULL, |
178 | { | 169 | { |
179 | { | 170 | { |
180 | .ctl_name = NET_DECNET_CONF_DEV_FORWARDING, | ||
181 | .procname = "forwarding", | 171 | .procname = "forwarding", |
182 | .data = (void *)DN_DEV_PARMS_OFFSET(forwarding), | 172 | .data = (void *)DN_DEV_PARMS_OFFSET(forwarding), |
183 | .maxlen = sizeof(int), | 173 | .maxlen = sizeof(int), |
184 | .mode = 0644, | 174 | .mode = 0644, |
185 | .proc_handler = dn_forwarding_proc, | 175 | .proc_handler = dn_forwarding_proc, |
186 | .strategy = dn_forwarding_sysctl, | ||
187 | }, | 176 | }, |
188 | { | 177 | { |
189 | .ctl_name = NET_DECNET_CONF_DEV_PRIORITY, | ||
190 | .procname = "priority", | 178 | .procname = "priority", |
191 | .data = (void *)DN_DEV_PARMS_OFFSET(priority), | 179 | .data = (void *)DN_DEV_PARMS_OFFSET(priority), |
192 | .maxlen = sizeof(int), | 180 | .maxlen = sizeof(int), |
193 | .mode = 0644, | 181 | .mode = 0644, |
194 | .proc_handler = proc_dointvec_minmax, | 182 | .proc_handler = proc_dointvec_minmax, |
195 | .strategy = sysctl_intvec, | ||
196 | .extra1 = &min_priority, | 183 | .extra1 = &min_priority, |
197 | .extra2 = &max_priority | 184 | .extra2 = &max_priority |
198 | }, | 185 | }, |
199 | { | 186 | { |
200 | .ctl_name = NET_DECNET_CONF_DEV_T2, | ||
201 | .procname = "t2", | 187 | .procname = "t2", |
202 | .data = (void *)DN_DEV_PARMS_OFFSET(t2), | 188 | .data = (void *)DN_DEV_PARMS_OFFSET(t2), |
203 | .maxlen = sizeof(int), | 189 | .maxlen = sizeof(int), |
204 | .mode = 0644, | 190 | .mode = 0644, |
205 | .proc_handler = proc_dointvec_minmax, | 191 | .proc_handler = proc_dointvec_minmax, |
206 | .strategy = sysctl_intvec, | ||
207 | .extra1 = &min_t2, | 192 | .extra1 = &min_t2, |
208 | .extra2 = &max_t2 | 193 | .extra2 = &max_t2 |
209 | }, | 194 | }, |
210 | { | 195 | { |
211 | .ctl_name = NET_DECNET_CONF_DEV_T3, | ||
212 | .procname = "t3", | 196 | .procname = "t3", |
213 | .data = (void *)DN_DEV_PARMS_OFFSET(t3), | 197 | .data = (void *)DN_DEV_PARMS_OFFSET(t3), |
214 | .maxlen = sizeof(int), | 198 | .maxlen = sizeof(int), |
215 | .mode = 0644, | 199 | .mode = 0644, |
216 | .proc_handler = proc_dointvec_minmax, | 200 | .proc_handler = proc_dointvec_minmax, |
217 | .strategy = sysctl_intvec, | ||
218 | .extra1 = &min_t3, | 201 | .extra1 = &min_t3, |
219 | .extra2 = &max_t3 | 202 | .extra2 = &max_t3 |
220 | }, | 203 | }, |
@@ -230,9 +213,9 @@ static void dn_dev_sysctl_register(struct net_device *dev, struct dn_dev_parms * | |||
230 | #define DN_CTL_PATH_DEV 3 | 213 | #define DN_CTL_PATH_DEV 3 |
231 | 214 | ||
232 | struct ctl_path dn_ctl_path[] = { | 215 | struct ctl_path dn_ctl_path[] = { |
233 | { .procname = "net", .ctl_name = CTL_NET, }, | 216 | { .procname = "net", }, |
234 | { .procname = "decnet", .ctl_name = NET_DECNET, }, | 217 | { .procname = "decnet", }, |
235 | { .procname = "conf", .ctl_name = NET_DECNET_CONF, }, | 218 | { .procname = "conf", }, |
236 | { /* to be set */ }, | 219 | { /* to be set */ }, |
237 | { }, | 220 | { }, |
238 | }; | 221 | }; |
@@ -248,10 +231,8 @@ static void dn_dev_sysctl_register(struct net_device *dev, struct dn_dev_parms * | |||
248 | 231 | ||
249 | if (dev) { | 232 | if (dev) { |
250 | dn_ctl_path[DN_CTL_PATH_DEV].procname = dev->name; | 233 | dn_ctl_path[DN_CTL_PATH_DEV].procname = dev->name; |
251 | dn_ctl_path[DN_CTL_PATH_DEV].ctl_name = dev->ifindex; | ||
252 | } else { | 234 | } else { |
253 | dn_ctl_path[DN_CTL_PATH_DEV].procname = parms->name; | 235 | dn_ctl_path[DN_CTL_PATH_DEV].procname = parms->name; |
254 | dn_ctl_path[DN_CTL_PATH_DEV].ctl_name = parms->ctl_name; | ||
255 | } | 236 | } |
256 | 237 | ||
257 | t->dn_dev_vars[0].extra1 = (void *)dev; | 238 | t->dn_dev_vars[0].extra1 = (void *)dev; |
@@ -317,44 +298,6 @@ static int dn_forwarding_proc(ctl_table *table, int write, | |||
317 | #endif | 298 | #endif |
318 | } | 299 | } |
319 | 300 | ||
320 | static int dn_forwarding_sysctl(ctl_table *table, | ||
321 | void __user *oldval, size_t __user *oldlenp, | ||
322 | void __user *newval, size_t newlen) | ||
323 | { | ||
324 | #ifdef CONFIG_DECNET_ROUTER | ||
325 | struct net_device *dev = table->extra1; | ||
326 | struct dn_dev *dn_db; | ||
327 | int value; | ||
328 | |||
329 | if (table->extra1 == NULL) | ||
330 | return -EINVAL; | ||
331 | |||
332 | dn_db = dev->dn_ptr; | ||
333 | |||
334 | if (newval && newlen) { | ||
335 | if (newlen != sizeof(int)) | ||
336 | return -EINVAL; | ||
337 | |||
338 | if (get_user(value, (int __user *)newval)) | ||
339 | return -EFAULT; | ||
340 | if (value < 0) | ||
341 | return -EINVAL; | ||
342 | if (value > 2) | ||
343 | return -EINVAL; | ||
344 | |||
345 | if (dn_db->parms.down) | ||
346 | dn_db->parms.down(dev); | ||
347 | dn_db->parms.forwarding = value; | ||
348 | if (dn_db->parms.up) | ||
349 | dn_db->parms.up(dev); | ||
350 | } | ||
351 | |||
352 | return 0; | ||
353 | #else | ||
354 | return -EINVAL; | ||
355 | #endif | ||
356 | } | ||
357 | |||
358 | #else /* CONFIG_SYSCTL */ | 301 | #else /* CONFIG_SYSCTL */ |
359 | static void dn_dev_sysctl_unregister(struct dn_dev_parms *parms) | 302 | static void dn_dev_sysctl_unregister(struct dn_dev_parms *parms) |
360 | { | 303 | { |
@@ -557,7 +500,8 @@ rarok: | |||
557 | struct net_device *dn_dev_get_default(void) | 500 | struct net_device *dn_dev_get_default(void) |
558 | { | 501 | { |
559 | struct net_device *dev; | 502 | struct net_device *dev; |
560 | read_lock(&dndev_lock); | 503 | |
504 | spin_lock(&dndev_lock); | ||
561 | dev = decnet_default_device; | 505 | dev = decnet_default_device; |
562 | if (dev) { | 506 | if (dev) { |
563 | if (dev->dn_ptr) | 507 | if (dev->dn_ptr) |
@@ -565,7 +509,8 @@ struct net_device *dn_dev_get_default(void) | |||
565 | else | 509 | else |
566 | dev = NULL; | 510 | dev = NULL; |
567 | } | 511 | } |
568 | read_unlock(&dndev_lock); | 512 | spin_unlock(&dndev_lock); |
513 | |||
569 | return dev; | 514 | return dev; |
570 | } | 515 | } |
571 | 516 | ||
@@ -575,13 +520,15 @@ int dn_dev_set_default(struct net_device *dev, int force) | |||
575 | int rv = -EBUSY; | 520 | int rv = -EBUSY; |
576 | if (!dev->dn_ptr) | 521 | if (!dev->dn_ptr) |
577 | return -ENODEV; | 522 | return -ENODEV; |
578 | write_lock(&dndev_lock); | 523 | |
524 | spin_lock(&dndev_lock); | ||
579 | if (force || decnet_default_device == NULL) { | 525 | if (force || decnet_default_device == NULL) { |
580 | old = decnet_default_device; | 526 | old = decnet_default_device; |
581 | decnet_default_device = dev; | 527 | decnet_default_device = dev; |
582 | rv = 0; | 528 | rv = 0; |
583 | } | 529 | } |
584 | write_unlock(&dndev_lock); | 530 | spin_unlock(&dndev_lock); |
531 | |||
585 | if (old) | 532 | if (old) |
586 | dev_put(old); | 533 | dev_put(old); |
587 | return rv; | 534 | return rv; |
@@ -589,26 +536,29 @@ int dn_dev_set_default(struct net_device *dev, int force) | |||
589 | 536 | ||
590 | static void dn_dev_check_default(struct net_device *dev) | 537 | static void dn_dev_check_default(struct net_device *dev) |
591 | { | 538 | { |
592 | write_lock(&dndev_lock); | 539 | spin_lock(&dndev_lock); |
593 | if (dev == decnet_default_device) { | 540 | if (dev == decnet_default_device) { |
594 | decnet_default_device = NULL; | 541 | decnet_default_device = NULL; |
595 | } else { | 542 | } else { |
596 | dev = NULL; | 543 | dev = NULL; |
597 | } | 544 | } |
598 | write_unlock(&dndev_lock); | 545 | spin_unlock(&dndev_lock); |
546 | |||
599 | if (dev) | 547 | if (dev) |
600 | dev_put(dev); | 548 | dev_put(dev); |
601 | } | 549 | } |
602 | 550 | ||
551 | /* | ||
552 | * Called with RTNL | ||
553 | */ | ||
603 | static struct dn_dev *dn_dev_by_index(int ifindex) | 554 | static struct dn_dev *dn_dev_by_index(int ifindex) |
604 | { | 555 | { |
605 | struct net_device *dev; | 556 | struct net_device *dev; |
606 | struct dn_dev *dn_dev = NULL; | 557 | struct dn_dev *dn_dev = NULL; |
607 | dev = dev_get_by_index(&init_net, ifindex); | 558 | |
608 | if (dev) { | 559 | dev = __dev_get_by_index(&init_net, ifindex); |
560 | if (dev) | ||
609 | dn_dev = dev->dn_ptr; | 561 | dn_dev = dev->dn_ptr; |
610 | dev_put(dev); | ||
611 | } | ||
612 | 562 | ||
613 | return dn_dev; | 563 | return dn_dev; |
614 | } | 564 | } |
@@ -629,7 +579,7 @@ static int dn_nl_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
629 | struct dn_ifaddr *ifa, **ifap; | 579 | struct dn_ifaddr *ifa, **ifap; |
630 | int err = -EINVAL; | 580 | int err = -EINVAL; |
631 | 581 | ||
632 | if (net != &init_net) | 582 | if (!net_eq(net, &init_net)) |
633 | goto errout; | 583 | goto errout; |
634 | 584 | ||
635 | err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, dn_ifa_policy); | 585 | err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, dn_ifa_policy); |
@@ -668,7 +618,7 @@ static int dn_nl_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
668 | struct dn_ifaddr *ifa; | 618 | struct dn_ifaddr *ifa; |
669 | int err; | 619 | int err; |
670 | 620 | ||
671 | if (net != &init_net) | 621 | if (!net_eq(net, &init_net)) |
672 | return -EINVAL; | 622 | return -EINVAL; |
673 | 623 | ||
674 | err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, dn_ifa_policy); | 624 | err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, dn_ifa_policy); |
@@ -782,7 +732,7 @@ static int dn_nl_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) | |||
782 | struct dn_dev *dn_db; | 732 | struct dn_dev *dn_db; |
783 | struct dn_ifaddr *ifa; | 733 | struct dn_ifaddr *ifa; |
784 | 734 | ||
785 | if (net != &init_net) | 735 | if (!net_eq(net, &init_net)) |
786 | return 0; | 736 | return 0; |
787 | 737 | ||
788 | skip_ndevs = cb->args[0]; | 738 | skip_ndevs = cb->args[0]; |
@@ -826,13 +776,17 @@ static int dn_dev_get_first(struct net_device *dev, __le16 *addr) | |||
826 | struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr; | 776 | struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr; |
827 | struct dn_ifaddr *ifa; | 777 | struct dn_ifaddr *ifa; |
828 | int rv = -ENODEV; | 778 | int rv = -ENODEV; |
779 | |||
829 | if (dn_db == NULL) | 780 | if (dn_db == NULL) |
830 | goto out; | 781 | goto out; |
782 | |||
783 | rtnl_lock(); | ||
831 | ifa = dn_db->ifa_list; | 784 | ifa = dn_db->ifa_list; |
832 | if (ifa != NULL) { | 785 | if (ifa != NULL) { |
833 | *addr = ifa->ifa_local; | 786 | *addr = ifa->ifa_local; |
834 | rv = 0; | 787 | rv = 0; |
835 | } | 788 | } |
789 | rtnl_unlock(); | ||
836 | out: | 790 | out: |
837 | return rv; | 791 | return rv; |
838 | } | 792 | } |
@@ -854,9 +808,7 @@ int dn_dev_bind_default(__le16 *addr) | |||
854 | dev = dn_dev_get_default(); | 808 | dev = dn_dev_get_default(); |
855 | last_chance: | 809 | last_chance: |
856 | if (dev) { | 810 | if (dev) { |
857 | read_lock(&dev_base_lock); | ||
858 | rv = dn_dev_get_first(dev, addr); | 811 | rv = dn_dev_get_first(dev, addr); |
859 | read_unlock(&dev_base_lock); | ||
860 | dev_put(dev); | 812 | dev_put(dev); |
861 | if (rv == 0 || dev == init_net.loopback_dev) | 813 | if (rv == 0 || dev == init_net.loopback_dev) |
862 | return rv; | 814 | return rv; |
@@ -1321,18 +1273,18 @@ static inline int is_dn_dev(struct net_device *dev) | |||
1321 | } | 1273 | } |
1322 | 1274 | ||
1323 | static void *dn_dev_seq_start(struct seq_file *seq, loff_t *pos) | 1275 | static void *dn_dev_seq_start(struct seq_file *seq, loff_t *pos) |
1324 | __acquires(&dev_base_lock) | 1276 | __acquires(rcu) |
1325 | { | 1277 | { |
1326 | int i; | 1278 | int i; |
1327 | struct net_device *dev; | 1279 | struct net_device *dev; |
1328 | 1280 | ||
1329 | read_lock(&dev_base_lock); | 1281 | rcu_read_lock(); |
1330 | 1282 | ||
1331 | if (*pos == 0) | 1283 | if (*pos == 0) |
1332 | return SEQ_START_TOKEN; | 1284 | return SEQ_START_TOKEN; |
1333 | 1285 | ||
1334 | i = 1; | 1286 | i = 1; |
1335 | for_each_netdev(&init_net, dev) { | 1287 | for_each_netdev_rcu(&init_net, dev) { |
1336 | if (!is_dn_dev(dev)) | 1288 | if (!is_dn_dev(dev)) |
1337 | continue; | 1289 | continue; |
1338 | 1290 | ||
@@ -1353,7 +1305,7 @@ static void *dn_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
1353 | if (v == SEQ_START_TOKEN) | 1305 | if (v == SEQ_START_TOKEN) |
1354 | dev = net_device_entry(&init_net.dev_base_head); | 1306 | dev = net_device_entry(&init_net.dev_base_head); |
1355 | 1307 | ||
1356 | for_each_netdev_continue(&init_net, dev) { | 1308 | for_each_netdev_continue_rcu(&init_net, dev) { |
1357 | if (!is_dn_dev(dev)) | 1309 | if (!is_dn_dev(dev)) |
1358 | continue; | 1310 | continue; |
1359 | 1311 | ||
@@ -1364,9 +1316,9 @@ static void *dn_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
1364 | } | 1316 | } |
1365 | 1317 | ||
1366 | static void dn_dev_seq_stop(struct seq_file *seq, void *v) | 1318 | static void dn_dev_seq_stop(struct seq_file *seq, void *v) |
1367 | __releases(&dev_base_lock) | 1319 | __releases(rcu) |
1368 | { | 1320 | { |
1369 | read_unlock(&dev_base_lock); | 1321 | rcu_read_unlock(); |
1370 | } | 1322 | } |
1371 | 1323 | ||
1372 | static char *dn_type2asc(char type) | 1324 | static char *dn_type2asc(char type) |