• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "socket.h"
39 #include "name_table.h"
40 #include "config.h"
41 #include "server.h"
42 
43 #define REPLY_TRUNCATED "<truncated>\n"
44 
45 static const void *req_tlv_area;	/* request message TLV area */
46 static int req_tlv_space;		/* request message TLV area size */
47 static int rep_headroom;		/* reply message headroom to use */
48 
tipc_cfg_reply_alloc(int payload_size)49 struct sk_buff *tipc_cfg_reply_alloc(int payload_size)
50 {
51 	struct sk_buff *buf;
52 
53 	buf = alloc_skb(rep_headroom + payload_size, GFP_ATOMIC);
54 	if (buf)
55 		skb_reserve(buf, rep_headroom);
56 	return buf;
57 }
58 
tipc_cfg_append_tlv(struct sk_buff * buf,int tlv_type,void * tlv_data,int tlv_data_size)59 int tipc_cfg_append_tlv(struct sk_buff *buf, int tlv_type,
60 			void *tlv_data, int tlv_data_size)
61 {
62 	struct tlv_desc *tlv = (struct tlv_desc *)skb_tail_pointer(buf);
63 	int new_tlv_space = TLV_SPACE(tlv_data_size);
64 
65 	if (skb_tailroom(buf) < new_tlv_space)
66 		return 0;
67 	skb_put(buf, new_tlv_space);
68 	tlv->tlv_type = htons(tlv_type);
69 	tlv->tlv_len  = htons(TLV_LENGTH(tlv_data_size));
70 	if (tlv_data_size && tlv_data)
71 		memcpy(TLV_DATA(tlv), tlv_data, tlv_data_size);
72 	return 1;
73 }
74 
tipc_cfg_reply_unsigned_type(u16 tlv_type,u32 value)75 static struct sk_buff *tipc_cfg_reply_unsigned_type(u16 tlv_type, u32 value)
76 {
77 	struct sk_buff *buf;
78 	__be32 value_net;
79 
80 	buf = tipc_cfg_reply_alloc(TLV_SPACE(sizeof(value)));
81 	if (buf) {
82 		value_net = htonl(value);
83 		tipc_cfg_append_tlv(buf, tlv_type, &value_net,
84 				    sizeof(value_net));
85 	}
86 	return buf;
87 }
88 
tipc_cfg_reply_unsigned(u32 value)89 static struct sk_buff *tipc_cfg_reply_unsigned(u32 value)
90 {
91 	return tipc_cfg_reply_unsigned_type(TIPC_TLV_UNSIGNED, value);
92 }
93 
tipc_cfg_reply_string_type(u16 tlv_type,char * string)94 struct sk_buff *tipc_cfg_reply_string_type(u16 tlv_type, char *string)
95 {
96 	struct sk_buff *buf;
97 	int string_len = strlen(string) + 1;
98 
99 	buf = tipc_cfg_reply_alloc(TLV_SPACE(string_len));
100 	if (buf)
101 		tipc_cfg_append_tlv(buf, tlv_type, string, string_len);
102 	return buf;
103 }
104 
tipc_show_stats(void)105 static struct sk_buff *tipc_show_stats(void)
106 {
107 	struct sk_buff *buf;
108 	struct tlv_desc *rep_tlv;
109 	char *pb;
110 	int pb_len;
111 	int str_len;
112 	u32 value;
113 
114 	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
115 		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
116 
117 	value = ntohl(*(u32 *)TLV_DATA(req_tlv_area));
118 	if (value != 0)
119 		return tipc_cfg_reply_error_string("unsupported argument");
120 
121 	buf = tipc_cfg_reply_alloc(TLV_SPACE(ULTRA_STRING_MAX_LEN));
122 	if (buf == NULL)
123 		return NULL;
124 
125 	rep_tlv = (struct tlv_desc *)buf->data;
126 	pb = TLV_DATA(rep_tlv);
127 	pb_len = ULTRA_STRING_MAX_LEN;
128 
129 	str_len = tipc_snprintf(pb, pb_len, "TIPC version " TIPC_MOD_VER "\n");
130 	str_len += 1;	/* for "\0" */
131 	skb_put(buf, TLV_SPACE(str_len));
132 	TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
133 
134 	return buf;
135 }
136 
cfg_enable_bearer(void)137 static struct sk_buff *cfg_enable_bearer(void)
138 {
139 	struct tipc_bearer_config *args;
140 
141 	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_BEARER_CONFIG))
142 		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
143 
144 	args = (struct tipc_bearer_config *)TLV_DATA(req_tlv_area);
145 	if (tipc_enable_bearer(args->name,
146 			       ntohl(args->disc_domain),
147 			       ntohl(args->priority)))
148 		return tipc_cfg_reply_error_string("unable to enable bearer");
149 
150 	return tipc_cfg_reply_none();
151 }
152 
cfg_disable_bearer(void)153 static struct sk_buff *cfg_disable_bearer(void)
154 {
155 	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_BEARER_NAME))
156 		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
157 
158 	if (tipc_disable_bearer((char *)TLV_DATA(req_tlv_area)))
159 		return tipc_cfg_reply_error_string("unable to disable bearer");
160 
161 	return tipc_cfg_reply_none();
162 }
163 
cfg_set_own_addr(void)164 static struct sk_buff *cfg_set_own_addr(void)
165 {
166 	u32 addr;
167 
168 	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
169 		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
170 
171 	addr = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
172 	if (addr == tipc_own_addr)
173 		return tipc_cfg_reply_none();
174 	if (!tipc_addr_node_valid(addr))
175 		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
176 						   " (node address)");
177 	if (tipc_own_addr)
178 		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
179 						   " (cannot change node address once assigned)");
180 	if (!tipc_net_start(addr))
181 		return tipc_cfg_reply_none();
182 
183 	return tipc_cfg_reply_error_string("cannot change to network mode");
184 }
185 
cfg_set_max_ports(void)186 static 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 
cfg_set_netid(void)202 static 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 
tipc_cfg_do_cmd(u32 orig_node,u16 cmd,const void * request_area,int request_space,int reply_headroom)221 struct 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 	rtnl_lock();
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_sk_socks_show();
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 */
339 exit:
340 	rtnl_unlock();
341 	return rep_tlv_buf;
342 }
343