tipc: involve namespace infrastructure
[deliverable/linux.git] / net / tipc / bearer.c
CommitLineData
b97bf3fd
PL
1/*
2 * net/tipc/bearer.c: TIPC bearer code
c4307285 3 *
0655f6a8 4 * Copyright (c) 1996-2006, 2013-2014, Ericsson AB
e4d050cb 5 * Copyright (c) 2004-2006, 2010-2013, Wind River Systems
b97bf3fd
PL
6 * All rights reserved.
7 *
9ea1fd3c 8 * Redistribution and use in source and binary forms, with or without
b97bf3fd
PL
9 * modification, are permitted provided that the following conditions are met:
10 *
9ea1fd3c
PL
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the names of the copyright holders nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
b97bf3fd 19 *
9ea1fd3c
PL
20 * Alternatively, this software may be distributed under the terms of the
21 * GNU General Public License ("GPL") version 2 as published by the Free
22 * Software Foundation.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
b97bf3fd
PL
34 * POSSIBILITY OF SUCH DAMAGE.
35 */
36
37#include "core.h"
38#include "config.h"
b97bf3fd 39#include "bearer.h"
0655f6a8 40#include "link.h"
b97bf3fd 41#include "discover.h"
b97bf3fd 42
a29a194a 43#define MAX_ADDR_STR 60
b97bf3fd 44
ef72a7e0 45static struct tipc_media * const media_info_array[] = {
5702dbab
JPM
46 &eth_media_info,
47#ifdef CONFIG_TIPC_MEDIA_IB
48 &ib_media_info,
49#endif
50 NULL
51};
b97bf3fd 52
0655f6a8
RA
53static const struct nla_policy
54tipc_nl_bearer_policy[TIPC_NLA_BEARER_MAX + 1] = {
55 [TIPC_NLA_BEARER_UNSPEC] = { .type = NLA_UNSPEC },
56 [TIPC_NLA_BEARER_NAME] = {
57 .type = NLA_STRING,
58 .len = TIPC_MAX_BEARER_NAME
59 },
60 [TIPC_NLA_BEARER_PROP] = { .type = NLA_NESTED },
61 [TIPC_NLA_BEARER_DOMAIN] = { .type = NLA_U32 }
62};
63
46f15c67
RA
64static const struct nla_policy tipc_nl_media_policy[TIPC_NLA_MEDIA_MAX + 1] = {
65 [TIPC_NLA_MEDIA_UNSPEC] = { .type = NLA_UNSPEC },
66 [TIPC_NLA_MEDIA_NAME] = { .type = NLA_STRING },
67 [TIPC_NLA_MEDIA_PROP] = { .type = NLA_NESTED }
68};
69
f8322dfc 70struct tipc_bearer __rcu *bearer_list[MAX_BEARERS + 1];
b97bf3fd 71
7d33939f 72static void bearer_disable(struct tipc_bearer *b_ptr, bool shutting_down);
3a777ff8 73
b97bf3fd 74/**
5c216e1d 75 * tipc_media_find - locates specified media object by name
b97bf3fd 76 */
358a0d1c 77struct tipc_media *tipc_media_find(const char *name)
b97bf3fd 78{
b97bf3fd
PL
79 u32 i;
80
ef72a7e0
JPM
81 for (i = 0; media_info_array[i] != NULL; i++) {
82 if (!strcmp(media_info_array[i]->name, name))
5702dbab 83 break;
b97bf3fd 84 }
ef72a7e0 85 return media_info_array[i];
b97bf3fd
PL
86}
87
c79be454
AS
88/**
89 * media_find_id - locates specified media object by type identifier
90 */
358a0d1c 91static struct tipc_media *media_find_id(u8 type)
c79be454
AS
92{
93 u32 i;
94
ef72a7e0
JPM
95 for (i = 0; media_info_array[i] != NULL; i++) {
96 if (media_info_array[i]->type_id == type)
5702dbab 97 break;
c79be454 98 }
ef72a7e0 99 return media_info_array[i];
b97bf3fd
PL
100}
101
102/**
4323add6 103 * tipc_media_addr_printf - record media address in print buffer
b97bf3fd 104 */
dc1aed37 105void tipc_media_addr_printf(char *buf, int len, struct tipc_media_addr *a)
b97bf3fd 106{
c61b666e 107 char addr_str[MAX_ADDR_STR];
358a0d1c 108 struct tipc_media *m_ptr;
dc1aed37 109 int ret;
b97bf3fd 110
3d749a6a 111 m_ptr = media_find_id(a->media_id);
b97bf3fd 112
c61b666e 113 if (m_ptr && !m_ptr->addr2str(a, addr_str, sizeof(addr_str)))
dc1aed37 114 ret = tipc_snprintf(buf, len, "%s(%s)", m_ptr->name, addr_str);
c61b666e 115 else {
c61b666e 116 u32 i;
b97bf3fd 117
dc1aed37 118 ret = tipc_snprintf(buf, len, "UNKNOWN(%u)", a->media_id);
3d749a6a 119 for (i = 0; i < sizeof(a->value); i++)
dc1aed37
EH
120 ret += tipc_snprintf(buf - ret, len + ret,
121 "-%02x", a->value[i]);
b97bf3fd
PL
122 }
123}
124
125/**
4323add6 126 * tipc_media_get_names - record names of registered media in buffer
b97bf3fd 127 */
4323add6 128struct sk_buff *tipc_media_get_names(void)
b97bf3fd
PL
129{
130 struct sk_buff *buf;
b97bf3fd
PL
131 int i;
132
4323add6 133 buf = tipc_cfg_reply_alloc(MAX_MEDIA * TLV_SPACE(TIPC_MAX_MEDIA_NAME));
b97bf3fd
PL
134 if (!buf)
135 return NULL;
136
ef72a7e0 137 for (i = 0; media_info_array[i] != NULL; i++) {
a31abe8d 138 tipc_cfg_append_tlv(buf, TIPC_TLV_MEDIA_NAME,
ef72a7e0
JPM
139 media_info_array[i]->name,
140 strlen(media_info_array[i]->name) + 1);
b97bf3fd 141 }
b97bf3fd
PL
142 return buf;
143}
144
145/**
146 * bearer_name_validate - validate & (optionally) deconstruct bearer name
2c53040f
BH
147 * @name: ptr to bearer name string
148 * @name_parts: ptr to area for bearer name components (or NULL if not needed)
c4307285 149 *
b97bf3fd
PL
150 * Returns 1 if bearer name is valid, otherwise 0.
151 */
c4307285 152static int bearer_name_validate(const char *name,
f19765f4 153 struct tipc_bearer_names *name_parts)
b97bf3fd
PL
154{
155 char name_copy[TIPC_MAX_BEARER_NAME];
156 char *media_name;
157 char *if_name;
158 u32 media_len;
159 u32 if_len;
160
161 /* copy bearer name & ensure length is OK */
b97bf3fd
PL
162 name_copy[TIPC_MAX_BEARER_NAME - 1] = 0;
163 /* need above in case non-Posix strncpy() doesn't pad with nulls */
164 strncpy(name_copy, name, TIPC_MAX_BEARER_NAME);
165 if (name_copy[TIPC_MAX_BEARER_NAME - 1] != 0)
166 return 0;
167
168 /* ensure all component parts of bearer name are present */
b97bf3fd 169 media_name = name_copy;
2db9983a
AS
170 if_name = strchr(media_name, ':');
171 if (if_name == NULL)
b97bf3fd
PL
172 return 0;
173 *(if_name++) = 0;
174 media_len = if_name - media_name;
175 if_len = strlen(if_name) + 1;
176
177 /* validate component parts of bearer name */
c4307285 178 if ((media_len <= 1) || (media_len > TIPC_MAX_MEDIA_NAME) ||
fc073938 179 (if_len <= 1) || (if_len > TIPC_MAX_IF_NAME))
b97bf3fd
PL
180 return 0;
181
182 /* return bearer name components, if necessary */
b97bf3fd
PL
183 if (name_parts) {
184 strcpy(name_parts->media_name, media_name);
185 strcpy(name_parts->if_name, if_name);
186 }
187 return 1;
188}
189
190/**
5c216e1d 191 * tipc_bearer_find - locates bearer object with matching bearer name
b97bf3fd 192 */
5c216e1d 193struct tipc_bearer *tipc_bearer_find(const char *name)
b97bf3fd 194{
2d627b92 195 struct tipc_bearer *b_ptr;
b97bf3fd
PL
196 u32 i;
197
3874ccbb 198 for (i = 0; i < MAX_BEARERS; i++) {
f8322dfc 199 b_ptr = rtnl_dereference(bearer_list[i]);
f47de12b 200 if (b_ptr && (!strcmp(b_ptr->name, name)))
b97bf3fd
PL
201 return b_ptr;
202 }
1fc54d8f 203 return NULL;
b97bf3fd
PL
204}
205
206/**
4323add6 207 * tipc_bearer_get_names - record names of bearers in buffer
b97bf3fd 208 */
4323add6 209struct sk_buff *tipc_bearer_get_names(void)
b97bf3fd
PL
210{
211 struct sk_buff *buf;
ef72a7e0 212 struct tipc_bearer *b;
b97bf3fd
PL
213 int i, j;
214
4323add6 215 buf = tipc_cfg_reply_alloc(MAX_BEARERS * TLV_SPACE(TIPC_MAX_BEARER_NAME));
b97bf3fd
PL
216 if (!buf)
217 return NULL;
218
ef72a7e0 219 for (i = 0; media_info_array[i] != NULL; i++) {
b97bf3fd 220 for (j = 0; j < MAX_BEARERS; j++) {
f8322dfc 221 b = rtnl_dereference(bearer_list[j]);
3874ccbb
YX
222 if (!b)
223 continue;
f47de12b 224 if (b->media == media_info_array[i]) {
c4307285 225 tipc_cfg_append_tlv(buf, TIPC_TLV_BEARER_NAME,
ef72a7e0
JPM
226 b->name,
227 strlen(b->name) + 1);
b97bf3fd
PL
228 }
229 }
230 }
b97bf3fd
PL
231 return buf;
232}
233
7a2f7d18 234void tipc_bearer_add_dest(u32 bearer_id, u32 dest)
b97bf3fd 235{
7a2f7d18
YX
236 struct tipc_bearer *b_ptr;
237
238 rcu_read_lock();
239 b_ptr = rcu_dereference_rtnl(bearer_list[bearer_id]);
240 if (b_ptr) {
28dd9418 241 tipc_bcbearer_sort(&b_ptr->nodes, dest, true);
7a2f7d18
YX
242 tipc_disc_add_dest(b_ptr->link_req);
243 }
244 rcu_read_unlock();
b97bf3fd
PL
245}
246
7a2f7d18 247void tipc_bearer_remove_dest(u32 bearer_id, u32 dest)
b97bf3fd 248{
7a2f7d18
YX
249 struct tipc_bearer *b_ptr;
250
251 rcu_read_lock();
252 b_ptr = rcu_dereference_rtnl(bearer_list[bearer_id]);
253 if (b_ptr) {
28dd9418 254 tipc_bcbearer_sort(&b_ptr->nodes, dest, false);
7a2f7d18
YX
255 tipc_disc_remove_dest(b_ptr->link_req);
256 }
257 rcu_read_unlock();
b97bf3fd
PL
258}
259
b97bf3fd
PL
260/**
261 * tipc_enable_bearer - enable bearer with the given name
c4307285 262 */
c93d3baa
YX
263int tipc_enable_bearer(struct net *net, const char *name, u32 disc_domain,
264 u32 priority)
b97bf3fd 265{
2d627b92 266 struct tipc_bearer *b_ptr;
358a0d1c 267 struct tipc_media *m_ptr;
f19765f4 268 struct tipc_bearer_names b_names;
b97bf3fd
PL
269 char addr_string[16];
270 u32 bearer_id;
271 u32 with_this_prio;
272 u32 i;
273 int res = -EINVAL;
274
b58343f9 275 if (!tipc_own_addr) {
2cf8aa19
EH
276 pr_warn("Bearer <%s> rejected, not supported in standalone mode\n",
277 name);
b97bf3fd 278 return -ENOPROTOOPT;
a10bd924 279 }
f19765f4 280 if (!bearer_name_validate(name, &b_names)) {
2cf8aa19 281 pr_warn("Bearer <%s> rejected, illegal name\n", name);
16cb4b33 282 return -EINVAL;
a10bd924 283 }
66e019a6
AS
284 if (tipc_addr_domain_valid(disc_domain) &&
285 (disc_domain != tipc_own_addr)) {
286 if (tipc_in_scope(disc_domain, tipc_own_addr)) {
287 disc_domain = tipc_own_addr & TIPC_CLUSTER_MASK;
288 res = 0; /* accept any node in own cluster */
336ebf5b 289 } else if (in_own_cluster_exact(disc_domain))
66e019a6
AS
290 res = 0; /* accept specified node in own cluster */
291 }
292 if (res) {
2cf8aa19
EH
293 pr_warn("Bearer <%s> rejected, illegal discovery domain\n",
294 name);
a10bd924
AS
295 return -EINVAL;
296 }
9efde4a0 297 if ((priority > TIPC_MAX_LINK_PRI) &&
a10bd924 298 (priority != TIPC_MEDIA_LINK_PRI)) {
2cf8aa19 299 pr_warn("Bearer <%s> rejected, illegal priority\n", name);
b97bf3fd 300 return -EINVAL;
a10bd924 301 }
b97bf3fd 302
f19765f4 303 m_ptr = tipc_media_find(b_names.media_name);
b97bf3fd 304 if (!m_ptr) {
2cf8aa19
EH
305 pr_warn("Bearer <%s> rejected, media <%s> not registered\n",
306 name, b_names.media_name);
7216cd94 307 return -EINVAL;
b97bf3fd 308 }
16cb4b33
PL
309
310 if (priority == TIPC_MEDIA_LINK_PRI)
b97bf3fd
PL
311 priority = m_ptr->priority;
312
313restart:
314 bearer_id = MAX_BEARERS;
315 with_this_prio = 1;
316 for (i = MAX_BEARERS; i-- != 0; ) {
f8322dfc 317 b_ptr = rtnl_dereference(bearer_list[i]);
f47de12b 318 if (!b_ptr) {
b97bf3fd
PL
319 bearer_id = i;
320 continue;
321 }
3874ccbb 322 if (!strcmp(name, b_ptr->name)) {
2cf8aa19
EH
323 pr_warn("Bearer <%s> rejected, already enabled\n",
324 name);
7216cd94 325 return -EINVAL;
b97bf3fd 326 }
3874ccbb 327 if ((b_ptr->priority == priority) &&
b97bf3fd
PL
328 (++with_this_prio > 2)) {
329 if (priority-- == 0) {
2cf8aa19
EH
330 pr_warn("Bearer <%s> rejected, duplicate priority\n",
331 name);
7216cd94 332 return -EINVAL;
b97bf3fd 333 }
2cf8aa19
EH
334 pr_warn("Bearer <%s> priority adjustment required %u->%u\n",
335 name, priority + 1, priority);
b97bf3fd
PL
336 goto restart;
337 }
338 }
339 if (bearer_id >= MAX_BEARERS) {
2cf8aa19
EH
340 pr_warn("Bearer <%s> rejected, bearer limit reached (%u)\n",
341 name, MAX_BEARERS);
7216cd94 342 return -EINVAL;
b97bf3fd
PL
343 }
344
3874ccbb 345 b_ptr = kzalloc(sizeof(*b_ptr), GFP_ATOMIC);
7216cd94
YX
346 if (!b_ptr)
347 return -ENOMEM;
348
2d627b92 349 strcpy(b_ptr->name, name);
e4d050cb 350 b_ptr->media = m_ptr;
4babbaa8 351 res = m_ptr->enable_media(b_ptr);
b97bf3fd 352 if (res) {
2cf8aa19
EH
353 pr_warn("Bearer <%s> rejected, enable failure (%d)\n",
354 name, -res);
7216cd94 355 return -EINVAL;
b97bf3fd
PL
356 }
357
358 b_ptr->identity = bearer_id;
5c216e1d
AS
359 b_ptr->tolerance = m_ptr->tolerance;
360 b_ptr->window = m_ptr->window;
a21a584d 361 b_ptr->domain = disc_domain;
b97bf3fd 362 b_ptr->net_plane = bearer_id + 'A';
b97bf3fd 363 b_ptr->priority = priority;
3a777ff8 364
c93d3baa 365 res = tipc_disc_create(net, b_ptr, &b_ptr->bcast_addr);
3a777ff8 366 if (res) {
7d33939f 367 bearer_disable(b_ptr, false);
2cf8aa19
EH
368 pr_warn("Bearer <%s> rejected, discovery object creation failed\n",
369 name);
7216cd94 370 return -EINVAL;
3a777ff8 371 }
3874ccbb 372
f8322dfc 373 rcu_assign_pointer(bearer_list[bearer_id], b_ptr);
3874ccbb 374
2cf8aa19
EH
375 pr_info("Enabled bearer <%s>, discovery domain %s, priority %u\n",
376 name,
377 tipc_addr_string_fill(addr_string, disc_domain), priority);
b97bf3fd
PL
378 return res;
379}
380
381/**
512137ee 382 * tipc_reset_bearer - Reset all links established over this bearer
b97bf3fd 383 */
c93d3baa 384static int tipc_reset_bearer(struct net *net, struct tipc_bearer *b_ptr)
b97bf3fd 385{
512137ee 386 pr_info("Resetting bearer <%s>\n", b_ptr->name);
c61dd61d 387 tipc_link_reset_list(b_ptr->identity);
c93d3baa 388 tipc_disc_reset(net, b_ptr);
0e35fd5e 389 return 0;
b97bf3fd
PL
390}
391
392/**
617d3c7a 393 * bearer_disable
c4307285 394 *
7216cd94 395 * Note: This routine assumes caller holds RTNL lock.
b97bf3fd 396 */
7d33939f 397static void bearer_disable(struct tipc_bearer *b_ptr, bool shutting_down)
b97bf3fd 398{
3874ccbb
YX
399 u32 i;
400
2cf8aa19 401 pr_info("Disabling bearer <%s>\n", b_ptr->name);
4babbaa8 402 b_ptr->media->disable_media(b_ptr);
d4cca39d 403
a8304529
YX
404 tipc_link_delete_list(b_ptr->identity, shutting_down);
405 if (b_ptr->link_req)
406 tipc_disc_delete(b_ptr->link_req);
3874ccbb
YX
407
408 for (i = 0; i < MAX_BEARERS; i++) {
f8322dfc
YX
409 if (b_ptr == rtnl_dereference(bearer_list[i])) {
410 RCU_INIT_POINTER(bearer_list[i], NULL);
3874ccbb
YX
411 break;
412 }
413 }
f8322dfc 414 kfree_rcu(b_ptr, rcu);
b97bf3fd
PL
415}
416
417int tipc_disable_bearer(const char *name)
418{
2d627b92 419 struct tipc_bearer *b_ptr;
b97bf3fd
PL
420 int res;
421
5c216e1d 422 b_ptr = tipc_bearer_find(name);
ccc901ee 423 if (b_ptr == NULL) {
2cf8aa19 424 pr_warn("Attempt to disable unknown bearer <%s>\n", name);
ccc901ee 425 res = -EINVAL;
28cc937e 426 } else {
7d33939f 427 bearer_disable(b_ptr, false);
28cc937e
AS
428 res = 0;
429 }
b97bf3fd
PL
430 return res;
431}
432
e4d050cb
YX
433int tipc_enable_l2_media(struct tipc_bearer *b)
434{
435 struct net_device *dev;
436 char *driver_name = strchr((const char *)b->name, ':') + 1;
437
438 /* Find device with specified name */
439 dev = dev_get_by_name(&init_net, driver_name);
440 if (!dev)
441 return -ENODEV;
442
38504c28 443 /* Associate TIPC bearer with L2 bearer */
2231c5af 444 rcu_assign_pointer(b->media_ptr, dev);
38504c28 445 memset(&b->bcast_addr, 0, sizeof(b->bcast_addr));
e4d050cb
YX
446 memcpy(b->bcast_addr.value, dev->broadcast, b->media->hwaddr_len);
447 b->bcast_addr.media_id = b->media->type_id;
448 b->bcast_addr.broadcast = 1;
449 b->mtu = dev->mtu;
38504c28 450 b->media->raw2addr(b, &b->addr, (char *)dev->dev_addr);
e4d050cb
YX
451 rcu_assign_pointer(dev->tipc_ptr, b);
452 return 0;
453}
454
38504c28 455/* tipc_disable_l2_media - detach TIPC bearer from an L2 interface
e4d050cb 456 *
38504c28 457 * Mark L2 bearer as inactive so that incoming buffers are thrown away,
e4d050cb
YX
458 * then get worker thread to complete bearer cleanup. (Can't do cleanup
459 * here because cleanup code needs to sleep and caller holds spinlocks.)
460 */
461void tipc_disable_l2_media(struct tipc_bearer *b)
462{
2231c5af
YX
463 struct net_device *dev;
464
465 dev = (struct net_device *)rtnl_dereference(b->media_ptr);
466 RCU_INIT_POINTER(b->media_ptr, NULL);
e4d050cb 467 RCU_INIT_POINTER(dev->tipc_ptr, NULL);
f1c8d8cb 468 synchronize_net();
e4d050cb
YX
469 dev_put(dev);
470}
471
472/**
38504c28 473 * tipc_l2_send_msg - send a TIPC packet out over an L2 interface
e4d050cb 474 * @buf: the packet to be sent
963a1855 475 * @b_ptr: the bearer through which the packet is to be sent
e4d050cb
YX
476 * @dest: peer destination address
477 */
478int tipc_l2_send_msg(struct sk_buff *buf, struct tipc_bearer *b,
479 struct tipc_media_addr *dest)
480{
481 struct sk_buff *clone;
2231c5af 482 struct net_device *dev;
e4d050cb 483 int delta;
2231c5af
YX
484
485 dev = (struct net_device *)rcu_dereference_rtnl(b->media_ptr);
486 if (!dev)
487 return 0;
e4d050cb
YX
488
489 clone = skb_clone(buf, GFP_ATOMIC);
490 if (!clone)
491 return 0;
492
493 delta = dev->hard_header_len - skb_headroom(buf);
494 if ((delta > 0) &&
495 pskb_expand_head(clone, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC)) {
496 kfree_skb(clone);
497 return 0;
498 }
499
500 skb_reset_network_header(clone);
501 clone->dev = dev;
502 clone->protocol = htons(ETH_P_TIPC);
503 dev_hard_header(clone, dev, ETH_P_TIPC, dest->value,
504 dev->dev_addr, clone->len);
505 dev_queue_xmit(clone);
506 return 0;
507}
508
509/* tipc_bearer_send- sends buffer to destination over bearer
510 *
511 * IMPORTANT:
512 * The media send routine must not alter the buffer being passed in
513 * as it may be needed for later retransmission!
514 */
7a2f7d18 515void tipc_bearer_send(u32 bearer_id, struct sk_buff *buf,
e4d050cb
YX
516 struct tipc_media_addr *dest)
517{
7a2f7d18
YX
518 struct tipc_bearer *b_ptr;
519
520 rcu_read_lock();
521 b_ptr = rcu_dereference_rtnl(bearer_list[bearer_id]);
522 if (likely(b_ptr))
523 b_ptr->media->send_msg(buf, b_ptr, dest);
524 rcu_read_unlock();
e4d050cb
YX
525}
526
6e967adf
YX
527/**
528 * tipc_l2_rcv_msg - handle incoming TIPC message from an interface
529 * @buf: the received packet
530 * @dev: the net device that the packet was received on
531 * @pt: the packet_type structure which was used to register this handler
532 * @orig_dev: the original receive net device in case the device is a bond
533 *
534 * Accept only packets explicitly sent to this node, or broadcast packets;
535 * ignores packets sent using interface multicast, and traffic sent to other
536 * nodes (which can happen if interface is running in promiscuous mode).
537 */
538static int tipc_l2_rcv_msg(struct sk_buff *buf, struct net_device *dev,
539 struct packet_type *pt, struct net_device *orig_dev)
540{
541 struct tipc_bearer *b_ptr;
542
6e967adf 543 rcu_read_lock();
ca07fb07 544 b_ptr = rcu_dereference_rtnl(dev->tipc_ptr);
6e967adf
YX
545 if (likely(b_ptr)) {
546 if (likely(buf->pkt_type <= PACKET_BROADCAST)) {
547 buf->next = NULL;
c93d3baa 548 tipc_rcv(dev_net(dev), buf, b_ptr);
6e967adf
YX
549 rcu_read_unlock();
550 return NET_RX_SUCCESS;
551 }
552 }
553 rcu_read_unlock();
554
555 kfree_skb(buf);
556 return NET_RX_DROP;
557}
558
559/**
560 * tipc_l2_device_event - handle device events from network device
561 * @nb: the context of the notification
562 * @evt: the type of event
563 * @ptr: the net device that the event was on
564 *
565 * This function is called by the Ethernet driver in case of link
566 * change event.
567 */
568static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt,
569 void *ptr)
570{
6e967adf 571 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
c93d3baa
YX
572 struct net *net = dev_net(dev);
573 struct tipc_bearer *b_ptr;
6e967adf 574
ca07fb07
YX
575 b_ptr = rtnl_dereference(dev->tipc_ptr);
576 if (!b_ptr)
6e967adf 577 return NOTIFY_DONE;
6e967adf
YX
578
579 b_ptr->mtu = dev->mtu;
580
581 switch (evt) {
582 case NETDEV_CHANGE:
583 if (netif_carrier_ok(dev))
584 break;
585 case NETDEV_DOWN:
586 case NETDEV_CHANGEMTU:
c93d3baa 587 tipc_reset_bearer(net, b_ptr);
a21a584d 588 break;
6e967adf 589 case NETDEV_CHANGEADDR:
38504c28 590 b_ptr->media->raw2addr(b_ptr, &b_ptr->addr,
a21a584d 591 (char *)dev->dev_addr);
c93d3baa 592 tipc_reset_bearer(net, b_ptr);
6e967adf
YX
593 break;
594 case NETDEV_UNREGISTER:
595 case NETDEV_CHANGENAME:
4ae88c94 596 bearer_disable(b_ptr, false);
6e967adf
YX
597 break;
598 }
6e967adf
YX
599 return NOTIFY_OK;
600}
601
602static struct packet_type tipc_packet_type __read_mostly = {
184593c7 603 .type = htons(ETH_P_TIPC),
6e967adf
YX
604 .func = tipc_l2_rcv_msg,
605};
606
607static struct notifier_block notifier = {
608 .notifier_call = tipc_l2_device_event,
609 .priority = 0,
610};
611
612int tipc_bearer_setup(void)
613{
970122fd
YX
614 int err;
615
616 err = register_netdevice_notifier(&notifier);
617 if (err)
618 return err;
6e967adf 619 dev_add_pack(&tipc_packet_type);
970122fd 620 return 0;
6e967adf
YX
621}
622
623void tipc_bearer_cleanup(void)
624{
625 unregister_netdevice_notifier(&notifier);
626 dev_remove_pack(&tipc_packet_type);
627}
b97bf3fd 628
4323add6 629void tipc_bearer_stop(void)
b97bf3fd 630{
3874ccbb 631 struct tipc_bearer *b_ptr;
b97bf3fd
PL
632 u32 i;
633
b97bf3fd 634 for (i = 0; i < MAX_BEARERS; i++) {
f8322dfc 635 b_ptr = rtnl_dereference(bearer_list[i]);
f47de12b 636 if (b_ptr) {
3874ccbb
YX
637 bearer_disable(b_ptr, true);
638 bearer_list[i] = NULL;
639 }
b97bf3fd 640 }
b97bf3fd 641}
0655f6a8 642
35b9dd76 643/* Caller should hold rtnl_lock to protect the bearer */
d8182804
RA
644static int __tipc_nl_add_bearer(struct tipc_nl_msg *msg,
645 struct tipc_bearer *bearer)
35b9dd76
RA
646{
647 void *hdr;
648 struct nlattr *attrs;
649 struct nlattr *prop;
650
651 hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_v2_family,
652 NLM_F_MULTI, TIPC_NL_BEARER_GET);
653 if (!hdr)
654 return -EMSGSIZE;
655
656 attrs = nla_nest_start(msg->skb, TIPC_NLA_BEARER);
657 if (!attrs)
658 goto msg_full;
659
660 if (nla_put_string(msg->skb, TIPC_NLA_BEARER_NAME, bearer->name))
661 goto attr_msg_full;
662
663 prop = nla_nest_start(msg->skb, TIPC_NLA_BEARER_PROP);
664 if (!prop)
665 goto prop_msg_full;
666 if (nla_put_u32(msg->skb, TIPC_NLA_PROP_PRIO, bearer->priority))
667 goto prop_msg_full;
668 if (nla_put_u32(msg->skb, TIPC_NLA_PROP_TOL, bearer->tolerance))
669 goto prop_msg_full;
670 if (nla_put_u32(msg->skb, TIPC_NLA_PROP_WIN, bearer->window))
671 goto prop_msg_full;
672
673 nla_nest_end(msg->skb, prop);
674 nla_nest_end(msg->skb, attrs);
675 genlmsg_end(msg->skb, hdr);
676
677 return 0;
678
679prop_msg_full:
680 nla_nest_cancel(msg->skb, prop);
681attr_msg_full:
682 nla_nest_cancel(msg->skb, attrs);
683msg_full:
684 genlmsg_cancel(msg->skb, hdr);
685
686 return -EMSGSIZE;
687}
688
689int tipc_nl_bearer_dump(struct sk_buff *skb, struct netlink_callback *cb)
690{
691 int err;
692 int i = cb->args[0];
693 struct tipc_bearer *bearer;
694 struct tipc_nl_msg msg;
695
696 if (i == MAX_BEARERS)
697 return 0;
698
699 msg.skb = skb;
700 msg.portid = NETLINK_CB(cb->skb).portid;
701 msg.seq = cb->nlh->nlmsg_seq;
702
703 rtnl_lock();
704 for (i = 0; i < MAX_BEARERS; i++) {
705 bearer = rtnl_dereference(bearer_list[i]);
706 if (!bearer)
707 continue;
708
709 err = __tipc_nl_add_bearer(&msg, bearer);
710 if (err)
711 break;
712 }
713 rtnl_unlock();
714
715 cb->args[0] = i;
716 return skb->len;
717}
718
719int tipc_nl_bearer_get(struct sk_buff *skb, struct genl_info *info)
720{
721 int err;
722 char *name;
723 struct sk_buff *rep;
724 struct tipc_bearer *bearer;
725 struct tipc_nl_msg msg;
726 struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1];
727
728 if (!info->attrs[TIPC_NLA_BEARER])
729 return -EINVAL;
730
731 err = nla_parse_nested(attrs, TIPC_NLA_BEARER_MAX,
732 info->attrs[TIPC_NLA_BEARER],
733 tipc_nl_bearer_policy);
734 if (err)
735 return err;
736
737 if (!attrs[TIPC_NLA_BEARER_NAME])
738 return -EINVAL;
739 name = nla_data(attrs[TIPC_NLA_BEARER_NAME]);
740
741 rep = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
742 if (!rep)
743 return -ENOMEM;
744
745 msg.skb = rep;
746 msg.portid = info->snd_portid;
747 msg.seq = info->snd_seq;
748
749 rtnl_lock();
750 bearer = tipc_bearer_find(name);
751 if (!bearer) {
752 err = -EINVAL;
753 goto err_out;
754 }
755
756 err = __tipc_nl_add_bearer(&msg, bearer);
757 if (err)
758 goto err_out;
759 rtnl_unlock();
760
761 return genlmsg_reply(rep, info);
762err_out:
763 rtnl_unlock();
764 nlmsg_free(rep);
765
766 return err;
767}
768
0655f6a8
RA
769int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info)
770{
771 int err;
772 char *name;
773 struct tipc_bearer *bearer;
774 struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1];
775
776 if (!info->attrs[TIPC_NLA_BEARER])
777 return -EINVAL;
778
779 err = nla_parse_nested(attrs, TIPC_NLA_BEARER_MAX,
780 info->attrs[TIPC_NLA_BEARER],
781 tipc_nl_bearer_policy);
782 if (err)
783 return err;
784
785 if (!attrs[TIPC_NLA_BEARER_NAME])
786 return -EINVAL;
787
788 name = nla_data(attrs[TIPC_NLA_BEARER_NAME]);
789
790 rtnl_lock();
791 bearer = tipc_bearer_find(name);
792 if (!bearer) {
793 rtnl_unlock();
794 return -EINVAL;
795 }
796
797 bearer_disable(bearer, false);
798 rtnl_unlock();
799
800 return 0;
801}
802
803int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info)
804{
c93d3baa 805 struct net *net = genl_info_net(info);
0655f6a8
RA
806 int err;
807 char *bearer;
808 struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1];
809 u32 domain;
810 u32 prio;
811
812 prio = TIPC_MEDIA_LINK_PRI;
813 domain = tipc_own_addr & TIPC_CLUSTER_MASK;
814
815 if (!info->attrs[TIPC_NLA_BEARER])
816 return -EINVAL;
817
818 err = nla_parse_nested(attrs, TIPC_NLA_BEARER_MAX,
819 info->attrs[TIPC_NLA_BEARER],
820 tipc_nl_bearer_policy);
821 if (err)
822 return err;
823
824 if (!attrs[TIPC_NLA_BEARER_NAME])
825 return -EINVAL;
826
827 bearer = nla_data(attrs[TIPC_NLA_BEARER_NAME]);
828
829 if (attrs[TIPC_NLA_BEARER_DOMAIN])
830 domain = nla_get_u32(attrs[TIPC_NLA_BEARER_DOMAIN]);
831
832 if (attrs[TIPC_NLA_BEARER_PROP]) {
833 struct nlattr *props[TIPC_NLA_PROP_MAX + 1];
834
835 err = tipc_nl_parse_link_prop(attrs[TIPC_NLA_BEARER_PROP],
836 props);
837 if (err)
838 return err;
839
840 if (props[TIPC_NLA_PROP_PRIO])
841 prio = nla_get_u32(props[TIPC_NLA_PROP_PRIO]);
842 }
843
844 rtnl_lock();
c93d3baa 845 err = tipc_enable_bearer(net, bearer, domain, prio);
0655f6a8
RA
846 if (err) {
847 rtnl_unlock();
848 return err;
849 }
850 rtnl_unlock();
851
852 return 0;
853}
315c00bc
RA
854
855int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info)
856{
857 int err;
858 char *name;
859 struct tipc_bearer *b;
860 struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1];
861
862 if (!info->attrs[TIPC_NLA_BEARER])
863 return -EINVAL;
864
865 err = nla_parse_nested(attrs, TIPC_NLA_BEARER_MAX,
866 info->attrs[TIPC_NLA_BEARER],
867 tipc_nl_bearer_policy);
868 if (err)
869 return err;
870
871 if (!attrs[TIPC_NLA_BEARER_NAME])
872 return -EINVAL;
873 name = nla_data(attrs[TIPC_NLA_BEARER_NAME]);
874
875 rtnl_lock();
876 b = tipc_bearer_find(name);
877 if (!b) {
878 rtnl_unlock();
879 return -EINVAL;
880 }
881
882 if (attrs[TIPC_NLA_BEARER_PROP]) {
883 struct nlattr *props[TIPC_NLA_PROP_MAX + 1];
884
885 err = tipc_nl_parse_link_prop(attrs[TIPC_NLA_BEARER_PROP],
886 props);
887 if (err) {
888 rtnl_unlock();
889 return err;
890 }
891
892 if (props[TIPC_NLA_PROP_TOL])
893 b->tolerance = nla_get_u32(props[TIPC_NLA_PROP_TOL]);
894 if (props[TIPC_NLA_PROP_PRIO])
895 b->priority = nla_get_u32(props[TIPC_NLA_PROP_PRIO]);
896 if (props[TIPC_NLA_PROP_WIN])
897 b->window = nla_get_u32(props[TIPC_NLA_PROP_WIN]);
898 }
899 rtnl_unlock();
900
901 return 0;
902}
46f15c67 903
d8182804
RA
904static int __tipc_nl_add_media(struct tipc_nl_msg *msg,
905 struct tipc_media *media)
46f15c67
RA
906{
907 void *hdr;
908 struct nlattr *attrs;
909 struct nlattr *prop;
910
911 hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_v2_family,
912 NLM_F_MULTI, TIPC_NL_MEDIA_GET);
913 if (!hdr)
914 return -EMSGSIZE;
915
916 attrs = nla_nest_start(msg->skb, TIPC_NLA_MEDIA);
917 if (!attrs)
918 goto msg_full;
919
920 if (nla_put_string(msg->skb, TIPC_NLA_MEDIA_NAME, media->name))
921 goto attr_msg_full;
922
923 prop = nla_nest_start(msg->skb, TIPC_NLA_MEDIA_PROP);
924 if (!prop)
925 goto prop_msg_full;
926 if (nla_put_u32(msg->skb, TIPC_NLA_PROP_PRIO, media->priority))
927 goto prop_msg_full;
928 if (nla_put_u32(msg->skb, TIPC_NLA_PROP_TOL, media->tolerance))
929 goto prop_msg_full;
930 if (nla_put_u32(msg->skb, TIPC_NLA_PROP_WIN, media->window))
931 goto prop_msg_full;
932
933 nla_nest_end(msg->skb, prop);
934 nla_nest_end(msg->skb, attrs);
935 genlmsg_end(msg->skb, hdr);
936
937 return 0;
938
939prop_msg_full:
940 nla_nest_cancel(msg->skb, prop);
941attr_msg_full:
942 nla_nest_cancel(msg->skb, attrs);
943msg_full:
944 genlmsg_cancel(msg->skb, hdr);
945
946 return -EMSGSIZE;
947}
948
949int tipc_nl_media_dump(struct sk_buff *skb, struct netlink_callback *cb)
950{
951 int err;
952 int i = cb->args[0];
953 struct tipc_nl_msg msg;
954
955 if (i == MAX_MEDIA)
956 return 0;
957
958 msg.skb = skb;
959 msg.portid = NETLINK_CB(cb->skb).portid;
960 msg.seq = cb->nlh->nlmsg_seq;
961
962 rtnl_lock();
963 for (; media_info_array[i] != NULL; i++) {
964 err = __tipc_nl_add_media(&msg, media_info_array[i]);
965 if (err)
966 break;
967 }
968 rtnl_unlock();
969
970 cb->args[0] = i;
971 return skb->len;
972}
973
974int tipc_nl_media_get(struct sk_buff *skb, struct genl_info *info)
975{
976 int err;
977 char *name;
978 struct tipc_nl_msg msg;
979 struct tipc_media *media;
980 struct sk_buff *rep;
981 struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1];
982
983 if (!info->attrs[TIPC_NLA_MEDIA])
984 return -EINVAL;
985
986 err = nla_parse_nested(attrs, TIPC_NLA_MEDIA_MAX,
987 info->attrs[TIPC_NLA_MEDIA],
988 tipc_nl_media_policy);
989 if (err)
990 return err;
991
992 if (!attrs[TIPC_NLA_MEDIA_NAME])
993 return -EINVAL;
994 name = nla_data(attrs[TIPC_NLA_MEDIA_NAME]);
995
996 rep = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
997 if (!rep)
998 return -ENOMEM;
999
1000 msg.skb = rep;
1001 msg.portid = info->snd_portid;
1002 msg.seq = info->snd_seq;
1003
1004 rtnl_lock();
1005 media = tipc_media_find(name);
1006 if (!media) {
1007 err = -EINVAL;
1008 goto err_out;
1009 }
1010
1011 err = __tipc_nl_add_media(&msg, media);
1012 if (err)
1013 goto err_out;
1014 rtnl_unlock();
1015
1016 return genlmsg_reply(rep, info);
1017err_out:
1018 rtnl_unlock();
1019 nlmsg_free(rep);
1020
1021 return err;
1022}
1e55417d
RA
1023
1024int tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info)
1025{
1026 int err;
1027 char *name;
1028 struct tipc_media *m;
1029 struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1];
1030
1031 if (!info->attrs[TIPC_NLA_MEDIA])
1032 return -EINVAL;
1033
1034 err = nla_parse_nested(attrs, TIPC_NLA_MEDIA_MAX,
1035 info->attrs[TIPC_NLA_MEDIA],
1036 tipc_nl_media_policy);
1037
1038 if (!attrs[TIPC_NLA_MEDIA_NAME])
1039 return -EINVAL;
1040 name = nla_data(attrs[TIPC_NLA_MEDIA_NAME]);
1041
1042 rtnl_lock();
1043 m = tipc_media_find(name);
1044 if (!m) {
1045 rtnl_unlock();
1046 return -EINVAL;
1047 }
1048
1049 if (attrs[TIPC_NLA_MEDIA_PROP]) {
1050 struct nlattr *props[TIPC_NLA_PROP_MAX + 1];
1051
1052 err = tipc_nl_parse_link_prop(attrs[TIPC_NLA_MEDIA_PROP],
1053 props);
1054 if (err) {
1055 rtnl_unlock();
1056 return err;
1057 }
1058
1059 if (props[TIPC_NLA_PROP_TOL])
1060 m->tolerance = nla_get_u32(props[TIPC_NLA_PROP_TOL]);
1061 if (props[TIPC_NLA_PROP_PRIO])
1062 m->priority = nla_get_u32(props[TIPC_NLA_PROP_PRIO]);
1063 if (props[TIPC_NLA_PROP_WIN])
1064 m->window = nla_get_u32(props[TIPC_NLA_PROP_WIN]);
1065 }
1066 rtnl_unlock();
1067
1068 return 0;
1069}
This page took 1.000191 seconds and 5 git commands to generate.