~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/tipc/bearer.c

Version: ~ [ linux-5.11-rc3 ] ~ [ linux-5.10.7 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.89 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.167 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.215 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.251 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.251 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp