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-2011, 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
 42static u32 config_port_ref;
 43
 44static DEFINE_SPINLOCK(config_lock);
 45
 46static const void *req_tlv_area;	/* request message TLV area */
 47static int req_tlv_space;		/* request message TLV area size */
 48static int rep_headroom;		/* reply message headroom to use */
 49
 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
107#define MAX_STATS_INFO 2000
108
109static struct sk_buff *tipc_show_stats(void)
110{
111	struct sk_buff *buf;
112	struct tlv_desc *rep_tlv;
113	struct print_buf pb;
114	int str_len;
115	u32 value;
116
117	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
118		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
119
120	value = ntohl(*(u32 *)TLV_DATA(req_tlv_area));
121	if (value != 0)
122		return tipc_cfg_reply_error_string("unsupported argument");
123
124	buf = tipc_cfg_reply_alloc(TLV_SPACE(MAX_STATS_INFO));
125	if (buf == NULL)
126		return NULL;
127
128	rep_tlv = (struct tlv_desc *)buf->data;
129	tipc_printbuf_init(&pb, (char *)TLV_DATA(rep_tlv), MAX_STATS_INFO);
130
131	tipc_printf(&pb, "TIPC version " TIPC_MOD_VER "\n");
132
133	/* Use additional tipc_printf()'s to return more info ... */
134
135	str_len = tipc_printbuf_validate(&pb);
136	skb_put(buf, TLV_SPACE(str_len));
137	TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
138
139	return buf;
140}
141
142static struct sk_buff *cfg_enable_bearer(void)
143{
144	struct tipc_bearer_config *args;
145
146	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_BEARER_CONFIG))
147		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
148
149	args = (struct tipc_bearer_config *)TLV_DATA(req_tlv_area);
150	if (tipc_enable_bearer(args->name,
151			       ntohl(args->disc_domain),
152			       ntohl(args->priority)))
153		return tipc_cfg_reply_error_string("unable to enable bearer");
154
155	return tipc_cfg_reply_none();
156}
157
158static struct sk_buff *cfg_disable_bearer(void)
159{
160	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_BEARER_NAME))
161		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
162
163	if (tipc_disable_bearer((char *)TLV_DATA(req_tlv_area)))
164		return tipc_cfg_reply_error_string("unable to disable bearer");
165
166	return tipc_cfg_reply_none();
167}
168
169static struct sk_buff *cfg_set_own_addr(void)
170{
171	u32 addr;
172
173	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
174		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
175
176	addr = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
177	if (addr == tipc_own_addr)
178		return tipc_cfg_reply_none();
179	if (!tipc_addr_node_valid(addr))
180		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
181						   " (node address)");
182	if (tipc_mode == TIPC_NET_MODE)
183		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
184						   " (cannot change node address once assigned)");
185
186	/*
187	 * Must release all spinlocks before calling start_net() because
188	 * Linux version of TIPC calls eth_media_start() which calls
189	 * register_netdevice_notifier() which may block!
190	 *
191	 * Temporarily releasing the lock should be harmless for non-Linux TIPC,
192	 * but Linux version of eth_media_start() should really be reworked
193	 * so that it can be called with spinlocks held.
194	 */
195
196	spin_unlock_bh(&config_lock);
197	tipc_core_start_net(addr);
198	spin_lock_bh(&config_lock);
199	return tipc_cfg_reply_none();
200}
201
202static struct sk_buff *cfg_set_remote_mng(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
209	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
210	tipc_remote_management = (value != 0);
211	return tipc_cfg_reply_none();
212}
213
214static struct sk_buff *cfg_set_max_publications(void)
215{
216	u32 value;
217
218	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
219		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
220
221	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
222	if (value != delimit(value, 1, 65535))
223		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
224						   " (max publications must be 1-65535)");
225	tipc_max_publications = value;
226	return tipc_cfg_reply_none();
227}
228
229static struct sk_buff *cfg_set_max_subscriptions(void)
230{
231	u32 value;
232
233	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
234		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
235
236	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
237	if (value != delimit(value, 1, 65535))
238		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
239						   " (max subscriptions must be 1-65535");
240	tipc_max_subscriptions = value;
241	return tipc_cfg_reply_none();
242}
243
244static struct sk_buff *cfg_set_max_ports(void)
245{
246	u32 value;
247
248	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
249		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
250	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
251	if (value == tipc_max_ports)
252		return tipc_cfg_reply_none();
253	if (value != delimit(value, 127, 65535))
254		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
255						   " (max ports must be 127-65535)");
256	if (tipc_mode != TIPC_NOT_RUNNING)
257		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
258			" (cannot change max ports while TIPC is active)");
259	tipc_max_ports = value;
260	return tipc_cfg_reply_none();
261}
262
263static struct sk_buff *cfg_set_netid(void)
264{
265	u32 value;
266
267	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
268		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
269	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
270	if (value == tipc_net_id)
271		return tipc_cfg_reply_none();
272	if (value != delimit(value, 1, 9999))
273		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
274						   " (network id must be 1-9999)");
275	if (tipc_mode == TIPC_NET_MODE)
276		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
277			" (cannot change network id once TIPC has joined a network)");
278	tipc_net_id = value;
279	return tipc_cfg_reply_none();
280}
281
282struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area,
283				int request_space, int reply_headroom)
284{
285	struct sk_buff *rep_tlv_buf;
286
287	spin_lock_bh(&config_lock);
288
289	/* Save request and reply details in a well-known location */
290
291	req_tlv_area = request_area;
292	req_tlv_space = request_space;
293	rep_headroom = reply_headroom;
294
295	/* Check command authorization */
296
297	if (likely(orig_node == tipc_own_addr)) {
298		/* command is permitted */
299	} else if (cmd >= 0x8000) {
300		rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
301							  " (cannot be done remotely)");
302		goto exit;
303	} else if (!tipc_remote_management) {
304		rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NO_REMOTE);
305		goto exit;
306	} else if (cmd >= 0x4000) {
307		u32 domain = 0;
308
309		if ((tipc_nametbl_translate(TIPC_ZM_SRV, 0, &domain) == 0) ||
310		    (domain != orig_node)) {
311			rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_ZONE_MSTR);
312			goto exit;
313		}
314	}
315
316	/* Call appropriate processing routine */
317
318	switch (cmd) {
319	case TIPC_CMD_NOOP:
320		rep_tlv_buf = tipc_cfg_reply_none();
321		break;
322	case TIPC_CMD_GET_NODES:
323		rep_tlv_buf = tipc_node_get_nodes(req_tlv_area, req_tlv_space);
324		break;
325	case TIPC_CMD_GET_LINKS:
326		rep_tlv_buf = tipc_node_get_links(req_tlv_area, req_tlv_space);
327		break;
328	case TIPC_CMD_SHOW_LINK_STATS:
329		rep_tlv_buf = tipc_link_cmd_show_stats(req_tlv_area, req_tlv_space);
330		break;
331	case TIPC_CMD_RESET_LINK_STATS:
332		rep_tlv_buf = tipc_link_cmd_reset_stats(req_tlv_area, req_tlv_space);
333		break;
334	case TIPC_CMD_SHOW_NAME_TABLE:
335		rep_tlv_buf = tipc_nametbl_get(req_tlv_area, req_tlv_space);
336		break;
337	case TIPC_CMD_GET_BEARER_NAMES:
338		rep_tlv_buf = tipc_bearer_get_names();
339		break;
340	case TIPC_CMD_GET_MEDIA_NAMES:
341		rep_tlv_buf = tipc_media_get_names();
342		break;
343	case TIPC_CMD_SHOW_PORTS:
344		rep_tlv_buf = tipc_port_get_ports();
345		break;
346	case TIPC_CMD_SET_LOG_SIZE:
347		rep_tlv_buf = tipc_log_resize_cmd(req_tlv_area, req_tlv_space);
348		break;
349	case TIPC_CMD_DUMP_LOG:
350		rep_tlv_buf = tipc_log_dump();
351		break;
352	case TIPC_CMD_SHOW_STATS:
353		rep_tlv_buf = tipc_show_stats();
354		break;
355	case TIPC_CMD_SET_LINK_TOL:
356	case TIPC_CMD_SET_LINK_PRI:
357	case TIPC_CMD_SET_LINK_WINDOW:
358		rep_tlv_buf = tipc_link_cmd_config(req_tlv_area, req_tlv_space, cmd);
359		break;
360	case TIPC_CMD_ENABLE_BEARER:
361		rep_tlv_buf = cfg_enable_bearer();
362		break;
363	case TIPC_CMD_DISABLE_BEARER:
364		rep_tlv_buf = cfg_disable_bearer();
365		break;
366	case TIPC_CMD_SET_NODE_ADDR:
367		rep_tlv_buf = cfg_set_own_addr();
368		break;
369	case TIPC_CMD_SET_REMOTE_MNG:
370		rep_tlv_buf = cfg_set_remote_mng();
371		break;
372	case TIPC_CMD_SET_MAX_PORTS:
373		rep_tlv_buf = cfg_set_max_ports();
374		break;
375	case TIPC_CMD_SET_MAX_PUBL:
376		rep_tlv_buf = cfg_set_max_publications();
377		break;
378	case TIPC_CMD_SET_MAX_SUBSCR:
379		rep_tlv_buf = cfg_set_max_subscriptions();
380		break;
381	case TIPC_CMD_SET_NETID:
382		rep_tlv_buf = cfg_set_netid();
383		break;
384	case TIPC_CMD_GET_REMOTE_MNG:
385		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_remote_management);
386		break;
387	case TIPC_CMD_GET_MAX_PORTS:
388		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_ports);
389		break;
390	case TIPC_CMD_GET_MAX_PUBL:
391		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_publications);
392		break;
393	case TIPC_CMD_GET_MAX_SUBSCR:
394		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_subscriptions);
395		break;
396	case TIPC_CMD_GET_NETID:
397		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_net_id);
398		break;
399	case TIPC_CMD_NOT_NET_ADMIN:
400		rep_tlv_buf =
401			tipc_cfg_reply_error_string(TIPC_CFG_NOT_NET_ADMIN);
402		break;
403	case TIPC_CMD_SET_MAX_ZONES:
404	case TIPC_CMD_GET_MAX_ZONES:
405	case TIPC_CMD_SET_MAX_SLAVES:
406	case TIPC_CMD_GET_MAX_SLAVES:
407	case TIPC_CMD_SET_MAX_CLUSTERS:
408	case TIPC_CMD_GET_MAX_CLUSTERS:
409	case TIPC_CMD_SET_MAX_NODES:
410	case TIPC_CMD_GET_MAX_NODES:
411		rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
412							  " (obsolete command)");
413		break;
414	default:
415		rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
416							  " (unknown command)");
417		break;
418	}
419
420	/* Return reply buffer */
421exit:
422	spin_unlock_bh(&config_lock);
423	return rep_tlv_buf;
424}
425
426static void cfg_named_msg_event(void *userdata,
427				u32 port_ref,
428				struct sk_buff **buf,
429				const unchar *msg,
430				u32 size,
431				u32 importance,
432				struct tipc_portid const *orig,
433				struct tipc_name_seq const *dest)
434{
435	struct tipc_cfg_msg_hdr *req_hdr;
436	struct tipc_cfg_msg_hdr *rep_hdr;
437	struct sk_buff *rep_buf;
438
439	/* Validate configuration message header (ignore invalid message) */
440
441	req_hdr = (struct tipc_cfg_msg_hdr *)msg;
442	if ((size < sizeof(*req_hdr)) ||
443	    (size != TCM_ALIGN(ntohl(req_hdr->tcm_len))) ||
444	    (ntohs(req_hdr->tcm_flags) != TCM_F_REQUEST)) {
445		warn("Invalid configuration message discarded\n");
446		return;
447	}
448
449	/* Generate reply for request (if can't, return request) */
450
451	rep_buf = tipc_cfg_do_cmd(orig->node,
452				  ntohs(req_hdr->tcm_type),
453				  msg + sizeof(*req_hdr),
454				  size - sizeof(*req_hdr),
455				  BUF_HEADROOM + MAX_H_SIZE + sizeof(*rep_hdr));
456	if (rep_buf) {
457		skb_push(rep_buf, sizeof(*rep_hdr));
458		rep_hdr = (struct tipc_cfg_msg_hdr *)rep_buf->data;
459		memcpy(rep_hdr, req_hdr, sizeof(*rep_hdr));
460		rep_hdr->tcm_len = htonl(rep_buf->len);
461		rep_hdr->tcm_flags &= htons(~TCM_F_REQUEST);
462	} else {
463		rep_buf = *buf;
464		*buf = NULL;
465	}
466
467	/* NEED TO ADD CODE TO HANDLE FAILED SEND (SUCH AS CONGESTION) */
468	tipc_send_buf2port(port_ref, orig, rep_buf, rep_buf->len);
469}
470
471int tipc_cfg_init(void)
472{
473	struct tipc_name_seq seq;
474	int res;
475
476	res = tipc_createport(NULL, TIPC_CRITICAL_IMPORTANCE,
477			      NULL, NULL, NULL,
478			      NULL, cfg_named_msg_event, NULL,
479			      NULL, &config_port_ref);
480	if (res)
481		goto failed;
482
483	seq.type = TIPC_CFG_SRV;
484	seq.lower = seq.upper = tipc_own_addr;
485	res = tipc_nametbl_publish_rsv(config_port_ref, TIPC_ZONE_SCOPE, &seq);
486	if (res)
487		goto failed;
488
489	return 0;
490
491failed:
492	err("Unable to create configuration service\n");
493	return res;
494}
495
496void tipc_cfg_stop(void)
497{
498	if (config_port_ref) {
499		tipc_deleteport(config_port_ref);
500		config_port_ref = 0;
501	}
502}