diff options
Diffstat (limited to 'net/phonet')
-rw-r--r-- | net/phonet/af_phonet.c | 31 | ||||
-rw-r--r-- | net/phonet/pn_dev.c | 119 | ||||
-rw-r--r-- | net/phonet/pn_netlink.c | 24 |
3 files changed, 111 insertions, 63 deletions
diff --git a/net/phonet/af_phonet.c b/net/phonet/af_phonet.c index 13cb323f8c38..81795ea87794 100644 --- a/net/phonet/af_phonet.c +++ b/net/phonet/af_phonet.c | |||
@@ -275,8 +275,6 @@ static inline int can_respond(struct sk_buff *skb) | |||
275 | return 0; | 275 | return 0; |
276 | 276 | ||
277 | ph = pn_hdr(skb); | 277 | ph = pn_hdr(skb); |
278 | if (phonet_address_get(skb->dev, ph->pn_rdev) != ph->pn_rdev) | ||
279 | return 0; /* we are not the destination */ | ||
280 | if (ph->pn_res == PN_PREFIX && !pskb_may_pull(skb, 5)) | 278 | if (ph->pn_res == PN_PREFIX && !pskb_may_pull(skb, 5)) |
281 | return 0; | 279 | return 0; |
282 | if (ph->pn_res == PN_COMMGR) /* indications */ | 280 | if (ph->pn_res == PN_COMMGR) /* indications */ |
@@ -344,8 +342,8 @@ static int phonet_rcv(struct sk_buff *skb, struct net_device *dev, | |||
344 | struct packet_type *pkttype, | 342 | struct packet_type *pkttype, |
345 | struct net_device *orig_dev) | 343 | struct net_device *orig_dev) |
346 | { | 344 | { |
345 | struct net *net = dev_net(dev); | ||
347 | struct phonethdr *ph; | 346 | struct phonethdr *ph; |
348 | struct sock *sk; | ||
349 | struct sockaddr_pn sa; | 347 | struct sockaddr_pn sa; |
350 | u16 len; | 348 | u16 len; |
351 | 349 | ||
@@ -364,28 +362,28 @@ static int phonet_rcv(struct sk_buff *skb, struct net_device *dev, | |||
364 | skb_reset_transport_header(skb); | 362 | skb_reset_transport_header(skb); |
365 | 363 | ||
366 | pn_skb_get_dst_sockaddr(skb, &sa); | 364 | pn_skb_get_dst_sockaddr(skb, &sa); |
367 | if (pn_sockaddr_get_addr(&sa) == 0) | ||
368 | goto out; /* currently, we cannot be device 0 */ | ||
369 | 365 | ||
370 | sk = pn_find_sock_by_sa(dev_net(dev), &sa); | 366 | /* check if we are the destination */ |
371 | if (sk == NULL) { | 367 | if (phonet_address_lookup(net, pn_sockaddr_get_addr(&sa)) == 0) { |
368 | /* Phonet packet input */ | ||
369 | struct sock *sk = pn_find_sock_by_sa(net, &sa); | ||
370 | |||
371 | if (sk) | ||
372 | return sk_receive_skb(sk, skb, 0); | ||
373 | |||
372 | if (can_respond(skb)) { | 374 | if (can_respond(skb)) { |
373 | send_obj_unreachable(skb); | 375 | send_obj_unreachable(skb); |
374 | send_reset_indications(skb); | 376 | send_reset_indications(skb); |
375 | } | 377 | } |
376 | goto out; | ||
377 | } | 378 | } |
378 | 379 | ||
379 | /* Push data to the socket (or other sockets connected to it). */ | ||
380 | return sk_receive_skb(sk, skb, 0); | ||
381 | |||
382 | out: | 380 | out: |
383 | kfree_skb(skb); | 381 | kfree_skb(skb); |
384 | return NET_RX_DROP; | 382 | return NET_RX_DROP; |
385 | } | 383 | } |
386 | 384 | ||
387 | static struct packet_type phonet_packet_type = { | 385 | static struct packet_type phonet_packet_type = { |
388 | .type = __constant_htons(ETH_P_PHONET), | 386 | .type = cpu_to_be16(ETH_P_PHONET), |
389 | .dev = NULL, | 387 | .dev = NULL, |
390 | .func = phonet_rcv, | 388 | .func = phonet_rcv, |
391 | }; | 389 | }; |
@@ -428,16 +426,18 @@ static int __init phonet_init(void) | |||
428 | { | 426 | { |
429 | int err; | 427 | int err; |
430 | 428 | ||
429 | err = phonet_device_init(); | ||
430 | if (err) | ||
431 | return err; | ||
432 | |||
431 | err = sock_register(&phonet_proto_family); | 433 | err = sock_register(&phonet_proto_family); |
432 | if (err) { | 434 | if (err) { |
433 | printk(KERN_ALERT | 435 | printk(KERN_ALERT |
434 | "phonet protocol family initialization failed\n"); | 436 | "phonet protocol family initialization failed\n"); |
435 | return err; | 437 | goto err_sock; |
436 | } | 438 | } |
437 | 439 | ||
438 | phonet_device_init(); | ||
439 | dev_add_pack(&phonet_packet_type); | 440 | dev_add_pack(&phonet_packet_type); |
440 | phonet_netlink_register(); | ||
441 | phonet_sysctl_init(); | 441 | phonet_sysctl_init(); |
442 | 442 | ||
443 | err = isi_register(); | 443 | err = isi_register(); |
@@ -449,6 +449,7 @@ err: | |||
449 | phonet_sysctl_exit(); | 449 | phonet_sysctl_exit(); |
450 | sock_unregister(PF_PHONET); | 450 | sock_unregister(PF_PHONET); |
451 | dev_remove_pack(&phonet_packet_type); | 451 | dev_remove_pack(&phonet_packet_type); |
452 | err_sock: | ||
452 | phonet_device_exit(); | 453 | phonet_device_exit(); |
453 | return err; | 454 | return err; |
454 | } | 455 | } |
diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c index 5491bf5e354b..80a322d77909 100644 --- a/net/phonet/pn_dev.c +++ b/net/phonet/pn_dev.c | |||
@@ -28,32 +28,41 @@ | |||
28 | #include <linux/netdevice.h> | 28 | #include <linux/netdevice.h> |
29 | #include <linux/phonet.h> | 29 | #include <linux/phonet.h> |
30 | #include <net/sock.h> | 30 | #include <net/sock.h> |
31 | #include <net/netns/generic.h> | ||
31 | #include <net/phonet/pn_dev.h> | 32 | #include <net/phonet/pn_dev.h> |
32 | 33 | ||
33 | /* when accessing, remember to lock with spin_lock(&pndevs.lock); */ | 34 | struct phonet_net { |
34 | struct phonet_device_list pndevs = { | 35 | struct phonet_device_list pndevs; |
35 | .list = LIST_HEAD_INIT(pndevs.list), | ||
36 | .lock = __SPIN_LOCK_UNLOCKED(pndevs.lock), | ||
37 | }; | 36 | }; |
38 | 37 | ||
38 | int phonet_net_id; | ||
39 | |||
40 | struct phonet_device_list *phonet_device_list(struct net *net) | ||
41 | { | ||
42 | struct phonet_net *pnn = net_generic(net, phonet_net_id); | ||
43 | return &pnn->pndevs; | ||
44 | } | ||
45 | |||
39 | /* Allocate new Phonet device. */ | 46 | /* Allocate new Phonet device. */ |
40 | static struct phonet_device *__phonet_device_alloc(struct net_device *dev) | 47 | static struct phonet_device *__phonet_device_alloc(struct net_device *dev) |
41 | { | 48 | { |
49 | struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev)); | ||
42 | struct phonet_device *pnd = kmalloc(sizeof(*pnd), GFP_ATOMIC); | 50 | struct phonet_device *pnd = kmalloc(sizeof(*pnd), GFP_ATOMIC); |
43 | if (pnd == NULL) | 51 | if (pnd == NULL) |
44 | return NULL; | 52 | return NULL; |
45 | pnd->netdev = dev; | 53 | pnd->netdev = dev; |
46 | bitmap_zero(pnd->addrs, 64); | 54 | bitmap_zero(pnd->addrs, 64); |
47 | 55 | ||
48 | list_add(&pnd->list, &pndevs.list); | 56 | list_add(&pnd->list, &pndevs->list); |
49 | return pnd; | 57 | return pnd; |
50 | } | 58 | } |
51 | 59 | ||
52 | static struct phonet_device *__phonet_get(struct net_device *dev) | 60 | static struct phonet_device *__phonet_get(struct net_device *dev) |
53 | { | 61 | { |
62 | struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev)); | ||
54 | struct phonet_device *pnd; | 63 | struct phonet_device *pnd; |
55 | 64 | ||
56 | list_for_each_entry(pnd, &pndevs.list, list) { | 65 | list_for_each_entry(pnd, &pndevs->list, list) { |
57 | if (pnd->netdev == dev) | 66 | if (pnd->netdev == dev) |
58 | return pnd; | 67 | return pnd; |
59 | } | 68 | } |
@@ -68,32 +77,33 @@ static void __phonet_device_free(struct phonet_device *pnd) | |||
68 | 77 | ||
69 | struct net_device *phonet_device_get(struct net *net) | 78 | struct net_device *phonet_device_get(struct net *net) |
70 | { | 79 | { |
80 | struct phonet_device_list *pndevs = phonet_device_list(net); | ||
71 | struct phonet_device *pnd; | 81 | struct phonet_device *pnd; |
72 | struct net_device *dev; | 82 | struct net_device *dev; |
73 | 83 | ||
74 | spin_lock_bh(&pndevs.lock); | 84 | spin_lock_bh(&pndevs->lock); |
75 | list_for_each_entry(pnd, &pndevs.list, list) { | 85 | list_for_each_entry(pnd, &pndevs->list, list) { |
76 | dev = pnd->netdev; | 86 | dev = pnd->netdev; |
77 | BUG_ON(!dev); | 87 | BUG_ON(!dev); |
78 | 88 | ||
79 | if (net_eq(dev_net(dev), net) && | 89 | if ((dev->reg_state == NETREG_REGISTERED) && |
80 | (dev->reg_state == NETREG_REGISTERED) && | ||
81 | ((pnd->netdev->flags & IFF_UP)) == IFF_UP) | 90 | ((pnd->netdev->flags & IFF_UP)) == IFF_UP) |
82 | break; | 91 | break; |
83 | dev = NULL; | 92 | dev = NULL; |
84 | } | 93 | } |
85 | if (dev) | 94 | if (dev) |
86 | dev_hold(dev); | 95 | dev_hold(dev); |
87 | spin_unlock_bh(&pndevs.lock); | 96 | spin_unlock_bh(&pndevs->lock); |
88 | return dev; | 97 | return dev; |
89 | } | 98 | } |
90 | 99 | ||
91 | int phonet_address_add(struct net_device *dev, u8 addr) | 100 | int phonet_address_add(struct net_device *dev, u8 addr) |
92 | { | 101 | { |
102 | struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev)); | ||
93 | struct phonet_device *pnd; | 103 | struct phonet_device *pnd; |
94 | int err = 0; | 104 | int err = 0; |
95 | 105 | ||
96 | spin_lock_bh(&pndevs.lock); | 106 | spin_lock_bh(&pndevs->lock); |
97 | /* Find or create Phonet-specific device data */ | 107 | /* Find or create Phonet-specific device data */ |
98 | pnd = __phonet_get(dev); | 108 | pnd = __phonet_get(dev); |
99 | if (pnd == NULL) | 109 | if (pnd == NULL) |
@@ -102,31 +112,33 @@ int phonet_address_add(struct net_device *dev, u8 addr) | |||
102 | err = -ENOMEM; | 112 | err = -ENOMEM; |
103 | else if (test_and_set_bit(addr >> 2, pnd->addrs)) | 113 | else if (test_and_set_bit(addr >> 2, pnd->addrs)) |
104 | err = -EEXIST; | 114 | err = -EEXIST; |
105 | spin_unlock_bh(&pndevs.lock); | 115 | spin_unlock_bh(&pndevs->lock); |
106 | return err; | 116 | return err; |
107 | } | 117 | } |
108 | 118 | ||
109 | int phonet_address_del(struct net_device *dev, u8 addr) | 119 | int phonet_address_del(struct net_device *dev, u8 addr) |
110 | { | 120 | { |
121 | struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev)); | ||
111 | struct phonet_device *pnd; | 122 | struct phonet_device *pnd; |
112 | int err = 0; | 123 | int err = 0; |
113 | 124 | ||
114 | spin_lock_bh(&pndevs.lock); | 125 | spin_lock_bh(&pndevs->lock); |
115 | pnd = __phonet_get(dev); | 126 | pnd = __phonet_get(dev); |
116 | if (!pnd || !test_and_clear_bit(addr >> 2, pnd->addrs)) | 127 | if (!pnd || !test_and_clear_bit(addr >> 2, pnd->addrs)) |
117 | err = -EADDRNOTAVAIL; | 128 | err = -EADDRNOTAVAIL; |
118 | else if (bitmap_empty(pnd->addrs, 64)) | 129 | else if (bitmap_empty(pnd->addrs, 64)) |
119 | __phonet_device_free(pnd); | 130 | __phonet_device_free(pnd); |
120 | spin_unlock_bh(&pndevs.lock); | 131 | spin_unlock_bh(&pndevs->lock); |
121 | return err; | 132 | return err; |
122 | } | 133 | } |
123 | 134 | ||
124 | /* Gets a source address toward a destination, through a interface. */ | 135 | /* Gets a source address toward a destination, through a interface. */ |
125 | u8 phonet_address_get(struct net_device *dev, u8 addr) | 136 | u8 phonet_address_get(struct net_device *dev, u8 addr) |
126 | { | 137 | { |
138 | struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev)); | ||
127 | struct phonet_device *pnd; | 139 | struct phonet_device *pnd; |
128 | 140 | ||
129 | spin_lock_bh(&pndevs.lock); | 141 | spin_lock_bh(&pndevs->lock); |
130 | pnd = __phonet_get(dev); | 142 | pnd = __phonet_get(dev); |
131 | if (pnd) { | 143 | if (pnd) { |
132 | BUG_ON(bitmap_empty(pnd->addrs, 64)); | 144 | BUG_ON(bitmap_empty(pnd->addrs, 64)); |
@@ -136,30 +148,31 @@ u8 phonet_address_get(struct net_device *dev, u8 addr) | |||
136 | addr = find_first_bit(pnd->addrs, 64) << 2; | 148 | addr = find_first_bit(pnd->addrs, 64) << 2; |
137 | } else | 149 | } else |
138 | addr = PN_NO_ADDR; | 150 | addr = PN_NO_ADDR; |
139 | spin_unlock_bh(&pndevs.lock); | 151 | spin_unlock_bh(&pndevs->lock); |
140 | return addr; | 152 | return addr; |
141 | } | 153 | } |
142 | 154 | ||
143 | int phonet_address_lookup(struct net *net, u8 addr) | 155 | int phonet_address_lookup(struct net *net, u8 addr) |
144 | { | 156 | { |
157 | struct phonet_device_list *pndevs = phonet_device_list(net); | ||
145 | struct phonet_device *pnd; | 158 | struct phonet_device *pnd; |
159 | int err = -EADDRNOTAVAIL; | ||
146 | 160 | ||
147 | spin_lock_bh(&pndevs.lock); | 161 | spin_lock_bh(&pndevs->lock); |
148 | list_for_each_entry(pnd, &pndevs.list, list) { | 162 | list_for_each_entry(pnd, &pndevs->list, list) { |
149 | if (!net_eq(dev_net(pnd->netdev), net)) | ||
150 | continue; | ||
151 | /* Don't allow unregistering devices! */ | 163 | /* Don't allow unregistering devices! */ |
152 | if ((pnd->netdev->reg_state != NETREG_REGISTERED) || | 164 | if ((pnd->netdev->reg_state != NETREG_REGISTERED) || |
153 | ((pnd->netdev->flags & IFF_UP)) != IFF_UP) | 165 | ((pnd->netdev->flags & IFF_UP)) != IFF_UP) |
154 | continue; | 166 | continue; |
155 | 167 | ||
156 | if (test_bit(addr >> 2, pnd->addrs)) { | 168 | if (test_bit(addr >> 2, pnd->addrs)) { |
157 | spin_unlock_bh(&pndevs.lock); | 169 | err = 0; |
158 | return 0; | 170 | goto found; |
159 | } | 171 | } |
160 | } | 172 | } |
161 | spin_unlock_bh(&pndevs.lock); | 173 | found: |
162 | return -EADDRNOTAVAIL; | 174 | spin_unlock_bh(&pndevs->lock); |
175 | return err; | ||
163 | } | 176 | } |
164 | 177 | ||
165 | /* notify Phonet of device events */ | 178 | /* notify Phonet of device events */ |
@@ -169,14 +182,16 @@ static int phonet_device_notify(struct notifier_block *me, unsigned long what, | |||
169 | struct net_device *dev = arg; | 182 | struct net_device *dev = arg; |
170 | 183 | ||
171 | if (what == NETDEV_UNREGISTER) { | 184 | if (what == NETDEV_UNREGISTER) { |
185 | struct phonet_device_list *pndevs; | ||
172 | struct phonet_device *pnd; | 186 | struct phonet_device *pnd; |
173 | 187 | ||
174 | /* Destroy phonet-specific device data */ | 188 | /* Destroy phonet-specific device data */ |
175 | spin_lock_bh(&pndevs.lock); | 189 | pndevs = phonet_device_list(dev_net(dev)); |
190 | spin_lock_bh(&pndevs->lock); | ||
176 | pnd = __phonet_get(dev); | 191 | pnd = __phonet_get(dev); |
177 | if (pnd) | 192 | if (pnd) |
178 | __phonet_device_free(pnd); | 193 | __phonet_device_free(pnd); |
179 | spin_unlock_bh(&pndevs.lock); | 194 | spin_unlock_bh(&pndevs->lock); |
180 | } | 195 | } |
181 | return 0; | 196 | return 0; |
182 | 197 | ||
@@ -187,24 +202,52 @@ static struct notifier_block phonet_device_notifier = { | |||
187 | .priority = 0, | 202 | .priority = 0, |
188 | }; | 203 | }; |
189 | 204 | ||
190 | /* Initialize Phonet devices list */ | 205 | /* Per-namespace Phonet devices handling */ |
191 | void phonet_device_init(void) | 206 | static int phonet_init_net(struct net *net) |
192 | { | 207 | { |
193 | register_netdevice_notifier(&phonet_device_notifier); | 208 | struct phonet_net *pnn = kmalloc(sizeof(*pnn), GFP_KERNEL); |
209 | if (!pnn) | ||
210 | return -ENOMEM; | ||
211 | |||
212 | INIT_LIST_HEAD(&pnn->pndevs.list); | ||
213 | spin_lock_init(&pnn->pndevs.lock); | ||
214 | net_assign_generic(net, phonet_net_id, pnn); | ||
215 | return 0; | ||
194 | } | 216 | } |
195 | 217 | ||
196 | void phonet_device_exit(void) | 218 | static void phonet_exit_net(struct net *net) |
197 | { | 219 | { |
220 | struct phonet_net *pnn = net_generic(net, phonet_net_id); | ||
198 | struct phonet_device *pnd, *n; | 221 | struct phonet_device *pnd, *n; |
199 | 222 | ||
200 | rtnl_unregister_all(PF_PHONET); | 223 | list_for_each_entry_safe(pnd, n, &pnn->pndevs.list, list) |
201 | rtnl_lock(); | ||
202 | spin_lock_bh(&pndevs.lock); | ||
203 | |||
204 | list_for_each_entry_safe(pnd, n, &pndevs.list, list) | ||
205 | __phonet_device_free(pnd); | 224 | __phonet_device_free(pnd); |
206 | 225 | ||
207 | spin_unlock_bh(&pndevs.lock); | 226 | kfree(pnn); |
208 | rtnl_unlock(); | 227 | } |
228 | |||
229 | static struct pernet_operations phonet_net_ops = { | ||
230 | .init = phonet_init_net, | ||
231 | .exit = phonet_exit_net, | ||
232 | }; | ||
233 | |||
234 | /* Initialize Phonet devices list */ | ||
235 | int __init phonet_device_init(void) | ||
236 | { | ||
237 | int err = register_pernet_gen_device(&phonet_net_id, &phonet_net_ops); | ||
238 | if (err) | ||
239 | return err; | ||
240 | |||
241 | register_netdevice_notifier(&phonet_device_notifier); | ||
242 | err = phonet_netlink_register(); | ||
243 | if (err) | ||
244 | phonet_device_exit(); | ||
245 | return err; | ||
246 | } | ||
247 | |||
248 | void phonet_device_exit(void) | ||
249 | { | ||
250 | rtnl_unregister_all(PF_PHONET); | ||
209 | unregister_netdevice_notifier(&phonet_device_notifier); | 251 | unregister_netdevice_notifier(&phonet_device_notifier); |
252 | unregister_pernet_gen_device(phonet_net_id, &phonet_net_ops); | ||
210 | } | 253 | } |
diff --git a/net/phonet/pn_netlink.c b/net/phonet/pn_netlink.c index 242fe8f8c322..1ceea1f92413 100644 --- a/net/phonet/pn_netlink.c +++ b/net/phonet/pn_netlink.c | |||
@@ -123,17 +123,16 @@ nla_put_failure: | |||
123 | 123 | ||
124 | static int getaddr_dumpit(struct sk_buff *skb, struct netlink_callback *cb) | 124 | static int getaddr_dumpit(struct sk_buff *skb, struct netlink_callback *cb) |
125 | { | 125 | { |
126 | struct net *net = sock_net(skb->sk); | 126 | struct phonet_device_list *pndevs; |
127 | struct phonet_device *pnd; | 127 | struct phonet_device *pnd; |
128 | int dev_idx = 0, dev_start_idx = cb->args[0]; | 128 | int dev_idx = 0, dev_start_idx = cb->args[0]; |
129 | int addr_idx = 0, addr_start_idx = cb->args[1]; | 129 | int addr_idx = 0, addr_start_idx = cb->args[1]; |
130 | 130 | ||
131 | spin_lock_bh(&pndevs.lock); | 131 | pndevs = phonet_device_list(sock_net(skb->sk)); |
132 | list_for_each_entry(pnd, &pndevs.list, list) { | 132 | spin_lock_bh(&pndevs->lock); |
133 | list_for_each_entry(pnd, &pndevs->list, list) { | ||
133 | u8 addr; | 134 | u8 addr; |
134 | 135 | ||
135 | if (!net_eq(dev_net(pnd->netdev), net)) | ||
136 | continue; | ||
137 | if (dev_idx > dev_start_idx) | 136 | if (dev_idx > dev_start_idx) |
138 | addr_start_idx = 0; | 137 | addr_start_idx = 0; |
139 | if (dev_idx++ < dev_start_idx) | 138 | if (dev_idx++ < dev_start_idx) |
@@ -153,16 +152,21 @@ static int getaddr_dumpit(struct sk_buff *skb, struct netlink_callback *cb) | |||
153 | } | 152 | } |
154 | 153 | ||
155 | out: | 154 | out: |
156 | spin_unlock_bh(&pndevs.lock); | 155 | spin_unlock_bh(&pndevs->lock); |
157 | cb->args[0] = dev_idx; | 156 | cb->args[0] = dev_idx; |
158 | cb->args[1] = addr_idx; | 157 | cb->args[1] = addr_idx; |
159 | 158 | ||
160 | return skb->len; | 159 | return skb->len; |
161 | } | 160 | } |
162 | 161 | ||
163 | void __init phonet_netlink_register(void) | 162 | int __init phonet_netlink_register(void) |
164 | { | 163 | { |
165 | rtnl_register(PF_PHONET, RTM_NEWADDR, addr_doit, NULL); | 164 | int err = __rtnl_register(PF_PHONET, RTM_NEWADDR, addr_doit, NULL); |
166 | rtnl_register(PF_PHONET, RTM_DELADDR, addr_doit, NULL); | 165 | if (err) |
167 | rtnl_register(PF_PHONET, RTM_GETADDR, NULL, getaddr_dumpit); | 166 | return err; |
167 | |||
168 | /* Further __rtnl_register() cannot fail */ | ||
169 | __rtnl_register(PF_PHONET, RTM_DELADDR, addr_doit, NULL); | ||
170 | __rtnl_register(PF_PHONET, RTM_GETADDR, NULL, getaddr_dumpit); | ||
171 | return 0; | ||
168 | } | 172 | } |