tipc: add link stat reset to new netlink api
[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
f8322dfc 64struct tipc_bearer __rcu *bearer_list[MAX_BEARERS + 1];
b97bf3fd 65
7d33939f 66static void bearer_disable(struct tipc_bearer *b_ptr, bool shutting_down);
3a777ff8 67
b97bf3fd 68/**
5c216e1d 69 * tipc_media_find - locates specified media object by name
b97bf3fd 70 */
358a0d1c 71struct tipc_media *tipc_media_find(const char *name)
b97bf3fd 72{
b97bf3fd
PL
73 u32 i;
74
ef72a7e0
JPM
75 for (i = 0; media_info_array[i] != NULL; i++) {
76 if (!strcmp(media_info_array[i]->name, name))
5702dbab 77 break;
b97bf3fd 78 }
ef72a7e0 79 return media_info_array[i];
b97bf3fd
PL
80}
81
c79be454
AS
82/**
83 * media_find_id - locates specified media object by type identifier
84 */
358a0d1c 85static struct tipc_media *media_find_id(u8 type)
c79be454
AS
86{
87 u32 i;
88
ef72a7e0
JPM
89 for (i = 0; media_info_array[i] != NULL; i++) {
90 if (media_info_array[i]->type_id == type)
5702dbab 91 break;
c79be454 92 }
ef72a7e0 93 return media_info_array[i];
b97bf3fd
PL
94}
95
96/**
4323add6 97 * tipc_media_addr_printf - record media address in print buffer
b97bf3fd 98 */
dc1aed37 99void tipc_media_addr_printf(char *buf, int len, struct tipc_media_addr *a)
b97bf3fd 100{
c61b666e 101 char addr_str[MAX_ADDR_STR];
358a0d1c 102 struct tipc_media *m_ptr;
dc1aed37 103 int ret;
b97bf3fd 104
3d749a6a 105 m_ptr = media_find_id(a->media_id);
b97bf3fd 106
c61b666e 107 if (m_ptr && !m_ptr->addr2str(a, addr_str, sizeof(addr_str)))
dc1aed37 108 ret = tipc_snprintf(buf, len, "%s(%s)", m_ptr->name, addr_str);
c61b666e 109 else {
c61b666e 110 u32 i;
b97bf3fd 111
dc1aed37 112 ret = tipc_snprintf(buf, len, "UNKNOWN(%u)", a->media_id);
3d749a6a 113 for (i = 0; i < sizeof(a->value); i++)
dc1aed37
EH
114 ret += tipc_snprintf(buf - ret, len + ret,
115 "-%02x", a->value[i]);
b97bf3fd
PL
116 }
117}
118
119/**
4323add6 120 * tipc_media_get_names - record names of registered media in buffer
b97bf3fd 121 */
4323add6 122struct sk_buff *tipc_media_get_names(void)
b97bf3fd
PL
123{
124 struct sk_buff *buf;
b97bf3fd
PL
125 int i;
126
4323add6 127 buf = tipc_cfg_reply_alloc(MAX_MEDIA * TLV_SPACE(TIPC_MAX_MEDIA_NAME));
b97bf3fd
PL
128 if (!buf)
129 return NULL;
130
ef72a7e0 131 for (i = 0; media_info_array[i] != NULL; i++) {
a31abe8d 132 tipc_cfg_append_tlv(buf, TIPC_TLV_MEDIA_NAME,
ef72a7e0
JPM
133 media_info_array[i]->name,
134 strlen(media_info_array[i]->name) + 1);
b97bf3fd 135 }
b97bf3fd
PL
136 return buf;
137}
138
139/**
140 * bearer_name_validate - validate & (optionally) deconstruct bearer name
2c53040f
BH
141 * @name: ptr to bearer name string
142 * @name_parts: ptr to area for bearer name components (or NULL if not needed)
c4307285 143 *
b97bf3fd
PL
144 * Returns 1 if bearer name is valid, otherwise 0.
145 */
c4307285 146static int bearer_name_validate(const char *name,
f19765f4 147 struct tipc_bearer_names *name_parts)
b97bf3fd
PL
148{
149 char name_copy[TIPC_MAX_BEARER_NAME];
150 char *media_name;
151 char *if_name;
152 u32 media_len;
153 u32 if_len;
154
155 /* copy bearer name & ensure length is OK */
b97bf3fd
PL
156 name_copy[TIPC_MAX_BEARER_NAME - 1] = 0;
157 /* need above in case non-Posix strncpy() doesn't pad with nulls */
158 strncpy(name_copy, name, TIPC_MAX_BEARER_NAME);
159 if (name_copy[TIPC_MAX_BEARER_NAME - 1] != 0)
160 return 0;
161
162 /* ensure all component parts of bearer name are present */
b97bf3fd 163 media_name = name_copy;
2db9983a
AS
164 if_name = strchr(media_name, ':');
165 if (if_name == NULL)
b97bf3fd
PL
166 return 0;
167 *(if_name++) = 0;
168 media_len = if_name - media_name;
169 if_len = strlen(if_name) + 1;
170
171 /* validate component parts of bearer name */
c4307285 172 if ((media_len <= 1) || (media_len > TIPC_MAX_MEDIA_NAME) ||
fc073938 173 (if_len <= 1) || (if_len > TIPC_MAX_IF_NAME))
b97bf3fd
PL
174 return 0;
175
176 /* return bearer name components, if necessary */
b97bf3fd
PL
177 if (name_parts) {
178 strcpy(name_parts->media_name, media_name);
179 strcpy(name_parts->if_name, if_name);
180 }
181 return 1;
182}
183
184/**
5c216e1d 185 * tipc_bearer_find - locates bearer object with matching bearer name
b97bf3fd 186 */
5c216e1d 187struct tipc_bearer *tipc_bearer_find(const char *name)
b97bf3fd 188{
2d627b92 189 struct tipc_bearer *b_ptr;
b97bf3fd
PL
190 u32 i;
191
3874ccbb 192 for (i = 0; i < MAX_BEARERS; i++) {
f8322dfc 193 b_ptr = rtnl_dereference(bearer_list[i]);
f47de12b 194 if (b_ptr && (!strcmp(b_ptr->name, name)))
b97bf3fd
PL
195 return b_ptr;
196 }
1fc54d8f 197 return NULL;
b97bf3fd
PL
198}
199
200/**
4323add6 201 * tipc_bearer_get_names - record names of bearers in buffer
b97bf3fd 202 */
4323add6 203struct sk_buff *tipc_bearer_get_names(void)
b97bf3fd
PL
204{
205 struct sk_buff *buf;
ef72a7e0 206 struct tipc_bearer *b;
b97bf3fd
PL
207 int i, j;
208
4323add6 209 buf = tipc_cfg_reply_alloc(MAX_BEARERS * TLV_SPACE(TIPC_MAX_BEARER_NAME));
b97bf3fd
PL
210 if (!buf)
211 return NULL;
212
ef72a7e0 213 for (i = 0; media_info_array[i] != NULL; i++) {
b97bf3fd 214 for (j = 0; j < MAX_BEARERS; j++) {
f8322dfc 215 b = rtnl_dereference(bearer_list[j]);
3874ccbb
YX
216 if (!b)
217 continue;
f47de12b 218 if (b->media == media_info_array[i]) {
c4307285 219 tipc_cfg_append_tlv(buf, TIPC_TLV_BEARER_NAME,
ef72a7e0
JPM
220 b->name,
221 strlen(b->name) + 1);
b97bf3fd
PL
222 }
223 }
224 }
b97bf3fd
PL
225 return buf;
226}
227
7a2f7d18 228void tipc_bearer_add_dest(u32 bearer_id, u32 dest)
b97bf3fd 229{
7a2f7d18
YX
230 struct tipc_bearer *b_ptr;
231
232 rcu_read_lock();
233 b_ptr = rcu_dereference_rtnl(bearer_list[bearer_id]);
234 if (b_ptr) {
28dd9418 235 tipc_bcbearer_sort(&b_ptr->nodes, dest, true);
7a2f7d18
YX
236 tipc_disc_add_dest(b_ptr->link_req);
237 }
238 rcu_read_unlock();
b97bf3fd
PL
239}
240
7a2f7d18 241void tipc_bearer_remove_dest(u32 bearer_id, u32 dest)
b97bf3fd 242{
7a2f7d18
YX
243 struct tipc_bearer *b_ptr;
244
245 rcu_read_lock();
246 b_ptr = rcu_dereference_rtnl(bearer_list[bearer_id]);
247 if (b_ptr) {
28dd9418 248 tipc_bcbearer_sort(&b_ptr->nodes, dest, false);
7a2f7d18
YX
249 tipc_disc_remove_dest(b_ptr->link_req);
250 }
251 rcu_read_unlock();
b97bf3fd
PL
252}
253
b97bf3fd
PL
254/**
255 * tipc_enable_bearer - enable bearer with the given name
c4307285 256 */
50d3e639 257int tipc_enable_bearer(const char *name, u32 disc_domain, u32 priority)
b97bf3fd 258{
2d627b92 259 struct tipc_bearer *b_ptr;
358a0d1c 260 struct tipc_media *m_ptr;
f19765f4 261 struct tipc_bearer_names b_names;
b97bf3fd
PL
262 char addr_string[16];
263 u32 bearer_id;
264 u32 with_this_prio;
265 u32 i;
266 int res = -EINVAL;
267
b58343f9 268 if (!tipc_own_addr) {
2cf8aa19
EH
269 pr_warn("Bearer <%s> rejected, not supported in standalone mode\n",
270 name);
b97bf3fd 271 return -ENOPROTOOPT;
a10bd924 272 }
f19765f4 273 if (!bearer_name_validate(name, &b_names)) {
2cf8aa19 274 pr_warn("Bearer <%s> rejected, illegal name\n", name);
16cb4b33 275 return -EINVAL;
a10bd924 276 }
66e019a6
AS
277 if (tipc_addr_domain_valid(disc_domain) &&
278 (disc_domain != tipc_own_addr)) {
279 if (tipc_in_scope(disc_domain, tipc_own_addr)) {
280 disc_domain = tipc_own_addr & TIPC_CLUSTER_MASK;
281 res = 0; /* accept any node in own cluster */
336ebf5b 282 } else if (in_own_cluster_exact(disc_domain))
66e019a6
AS
283 res = 0; /* accept specified node in own cluster */
284 }
285 if (res) {
2cf8aa19
EH
286 pr_warn("Bearer <%s> rejected, illegal discovery domain\n",
287 name);
a10bd924
AS
288 return -EINVAL;
289 }
9efde4a0 290 if ((priority > TIPC_MAX_LINK_PRI) &&
a10bd924 291 (priority != TIPC_MEDIA_LINK_PRI)) {
2cf8aa19 292 pr_warn("Bearer <%s> rejected, illegal priority\n", name);
b97bf3fd 293 return -EINVAL;
a10bd924 294 }
b97bf3fd 295
f19765f4 296 m_ptr = tipc_media_find(b_names.media_name);
b97bf3fd 297 if (!m_ptr) {
2cf8aa19
EH
298 pr_warn("Bearer <%s> rejected, media <%s> not registered\n",
299 name, b_names.media_name);
7216cd94 300 return -EINVAL;
b97bf3fd 301 }
16cb4b33
PL
302
303 if (priority == TIPC_MEDIA_LINK_PRI)
b97bf3fd
PL
304 priority = m_ptr->priority;
305
306restart:
307 bearer_id = MAX_BEARERS;
308 with_this_prio = 1;
309 for (i = MAX_BEARERS; i-- != 0; ) {
f8322dfc 310 b_ptr = rtnl_dereference(bearer_list[i]);
f47de12b 311 if (!b_ptr) {
b97bf3fd
PL
312 bearer_id = i;
313 continue;
314 }
3874ccbb 315 if (!strcmp(name, b_ptr->name)) {
2cf8aa19
EH
316 pr_warn("Bearer <%s> rejected, already enabled\n",
317 name);
7216cd94 318 return -EINVAL;
b97bf3fd 319 }
3874ccbb 320 if ((b_ptr->priority == priority) &&
b97bf3fd
PL
321 (++with_this_prio > 2)) {
322 if (priority-- == 0) {
2cf8aa19
EH
323 pr_warn("Bearer <%s> rejected, duplicate priority\n",
324 name);
7216cd94 325 return -EINVAL;
b97bf3fd 326 }
2cf8aa19
EH
327 pr_warn("Bearer <%s> priority adjustment required %u->%u\n",
328 name, priority + 1, priority);
b97bf3fd
PL
329 goto restart;
330 }
331 }
332 if (bearer_id >= MAX_BEARERS) {
2cf8aa19
EH
333 pr_warn("Bearer <%s> rejected, bearer limit reached (%u)\n",
334 name, MAX_BEARERS);
7216cd94 335 return -EINVAL;
b97bf3fd
PL
336 }
337
3874ccbb 338 b_ptr = kzalloc(sizeof(*b_ptr), GFP_ATOMIC);
7216cd94
YX
339 if (!b_ptr)
340 return -ENOMEM;
341
2d627b92 342 strcpy(b_ptr->name, name);
e4d050cb 343 b_ptr->media = m_ptr;
4babbaa8 344 res = m_ptr->enable_media(b_ptr);
b97bf3fd 345 if (res) {
2cf8aa19
EH
346 pr_warn("Bearer <%s> rejected, enable failure (%d)\n",
347 name, -res);
7216cd94 348 return -EINVAL;
b97bf3fd
PL
349 }
350
351 b_ptr->identity = bearer_id;
5c216e1d
AS
352 b_ptr->tolerance = m_ptr->tolerance;
353 b_ptr->window = m_ptr->window;
a21a584d 354 b_ptr->domain = disc_domain;
b97bf3fd 355 b_ptr->net_plane = bearer_id + 'A';
b97bf3fd 356 b_ptr->priority = priority;
3a777ff8 357
16470111 358 res = tipc_disc_create(b_ptr, &b_ptr->bcast_addr);
3a777ff8 359 if (res) {
7d33939f 360 bearer_disable(b_ptr, false);
2cf8aa19
EH
361 pr_warn("Bearer <%s> rejected, discovery object creation failed\n",
362 name);
7216cd94 363 return -EINVAL;
3a777ff8 364 }
3874ccbb 365
f8322dfc 366 rcu_assign_pointer(bearer_list[bearer_id], b_ptr);
3874ccbb 367
2cf8aa19
EH
368 pr_info("Enabled bearer <%s>, discovery domain %s, priority %u\n",
369 name,
370 tipc_addr_string_fill(addr_string, disc_domain), priority);
b97bf3fd
PL
371 return res;
372}
373
374/**
512137ee 375 * tipc_reset_bearer - Reset all links established over this bearer
b97bf3fd 376 */
6e967adf 377static int tipc_reset_bearer(struct tipc_bearer *b_ptr)
b97bf3fd 378{
512137ee 379 pr_info("Resetting bearer <%s>\n", b_ptr->name);
c61dd61d 380 tipc_link_reset_list(b_ptr->identity);
a8b9b96e 381 tipc_disc_reset(b_ptr);
0e35fd5e 382 return 0;
b97bf3fd
PL
383}
384
385/**
617d3c7a 386 * bearer_disable
c4307285 387 *
7216cd94 388 * Note: This routine assumes caller holds RTNL lock.
b97bf3fd 389 */
7d33939f 390static void bearer_disable(struct tipc_bearer *b_ptr, bool shutting_down)
b97bf3fd 391{
3874ccbb
YX
392 u32 i;
393
2cf8aa19 394 pr_info("Disabling bearer <%s>\n", b_ptr->name);
4babbaa8 395 b_ptr->media->disable_media(b_ptr);
d4cca39d 396
a8304529
YX
397 tipc_link_delete_list(b_ptr->identity, shutting_down);
398 if (b_ptr->link_req)
399 tipc_disc_delete(b_ptr->link_req);
3874ccbb
YX
400
401 for (i = 0; i < MAX_BEARERS; i++) {
f8322dfc
YX
402 if (b_ptr == rtnl_dereference(bearer_list[i])) {
403 RCU_INIT_POINTER(bearer_list[i], NULL);
3874ccbb
YX
404 break;
405 }
406 }
f8322dfc 407 kfree_rcu(b_ptr, rcu);
b97bf3fd
PL
408}
409
410int tipc_disable_bearer(const char *name)
411{
2d627b92 412 struct tipc_bearer *b_ptr;
b97bf3fd
PL
413 int res;
414
5c216e1d 415 b_ptr = tipc_bearer_find(name);
ccc901ee 416 if (b_ptr == NULL) {
2cf8aa19 417 pr_warn("Attempt to disable unknown bearer <%s>\n", name);
ccc901ee 418 res = -EINVAL;
28cc937e 419 } else {
7d33939f 420 bearer_disable(b_ptr, false);
28cc937e
AS
421 res = 0;
422 }
b97bf3fd
PL
423 return res;
424}
425
e4d050cb
YX
426int tipc_enable_l2_media(struct tipc_bearer *b)
427{
428 struct net_device *dev;
429 char *driver_name = strchr((const char *)b->name, ':') + 1;
430
431 /* Find device with specified name */
432 dev = dev_get_by_name(&init_net, driver_name);
433 if (!dev)
434 return -ENODEV;
435
38504c28 436 /* Associate TIPC bearer with L2 bearer */
2231c5af 437 rcu_assign_pointer(b->media_ptr, dev);
38504c28 438 memset(&b->bcast_addr, 0, sizeof(b->bcast_addr));
e4d050cb
YX
439 memcpy(b->bcast_addr.value, dev->broadcast, b->media->hwaddr_len);
440 b->bcast_addr.media_id = b->media->type_id;
441 b->bcast_addr.broadcast = 1;
442 b->mtu = dev->mtu;
38504c28 443 b->media->raw2addr(b, &b->addr, (char *)dev->dev_addr);
e4d050cb
YX
444 rcu_assign_pointer(dev->tipc_ptr, b);
445 return 0;
446}
447
38504c28 448/* tipc_disable_l2_media - detach TIPC bearer from an L2 interface
e4d050cb 449 *
38504c28 450 * Mark L2 bearer as inactive so that incoming buffers are thrown away,
e4d050cb
YX
451 * then get worker thread to complete bearer cleanup. (Can't do cleanup
452 * here because cleanup code needs to sleep and caller holds spinlocks.)
453 */
454void tipc_disable_l2_media(struct tipc_bearer *b)
455{
2231c5af
YX
456 struct net_device *dev;
457
458 dev = (struct net_device *)rtnl_dereference(b->media_ptr);
459 RCU_INIT_POINTER(b->media_ptr, NULL);
e4d050cb 460 RCU_INIT_POINTER(dev->tipc_ptr, NULL);
f1c8d8cb 461 synchronize_net();
e4d050cb
YX
462 dev_put(dev);
463}
464
465/**
38504c28 466 * tipc_l2_send_msg - send a TIPC packet out over an L2 interface
e4d050cb 467 * @buf: the packet to be sent
963a1855 468 * @b_ptr: the bearer through which the packet is to be sent
e4d050cb
YX
469 * @dest: peer destination address
470 */
471int tipc_l2_send_msg(struct sk_buff *buf, struct tipc_bearer *b,
472 struct tipc_media_addr *dest)
473{
474 struct sk_buff *clone;
2231c5af 475 struct net_device *dev;
e4d050cb 476 int delta;
2231c5af
YX
477
478 dev = (struct net_device *)rcu_dereference_rtnl(b->media_ptr);
479 if (!dev)
480 return 0;
e4d050cb
YX
481
482 clone = skb_clone(buf, GFP_ATOMIC);
483 if (!clone)
484 return 0;
485
486 delta = dev->hard_header_len - skb_headroom(buf);
487 if ((delta > 0) &&
488 pskb_expand_head(clone, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC)) {
489 kfree_skb(clone);
490 return 0;
491 }
492
493 skb_reset_network_header(clone);
494 clone->dev = dev;
495 clone->protocol = htons(ETH_P_TIPC);
496 dev_hard_header(clone, dev, ETH_P_TIPC, dest->value,
497 dev->dev_addr, clone->len);
498 dev_queue_xmit(clone);
499 return 0;
500}
501
502/* tipc_bearer_send- sends buffer to destination over bearer
503 *
504 * IMPORTANT:
505 * The media send routine must not alter the buffer being passed in
506 * as it may be needed for later retransmission!
507 */
7a2f7d18 508void tipc_bearer_send(u32 bearer_id, struct sk_buff *buf,
e4d050cb
YX
509 struct tipc_media_addr *dest)
510{
7a2f7d18
YX
511 struct tipc_bearer *b_ptr;
512
513 rcu_read_lock();
514 b_ptr = rcu_dereference_rtnl(bearer_list[bearer_id]);
515 if (likely(b_ptr))
516 b_ptr->media->send_msg(buf, b_ptr, dest);
517 rcu_read_unlock();
e4d050cb
YX
518}
519
6e967adf
YX
520/**
521 * tipc_l2_rcv_msg - handle incoming TIPC message from an interface
522 * @buf: the received packet
523 * @dev: the net device that the packet was received on
524 * @pt: the packet_type structure which was used to register this handler
525 * @orig_dev: the original receive net device in case the device is a bond
526 *
527 * Accept only packets explicitly sent to this node, or broadcast packets;
528 * ignores packets sent using interface multicast, and traffic sent to other
529 * nodes (which can happen if interface is running in promiscuous mode).
530 */
531static int tipc_l2_rcv_msg(struct sk_buff *buf, struct net_device *dev,
532 struct packet_type *pt, struct net_device *orig_dev)
533{
534 struct tipc_bearer *b_ptr;
535
536 if (!net_eq(dev_net(dev), &init_net)) {
537 kfree_skb(buf);
538 return NET_RX_DROP;
539 }
540
541 rcu_read_lock();
ca07fb07 542 b_ptr = rcu_dereference_rtnl(dev->tipc_ptr);
6e967adf
YX
543 if (likely(b_ptr)) {
544 if (likely(buf->pkt_type <= PACKET_BROADCAST)) {
545 buf->next = NULL;
170b3927 546 tipc_rcv(buf, b_ptr);
6e967adf
YX
547 rcu_read_unlock();
548 return NET_RX_SUCCESS;
549 }
550 }
551 rcu_read_unlock();
552
553 kfree_skb(buf);
554 return NET_RX_DROP;
555}
556
557/**
558 * tipc_l2_device_event - handle device events from network device
559 * @nb: the context of the notification
560 * @evt: the type of event
561 * @ptr: the net device that the event was on
562 *
563 * This function is called by the Ethernet driver in case of link
564 * change event.
565 */
566static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt,
567 void *ptr)
568{
569 struct tipc_bearer *b_ptr;
570 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
b97bf3fd 571
6e967adf
YX
572 if (!net_eq(dev_net(dev), &init_net))
573 return NOTIFY_DONE;
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:
a21a584d
EH
587 tipc_reset_bearer(b_ptr);
588 break;
6e967adf 589 case NETDEV_CHANGEADDR:
38504c28 590 b_ptr->media->raw2addr(b_ptr, &b_ptr->addr,
a21a584d 591 (char *)dev->dev_addr);
6e967adf
YX
592 tipc_reset_bearer(b_ptr);
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
RA
643/* Caller should hold rtnl_lock to protect the bearer */
644int __tipc_nl_add_bearer(struct tipc_nl_msg *msg, struct tipc_bearer *bearer)
645{
646 void *hdr;
647 struct nlattr *attrs;
648 struct nlattr *prop;
649
650 hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_v2_family,
651 NLM_F_MULTI, TIPC_NL_BEARER_GET);
652 if (!hdr)
653 return -EMSGSIZE;
654
655 attrs = nla_nest_start(msg->skb, TIPC_NLA_BEARER);
656 if (!attrs)
657 goto msg_full;
658
659 if (nla_put_string(msg->skb, TIPC_NLA_BEARER_NAME, bearer->name))
660 goto attr_msg_full;
661
662 prop = nla_nest_start(msg->skb, TIPC_NLA_BEARER_PROP);
663 if (!prop)
664 goto prop_msg_full;
665 if (nla_put_u32(msg->skb, TIPC_NLA_PROP_PRIO, bearer->priority))
666 goto prop_msg_full;
667 if (nla_put_u32(msg->skb, TIPC_NLA_PROP_TOL, bearer->tolerance))
668 goto prop_msg_full;
669 if (nla_put_u32(msg->skb, TIPC_NLA_PROP_WIN, bearer->window))
670 goto prop_msg_full;
671
672 nla_nest_end(msg->skb, prop);
673 nla_nest_end(msg->skb, attrs);
674 genlmsg_end(msg->skb, hdr);
675
676 return 0;
677
678prop_msg_full:
679 nla_nest_cancel(msg->skb, prop);
680attr_msg_full:
681 nla_nest_cancel(msg->skb, attrs);
682msg_full:
683 genlmsg_cancel(msg->skb, hdr);
684
685 return -EMSGSIZE;
686}
687
688int tipc_nl_bearer_dump(struct sk_buff *skb, struct netlink_callback *cb)
689{
690 int err;
691 int i = cb->args[0];
692 struct tipc_bearer *bearer;
693 struct tipc_nl_msg msg;
694
695 if (i == MAX_BEARERS)
696 return 0;
697
698 msg.skb = skb;
699 msg.portid = NETLINK_CB(cb->skb).portid;
700 msg.seq = cb->nlh->nlmsg_seq;
701
702 rtnl_lock();
703 for (i = 0; i < MAX_BEARERS; i++) {
704 bearer = rtnl_dereference(bearer_list[i]);
705 if (!bearer)
706 continue;
707
708 err = __tipc_nl_add_bearer(&msg, bearer);
709 if (err)
710 break;
711 }
712 rtnl_unlock();
713
714 cb->args[0] = i;
715 return skb->len;
716}
717
718int tipc_nl_bearer_get(struct sk_buff *skb, struct genl_info *info)
719{
720 int err;
721 char *name;
722 struct sk_buff *rep;
723 struct tipc_bearer *bearer;
724 struct tipc_nl_msg msg;
725 struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1];
726
727 if (!info->attrs[TIPC_NLA_BEARER])
728 return -EINVAL;
729
730 err = nla_parse_nested(attrs, TIPC_NLA_BEARER_MAX,
731 info->attrs[TIPC_NLA_BEARER],
732 tipc_nl_bearer_policy);
733 if (err)
734 return err;
735
736 if (!attrs[TIPC_NLA_BEARER_NAME])
737 return -EINVAL;
738 name = nla_data(attrs[TIPC_NLA_BEARER_NAME]);
739
740 rep = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
741 if (!rep)
742 return -ENOMEM;
743
744 msg.skb = rep;
745 msg.portid = info->snd_portid;
746 msg.seq = info->snd_seq;
747
748 rtnl_lock();
749 bearer = tipc_bearer_find(name);
750 if (!bearer) {
751 err = -EINVAL;
752 goto err_out;
753 }
754
755 err = __tipc_nl_add_bearer(&msg, bearer);
756 if (err)
757 goto err_out;
758 rtnl_unlock();
759
760 return genlmsg_reply(rep, info);
761err_out:
762 rtnl_unlock();
763 nlmsg_free(rep);
764
765 return err;
766}
767
0655f6a8
RA
768int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info)
769{
770 int err;
771 char *name;
772 struct tipc_bearer *bearer;
773 struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1];
774
775 if (!info->attrs[TIPC_NLA_BEARER])
776 return -EINVAL;
777
778 err = nla_parse_nested(attrs, TIPC_NLA_BEARER_MAX,
779 info->attrs[TIPC_NLA_BEARER],
780 tipc_nl_bearer_policy);
781 if (err)
782 return err;
783
784 if (!attrs[TIPC_NLA_BEARER_NAME])
785 return -EINVAL;
786
787 name = nla_data(attrs[TIPC_NLA_BEARER_NAME]);
788
789 rtnl_lock();
790 bearer = tipc_bearer_find(name);
791 if (!bearer) {
792 rtnl_unlock();
793 return -EINVAL;
794 }
795
796 bearer_disable(bearer, false);
797 rtnl_unlock();
798
799 return 0;
800}
801
802int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info)
803{
804 int err;
805 char *bearer;
806 struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1];
807 u32 domain;
808 u32 prio;
809
810 prio = TIPC_MEDIA_LINK_PRI;
811 domain = tipc_own_addr & TIPC_CLUSTER_MASK;
812
813 if (!info->attrs[TIPC_NLA_BEARER])
814 return -EINVAL;
815
816 err = nla_parse_nested(attrs, TIPC_NLA_BEARER_MAX,
817 info->attrs[TIPC_NLA_BEARER],
818 tipc_nl_bearer_policy);
819 if (err)
820 return err;
821
822 if (!attrs[TIPC_NLA_BEARER_NAME])
823 return -EINVAL;
824
825 bearer = nla_data(attrs[TIPC_NLA_BEARER_NAME]);
826
827 if (attrs[TIPC_NLA_BEARER_DOMAIN])
828 domain = nla_get_u32(attrs[TIPC_NLA_BEARER_DOMAIN]);
829
830 if (attrs[TIPC_NLA_BEARER_PROP]) {
831 struct nlattr *props[TIPC_NLA_PROP_MAX + 1];
832
833 err = tipc_nl_parse_link_prop(attrs[TIPC_NLA_BEARER_PROP],
834 props);
835 if (err)
836 return err;
837
838 if (props[TIPC_NLA_PROP_PRIO])
839 prio = nla_get_u32(props[TIPC_NLA_PROP_PRIO]);
840 }
841
842 rtnl_lock();
843 err = tipc_enable_bearer(bearer, domain, prio);
844 if (err) {
845 rtnl_unlock();
846 return err;
847 }
848 rtnl_unlock();
849
850 return 0;
851}
315c00bc
RA
852
853int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info)
854{
855 int err;
856 char *name;
857 struct tipc_bearer *b;
858 struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1];
859
860 if (!info->attrs[TIPC_NLA_BEARER])
861 return -EINVAL;
862
863 err = nla_parse_nested(attrs, TIPC_NLA_BEARER_MAX,
864 info->attrs[TIPC_NLA_BEARER],
865 tipc_nl_bearer_policy);
866 if (err)
867 return err;
868
869 if (!attrs[TIPC_NLA_BEARER_NAME])
870 return -EINVAL;
871 name = nla_data(attrs[TIPC_NLA_BEARER_NAME]);
872
873 rtnl_lock();
874 b = tipc_bearer_find(name);
875 if (!b) {
876 rtnl_unlock();
877 return -EINVAL;
878 }
879
880 if (attrs[TIPC_NLA_BEARER_PROP]) {
881 struct nlattr *props[TIPC_NLA_PROP_MAX + 1];
882
883 err = tipc_nl_parse_link_prop(attrs[TIPC_NLA_BEARER_PROP],
884 props);
885 if (err) {
886 rtnl_unlock();
887 return err;
888 }
889
890 if (props[TIPC_NLA_PROP_TOL])
891 b->tolerance = nla_get_u32(props[TIPC_NLA_PROP_TOL]);
892 if (props[TIPC_NLA_PROP_PRIO])
893 b->priority = nla_get_u32(props[TIPC_NLA_PROP_PRIO]);
894 if (props[TIPC_NLA_PROP_WIN])
895 b->window = nla_get_u32(props[TIPC_NLA_PROP_WIN]);
896 }
897 rtnl_unlock();
898
899 return 0;
900}
This page took 0.694286 seconds and 5 git commands to generate.