Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.17.
  1/*
  2 * net/tipc/config.c: TIPC configuration management code
  3 *
  4 * Copyright (c) 2002-2006, Ericsson AB
  5 * Copyright (c) 2004-2007, 2010-2013, Wind River Systems
  6 * All rights reserved.
  7 *
  8 * Redistribution and use in source and binary forms, with or without
  9 * modification, are permitted provided that the following conditions are met:
 10 *
 11 * 1. Redistributions of source code must retain the above copyright
 12 *    notice, this list of conditions and the following disclaimer.
 13 * 2. Redistributions in binary form must reproduce the above copyright
 14 *    notice, this list of conditions and the following disclaimer in the
 15 *    documentation and/or other materials provided with the distribution.
 16 * 3. Neither the names of the copyright holders nor the names of its
 17 *    contributors may be used to endorse or promote products derived from
 18 *    this software without specific prior written permission.
 19 *
 20 * Alternatively, this software may be distributed under the terms of the
 21 * GNU General Public License ("GPL") version 2 as published by the Free
 22 * Software Foundation.
 23 *
 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 34 * POSSIBILITY OF SUCH DAMAGE.
 35 */
 36
 37#include "core.h"
 38#include "port.h"
 39#include "name_table.h"
 40#include "config.h"
 41#include "server.h"
 42
 43#define REPLY_TRUNCATED "<truncated>\n"
 44
 45static DEFINE_MUTEX(config_mutex);
 46
 47static const void *req_tlv_area;	/* request message TLV area */
 48static int req_tlv_space;		/* request message TLV area size */
 49static int rep_headroom;		/* reply message headroom to use */
 50
 51struct sk_buff *tipc_cfg_reply_alloc(int payload_size)
 52{
 53	struct sk_buff *buf;
 54
 55	buf = alloc_skb(rep_headroom + payload_size, GFP_ATOMIC);
 56	if (buf)
 57		skb_reserve(buf, rep_headroom);
 58	return buf;
 59}
 60
 61int tipc_cfg_append_tlv(struct sk_buff *buf, int tlv_type,
 62			void *tlv_data, int tlv_data_size)
 63{
 64	struct tlv_desc *tlv = (struct tlv_desc *)skb_tail_pointer(buf);
 65	int new_tlv_space = TLV_SPACE(tlv_data_size);
 66
 67	if (skb_tailroom(buf) < new_tlv_space)
 68		return 0;
 69	skb_put(buf, new_tlv_space);
 70	tlv->tlv_type = htons(tlv_type);
 71	tlv->tlv_len  = htons(TLV_LENGTH(tlv_data_size));
 72	if (tlv_data_size && tlv_data)
 73		memcpy(TLV_DATA(tlv), tlv_data, tlv_data_size);
 74	return 1;
 75}
 76
 77static struct sk_buff *tipc_cfg_reply_unsigned_type(u16 tlv_type, u32 value)
 78{
 79	struct sk_buff *buf;
 80	__be32 value_net;
 81
 82	buf = tipc_cfg_reply_alloc(TLV_SPACE(sizeof(value)));
 83	if (buf) {
 84		value_net = htonl(value);
 85		tipc_cfg_append_tlv(buf, tlv_type, &value_net,
 86				    sizeof(value_net));
 87	}
 88	return buf;
 89}
 90
 91static struct sk_buff *tipc_cfg_reply_unsigned(u32 value)
 92{
 93	return tipc_cfg_reply_unsigned_type(TIPC_TLV_UNSIGNED, value);
 94}
 95
 96struct sk_buff *tipc_cfg_reply_string_type(u16 tlv_type, char *string)
 97{
 98	struct sk_buff *buf;
 99	int string_len = strlen(string) + 1;
100
101	buf = tipc_cfg_reply_alloc(TLV_SPACE(string_len));
102	if (buf)
103		tipc_cfg_append_tlv(buf, tlv_type, string, string_len);
104	return buf;
105}
106
107static struct sk_buff *tipc_show_stats(void)
108{
109	struct sk_buff *buf;
110	struct tlv_desc *rep_tlv;
111	char *pb;
112	int pb_len;
113	int str_len;
114	u32 value;
115
116	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
117		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
118
119	value = ntohl(*(u32 *)TLV_DATA(req_tlv_area));
120	if (value != 0)
121		return tipc_cfg_reply_error_string("unsupported argument");
122
123	buf = tipc_cfg_reply_alloc(TLV_SPACE(ULTRA_STRING_MAX_LEN));
124	if (buf == NULL)
125		return NULL;
126
127	rep_tlv = (struct tlv_desc *)buf->data;
128	pb = TLV_DATA(rep_tlv);
129	pb_len = ULTRA_STRING_MAX_LEN;
130
131	str_len = tipc_snprintf(pb, pb_len, "TIPC version " TIPC_MOD_VER "\n");
132	str_len += 1;	/* for "\0" */
133	skb_put(buf, TLV_SPACE(str_len));
134	TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
135
136	return buf;
137}
138
139static struct sk_buff *cfg_enable_bearer(void)
140{
141	struct tipc_bearer_config *args;
142
143	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_BEARER_CONFIG))
144		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
145
146	args = (struct tipc_bearer_config *)TLV_DATA(req_tlv_area);
147	if (tipc_enable_bearer(args->name,
148			       ntohl(args->disc_domain),
149			       ntohl(args->priority)))
150		return tipc_cfg_reply_error_string("unable to enable bearer");
151
152	return tipc_cfg_reply_none();
153}
154
155static struct sk_buff *cfg_disable_bearer(void)
156{
157	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_BEARER_NAME))
158		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
159
160	if (tipc_disable_bearer((char *)TLV_DATA(req_tlv_area)))
161		return tipc_cfg_reply_error_string("unable to disable bearer");
162
163	return tipc_cfg_reply_none();
164}
165
166static struct sk_buff *cfg_set_own_addr(void)
167{
168	u32 addr;
169
170	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
171		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
172
173	addr = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
174	if (addr == tipc_own_addr)
175		return tipc_cfg_reply_none();
176	if (!tipc_addr_node_valid(addr))
177		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
178						   " (node address)");
179	if (tipc_own_addr)
180		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
181						   " (cannot change node address once assigned)");
182	tipc_net_start(addr);
183	return tipc_cfg_reply_none();
184}
185
186static struct sk_buff *cfg_set_max_ports(void)
187{
188	u32 value;
189
190	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
191		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
192	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
193	if (value == tipc_max_ports)
194		return tipc_cfg_reply_none();
195	if (value < 127 || value > 65535)
196		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
197						   " (max ports must be 127-65535)");
198	return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
199		" (cannot change max ports while TIPC is active)");
200}
201
202static struct sk_buff *cfg_set_netid(void)
203{
204	u32 value;
205
206	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
207		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
208	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
209	if (value == tipc_net_id)
210		return tipc_cfg_reply_none();
211	if (value < 1 || value > 9999)
212		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
213						   " (network id must be 1-9999)");
214	if (tipc_own_addr)
215		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
216			" (cannot change network id once TIPC has joined a network)");
217	tipc_net_id = value;
218	return tipc_cfg_reply_none();
219}
220
221struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area,
222				int request_space, int reply_headroom)
223{
224	struct sk_buff *rep_tlv_buf;
225
226	mutex_lock(&config_mutex);
227
228	/* Save request and reply details in a well-known location */
229	req_tlv_area = request_area;
230	req_tlv_space = request_space;
231	rep_headroom = reply_headroom;
232
233	/* Check command authorization */
234	if (likely(in_own_node(orig_node))) {
235		/* command is permitted */
236	} else {
237		rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
238							  " (cannot be done remotely)");
239		goto exit;
240	}
241
242	/* Call appropriate processing routine */
243	switch (cmd) {
244	case TIPC_CMD_NOOP:
245		rep_tlv_buf = tipc_cfg_reply_none();
246		break;
247	case TIPC_CMD_GET_NODES:
248		rep_tlv_buf = tipc_node_get_nodes(req_tlv_area, req_tlv_space);
249		break;
250	case TIPC_CMD_GET_LINKS:
251		rep_tlv_buf = tipc_node_get_links(req_tlv_area, req_tlv_space);
252		break;
253	case TIPC_CMD_SHOW_LINK_STATS:
254		rep_tlv_buf = tipc_link_cmd_show_stats(req_tlv_area, req_tlv_space);
255		break;
256	case TIPC_CMD_RESET_LINK_STATS:
257		rep_tlv_buf = tipc_link_cmd_reset_stats(req_tlv_area, req_tlv_space);
258		break;
259	case TIPC_CMD_SHOW_NAME_TABLE:
260		rep_tlv_buf = tipc_nametbl_get(req_tlv_area, req_tlv_space);
261		break;
262	case TIPC_CMD_GET_BEARER_NAMES:
263		rep_tlv_buf = tipc_bearer_get_names();
264		break;
265	case TIPC_CMD_GET_MEDIA_NAMES:
266		rep_tlv_buf = tipc_media_get_names();
267		break;
268	case TIPC_CMD_SHOW_PORTS:
269		rep_tlv_buf = tipc_port_get_ports();
270		break;
271	case TIPC_CMD_SHOW_STATS:
272		rep_tlv_buf = tipc_show_stats();
273		break;
274	case TIPC_CMD_SET_LINK_TOL:
275	case TIPC_CMD_SET_LINK_PRI:
276	case TIPC_CMD_SET_LINK_WINDOW:
277		rep_tlv_buf = tipc_link_cmd_config(req_tlv_area, req_tlv_space, cmd);
278		break;
279	case TIPC_CMD_ENABLE_BEARER:
280		rep_tlv_buf = cfg_enable_bearer();
281		break;
282	case TIPC_CMD_DISABLE_BEARER:
283		rep_tlv_buf = cfg_disable_bearer();
284		break;
285	case TIPC_CMD_SET_NODE_ADDR:
286		rep_tlv_buf = cfg_set_own_addr();
287		break;
288	case TIPC_CMD_SET_MAX_PORTS:
289		rep_tlv_buf = cfg_set_max_ports();
290		break;
291	case TIPC_CMD_SET_NETID:
292		rep_tlv_buf = cfg_set_netid();
293		break;
294	case TIPC_CMD_GET_MAX_PORTS:
295		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_ports);
296		break;
297	case TIPC_CMD_GET_NETID:
298		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_net_id);
299		break;
300	case TIPC_CMD_NOT_NET_ADMIN:
301		rep_tlv_buf =
302			tipc_cfg_reply_error_string(TIPC_CFG_NOT_NET_ADMIN);
303		break;
304	case TIPC_CMD_SET_MAX_ZONES:
305	case TIPC_CMD_GET_MAX_ZONES:
306	case TIPC_CMD_SET_MAX_SLAVES:
307	case TIPC_CMD_GET_MAX_SLAVES:
308	case TIPC_CMD_SET_MAX_CLUSTERS:
309	case TIPC_CMD_GET_MAX_CLUSTERS:
310	case TIPC_CMD_SET_MAX_NODES:
311	case TIPC_CMD_GET_MAX_NODES:
312	case TIPC_CMD_SET_MAX_SUBSCR:
313	case TIPC_CMD_GET_MAX_SUBSCR:
314	case TIPC_CMD_SET_MAX_PUBL:
315	case TIPC_CMD_GET_MAX_PUBL:
316	case TIPC_CMD_SET_LOG_SIZE:
317	case TIPC_CMD_SET_REMOTE_MNG:
318	case TIPC_CMD_GET_REMOTE_MNG:
319	case TIPC_CMD_DUMP_LOG:
320		rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
321							  " (obsolete command)");
322		break;
323	default:
324		rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
325							  " (unknown command)");
326		break;
327	}
328
329	WARN_ON(rep_tlv_buf->len > TLV_SPACE(ULTRA_STRING_MAX_LEN));
330
331	/* Append an error message if we cannot return all requested data */
332	if (rep_tlv_buf->len == TLV_SPACE(ULTRA_STRING_MAX_LEN)) {
333		if (*(rep_tlv_buf->data + ULTRA_STRING_MAX_LEN) != '\0')
334			sprintf(rep_tlv_buf->data + rep_tlv_buf->len -
335				sizeof(REPLY_TRUNCATED) - 1, REPLY_TRUNCATED);
336	}
337
338	/* Return reply buffer */
339exit:
340	mutex_unlock(&config_mutex);
341	return rep_tlv_buf;
342}