18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * net/tipc/bearer.c: TIPC bearer code 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (c) 1996-2006, 2013-2016, Ericsson AB 58c2ecf20Sopenharmony_ci * Copyright (c) 2004-2006, 2010-2013, Wind River Systems 68c2ecf20Sopenharmony_ci * All rights reserved. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 98c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions are met: 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 128c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 138c2ecf20Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 148c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 158c2ecf20Sopenharmony_ci * documentation and/or other materials provided with the distribution. 168c2ecf20Sopenharmony_ci * 3. Neither the names of the copyright holders nor the names of its 178c2ecf20Sopenharmony_ci * contributors may be used to endorse or promote products derived from 188c2ecf20Sopenharmony_ci * this software without specific prior written permission. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * Alternatively, this software may be distributed under the terms of the 218c2ecf20Sopenharmony_ci * GNU General Public License ("GPL") version 2 as published by the Free 228c2ecf20Sopenharmony_ci * Software Foundation. 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 258c2ecf20Sopenharmony_ci * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 268c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 278c2ecf20Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 288c2ecf20Sopenharmony_ci * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 298c2ecf20Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 308c2ecf20Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 318c2ecf20Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 328c2ecf20Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 338c2ecf20Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 348c2ecf20Sopenharmony_ci * POSSIBILITY OF SUCH DAMAGE. 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include <net/sock.h> 388c2ecf20Sopenharmony_ci#include "core.h" 398c2ecf20Sopenharmony_ci#include "bearer.h" 408c2ecf20Sopenharmony_ci#include "link.h" 418c2ecf20Sopenharmony_ci#include "discover.h" 428c2ecf20Sopenharmony_ci#include "monitor.h" 438c2ecf20Sopenharmony_ci#include "bcast.h" 448c2ecf20Sopenharmony_ci#include "netlink.h" 458c2ecf20Sopenharmony_ci#include "udp_media.h" 468c2ecf20Sopenharmony_ci#include "trace.h" 478c2ecf20Sopenharmony_ci#include "crypto.h" 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#define MAX_ADDR_STR 60 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic struct tipc_media * const media_info_array[] = { 528c2ecf20Sopenharmony_ci ð_media_info, 538c2ecf20Sopenharmony_ci#ifdef CONFIG_TIPC_MEDIA_IB 548c2ecf20Sopenharmony_ci &ib_media_info, 558c2ecf20Sopenharmony_ci#endif 568c2ecf20Sopenharmony_ci#ifdef CONFIG_TIPC_MEDIA_UDP 578c2ecf20Sopenharmony_ci &udp_media_info, 588c2ecf20Sopenharmony_ci#endif 598c2ecf20Sopenharmony_ci NULL 608c2ecf20Sopenharmony_ci}; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic struct tipc_bearer *bearer_get(struct net *net, int bearer_id) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci struct tipc_net *tn = tipc_net(net); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci return rcu_dereference(tn->bearer_list[bearer_id]); 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic void bearer_disable(struct net *net, struct tipc_bearer *b); 708c2ecf20Sopenharmony_cistatic int tipc_l2_rcv_msg(struct sk_buff *skb, struct net_device *dev, 718c2ecf20Sopenharmony_ci struct packet_type *pt, struct net_device *orig_dev); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/** 748c2ecf20Sopenharmony_ci * tipc_media_find - locates specified media object by name 758c2ecf20Sopenharmony_ci */ 768c2ecf20Sopenharmony_cistruct tipc_media *tipc_media_find(const char *name) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci u32 i; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci for (i = 0; media_info_array[i] != NULL; i++) { 818c2ecf20Sopenharmony_ci if (!strcmp(media_info_array[i]->name, name)) 828c2ecf20Sopenharmony_ci break; 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci return media_info_array[i]; 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/** 888c2ecf20Sopenharmony_ci * media_find_id - locates specified media object by type identifier 898c2ecf20Sopenharmony_ci */ 908c2ecf20Sopenharmony_cistatic struct tipc_media *media_find_id(u8 type) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci u32 i; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci for (i = 0; media_info_array[i] != NULL; i++) { 958c2ecf20Sopenharmony_ci if (media_info_array[i]->type_id == type) 968c2ecf20Sopenharmony_ci break; 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci return media_info_array[i]; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci/** 1028c2ecf20Sopenharmony_ci * tipc_media_addr_printf - record media address in print buffer 1038c2ecf20Sopenharmony_ci */ 1048c2ecf20Sopenharmony_ciint tipc_media_addr_printf(char *buf, int len, struct tipc_media_addr *a) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci char addr_str[MAX_ADDR_STR]; 1078c2ecf20Sopenharmony_ci struct tipc_media *m; 1088c2ecf20Sopenharmony_ci int ret; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci m = media_find_id(a->media_id); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci if (m && !m->addr2str(a, addr_str, sizeof(addr_str))) 1138c2ecf20Sopenharmony_ci ret = scnprintf(buf, len, "%s(%s)", m->name, addr_str); 1148c2ecf20Sopenharmony_ci else { 1158c2ecf20Sopenharmony_ci u32 i; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci ret = scnprintf(buf, len, "UNKNOWN(%u)", a->media_id); 1188c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(a->value); i++) 1198c2ecf20Sopenharmony_ci ret += scnprintf(buf + ret, len - ret, 1208c2ecf20Sopenharmony_ci "-%x", a->value[i]); 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci return ret; 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci/** 1268c2ecf20Sopenharmony_ci * bearer_name_validate - validate & (optionally) deconstruct bearer name 1278c2ecf20Sopenharmony_ci * @name: ptr to bearer name string 1288c2ecf20Sopenharmony_ci * @name_parts: ptr to area for bearer name components (or NULL if not needed) 1298c2ecf20Sopenharmony_ci * 1308c2ecf20Sopenharmony_ci * Returns 1 if bearer name is valid, otherwise 0. 1318c2ecf20Sopenharmony_ci */ 1328c2ecf20Sopenharmony_cistatic int bearer_name_validate(const char *name, 1338c2ecf20Sopenharmony_ci struct tipc_bearer_names *name_parts) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci char name_copy[TIPC_MAX_BEARER_NAME]; 1368c2ecf20Sopenharmony_ci char *media_name; 1378c2ecf20Sopenharmony_ci char *if_name; 1388c2ecf20Sopenharmony_ci u32 media_len; 1398c2ecf20Sopenharmony_ci u32 if_len; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci /* copy bearer name & ensure length is OK */ 1428c2ecf20Sopenharmony_ci name_copy[TIPC_MAX_BEARER_NAME - 1] = 0; 1438c2ecf20Sopenharmony_ci /* need above in case non-Posix strncpy() doesn't pad with nulls */ 1448c2ecf20Sopenharmony_ci strncpy(name_copy, name, TIPC_MAX_BEARER_NAME); 1458c2ecf20Sopenharmony_ci if (name_copy[TIPC_MAX_BEARER_NAME - 1] != 0) 1468c2ecf20Sopenharmony_ci return 0; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci /* ensure all component parts of bearer name are present */ 1498c2ecf20Sopenharmony_ci media_name = name_copy; 1508c2ecf20Sopenharmony_ci if_name = strchr(media_name, ':'); 1518c2ecf20Sopenharmony_ci if (if_name == NULL) 1528c2ecf20Sopenharmony_ci return 0; 1538c2ecf20Sopenharmony_ci *(if_name++) = 0; 1548c2ecf20Sopenharmony_ci media_len = if_name - media_name; 1558c2ecf20Sopenharmony_ci if_len = strlen(if_name) + 1; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci /* validate component parts of bearer name */ 1588c2ecf20Sopenharmony_ci if ((media_len <= 1) || (media_len > TIPC_MAX_MEDIA_NAME) || 1598c2ecf20Sopenharmony_ci (if_len <= 1) || (if_len > TIPC_MAX_IF_NAME)) 1608c2ecf20Sopenharmony_ci return 0; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci /* return bearer name components, if necessary */ 1638c2ecf20Sopenharmony_ci if (name_parts) { 1648c2ecf20Sopenharmony_ci strcpy(name_parts->media_name, media_name); 1658c2ecf20Sopenharmony_ci strcpy(name_parts->if_name, if_name); 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci return 1; 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci/** 1718c2ecf20Sopenharmony_ci * tipc_bearer_find - locates bearer object with matching bearer name 1728c2ecf20Sopenharmony_ci */ 1738c2ecf20Sopenharmony_cistruct tipc_bearer *tipc_bearer_find(struct net *net, const char *name) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci struct tipc_net *tn = net_generic(net, tipc_net_id); 1768c2ecf20Sopenharmony_ci struct tipc_bearer *b; 1778c2ecf20Sopenharmony_ci u32 i; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci for (i = 0; i < MAX_BEARERS; i++) { 1808c2ecf20Sopenharmony_ci b = rtnl_dereference(tn->bearer_list[i]); 1818c2ecf20Sopenharmony_ci if (b && (!strcmp(b->name, name))) 1828c2ecf20Sopenharmony_ci return b; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci return NULL; 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci/* tipc_bearer_get_name - get the bearer name from its id. 1888c2ecf20Sopenharmony_ci * @net: network namespace 1898c2ecf20Sopenharmony_ci * @name: a pointer to the buffer where the name will be stored. 1908c2ecf20Sopenharmony_ci * @bearer_id: the id to get the name from. 1918c2ecf20Sopenharmony_ci */ 1928c2ecf20Sopenharmony_ciint tipc_bearer_get_name(struct net *net, char *name, u32 bearer_id) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci struct tipc_net *tn = tipc_net(net); 1958c2ecf20Sopenharmony_ci struct tipc_bearer *b; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci if (bearer_id >= MAX_BEARERS) 1988c2ecf20Sopenharmony_ci return -EINVAL; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci b = rtnl_dereference(tn->bearer_list[bearer_id]); 2018c2ecf20Sopenharmony_ci if (!b) 2028c2ecf20Sopenharmony_ci return -EINVAL; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci strcpy(name, b->name); 2058c2ecf20Sopenharmony_ci return 0; 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_civoid tipc_bearer_add_dest(struct net *net, u32 bearer_id, u32 dest) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci struct tipc_net *tn = net_generic(net, tipc_net_id); 2118c2ecf20Sopenharmony_ci struct tipc_bearer *b; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci rcu_read_lock(); 2148c2ecf20Sopenharmony_ci b = rcu_dereference(tn->bearer_list[bearer_id]); 2158c2ecf20Sopenharmony_ci if (b) 2168c2ecf20Sopenharmony_ci tipc_disc_add_dest(b->disc); 2178c2ecf20Sopenharmony_ci rcu_read_unlock(); 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_civoid tipc_bearer_remove_dest(struct net *net, u32 bearer_id, u32 dest) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci struct tipc_net *tn = net_generic(net, tipc_net_id); 2238c2ecf20Sopenharmony_ci struct tipc_bearer *b; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci rcu_read_lock(); 2268c2ecf20Sopenharmony_ci b = rcu_dereference(tn->bearer_list[bearer_id]); 2278c2ecf20Sopenharmony_ci if (b) 2288c2ecf20Sopenharmony_ci tipc_disc_remove_dest(b->disc); 2298c2ecf20Sopenharmony_ci rcu_read_unlock(); 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci/** 2338c2ecf20Sopenharmony_ci * tipc_enable_bearer - enable bearer with the given name 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_cistatic int tipc_enable_bearer(struct net *net, const char *name, 2368c2ecf20Sopenharmony_ci u32 disc_domain, u32 prio, 2378c2ecf20Sopenharmony_ci struct nlattr *attr[], 2388c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci struct tipc_net *tn = tipc_net(net); 2418c2ecf20Sopenharmony_ci struct tipc_bearer_names b_names; 2428c2ecf20Sopenharmony_ci int with_this_prio = 1; 2438c2ecf20Sopenharmony_ci struct tipc_bearer *b; 2448c2ecf20Sopenharmony_ci struct tipc_media *m; 2458c2ecf20Sopenharmony_ci struct sk_buff *skb; 2468c2ecf20Sopenharmony_ci int bearer_id = 0; 2478c2ecf20Sopenharmony_ci int res = -EINVAL; 2488c2ecf20Sopenharmony_ci char *errstr = ""; 2498c2ecf20Sopenharmony_ci u32 i; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if (!bearer_name_validate(name, &b_names)) { 2528c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(extack, "Illegal name"); 2538c2ecf20Sopenharmony_ci return res; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (prio > TIPC_MAX_LINK_PRI && prio != TIPC_MEDIA_LINK_PRI) { 2578c2ecf20Sopenharmony_ci errstr = "illegal priority"; 2588c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(extack, "Illegal priority"); 2598c2ecf20Sopenharmony_ci goto rejected; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci m = tipc_media_find(b_names.media_name); 2638c2ecf20Sopenharmony_ci if (!m) { 2648c2ecf20Sopenharmony_ci errstr = "media not registered"; 2658c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(extack, "Media not registered"); 2668c2ecf20Sopenharmony_ci goto rejected; 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci if (prio == TIPC_MEDIA_LINK_PRI) 2708c2ecf20Sopenharmony_ci prio = m->priority; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci /* Check new bearer vs existing ones and find free bearer id if any */ 2738c2ecf20Sopenharmony_ci bearer_id = MAX_BEARERS; 2748c2ecf20Sopenharmony_ci i = MAX_BEARERS; 2758c2ecf20Sopenharmony_ci while (i-- != 0) { 2768c2ecf20Sopenharmony_ci b = rtnl_dereference(tn->bearer_list[i]); 2778c2ecf20Sopenharmony_ci if (!b) { 2788c2ecf20Sopenharmony_ci bearer_id = i; 2798c2ecf20Sopenharmony_ci continue; 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci if (!strcmp(name, b->name)) { 2828c2ecf20Sopenharmony_ci errstr = "already enabled"; 2838c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(extack, "Already enabled"); 2848c2ecf20Sopenharmony_ci goto rejected; 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci if (b->priority == prio && 2888c2ecf20Sopenharmony_ci (++with_this_prio > 2)) { 2898c2ecf20Sopenharmony_ci pr_warn("Bearer <%s>: already 2 bearers with priority %u\n", 2908c2ecf20Sopenharmony_ci name, prio); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci if (prio == TIPC_MIN_LINK_PRI) { 2938c2ecf20Sopenharmony_ci errstr = "cannot adjust to lower"; 2948c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(extack, "Cannot adjust to lower"); 2958c2ecf20Sopenharmony_ci goto rejected; 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci pr_warn("Bearer <%s>: trying with adjusted priority\n", 2998c2ecf20Sopenharmony_ci name); 3008c2ecf20Sopenharmony_ci prio--; 3018c2ecf20Sopenharmony_ci bearer_id = MAX_BEARERS; 3028c2ecf20Sopenharmony_ci i = MAX_BEARERS; 3038c2ecf20Sopenharmony_ci with_this_prio = 1; 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if (bearer_id >= MAX_BEARERS) { 3088c2ecf20Sopenharmony_ci errstr = "max 3 bearers permitted"; 3098c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(extack, "Max 3 bearers permitted"); 3108c2ecf20Sopenharmony_ci goto rejected; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci b = kzalloc(sizeof(*b), GFP_ATOMIC); 3148c2ecf20Sopenharmony_ci if (!b) 3158c2ecf20Sopenharmony_ci return -ENOMEM; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci strcpy(b->name, name); 3188c2ecf20Sopenharmony_ci b->media = m; 3198c2ecf20Sopenharmony_ci res = m->enable_media(net, b, attr); 3208c2ecf20Sopenharmony_ci if (res) { 3218c2ecf20Sopenharmony_ci kfree(b); 3228c2ecf20Sopenharmony_ci errstr = "failed to enable media"; 3238c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(extack, "Failed to enable media"); 3248c2ecf20Sopenharmony_ci goto rejected; 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci b->identity = bearer_id; 3288c2ecf20Sopenharmony_ci b->tolerance = m->tolerance; 3298c2ecf20Sopenharmony_ci b->min_win = m->min_win; 3308c2ecf20Sopenharmony_ci b->max_win = m->max_win; 3318c2ecf20Sopenharmony_ci b->domain = disc_domain; 3328c2ecf20Sopenharmony_ci b->net_plane = bearer_id + 'A'; 3338c2ecf20Sopenharmony_ci b->priority = prio; 3348c2ecf20Sopenharmony_ci refcount_set(&b->refcnt, 1); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci res = tipc_disc_create(net, b, &b->bcast_addr, &skb); 3378c2ecf20Sopenharmony_ci if (res) { 3388c2ecf20Sopenharmony_ci bearer_disable(net, b); 3398c2ecf20Sopenharmony_ci errstr = "failed to create discoverer"; 3408c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(extack, "Failed to create discoverer"); 3418c2ecf20Sopenharmony_ci goto rejected; 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci /* Create monitoring data before accepting activate messages */ 3458c2ecf20Sopenharmony_ci if (tipc_mon_create(net, bearer_id)) { 3468c2ecf20Sopenharmony_ci bearer_disable(net, b); 3478c2ecf20Sopenharmony_ci kfree_skb(skb); 3488c2ecf20Sopenharmony_ci return -ENOMEM; 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci test_and_set_bit_lock(0, &b->up); 3528c2ecf20Sopenharmony_ci rcu_assign_pointer(tn->bearer_list[bearer_id], b); 3538c2ecf20Sopenharmony_ci if (skb) 3548c2ecf20Sopenharmony_ci tipc_bearer_xmit_skb(net, bearer_id, skb, &b->bcast_addr); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci pr_info("Enabled bearer <%s>, priority %u\n", name, prio); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci return res; 3598c2ecf20Sopenharmony_cirejected: 3608c2ecf20Sopenharmony_ci pr_warn("Enabling of bearer <%s> rejected, %s\n", name, errstr); 3618c2ecf20Sopenharmony_ci return res; 3628c2ecf20Sopenharmony_ci} 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci/** 3658c2ecf20Sopenharmony_ci * tipc_reset_bearer - Reset all links established over this bearer 3668c2ecf20Sopenharmony_ci */ 3678c2ecf20Sopenharmony_cistatic int tipc_reset_bearer(struct net *net, struct tipc_bearer *b) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci pr_info("Resetting bearer <%s>\n", b->name); 3708c2ecf20Sopenharmony_ci tipc_node_delete_links(net, b->identity); 3718c2ecf20Sopenharmony_ci tipc_disc_reset(net, b); 3728c2ecf20Sopenharmony_ci return 0; 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cibool tipc_bearer_hold(struct tipc_bearer *b) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci return (b && refcount_inc_not_zero(&b->refcnt)); 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_civoid tipc_bearer_put(struct tipc_bearer *b) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci if (b && refcount_dec_and_test(&b->refcnt)) 3838c2ecf20Sopenharmony_ci kfree_rcu(b, rcu); 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci/** 3878c2ecf20Sopenharmony_ci * bearer_disable 3888c2ecf20Sopenharmony_ci * 3898c2ecf20Sopenharmony_ci * Note: This routine assumes caller holds RTNL lock. 3908c2ecf20Sopenharmony_ci */ 3918c2ecf20Sopenharmony_cistatic void bearer_disable(struct net *net, struct tipc_bearer *b) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci struct tipc_net *tn = tipc_net(net); 3948c2ecf20Sopenharmony_ci int bearer_id = b->identity; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci pr_info("Disabling bearer <%s>\n", b->name); 3978c2ecf20Sopenharmony_ci clear_bit_unlock(0, &b->up); 3988c2ecf20Sopenharmony_ci tipc_node_delete_links(net, bearer_id); 3998c2ecf20Sopenharmony_ci b->media->disable_media(b); 4008c2ecf20Sopenharmony_ci RCU_INIT_POINTER(b->media_ptr, NULL); 4018c2ecf20Sopenharmony_ci if (b->disc) 4028c2ecf20Sopenharmony_ci tipc_disc_delete(b->disc); 4038c2ecf20Sopenharmony_ci RCU_INIT_POINTER(tn->bearer_list[bearer_id], NULL); 4048c2ecf20Sopenharmony_ci tipc_bearer_put(b); 4058c2ecf20Sopenharmony_ci tipc_mon_delete(net, bearer_id); 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ciint tipc_enable_l2_media(struct net *net, struct tipc_bearer *b, 4098c2ecf20Sopenharmony_ci struct nlattr *attr[]) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci char *dev_name = strchr((const char *)b->name, ':') + 1; 4128c2ecf20Sopenharmony_ci int hwaddr_len = b->media->hwaddr_len; 4138c2ecf20Sopenharmony_ci u8 node_id[NODE_ID_LEN] = {0,}; 4148c2ecf20Sopenharmony_ci struct net_device *dev; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci /* Find device with specified name */ 4178c2ecf20Sopenharmony_ci dev = dev_get_by_name(net, dev_name); 4188c2ecf20Sopenharmony_ci if (!dev) 4198c2ecf20Sopenharmony_ci return -ENODEV; 4208c2ecf20Sopenharmony_ci if (tipc_mtu_bad(dev, 0)) { 4218c2ecf20Sopenharmony_ci dev_put(dev); 4228c2ecf20Sopenharmony_ci return -EINVAL; 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci if (dev == net->loopback_dev) { 4258c2ecf20Sopenharmony_ci dev_put(dev); 4268c2ecf20Sopenharmony_ci pr_info("Enabling <%s> not permitted\n", b->name); 4278c2ecf20Sopenharmony_ci return -EINVAL; 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci /* Autoconfigure own node identity if needed */ 4318c2ecf20Sopenharmony_ci if (!tipc_own_id(net) && hwaddr_len <= NODE_ID_LEN) { 4328c2ecf20Sopenharmony_ci memcpy(node_id, dev->dev_addr, hwaddr_len); 4338c2ecf20Sopenharmony_ci tipc_net_init(net, node_id, 0); 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci if (!tipc_own_id(net)) { 4368c2ecf20Sopenharmony_ci dev_put(dev); 4378c2ecf20Sopenharmony_ci pr_warn("Failed to obtain node identity\n"); 4388c2ecf20Sopenharmony_ci return -EINVAL; 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci /* Associate TIPC bearer with L2 bearer */ 4428c2ecf20Sopenharmony_ci rcu_assign_pointer(b->media_ptr, dev); 4438c2ecf20Sopenharmony_ci b->pt.dev = dev; 4448c2ecf20Sopenharmony_ci b->pt.type = htons(ETH_P_TIPC); 4458c2ecf20Sopenharmony_ci b->pt.func = tipc_l2_rcv_msg; 4468c2ecf20Sopenharmony_ci dev_add_pack(&b->pt); 4478c2ecf20Sopenharmony_ci memset(&b->bcast_addr, 0, sizeof(b->bcast_addr)); 4488c2ecf20Sopenharmony_ci memcpy(b->bcast_addr.value, dev->broadcast, hwaddr_len); 4498c2ecf20Sopenharmony_ci b->bcast_addr.media_id = b->media->type_id; 4508c2ecf20Sopenharmony_ci b->bcast_addr.broadcast = TIPC_BROADCAST_SUPPORT; 4518c2ecf20Sopenharmony_ci b->mtu = dev->mtu; 4528c2ecf20Sopenharmony_ci b->media->raw2addr(b, &b->addr, (char *)dev->dev_addr); 4538c2ecf20Sopenharmony_ci rcu_assign_pointer(dev->tipc_ptr, b); 4548c2ecf20Sopenharmony_ci return 0; 4558c2ecf20Sopenharmony_ci} 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci/* tipc_disable_l2_media - detach TIPC bearer from an L2 interface 4588c2ecf20Sopenharmony_ci * 4598c2ecf20Sopenharmony_ci * Mark L2 bearer as inactive so that incoming buffers are thrown away 4608c2ecf20Sopenharmony_ci */ 4618c2ecf20Sopenharmony_civoid tipc_disable_l2_media(struct tipc_bearer *b) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci struct net_device *dev; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci dev = (struct net_device *)rtnl_dereference(b->media_ptr); 4668c2ecf20Sopenharmony_ci dev_remove_pack(&b->pt); 4678c2ecf20Sopenharmony_ci RCU_INIT_POINTER(dev->tipc_ptr, NULL); 4688c2ecf20Sopenharmony_ci synchronize_net(); 4698c2ecf20Sopenharmony_ci dev_put(dev); 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci/** 4738c2ecf20Sopenharmony_ci * tipc_l2_send_msg - send a TIPC packet out over an L2 interface 4748c2ecf20Sopenharmony_ci * @skb: the packet to be sent 4758c2ecf20Sopenharmony_ci * @b: the bearer through which the packet is to be sent 4768c2ecf20Sopenharmony_ci * @dest: peer destination address 4778c2ecf20Sopenharmony_ci */ 4788c2ecf20Sopenharmony_ciint tipc_l2_send_msg(struct net *net, struct sk_buff *skb, 4798c2ecf20Sopenharmony_ci struct tipc_bearer *b, struct tipc_media_addr *dest) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci struct net_device *dev; 4828c2ecf20Sopenharmony_ci int delta; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci dev = (struct net_device *)rcu_dereference(b->media_ptr); 4858c2ecf20Sopenharmony_ci if (!dev) 4868c2ecf20Sopenharmony_ci return 0; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci delta = SKB_DATA_ALIGN(dev->hard_header_len - skb_headroom(skb)); 4898c2ecf20Sopenharmony_ci if ((delta > 0) && pskb_expand_head(skb, delta, 0, GFP_ATOMIC)) { 4908c2ecf20Sopenharmony_ci kfree_skb(skb); 4918c2ecf20Sopenharmony_ci return 0; 4928c2ecf20Sopenharmony_ci } 4938c2ecf20Sopenharmony_ci skb_reset_network_header(skb); 4948c2ecf20Sopenharmony_ci skb->dev = dev; 4958c2ecf20Sopenharmony_ci skb->protocol = htons(ETH_P_TIPC); 4968c2ecf20Sopenharmony_ci dev_hard_header(skb, dev, ETH_P_TIPC, dest->value, 4978c2ecf20Sopenharmony_ci dev->dev_addr, skb->len); 4988c2ecf20Sopenharmony_ci dev_queue_xmit(skb); 4998c2ecf20Sopenharmony_ci return 0; 5008c2ecf20Sopenharmony_ci} 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_cibool tipc_bearer_bcast_support(struct net *net, u32 bearer_id) 5038c2ecf20Sopenharmony_ci{ 5048c2ecf20Sopenharmony_ci bool supp = false; 5058c2ecf20Sopenharmony_ci struct tipc_bearer *b; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci rcu_read_lock(); 5088c2ecf20Sopenharmony_ci b = bearer_get(net, bearer_id); 5098c2ecf20Sopenharmony_ci if (b) 5108c2ecf20Sopenharmony_ci supp = (b->bcast_addr.broadcast == TIPC_BROADCAST_SUPPORT); 5118c2ecf20Sopenharmony_ci rcu_read_unlock(); 5128c2ecf20Sopenharmony_ci return supp; 5138c2ecf20Sopenharmony_ci} 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ciint tipc_bearer_mtu(struct net *net, u32 bearer_id) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci int mtu = 0; 5188c2ecf20Sopenharmony_ci struct tipc_bearer *b; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci rcu_read_lock(); 5218c2ecf20Sopenharmony_ci b = rcu_dereference(tipc_net(net)->bearer_list[bearer_id]); 5228c2ecf20Sopenharmony_ci if (b) 5238c2ecf20Sopenharmony_ci mtu = b->mtu; 5248c2ecf20Sopenharmony_ci rcu_read_unlock(); 5258c2ecf20Sopenharmony_ci return mtu; 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ciint tipc_bearer_min_mtu(struct net *net, u32 bearer_id) 5298c2ecf20Sopenharmony_ci{ 5308c2ecf20Sopenharmony_ci int mtu = TIPC_MIN_BEARER_MTU; 5318c2ecf20Sopenharmony_ci struct tipc_bearer *b; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci rcu_read_lock(); 5348c2ecf20Sopenharmony_ci b = bearer_get(net, bearer_id); 5358c2ecf20Sopenharmony_ci if (b) 5368c2ecf20Sopenharmony_ci mtu += b->encap_hlen; 5378c2ecf20Sopenharmony_ci rcu_read_unlock(); 5388c2ecf20Sopenharmony_ci return mtu; 5398c2ecf20Sopenharmony_ci} 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci/* tipc_bearer_xmit_skb - sends buffer to destination over bearer 5428c2ecf20Sopenharmony_ci */ 5438c2ecf20Sopenharmony_civoid tipc_bearer_xmit_skb(struct net *net, u32 bearer_id, 5448c2ecf20Sopenharmony_ci struct sk_buff *skb, 5458c2ecf20Sopenharmony_ci struct tipc_media_addr *dest) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci struct tipc_msg *hdr = buf_msg(skb); 5488c2ecf20Sopenharmony_ci struct tipc_bearer *b; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci rcu_read_lock(); 5518c2ecf20Sopenharmony_ci b = bearer_get(net, bearer_id); 5528c2ecf20Sopenharmony_ci if (likely(b && (test_bit(0, &b->up) || msg_is_reset(hdr)))) { 5538c2ecf20Sopenharmony_ci#ifdef CONFIG_TIPC_CRYPTO 5548c2ecf20Sopenharmony_ci tipc_crypto_xmit(net, &skb, b, dest, NULL); 5558c2ecf20Sopenharmony_ci if (skb) 5568c2ecf20Sopenharmony_ci#endif 5578c2ecf20Sopenharmony_ci b->media->send_msg(net, skb, b, dest); 5588c2ecf20Sopenharmony_ci } else { 5598c2ecf20Sopenharmony_ci kfree_skb(skb); 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci rcu_read_unlock(); 5628c2ecf20Sopenharmony_ci} 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci/* tipc_bearer_xmit() -send buffer to destination over bearer 5658c2ecf20Sopenharmony_ci */ 5668c2ecf20Sopenharmony_civoid tipc_bearer_xmit(struct net *net, u32 bearer_id, 5678c2ecf20Sopenharmony_ci struct sk_buff_head *xmitq, 5688c2ecf20Sopenharmony_ci struct tipc_media_addr *dst, 5698c2ecf20Sopenharmony_ci struct tipc_node *__dnode) 5708c2ecf20Sopenharmony_ci{ 5718c2ecf20Sopenharmony_ci struct tipc_bearer *b; 5728c2ecf20Sopenharmony_ci struct sk_buff *skb, *tmp; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci if (skb_queue_empty(xmitq)) 5758c2ecf20Sopenharmony_ci return; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci rcu_read_lock(); 5788c2ecf20Sopenharmony_ci b = bearer_get(net, bearer_id); 5798c2ecf20Sopenharmony_ci if (unlikely(!b)) 5808c2ecf20Sopenharmony_ci __skb_queue_purge(xmitq); 5818c2ecf20Sopenharmony_ci skb_queue_walk_safe(xmitq, skb, tmp) { 5828c2ecf20Sopenharmony_ci __skb_dequeue(xmitq); 5838c2ecf20Sopenharmony_ci if (likely(test_bit(0, &b->up) || msg_is_reset(buf_msg(skb)))) { 5848c2ecf20Sopenharmony_ci#ifdef CONFIG_TIPC_CRYPTO 5858c2ecf20Sopenharmony_ci tipc_crypto_xmit(net, &skb, b, dst, __dnode); 5868c2ecf20Sopenharmony_ci if (skb) 5878c2ecf20Sopenharmony_ci#endif 5888c2ecf20Sopenharmony_ci b->media->send_msg(net, skb, b, dst); 5898c2ecf20Sopenharmony_ci } else { 5908c2ecf20Sopenharmony_ci kfree_skb(skb); 5918c2ecf20Sopenharmony_ci } 5928c2ecf20Sopenharmony_ci } 5938c2ecf20Sopenharmony_ci rcu_read_unlock(); 5948c2ecf20Sopenharmony_ci} 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci/* tipc_bearer_bc_xmit() - broadcast buffers to all destinations 5978c2ecf20Sopenharmony_ci */ 5988c2ecf20Sopenharmony_civoid tipc_bearer_bc_xmit(struct net *net, u32 bearer_id, 5998c2ecf20Sopenharmony_ci struct sk_buff_head *xmitq) 6008c2ecf20Sopenharmony_ci{ 6018c2ecf20Sopenharmony_ci struct tipc_net *tn = tipc_net(net); 6028c2ecf20Sopenharmony_ci struct tipc_media_addr *dst; 6038c2ecf20Sopenharmony_ci int net_id = tn->net_id; 6048c2ecf20Sopenharmony_ci struct tipc_bearer *b; 6058c2ecf20Sopenharmony_ci struct sk_buff *skb, *tmp; 6068c2ecf20Sopenharmony_ci struct tipc_msg *hdr; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci rcu_read_lock(); 6098c2ecf20Sopenharmony_ci b = bearer_get(net, bearer_id); 6108c2ecf20Sopenharmony_ci if (unlikely(!b || !test_bit(0, &b->up))) 6118c2ecf20Sopenharmony_ci __skb_queue_purge(xmitq); 6128c2ecf20Sopenharmony_ci skb_queue_walk_safe(xmitq, skb, tmp) { 6138c2ecf20Sopenharmony_ci hdr = buf_msg(skb); 6148c2ecf20Sopenharmony_ci msg_set_non_seq(hdr, 1); 6158c2ecf20Sopenharmony_ci msg_set_mc_netid(hdr, net_id); 6168c2ecf20Sopenharmony_ci __skb_dequeue(xmitq); 6178c2ecf20Sopenharmony_ci dst = &b->bcast_addr; 6188c2ecf20Sopenharmony_ci#ifdef CONFIG_TIPC_CRYPTO 6198c2ecf20Sopenharmony_ci tipc_crypto_xmit(net, &skb, b, dst, NULL); 6208c2ecf20Sopenharmony_ci if (skb) 6218c2ecf20Sopenharmony_ci#endif 6228c2ecf20Sopenharmony_ci b->media->send_msg(net, skb, b, dst); 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci rcu_read_unlock(); 6258c2ecf20Sopenharmony_ci} 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci/** 6288c2ecf20Sopenharmony_ci * tipc_l2_rcv_msg - handle incoming TIPC message from an interface 6298c2ecf20Sopenharmony_ci * @skb: the received message 6308c2ecf20Sopenharmony_ci * @dev: the net device that the packet was received on 6318c2ecf20Sopenharmony_ci * @pt: the packet_type structure which was used to register this handler 6328c2ecf20Sopenharmony_ci * @orig_dev: the original receive net device in case the device is a bond 6338c2ecf20Sopenharmony_ci * 6348c2ecf20Sopenharmony_ci * Accept only packets explicitly sent to this node, or broadcast packets; 6358c2ecf20Sopenharmony_ci * ignores packets sent using interface multicast, and traffic sent to other 6368c2ecf20Sopenharmony_ci * nodes (which can happen if interface is running in promiscuous mode). 6378c2ecf20Sopenharmony_ci */ 6388c2ecf20Sopenharmony_cistatic int tipc_l2_rcv_msg(struct sk_buff *skb, struct net_device *dev, 6398c2ecf20Sopenharmony_ci struct packet_type *pt, struct net_device *orig_dev) 6408c2ecf20Sopenharmony_ci{ 6418c2ecf20Sopenharmony_ci struct tipc_bearer *b; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci rcu_read_lock(); 6448c2ecf20Sopenharmony_ci b = rcu_dereference(dev->tipc_ptr) ?: 6458c2ecf20Sopenharmony_ci rcu_dereference(orig_dev->tipc_ptr); 6468c2ecf20Sopenharmony_ci if (likely(b && test_bit(0, &b->up) && 6478c2ecf20Sopenharmony_ci (skb->pkt_type <= PACKET_MULTICAST))) { 6488c2ecf20Sopenharmony_ci skb_mark_not_on_list(skb); 6498c2ecf20Sopenharmony_ci TIPC_SKB_CB(skb)->flags = 0; 6508c2ecf20Sopenharmony_ci tipc_rcv(dev_net(b->pt.dev), skb, b); 6518c2ecf20Sopenharmony_ci rcu_read_unlock(); 6528c2ecf20Sopenharmony_ci return NET_RX_SUCCESS; 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci rcu_read_unlock(); 6558c2ecf20Sopenharmony_ci kfree_skb(skb); 6568c2ecf20Sopenharmony_ci return NET_RX_DROP; 6578c2ecf20Sopenharmony_ci} 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci/** 6608c2ecf20Sopenharmony_ci * tipc_l2_device_event - handle device events from network device 6618c2ecf20Sopenharmony_ci * @nb: the context of the notification 6628c2ecf20Sopenharmony_ci * @evt: the type of event 6638c2ecf20Sopenharmony_ci * @ptr: the net device that the event was on 6648c2ecf20Sopenharmony_ci * 6658c2ecf20Sopenharmony_ci * This function is called by the Ethernet driver in case of link 6668c2ecf20Sopenharmony_ci * change event. 6678c2ecf20Sopenharmony_ci */ 6688c2ecf20Sopenharmony_cistatic int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt, 6698c2ecf20Sopenharmony_ci void *ptr) 6708c2ecf20Sopenharmony_ci{ 6718c2ecf20Sopenharmony_ci struct net_device *dev = netdev_notifier_info_to_dev(ptr); 6728c2ecf20Sopenharmony_ci struct net *net = dev_net(dev); 6738c2ecf20Sopenharmony_ci struct tipc_bearer *b; 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci b = rtnl_dereference(dev->tipc_ptr); 6768c2ecf20Sopenharmony_ci if (!b) 6778c2ecf20Sopenharmony_ci return NOTIFY_DONE; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci trace_tipc_l2_device_event(dev, b, evt); 6808c2ecf20Sopenharmony_ci switch (evt) { 6818c2ecf20Sopenharmony_ci case NETDEV_CHANGE: 6828c2ecf20Sopenharmony_ci if (netif_carrier_ok(dev) && netif_oper_up(dev)) { 6838c2ecf20Sopenharmony_ci test_and_set_bit_lock(0, &b->up); 6848c2ecf20Sopenharmony_ci break; 6858c2ecf20Sopenharmony_ci } 6868c2ecf20Sopenharmony_ci fallthrough; 6878c2ecf20Sopenharmony_ci case NETDEV_GOING_DOWN: 6888c2ecf20Sopenharmony_ci clear_bit_unlock(0, &b->up); 6898c2ecf20Sopenharmony_ci tipc_reset_bearer(net, b); 6908c2ecf20Sopenharmony_ci break; 6918c2ecf20Sopenharmony_ci case NETDEV_UP: 6928c2ecf20Sopenharmony_ci test_and_set_bit_lock(0, &b->up); 6938c2ecf20Sopenharmony_ci break; 6948c2ecf20Sopenharmony_ci case NETDEV_CHANGEMTU: 6958c2ecf20Sopenharmony_ci if (tipc_mtu_bad(dev, 0)) { 6968c2ecf20Sopenharmony_ci bearer_disable(net, b); 6978c2ecf20Sopenharmony_ci break; 6988c2ecf20Sopenharmony_ci } 6998c2ecf20Sopenharmony_ci b->mtu = dev->mtu; 7008c2ecf20Sopenharmony_ci tipc_reset_bearer(net, b); 7018c2ecf20Sopenharmony_ci break; 7028c2ecf20Sopenharmony_ci case NETDEV_CHANGEADDR: 7038c2ecf20Sopenharmony_ci b->media->raw2addr(b, &b->addr, 7048c2ecf20Sopenharmony_ci (char *)dev->dev_addr); 7058c2ecf20Sopenharmony_ci tipc_reset_bearer(net, b); 7068c2ecf20Sopenharmony_ci break; 7078c2ecf20Sopenharmony_ci case NETDEV_UNREGISTER: 7088c2ecf20Sopenharmony_ci case NETDEV_CHANGENAME: 7098c2ecf20Sopenharmony_ci bearer_disable(net, b); 7108c2ecf20Sopenharmony_ci break; 7118c2ecf20Sopenharmony_ci } 7128c2ecf20Sopenharmony_ci return NOTIFY_OK; 7138c2ecf20Sopenharmony_ci} 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_cistatic struct notifier_block notifier = { 7168c2ecf20Sopenharmony_ci .notifier_call = tipc_l2_device_event, 7178c2ecf20Sopenharmony_ci .priority = 0, 7188c2ecf20Sopenharmony_ci}; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ciint tipc_bearer_setup(void) 7218c2ecf20Sopenharmony_ci{ 7228c2ecf20Sopenharmony_ci return register_netdevice_notifier(¬ifier); 7238c2ecf20Sopenharmony_ci} 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_civoid tipc_bearer_cleanup(void) 7268c2ecf20Sopenharmony_ci{ 7278c2ecf20Sopenharmony_ci unregister_netdevice_notifier(¬ifier); 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_civoid tipc_bearer_stop(struct net *net) 7318c2ecf20Sopenharmony_ci{ 7328c2ecf20Sopenharmony_ci struct tipc_net *tn = net_generic(net, tipc_net_id); 7338c2ecf20Sopenharmony_ci struct tipc_bearer *b; 7348c2ecf20Sopenharmony_ci u32 i; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci for (i = 0; i < MAX_BEARERS; i++) { 7378c2ecf20Sopenharmony_ci b = rtnl_dereference(tn->bearer_list[i]); 7388c2ecf20Sopenharmony_ci if (b) { 7398c2ecf20Sopenharmony_ci bearer_disable(net, b); 7408c2ecf20Sopenharmony_ci tn->bearer_list[i] = NULL; 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci} 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_civoid tipc_clone_to_loopback(struct net *net, struct sk_buff_head *pkts) 7468c2ecf20Sopenharmony_ci{ 7478c2ecf20Sopenharmony_ci struct net_device *dev = net->loopback_dev; 7488c2ecf20Sopenharmony_ci struct sk_buff *skb, *_skb; 7498c2ecf20Sopenharmony_ci int exp; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci skb_queue_walk(pkts, _skb) { 7528c2ecf20Sopenharmony_ci skb = pskb_copy(_skb, GFP_ATOMIC); 7538c2ecf20Sopenharmony_ci if (!skb) 7548c2ecf20Sopenharmony_ci continue; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci exp = SKB_DATA_ALIGN(dev->hard_header_len - skb_headroom(skb)); 7578c2ecf20Sopenharmony_ci if (exp > 0 && pskb_expand_head(skb, exp, 0, GFP_ATOMIC)) { 7588c2ecf20Sopenharmony_ci kfree_skb(skb); 7598c2ecf20Sopenharmony_ci continue; 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci skb_reset_network_header(skb); 7638c2ecf20Sopenharmony_ci dev_hard_header(skb, dev, ETH_P_TIPC, dev->dev_addr, 7648c2ecf20Sopenharmony_ci dev->dev_addr, skb->len); 7658c2ecf20Sopenharmony_ci skb->dev = dev; 7668c2ecf20Sopenharmony_ci skb->pkt_type = PACKET_HOST; 7678c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 7688c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, dev); 7698c2ecf20Sopenharmony_ci netif_rx_ni(skb); 7708c2ecf20Sopenharmony_ci } 7718c2ecf20Sopenharmony_ci} 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_cistatic int tipc_loopback_rcv_pkt(struct sk_buff *skb, struct net_device *dev, 7748c2ecf20Sopenharmony_ci struct packet_type *pt, struct net_device *od) 7758c2ecf20Sopenharmony_ci{ 7768c2ecf20Sopenharmony_ci consume_skb(skb); 7778c2ecf20Sopenharmony_ci return NET_RX_SUCCESS; 7788c2ecf20Sopenharmony_ci} 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ciint tipc_attach_loopback(struct net *net) 7818c2ecf20Sopenharmony_ci{ 7828c2ecf20Sopenharmony_ci struct net_device *dev = net->loopback_dev; 7838c2ecf20Sopenharmony_ci struct tipc_net *tn = tipc_net(net); 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci if (!dev) 7868c2ecf20Sopenharmony_ci return -ENODEV; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci dev_hold(dev); 7898c2ecf20Sopenharmony_ci tn->loopback_pt.dev = dev; 7908c2ecf20Sopenharmony_ci tn->loopback_pt.type = htons(ETH_P_TIPC); 7918c2ecf20Sopenharmony_ci tn->loopback_pt.func = tipc_loopback_rcv_pkt; 7928c2ecf20Sopenharmony_ci dev_add_pack(&tn->loopback_pt); 7938c2ecf20Sopenharmony_ci return 0; 7948c2ecf20Sopenharmony_ci} 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_civoid tipc_detach_loopback(struct net *net) 7978c2ecf20Sopenharmony_ci{ 7988c2ecf20Sopenharmony_ci struct tipc_net *tn = tipc_net(net); 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci dev_remove_pack(&tn->loopback_pt); 8018c2ecf20Sopenharmony_ci dev_put(net->loopback_dev); 8028c2ecf20Sopenharmony_ci} 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci/* Caller should hold rtnl_lock to protect the bearer */ 8058c2ecf20Sopenharmony_cistatic int __tipc_nl_add_bearer(struct tipc_nl_msg *msg, 8068c2ecf20Sopenharmony_ci struct tipc_bearer *bearer, int nlflags) 8078c2ecf20Sopenharmony_ci{ 8088c2ecf20Sopenharmony_ci void *hdr; 8098c2ecf20Sopenharmony_ci struct nlattr *attrs; 8108c2ecf20Sopenharmony_ci struct nlattr *prop; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family, 8138c2ecf20Sopenharmony_ci nlflags, TIPC_NL_BEARER_GET); 8148c2ecf20Sopenharmony_ci if (!hdr) 8158c2ecf20Sopenharmony_ci return -EMSGSIZE; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci attrs = nla_nest_start_noflag(msg->skb, TIPC_NLA_BEARER); 8188c2ecf20Sopenharmony_ci if (!attrs) 8198c2ecf20Sopenharmony_ci goto msg_full; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci if (nla_put_string(msg->skb, TIPC_NLA_BEARER_NAME, bearer->name)) 8228c2ecf20Sopenharmony_ci goto attr_msg_full; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci prop = nla_nest_start_noflag(msg->skb, TIPC_NLA_BEARER_PROP); 8258c2ecf20Sopenharmony_ci if (!prop) 8268c2ecf20Sopenharmony_ci goto prop_msg_full; 8278c2ecf20Sopenharmony_ci if (nla_put_u32(msg->skb, TIPC_NLA_PROP_PRIO, bearer->priority)) 8288c2ecf20Sopenharmony_ci goto prop_msg_full; 8298c2ecf20Sopenharmony_ci if (nla_put_u32(msg->skb, TIPC_NLA_PROP_TOL, bearer->tolerance)) 8308c2ecf20Sopenharmony_ci goto prop_msg_full; 8318c2ecf20Sopenharmony_ci if (nla_put_u32(msg->skb, TIPC_NLA_PROP_WIN, bearer->max_win)) 8328c2ecf20Sopenharmony_ci goto prop_msg_full; 8338c2ecf20Sopenharmony_ci if (bearer->media->type_id == TIPC_MEDIA_TYPE_UDP) 8348c2ecf20Sopenharmony_ci if (nla_put_u32(msg->skb, TIPC_NLA_PROP_MTU, bearer->mtu)) 8358c2ecf20Sopenharmony_ci goto prop_msg_full; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci nla_nest_end(msg->skb, prop); 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci#ifdef CONFIG_TIPC_MEDIA_UDP 8408c2ecf20Sopenharmony_ci if (bearer->media->type_id == TIPC_MEDIA_TYPE_UDP) { 8418c2ecf20Sopenharmony_ci if (tipc_udp_nl_add_bearer_data(msg, bearer)) 8428c2ecf20Sopenharmony_ci goto attr_msg_full; 8438c2ecf20Sopenharmony_ci } 8448c2ecf20Sopenharmony_ci#endif 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci nla_nest_end(msg->skb, attrs); 8478c2ecf20Sopenharmony_ci genlmsg_end(msg->skb, hdr); 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci return 0; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ciprop_msg_full: 8528c2ecf20Sopenharmony_ci nla_nest_cancel(msg->skb, prop); 8538c2ecf20Sopenharmony_ciattr_msg_full: 8548c2ecf20Sopenharmony_ci nla_nest_cancel(msg->skb, attrs); 8558c2ecf20Sopenharmony_cimsg_full: 8568c2ecf20Sopenharmony_ci genlmsg_cancel(msg->skb, hdr); 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci return -EMSGSIZE; 8598c2ecf20Sopenharmony_ci} 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ciint tipc_nl_bearer_dump(struct sk_buff *skb, struct netlink_callback *cb) 8628c2ecf20Sopenharmony_ci{ 8638c2ecf20Sopenharmony_ci int err; 8648c2ecf20Sopenharmony_ci int i = cb->args[0]; 8658c2ecf20Sopenharmony_ci struct tipc_bearer *bearer; 8668c2ecf20Sopenharmony_ci struct tipc_nl_msg msg; 8678c2ecf20Sopenharmony_ci struct net *net = sock_net(skb->sk); 8688c2ecf20Sopenharmony_ci struct tipc_net *tn = net_generic(net, tipc_net_id); 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci if (i == MAX_BEARERS) 8718c2ecf20Sopenharmony_ci return 0; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci msg.skb = skb; 8748c2ecf20Sopenharmony_ci msg.portid = NETLINK_CB(cb->skb).portid; 8758c2ecf20Sopenharmony_ci msg.seq = cb->nlh->nlmsg_seq; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci rtnl_lock(); 8788c2ecf20Sopenharmony_ci for (i = 0; i < MAX_BEARERS; i++) { 8798c2ecf20Sopenharmony_ci bearer = rtnl_dereference(tn->bearer_list[i]); 8808c2ecf20Sopenharmony_ci if (!bearer) 8818c2ecf20Sopenharmony_ci continue; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci err = __tipc_nl_add_bearer(&msg, bearer, NLM_F_MULTI); 8848c2ecf20Sopenharmony_ci if (err) 8858c2ecf20Sopenharmony_ci break; 8868c2ecf20Sopenharmony_ci } 8878c2ecf20Sopenharmony_ci rtnl_unlock(); 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci cb->args[0] = i; 8908c2ecf20Sopenharmony_ci return skb->len; 8918c2ecf20Sopenharmony_ci} 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ciint tipc_nl_bearer_get(struct sk_buff *skb, struct genl_info *info) 8948c2ecf20Sopenharmony_ci{ 8958c2ecf20Sopenharmony_ci int err; 8968c2ecf20Sopenharmony_ci char *name; 8978c2ecf20Sopenharmony_ci struct sk_buff *rep; 8988c2ecf20Sopenharmony_ci struct tipc_bearer *bearer; 8998c2ecf20Sopenharmony_ci struct tipc_nl_msg msg; 9008c2ecf20Sopenharmony_ci struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1]; 9018c2ecf20Sopenharmony_ci struct net *net = genl_info_net(info); 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci if (!info->attrs[TIPC_NLA_BEARER]) 9048c2ecf20Sopenharmony_ci return -EINVAL; 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci err = nla_parse_nested_deprecated(attrs, TIPC_NLA_BEARER_MAX, 9078c2ecf20Sopenharmony_ci info->attrs[TIPC_NLA_BEARER], 9088c2ecf20Sopenharmony_ci tipc_nl_bearer_policy, info->extack); 9098c2ecf20Sopenharmony_ci if (err) 9108c2ecf20Sopenharmony_ci return err; 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci if (!attrs[TIPC_NLA_BEARER_NAME]) 9138c2ecf20Sopenharmony_ci return -EINVAL; 9148c2ecf20Sopenharmony_ci name = nla_data(attrs[TIPC_NLA_BEARER_NAME]); 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci rep = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 9178c2ecf20Sopenharmony_ci if (!rep) 9188c2ecf20Sopenharmony_ci return -ENOMEM; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci msg.skb = rep; 9218c2ecf20Sopenharmony_ci msg.portid = info->snd_portid; 9228c2ecf20Sopenharmony_ci msg.seq = info->snd_seq; 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci rtnl_lock(); 9258c2ecf20Sopenharmony_ci bearer = tipc_bearer_find(net, name); 9268c2ecf20Sopenharmony_ci if (!bearer) { 9278c2ecf20Sopenharmony_ci err = -EINVAL; 9288c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(info->extack, "Bearer not found"); 9298c2ecf20Sopenharmony_ci goto err_out; 9308c2ecf20Sopenharmony_ci } 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci err = __tipc_nl_add_bearer(&msg, bearer, 0); 9338c2ecf20Sopenharmony_ci if (err) 9348c2ecf20Sopenharmony_ci goto err_out; 9358c2ecf20Sopenharmony_ci rtnl_unlock(); 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci return genlmsg_reply(rep, info); 9388c2ecf20Sopenharmony_cierr_out: 9398c2ecf20Sopenharmony_ci rtnl_unlock(); 9408c2ecf20Sopenharmony_ci nlmsg_free(rep); 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci return err; 9438c2ecf20Sopenharmony_ci} 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ciint __tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info) 9468c2ecf20Sopenharmony_ci{ 9478c2ecf20Sopenharmony_ci int err; 9488c2ecf20Sopenharmony_ci char *name; 9498c2ecf20Sopenharmony_ci struct tipc_bearer *bearer; 9508c2ecf20Sopenharmony_ci struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1]; 9518c2ecf20Sopenharmony_ci struct net *net = sock_net(skb->sk); 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci if (!info->attrs[TIPC_NLA_BEARER]) 9548c2ecf20Sopenharmony_ci return -EINVAL; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci err = nla_parse_nested_deprecated(attrs, TIPC_NLA_BEARER_MAX, 9578c2ecf20Sopenharmony_ci info->attrs[TIPC_NLA_BEARER], 9588c2ecf20Sopenharmony_ci tipc_nl_bearer_policy, info->extack); 9598c2ecf20Sopenharmony_ci if (err) 9608c2ecf20Sopenharmony_ci return err; 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci if (!attrs[TIPC_NLA_BEARER_NAME]) 9638c2ecf20Sopenharmony_ci return -EINVAL; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci name = nla_data(attrs[TIPC_NLA_BEARER_NAME]); 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci bearer = tipc_bearer_find(net, name); 9688c2ecf20Sopenharmony_ci if (!bearer) { 9698c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(info->extack, "Bearer not found"); 9708c2ecf20Sopenharmony_ci return -EINVAL; 9718c2ecf20Sopenharmony_ci } 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci bearer_disable(net, bearer); 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci return 0; 9768c2ecf20Sopenharmony_ci} 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ciint tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info) 9798c2ecf20Sopenharmony_ci{ 9808c2ecf20Sopenharmony_ci int err; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci rtnl_lock(); 9838c2ecf20Sopenharmony_ci err = __tipc_nl_bearer_disable(skb, info); 9848c2ecf20Sopenharmony_ci rtnl_unlock(); 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci return err; 9878c2ecf20Sopenharmony_ci} 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ciint __tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info) 9908c2ecf20Sopenharmony_ci{ 9918c2ecf20Sopenharmony_ci int err; 9928c2ecf20Sopenharmony_ci char *bearer; 9938c2ecf20Sopenharmony_ci struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1]; 9948c2ecf20Sopenharmony_ci struct net *net = sock_net(skb->sk); 9958c2ecf20Sopenharmony_ci u32 domain = 0; 9968c2ecf20Sopenharmony_ci u32 prio; 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci prio = TIPC_MEDIA_LINK_PRI; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci if (!info->attrs[TIPC_NLA_BEARER]) 10018c2ecf20Sopenharmony_ci return -EINVAL; 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci err = nla_parse_nested_deprecated(attrs, TIPC_NLA_BEARER_MAX, 10048c2ecf20Sopenharmony_ci info->attrs[TIPC_NLA_BEARER], 10058c2ecf20Sopenharmony_ci tipc_nl_bearer_policy, info->extack); 10068c2ecf20Sopenharmony_ci if (err) 10078c2ecf20Sopenharmony_ci return err; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci if (!attrs[TIPC_NLA_BEARER_NAME]) 10108c2ecf20Sopenharmony_ci return -EINVAL; 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci bearer = nla_data(attrs[TIPC_NLA_BEARER_NAME]); 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci if (attrs[TIPC_NLA_BEARER_DOMAIN]) 10158c2ecf20Sopenharmony_ci domain = nla_get_u32(attrs[TIPC_NLA_BEARER_DOMAIN]); 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci if (attrs[TIPC_NLA_BEARER_PROP]) { 10188c2ecf20Sopenharmony_ci struct nlattr *props[TIPC_NLA_PROP_MAX + 1]; 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci err = tipc_nl_parse_link_prop(attrs[TIPC_NLA_BEARER_PROP], 10218c2ecf20Sopenharmony_ci props); 10228c2ecf20Sopenharmony_ci if (err) 10238c2ecf20Sopenharmony_ci return err; 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci if (props[TIPC_NLA_PROP_PRIO]) 10268c2ecf20Sopenharmony_ci prio = nla_get_u32(props[TIPC_NLA_PROP_PRIO]); 10278c2ecf20Sopenharmony_ci } 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci return tipc_enable_bearer(net, bearer, domain, prio, attrs, 10308c2ecf20Sopenharmony_ci info->extack); 10318c2ecf20Sopenharmony_ci} 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ciint tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info) 10348c2ecf20Sopenharmony_ci{ 10358c2ecf20Sopenharmony_ci int err; 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci rtnl_lock(); 10388c2ecf20Sopenharmony_ci err = __tipc_nl_bearer_enable(skb, info); 10398c2ecf20Sopenharmony_ci rtnl_unlock(); 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci return err; 10428c2ecf20Sopenharmony_ci} 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ciint tipc_nl_bearer_add(struct sk_buff *skb, struct genl_info *info) 10458c2ecf20Sopenharmony_ci{ 10468c2ecf20Sopenharmony_ci int err; 10478c2ecf20Sopenharmony_ci char *name; 10488c2ecf20Sopenharmony_ci struct tipc_bearer *b; 10498c2ecf20Sopenharmony_ci struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1]; 10508c2ecf20Sopenharmony_ci struct net *net = sock_net(skb->sk); 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci if (!info->attrs[TIPC_NLA_BEARER]) 10538c2ecf20Sopenharmony_ci return -EINVAL; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci err = nla_parse_nested_deprecated(attrs, TIPC_NLA_BEARER_MAX, 10568c2ecf20Sopenharmony_ci info->attrs[TIPC_NLA_BEARER], 10578c2ecf20Sopenharmony_ci tipc_nl_bearer_policy, info->extack); 10588c2ecf20Sopenharmony_ci if (err) 10598c2ecf20Sopenharmony_ci return err; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci if (!attrs[TIPC_NLA_BEARER_NAME]) 10628c2ecf20Sopenharmony_ci return -EINVAL; 10638c2ecf20Sopenharmony_ci name = nla_data(attrs[TIPC_NLA_BEARER_NAME]); 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci rtnl_lock(); 10668c2ecf20Sopenharmony_ci b = tipc_bearer_find(net, name); 10678c2ecf20Sopenharmony_ci if (!b) { 10688c2ecf20Sopenharmony_ci rtnl_unlock(); 10698c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(info->extack, "Bearer not found"); 10708c2ecf20Sopenharmony_ci return -EINVAL; 10718c2ecf20Sopenharmony_ci } 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci#ifdef CONFIG_TIPC_MEDIA_UDP 10748c2ecf20Sopenharmony_ci if (attrs[TIPC_NLA_BEARER_UDP_OPTS]) { 10758c2ecf20Sopenharmony_ci if (b->media->type_id != TIPC_MEDIA_TYPE_UDP) { 10768c2ecf20Sopenharmony_ci rtnl_unlock(); 10778c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(info->extack, "UDP option is unsupported"); 10788c2ecf20Sopenharmony_ci return -EINVAL; 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci err = tipc_udp_nl_bearer_add(b, 10828c2ecf20Sopenharmony_ci attrs[TIPC_NLA_BEARER_UDP_OPTS]); 10838c2ecf20Sopenharmony_ci if (err) { 10848c2ecf20Sopenharmony_ci rtnl_unlock(); 10858c2ecf20Sopenharmony_ci return err; 10868c2ecf20Sopenharmony_ci } 10878c2ecf20Sopenharmony_ci } 10888c2ecf20Sopenharmony_ci#endif 10898c2ecf20Sopenharmony_ci rtnl_unlock(); 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci return 0; 10928c2ecf20Sopenharmony_ci} 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ciint __tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info) 10958c2ecf20Sopenharmony_ci{ 10968c2ecf20Sopenharmony_ci struct tipc_bearer *b; 10978c2ecf20Sopenharmony_ci struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1]; 10988c2ecf20Sopenharmony_ci struct net *net = sock_net(skb->sk); 10998c2ecf20Sopenharmony_ci char *name; 11008c2ecf20Sopenharmony_ci int err; 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci if (!info->attrs[TIPC_NLA_BEARER]) 11038c2ecf20Sopenharmony_ci return -EINVAL; 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci err = nla_parse_nested_deprecated(attrs, TIPC_NLA_BEARER_MAX, 11068c2ecf20Sopenharmony_ci info->attrs[TIPC_NLA_BEARER], 11078c2ecf20Sopenharmony_ci tipc_nl_bearer_policy, info->extack); 11088c2ecf20Sopenharmony_ci if (err) 11098c2ecf20Sopenharmony_ci return err; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci if (!attrs[TIPC_NLA_BEARER_NAME]) 11128c2ecf20Sopenharmony_ci return -EINVAL; 11138c2ecf20Sopenharmony_ci name = nla_data(attrs[TIPC_NLA_BEARER_NAME]); 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci b = tipc_bearer_find(net, name); 11168c2ecf20Sopenharmony_ci if (!b) { 11178c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(info->extack, "Bearer not found"); 11188c2ecf20Sopenharmony_ci return -EINVAL; 11198c2ecf20Sopenharmony_ci } 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci if (attrs[TIPC_NLA_BEARER_PROP]) { 11228c2ecf20Sopenharmony_ci struct nlattr *props[TIPC_NLA_PROP_MAX + 1]; 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci err = tipc_nl_parse_link_prop(attrs[TIPC_NLA_BEARER_PROP], 11258c2ecf20Sopenharmony_ci props); 11268c2ecf20Sopenharmony_ci if (err) 11278c2ecf20Sopenharmony_ci return err; 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci if (props[TIPC_NLA_PROP_TOL]) { 11308c2ecf20Sopenharmony_ci b->tolerance = nla_get_u32(props[TIPC_NLA_PROP_TOL]); 11318c2ecf20Sopenharmony_ci tipc_node_apply_property(net, b, TIPC_NLA_PROP_TOL); 11328c2ecf20Sopenharmony_ci } 11338c2ecf20Sopenharmony_ci if (props[TIPC_NLA_PROP_PRIO]) 11348c2ecf20Sopenharmony_ci b->priority = nla_get_u32(props[TIPC_NLA_PROP_PRIO]); 11358c2ecf20Sopenharmony_ci if (props[TIPC_NLA_PROP_WIN]) 11368c2ecf20Sopenharmony_ci b->max_win = nla_get_u32(props[TIPC_NLA_PROP_WIN]); 11378c2ecf20Sopenharmony_ci if (props[TIPC_NLA_PROP_MTU]) { 11388c2ecf20Sopenharmony_ci if (b->media->type_id != TIPC_MEDIA_TYPE_UDP) { 11398c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(info->extack, 11408c2ecf20Sopenharmony_ci "MTU property is unsupported"); 11418c2ecf20Sopenharmony_ci return -EINVAL; 11428c2ecf20Sopenharmony_ci } 11438c2ecf20Sopenharmony_ci#ifdef CONFIG_TIPC_MEDIA_UDP 11448c2ecf20Sopenharmony_ci if (nla_get_u32(props[TIPC_NLA_PROP_MTU]) < 11458c2ecf20Sopenharmony_ci b->encap_hlen + TIPC_MIN_BEARER_MTU) { 11468c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(info->extack, 11478c2ecf20Sopenharmony_ci "MTU value is out-of-range"); 11488c2ecf20Sopenharmony_ci return -EINVAL; 11498c2ecf20Sopenharmony_ci } 11508c2ecf20Sopenharmony_ci b->mtu = nla_get_u32(props[TIPC_NLA_PROP_MTU]); 11518c2ecf20Sopenharmony_ci tipc_node_apply_property(net, b, TIPC_NLA_PROP_MTU); 11528c2ecf20Sopenharmony_ci#endif 11538c2ecf20Sopenharmony_ci } 11548c2ecf20Sopenharmony_ci } 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci return 0; 11578c2ecf20Sopenharmony_ci} 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ciint tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info) 11608c2ecf20Sopenharmony_ci{ 11618c2ecf20Sopenharmony_ci int err; 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci rtnl_lock(); 11648c2ecf20Sopenharmony_ci err = __tipc_nl_bearer_set(skb, info); 11658c2ecf20Sopenharmony_ci rtnl_unlock(); 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci return err; 11688c2ecf20Sopenharmony_ci} 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_cistatic int __tipc_nl_add_media(struct tipc_nl_msg *msg, 11718c2ecf20Sopenharmony_ci struct tipc_media *media, int nlflags) 11728c2ecf20Sopenharmony_ci{ 11738c2ecf20Sopenharmony_ci void *hdr; 11748c2ecf20Sopenharmony_ci struct nlattr *attrs; 11758c2ecf20Sopenharmony_ci struct nlattr *prop; 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family, 11788c2ecf20Sopenharmony_ci nlflags, TIPC_NL_MEDIA_GET); 11798c2ecf20Sopenharmony_ci if (!hdr) 11808c2ecf20Sopenharmony_ci return -EMSGSIZE; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci attrs = nla_nest_start_noflag(msg->skb, TIPC_NLA_MEDIA); 11838c2ecf20Sopenharmony_ci if (!attrs) 11848c2ecf20Sopenharmony_ci goto msg_full; 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci if (nla_put_string(msg->skb, TIPC_NLA_MEDIA_NAME, media->name)) 11878c2ecf20Sopenharmony_ci goto attr_msg_full; 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci prop = nla_nest_start_noflag(msg->skb, TIPC_NLA_MEDIA_PROP); 11908c2ecf20Sopenharmony_ci if (!prop) 11918c2ecf20Sopenharmony_ci goto prop_msg_full; 11928c2ecf20Sopenharmony_ci if (nla_put_u32(msg->skb, TIPC_NLA_PROP_PRIO, media->priority)) 11938c2ecf20Sopenharmony_ci goto prop_msg_full; 11948c2ecf20Sopenharmony_ci if (nla_put_u32(msg->skb, TIPC_NLA_PROP_TOL, media->tolerance)) 11958c2ecf20Sopenharmony_ci goto prop_msg_full; 11968c2ecf20Sopenharmony_ci if (nla_put_u32(msg->skb, TIPC_NLA_PROP_WIN, media->max_win)) 11978c2ecf20Sopenharmony_ci goto prop_msg_full; 11988c2ecf20Sopenharmony_ci if (media->type_id == TIPC_MEDIA_TYPE_UDP) 11998c2ecf20Sopenharmony_ci if (nla_put_u32(msg->skb, TIPC_NLA_PROP_MTU, media->mtu)) 12008c2ecf20Sopenharmony_ci goto prop_msg_full; 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci nla_nest_end(msg->skb, prop); 12038c2ecf20Sopenharmony_ci nla_nest_end(msg->skb, attrs); 12048c2ecf20Sopenharmony_ci genlmsg_end(msg->skb, hdr); 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci return 0; 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ciprop_msg_full: 12098c2ecf20Sopenharmony_ci nla_nest_cancel(msg->skb, prop); 12108c2ecf20Sopenharmony_ciattr_msg_full: 12118c2ecf20Sopenharmony_ci nla_nest_cancel(msg->skb, attrs); 12128c2ecf20Sopenharmony_cimsg_full: 12138c2ecf20Sopenharmony_ci genlmsg_cancel(msg->skb, hdr); 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci return -EMSGSIZE; 12168c2ecf20Sopenharmony_ci} 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ciint tipc_nl_media_dump(struct sk_buff *skb, struct netlink_callback *cb) 12198c2ecf20Sopenharmony_ci{ 12208c2ecf20Sopenharmony_ci int err; 12218c2ecf20Sopenharmony_ci int i = cb->args[0]; 12228c2ecf20Sopenharmony_ci struct tipc_nl_msg msg; 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci if (i == MAX_MEDIA) 12258c2ecf20Sopenharmony_ci return 0; 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci msg.skb = skb; 12288c2ecf20Sopenharmony_ci msg.portid = NETLINK_CB(cb->skb).portid; 12298c2ecf20Sopenharmony_ci msg.seq = cb->nlh->nlmsg_seq; 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci rtnl_lock(); 12328c2ecf20Sopenharmony_ci for (; media_info_array[i] != NULL; i++) { 12338c2ecf20Sopenharmony_ci err = __tipc_nl_add_media(&msg, media_info_array[i], 12348c2ecf20Sopenharmony_ci NLM_F_MULTI); 12358c2ecf20Sopenharmony_ci if (err) 12368c2ecf20Sopenharmony_ci break; 12378c2ecf20Sopenharmony_ci } 12388c2ecf20Sopenharmony_ci rtnl_unlock(); 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci cb->args[0] = i; 12418c2ecf20Sopenharmony_ci return skb->len; 12428c2ecf20Sopenharmony_ci} 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ciint tipc_nl_media_get(struct sk_buff *skb, struct genl_info *info) 12458c2ecf20Sopenharmony_ci{ 12468c2ecf20Sopenharmony_ci int err; 12478c2ecf20Sopenharmony_ci char *name; 12488c2ecf20Sopenharmony_ci struct tipc_nl_msg msg; 12498c2ecf20Sopenharmony_ci struct tipc_media *media; 12508c2ecf20Sopenharmony_ci struct sk_buff *rep; 12518c2ecf20Sopenharmony_ci struct nlattr *attrs[TIPC_NLA_MEDIA_MAX + 1]; 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci if (!info->attrs[TIPC_NLA_MEDIA]) 12548c2ecf20Sopenharmony_ci return -EINVAL; 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci err = nla_parse_nested_deprecated(attrs, TIPC_NLA_MEDIA_MAX, 12578c2ecf20Sopenharmony_ci info->attrs[TIPC_NLA_MEDIA], 12588c2ecf20Sopenharmony_ci tipc_nl_media_policy, info->extack); 12598c2ecf20Sopenharmony_ci if (err) 12608c2ecf20Sopenharmony_ci return err; 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci if (!attrs[TIPC_NLA_MEDIA_NAME]) 12638c2ecf20Sopenharmony_ci return -EINVAL; 12648c2ecf20Sopenharmony_ci name = nla_data(attrs[TIPC_NLA_MEDIA_NAME]); 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci rep = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 12678c2ecf20Sopenharmony_ci if (!rep) 12688c2ecf20Sopenharmony_ci return -ENOMEM; 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci msg.skb = rep; 12718c2ecf20Sopenharmony_ci msg.portid = info->snd_portid; 12728c2ecf20Sopenharmony_ci msg.seq = info->snd_seq; 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci rtnl_lock(); 12758c2ecf20Sopenharmony_ci media = tipc_media_find(name); 12768c2ecf20Sopenharmony_ci if (!media) { 12778c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(info->extack, "Media not found"); 12788c2ecf20Sopenharmony_ci err = -EINVAL; 12798c2ecf20Sopenharmony_ci goto err_out; 12808c2ecf20Sopenharmony_ci } 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci err = __tipc_nl_add_media(&msg, media, 0); 12838c2ecf20Sopenharmony_ci if (err) 12848c2ecf20Sopenharmony_ci goto err_out; 12858c2ecf20Sopenharmony_ci rtnl_unlock(); 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci return genlmsg_reply(rep, info); 12888c2ecf20Sopenharmony_cierr_out: 12898c2ecf20Sopenharmony_ci rtnl_unlock(); 12908c2ecf20Sopenharmony_ci nlmsg_free(rep); 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci return err; 12938c2ecf20Sopenharmony_ci} 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ciint __tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info) 12968c2ecf20Sopenharmony_ci{ 12978c2ecf20Sopenharmony_ci int err; 12988c2ecf20Sopenharmony_ci char *name; 12998c2ecf20Sopenharmony_ci struct tipc_media *m; 13008c2ecf20Sopenharmony_ci struct nlattr *attrs[TIPC_NLA_MEDIA_MAX + 1]; 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci if (!info->attrs[TIPC_NLA_MEDIA]) 13038c2ecf20Sopenharmony_ci return -EINVAL; 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci err = nla_parse_nested_deprecated(attrs, TIPC_NLA_MEDIA_MAX, 13068c2ecf20Sopenharmony_ci info->attrs[TIPC_NLA_MEDIA], 13078c2ecf20Sopenharmony_ci tipc_nl_media_policy, info->extack); 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci if (!attrs[TIPC_NLA_MEDIA_NAME]) 13108c2ecf20Sopenharmony_ci return -EINVAL; 13118c2ecf20Sopenharmony_ci name = nla_data(attrs[TIPC_NLA_MEDIA_NAME]); 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci m = tipc_media_find(name); 13148c2ecf20Sopenharmony_ci if (!m) { 13158c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(info->extack, "Media not found"); 13168c2ecf20Sopenharmony_ci return -EINVAL; 13178c2ecf20Sopenharmony_ci } 13188c2ecf20Sopenharmony_ci if (attrs[TIPC_NLA_MEDIA_PROP]) { 13198c2ecf20Sopenharmony_ci struct nlattr *props[TIPC_NLA_PROP_MAX + 1]; 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci err = tipc_nl_parse_link_prop(attrs[TIPC_NLA_MEDIA_PROP], 13228c2ecf20Sopenharmony_ci props); 13238c2ecf20Sopenharmony_ci if (err) 13248c2ecf20Sopenharmony_ci return err; 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci if (props[TIPC_NLA_PROP_TOL]) 13278c2ecf20Sopenharmony_ci m->tolerance = nla_get_u32(props[TIPC_NLA_PROP_TOL]); 13288c2ecf20Sopenharmony_ci if (props[TIPC_NLA_PROP_PRIO]) 13298c2ecf20Sopenharmony_ci m->priority = nla_get_u32(props[TIPC_NLA_PROP_PRIO]); 13308c2ecf20Sopenharmony_ci if (props[TIPC_NLA_PROP_WIN]) 13318c2ecf20Sopenharmony_ci m->max_win = nla_get_u32(props[TIPC_NLA_PROP_WIN]); 13328c2ecf20Sopenharmony_ci if (props[TIPC_NLA_PROP_MTU]) { 13338c2ecf20Sopenharmony_ci if (m->type_id != TIPC_MEDIA_TYPE_UDP) { 13348c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(info->extack, 13358c2ecf20Sopenharmony_ci "MTU property is unsupported"); 13368c2ecf20Sopenharmony_ci return -EINVAL; 13378c2ecf20Sopenharmony_ci } 13388c2ecf20Sopenharmony_ci#ifdef CONFIG_TIPC_MEDIA_UDP 13398c2ecf20Sopenharmony_ci if (tipc_udp_mtu_bad(nla_get_u32 13408c2ecf20Sopenharmony_ci (props[TIPC_NLA_PROP_MTU]))) { 13418c2ecf20Sopenharmony_ci NL_SET_ERR_MSG(info->extack, 13428c2ecf20Sopenharmony_ci "MTU value is out-of-range"); 13438c2ecf20Sopenharmony_ci return -EINVAL; 13448c2ecf20Sopenharmony_ci } 13458c2ecf20Sopenharmony_ci m->mtu = nla_get_u32(props[TIPC_NLA_PROP_MTU]); 13468c2ecf20Sopenharmony_ci#endif 13478c2ecf20Sopenharmony_ci } 13488c2ecf20Sopenharmony_ci } 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci return 0; 13518c2ecf20Sopenharmony_ci} 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ciint tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info) 13548c2ecf20Sopenharmony_ci{ 13558c2ecf20Sopenharmony_ci int err; 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci rtnl_lock(); 13588c2ecf20Sopenharmony_ci err = __tipc_nl_media_set(skb, info); 13598c2ecf20Sopenharmony_ci rtnl_unlock(); 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci return err; 13628c2ecf20Sopenharmony_ci} 1363