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	&eth_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(&notifier);
7238c2ecf20Sopenharmony_ci}
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_civoid tipc_bearer_cleanup(void)
7268c2ecf20Sopenharmony_ci{
7278c2ecf20Sopenharmony_ci	unregister_netdevice_notifier(&notifier);
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