PageRenderTime 64ms CodeModel.GetById 18ms app.highlight 41ms RepoModel.GetById 1ms app.codeStats 0ms

/net/tipc/config.c

http://github.com/mirrors/linux
C | 448 lines | 347 code | 58 blank | 43 comment | 53 complexity | 6ff5c6cd3726b3153b137186c26b0c4a MD5 | raw file
  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);
 46static struct tipc_server cfgsrv;
 47
 48static const void *req_tlv_area;	/* request message TLV area */
 49static int req_tlv_space;		/* request message TLV area size */
 50static int rep_headroom;		/* reply message headroom to use */
 51
 52
 53struct sk_buff *tipc_cfg_reply_alloc(int payload_size)
 54{
 55	struct sk_buff *buf;
 56
 57	buf = alloc_skb(rep_headroom + payload_size, GFP_ATOMIC);
 58	if (buf)
 59		skb_reserve(buf, rep_headroom);
 60	return buf;
 61}
 62
 63int tipc_cfg_append_tlv(struct sk_buff *buf, int tlv_type,
 64			void *tlv_data, int tlv_data_size)
 65{
 66	struct tlv_desc *tlv = (struct tlv_desc *)skb_tail_pointer(buf);
 67	int new_tlv_space = TLV_SPACE(tlv_data_size);
 68
 69	if (skb_tailroom(buf) < new_tlv_space)
 70		return 0;
 71	skb_put(buf, new_tlv_space);
 72	tlv->tlv_type = htons(tlv_type);
 73	tlv->tlv_len  = htons(TLV_LENGTH(tlv_data_size));
 74	if (tlv_data_size && tlv_data)
 75		memcpy(TLV_DATA(tlv), tlv_data, tlv_data_size);
 76	return 1;
 77}
 78
 79static struct sk_buff *tipc_cfg_reply_unsigned_type(u16 tlv_type, u32 value)
 80{
 81	struct sk_buff *buf;
 82	__be32 value_net;
 83
 84	buf = tipc_cfg_reply_alloc(TLV_SPACE(sizeof(value)));
 85	if (buf) {
 86		value_net = htonl(value);
 87		tipc_cfg_append_tlv(buf, tlv_type, &value_net,
 88				    sizeof(value_net));
 89	}
 90	return buf;
 91}
 92
 93static struct sk_buff *tipc_cfg_reply_unsigned(u32 value)
 94{
 95	return tipc_cfg_reply_unsigned_type(TIPC_TLV_UNSIGNED, value);
 96}
 97
 98struct sk_buff *tipc_cfg_reply_string_type(u16 tlv_type, char *string)
 99{
100	struct sk_buff *buf;
101	int string_len = strlen(string) + 1;
102
103	buf = tipc_cfg_reply_alloc(TLV_SPACE(string_len));
104	if (buf)
105		tipc_cfg_append_tlv(buf, tlv_type, string, string_len);
106	return buf;
107}
108
109static struct sk_buff *tipc_show_stats(void)
110{
111	struct sk_buff *buf;
112	struct tlv_desc *rep_tlv;
113	char *pb;
114	int pb_len;
115	int str_len;
116	u32 value;
117
118	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
119		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
120
121	value = ntohl(*(u32 *)TLV_DATA(req_tlv_area));
122	if (value != 0)
123		return tipc_cfg_reply_error_string("unsupported argument");
124
125	buf = tipc_cfg_reply_alloc(TLV_SPACE(ULTRA_STRING_MAX_LEN));
126	if (buf == NULL)
127		return NULL;
128
129	rep_tlv = (struct tlv_desc *)buf->data;
130	pb = TLV_DATA(rep_tlv);
131	pb_len = ULTRA_STRING_MAX_LEN;
132
133	str_len = tipc_snprintf(pb, pb_len, "TIPC version " TIPC_MOD_VER "\n");
134	str_len += 1;	/* for "\0" */
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	tipc_core_start_net(addr);
185	return tipc_cfg_reply_none();
186}
187
188static struct sk_buff *cfg_set_remote_mng(void)
189{
190	u32 value;
191
192	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
193		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
194
195	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
196	tipc_remote_management = (value != 0);
197	return tipc_cfg_reply_none();
198}
199
200static struct sk_buff *cfg_set_max_ports(void)
201{
202	u32 value;
203
204	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
205		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
206	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
207	if (value == tipc_max_ports)
208		return tipc_cfg_reply_none();
209	if (value < 127 || value > 65535)
210		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
211						   " (max ports must be 127-65535)");
212	return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
213		" (cannot change max ports while TIPC is active)");
214}
215
216static struct sk_buff *cfg_set_netid(void)
217{
218	u32 value;
219
220	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
221		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
222	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
223	if (value == tipc_net_id)
224		return tipc_cfg_reply_none();
225	if (value < 1 || value > 9999)
226		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
227						   " (network id must be 1-9999)");
228	if (tipc_own_addr)
229		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
230			" (cannot change network id once TIPC has joined a network)");
231	tipc_net_id = value;
232	return tipc_cfg_reply_none();
233}
234
235struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area,
236				int request_space, int reply_headroom)
237{
238	struct sk_buff *rep_tlv_buf;
239
240	mutex_lock(&config_mutex);
241
242	/* Save request and reply details in a well-known location */
243	req_tlv_area = request_area;
244	req_tlv_space = request_space;
245	rep_headroom = reply_headroom;
246
247	/* Check command authorization */
248	if (likely(in_own_node(orig_node))) {
249		/* command is permitted */
250	} else if (cmd >= 0x8000) {
251		rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
252							  " (cannot be done remotely)");
253		goto exit;
254	} else if (!tipc_remote_management) {
255		rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NO_REMOTE);
256		goto exit;
257	} else if (cmd >= 0x4000) {
258		u32 domain = 0;
259
260		if ((tipc_nametbl_translate(TIPC_ZM_SRV, 0, &domain) == 0) ||
261		    (domain != orig_node)) {
262			rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_ZONE_MSTR);
263			goto exit;
264		}
265	}
266
267	/* Call appropriate processing routine */
268	switch (cmd) {
269	case TIPC_CMD_NOOP:
270		rep_tlv_buf = tipc_cfg_reply_none();
271		break;
272	case TIPC_CMD_GET_NODES:
273		rep_tlv_buf = tipc_node_get_nodes(req_tlv_area, req_tlv_space);
274		break;
275	case TIPC_CMD_GET_LINKS:
276		rep_tlv_buf = tipc_node_get_links(req_tlv_area, req_tlv_space);
277		break;
278	case TIPC_CMD_SHOW_LINK_STATS:
279		rep_tlv_buf = tipc_link_cmd_show_stats(req_tlv_area, req_tlv_space);
280		break;
281	case TIPC_CMD_RESET_LINK_STATS:
282		rep_tlv_buf = tipc_link_cmd_reset_stats(req_tlv_area, req_tlv_space);
283		break;
284	case TIPC_CMD_SHOW_NAME_TABLE:
285		rep_tlv_buf = tipc_nametbl_get(req_tlv_area, req_tlv_space);
286		break;
287	case TIPC_CMD_GET_BEARER_NAMES:
288		rep_tlv_buf = tipc_bearer_get_names();
289		break;
290	case TIPC_CMD_GET_MEDIA_NAMES:
291		rep_tlv_buf = tipc_media_get_names();
292		break;
293	case TIPC_CMD_SHOW_PORTS:
294		rep_tlv_buf = tipc_port_get_ports();
295		break;
296	case TIPC_CMD_SHOW_STATS:
297		rep_tlv_buf = tipc_show_stats();
298		break;
299	case TIPC_CMD_SET_LINK_TOL:
300	case TIPC_CMD_SET_LINK_PRI:
301	case TIPC_CMD_SET_LINK_WINDOW:
302		rep_tlv_buf = tipc_link_cmd_config(req_tlv_area, req_tlv_space, cmd);
303		break;
304	case TIPC_CMD_ENABLE_BEARER:
305		rep_tlv_buf = cfg_enable_bearer();
306		break;
307	case TIPC_CMD_DISABLE_BEARER:
308		rep_tlv_buf = cfg_disable_bearer();
309		break;
310	case TIPC_CMD_SET_NODE_ADDR:
311		rep_tlv_buf = cfg_set_own_addr();
312		break;
313	case TIPC_CMD_SET_REMOTE_MNG:
314		rep_tlv_buf = cfg_set_remote_mng();
315		break;
316	case TIPC_CMD_SET_MAX_PORTS:
317		rep_tlv_buf = cfg_set_max_ports();
318		break;
319	case TIPC_CMD_SET_NETID:
320		rep_tlv_buf = cfg_set_netid();
321		break;
322	case TIPC_CMD_GET_REMOTE_MNG:
323		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_remote_management);
324		break;
325	case TIPC_CMD_GET_MAX_PORTS:
326		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_ports);
327		break;
328	case TIPC_CMD_GET_NETID:
329		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_net_id);
330		break;
331	case TIPC_CMD_NOT_NET_ADMIN:
332		rep_tlv_buf =
333			tipc_cfg_reply_error_string(TIPC_CFG_NOT_NET_ADMIN);
334		break;
335	case TIPC_CMD_SET_MAX_ZONES:
336	case TIPC_CMD_GET_MAX_ZONES:
337	case TIPC_CMD_SET_MAX_SLAVES:
338	case TIPC_CMD_GET_MAX_SLAVES:
339	case TIPC_CMD_SET_MAX_CLUSTERS:
340	case TIPC_CMD_GET_MAX_CLUSTERS:
341	case TIPC_CMD_SET_MAX_NODES:
342	case TIPC_CMD_GET_MAX_NODES:
343	case TIPC_CMD_SET_MAX_SUBSCR:
344	case TIPC_CMD_GET_MAX_SUBSCR:
345	case TIPC_CMD_SET_MAX_PUBL:
346	case TIPC_CMD_GET_MAX_PUBL:
347	case TIPC_CMD_SET_LOG_SIZE:
348	case TIPC_CMD_DUMP_LOG:
349		rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
350							  " (obsolete command)");
351		break;
352	default:
353		rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
354							  " (unknown command)");
355		break;
356	}
357
358	WARN_ON(rep_tlv_buf->len > TLV_SPACE(ULTRA_STRING_MAX_LEN));
359
360	/* Append an error message if we cannot return all requested data */
361	if (rep_tlv_buf->len == TLV_SPACE(ULTRA_STRING_MAX_LEN)) {
362		if (*(rep_tlv_buf->data + ULTRA_STRING_MAX_LEN) != '\0')
363			sprintf(rep_tlv_buf->data + rep_tlv_buf->len -
364				sizeof(REPLY_TRUNCATED) - 1, REPLY_TRUNCATED);
365	}
366
367	/* Return reply buffer */
368exit:
369	mutex_unlock(&config_mutex);
370	return rep_tlv_buf;
371}
372
373static void cfg_conn_msg_event(int conid, struct sockaddr_tipc *addr,
374			       void *usr_data, void *buf, size_t len)
375{
376	struct tipc_cfg_msg_hdr *req_hdr;
377	struct tipc_cfg_msg_hdr *rep_hdr;
378	struct sk_buff *rep_buf;
379	int ret;
380
381	/* Validate configuration message header (ignore invalid message) */
382	req_hdr = (struct tipc_cfg_msg_hdr *)buf;
383	if ((len < sizeof(*req_hdr)) ||
384	    (len != TCM_ALIGN(ntohl(req_hdr->tcm_len))) ||
385	    (ntohs(req_hdr->tcm_flags) != TCM_F_REQUEST)) {
386		pr_warn("Invalid configuration message discarded\n");
387		return;
388	}
389
390	/* Generate reply for request (if can't, return request) */
391	rep_buf = tipc_cfg_do_cmd(addr->addr.id.node, ntohs(req_hdr->tcm_type),
392				  buf + sizeof(*req_hdr),
393				  len - sizeof(*req_hdr),
394				  BUF_HEADROOM + MAX_H_SIZE + sizeof(*rep_hdr));
395	if (rep_buf) {
396		skb_push(rep_buf, sizeof(*rep_hdr));
397		rep_hdr = (struct tipc_cfg_msg_hdr *)rep_buf->data;
398		memcpy(rep_hdr, req_hdr, sizeof(*rep_hdr));
399		rep_hdr->tcm_len = htonl(rep_buf->len);
400		rep_hdr->tcm_flags &= htons(~TCM_F_REQUEST);
401
402		ret = tipc_conn_sendmsg(&cfgsrv, conid, addr, rep_buf->data,
403					rep_buf->len);
404		if (ret < 0)
405			pr_err("Sending cfg reply message failed, no memory\n");
406
407		kfree_skb(rep_buf);
408	}
409}
410
411static struct sockaddr_tipc cfgsrv_addr __read_mostly = {
412	.family			= AF_TIPC,
413	.addrtype		= TIPC_ADDR_NAMESEQ,
414	.addr.nameseq.type	= TIPC_CFG_SRV,
415	.addr.nameseq.lower	= 0,
416	.addr.nameseq.upper	= 0,
417	.scope			= TIPC_ZONE_SCOPE
418};
419
420static struct tipc_server cfgsrv __read_mostly = {
421	.saddr			= &cfgsrv_addr,
422	.imp			= TIPC_CRITICAL_IMPORTANCE,
423	.type			= SOCK_RDM,
424	.max_rcvbuf_size	= 64 * 1024,
425	.name			= "cfg_server",
426	.tipc_conn_recvmsg	= cfg_conn_msg_event,
427	.tipc_conn_new		= NULL,
428	.tipc_conn_shutdown	= NULL
429};
430
431int tipc_cfg_init(void)
432{
433	return tipc_server_start(&cfgsrv);
434}
435
436void tipc_cfg_reinit(void)
437{
438	tipc_server_stop(&cfgsrv);
439
440	cfgsrv_addr.addr.nameseq.lower = tipc_own_addr;
441	cfgsrv_addr.addr.nameseq.upper = tipc_own_addr;
442	tipc_server_start(&cfgsrv);
443}
444
445void tipc_cfg_stop(void)
446{
447	tipc_server_stop(&cfgsrv);
448}