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