config.c revision 5cbded585d129d0226cb48ac4202b253c781be26
1/*
2 * net/tipc/config.c: TIPC configuration management code
3 *
4 * Copyright (c) 2002-2006, Ericsson AB
5 * Copyright (c) 2004-2006, 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 "dbg.h"
39#include "bearer.h"
40#include "port.h"
41#include "link.h"
42#include "zone.h"
43#include "addr.h"
44#include "name_table.h"
45#include "node.h"
46#include "config.h"
47#include "discover.h"
48
49struct subscr_data {
50	char usr_handle[8];
51	u32 domain;
52	u32 port_ref;
53	struct list_head subd_list;
54};
55
56struct manager {
57	u32 user_ref;
58	u32 port_ref;
59	u32 subscr_ref;
60	u32 link_subscriptions;
61	struct list_head link_subscribers;
62};
63
64static struct manager mng = { 0};
65
66static DEFINE_SPINLOCK(config_lock);
67
68static const void *req_tlv_area;	/* request message TLV area */
69static int req_tlv_space;		/* request message TLV area size */
70static int rep_headroom;		/* reply message headroom to use */
71
72
73void tipc_cfg_link_event(u32 addr, char *name, int up)
74{
75	/* TIPC DOESN'T HANDLE LINK EVENT SUBSCRIPTIONS AT THE MOMENT */
76}
77
78
79struct sk_buff *tipc_cfg_reply_alloc(int payload_size)
80{
81	struct sk_buff *buf;
82
83	buf = alloc_skb(rep_headroom + payload_size, GFP_ATOMIC);
84	if (buf)
85		skb_reserve(buf, rep_headroom);
86	return buf;
87}
88
89int tipc_cfg_append_tlv(struct sk_buff *buf, int tlv_type,
90			void *tlv_data, int tlv_data_size)
91{
92	struct tlv_desc *tlv = (struct tlv_desc *)buf->tail;
93	int new_tlv_space = TLV_SPACE(tlv_data_size);
94
95	if (skb_tailroom(buf) < new_tlv_space) {
96		dbg("tipc_cfg_append_tlv unable to append TLV\n");
97		return 0;
98	}
99	skb_put(buf, new_tlv_space);
100	tlv->tlv_type = htons(tlv_type);
101	tlv->tlv_len  = htons(TLV_LENGTH(tlv_data_size));
102	if (tlv_data_size && tlv_data)
103		memcpy(TLV_DATA(tlv), tlv_data, tlv_data_size);
104	return 1;
105}
106
107struct sk_buff *tipc_cfg_reply_unsigned_type(u16 tlv_type, u32 value)
108{
109	struct sk_buff *buf;
110	__be32 value_net;
111
112	buf = tipc_cfg_reply_alloc(TLV_SPACE(sizeof(value)));
113	if (buf) {
114		value_net = htonl(value);
115		tipc_cfg_append_tlv(buf, tlv_type, &value_net,
116				    sizeof(value_net));
117	}
118	return buf;
119}
120
121struct sk_buff *tipc_cfg_reply_string_type(u16 tlv_type, char *string)
122{
123	struct sk_buff *buf;
124	int string_len = strlen(string) + 1;
125
126	buf = tipc_cfg_reply_alloc(TLV_SPACE(string_len));
127	if (buf)
128		tipc_cfg_append_tlv(buf, tlv_type, string, string_len);
129	return buf;
130}
131
132
133
134
135#if 0
136
137/* Now obsolete code for handling commands not yet implemented the new way */
138
139int tipc_cfg_cmd(const struct tipc_cmd_msg * msg,
140		 char *data,
141		 u32 sz,
142		 u32 *ret_size,
143		 struct tipc_portid *orig)
144{
145	int rv = -EINVAL;
146	u32 cmd = msg->cmd;
147
148	*ret_size = 0;
149	switch (cmd) {
150	case TIPC_REMOVE_LINK:
151	case TIPC_CMD_BLOCK_LINK:
152	case TIPC_CMD_UNBLOCK_LINK:
153		if (!cfg_check_connection(orig))
154			rv = link_control(msg->argv.link_name, msg->cmd, 0);
155		break;
156	case TIPC_ESTABLISH:
157		{
158			int connected;
159
160			tipc_isconnected(mng.conn_port_ref, &connected);
161			if (connected || !orig) {
162				rv = TIPC_FAILURE;
163				break;
164			}
165			rv = tipc_connect2port(mng.conn_port_ref, orig);
166			if (rv == TIPC_OK)
167				orig = 0;
168			break;
169		}
170	case TIPC_GET_PEER_ADDRESS:
171		*ret_size = link_peer_addr(msg->argv.link_name, data, sz);
172		break;
173	case TIPC_GET_ROUTES:
174		rv = TIPC_OK;
175		break;
176	default: {}
177	}
178	if (*ret_size)
179		rv = TIPC_OK;
180	return rv;
181}
182
183static void cfg_cmd_event(struct tipc_cmd_msg *msg,
184			  char *data,
185			  u32 sz,
186			  struct tipc_portid const *orig)
187{
188	int rv = -EINVAL;
189	struct tipc_cmd_result_msg rmsg;
190	struct iovec msg_sect[2];
191	int *arg;
192
193	msg->cmd = ntohl(msg->cmd);
194
195	cfg_prepare_res_msg(msg->cmd, msg->usr_handle, rv, &rmsg, msg_sect,
196			    data, 0);
197	if (ntohl(msg->magic) != TIPC_MAGIC)
198		goto exit;
199
200	switch (msg->cmd) {
201	case TIPC_CREATE_LINK:
202		if (!cfg_check_connection(orig))
203			rv = disc_create_link(&msg->argv.create_link);
204		break;
205	case TIPC_LINK_SUBSCRIBE:
206		{
207			struct subscr_data *sub;
208
209			if (mng.link_subscriptions > 64)
210				break;
211			sub = kmalloc(sizeof(*sub),
212							    GFP_ATOMIC);
213			if (sub == NULL) {
214				warn("Memory squeeze; dropped remote link subscription\n");
215				break;
216			}
217			INIT_LIST_HEAD(&sub->subd_list);
218			tipc_createport(mng.user_ref,
219					(void *)sub,
220					TIPC_HIGH_IMPORTANCE,
221					0,
222					0,
223					(tipc_conn_shutdown_event)cfg_linksubscr_cancel,
224					0,
225					0,
226					(tipc_conn_msg_event)cfg_linksubscr_cancel,
227					0,
228					&sub->port_ref);
229			if (!sub->port_ref) {
230				kfree(sub);
231				break;
232			}
233			memcpy(sub->usr_handle,msg->usr_handle,
234			       sizeof(sub->usr_handle));
235			sub->domain = msg->argv.domain;
236			list_add_tail(&sub->subd_list, &mng.link_subscribers);
237			tipc_connect2port(sub->port_ref, orig);
238			rmsg.retval = TIPC_OK;
239			tipc_send(sub->port_ref, 2u, msg_sect);
240			mng.link_subscriptions++;
241			return;
242		}
243	default:
244		rv = tipc_cfg_cmd(msg, data, sz, (u32 *)&msg_sect[1].iov_len, orig);
245	}
246	exit:
247	rmsg.result_len = htonl(msg_sect[1].iov_len);
248	rmsg.retval = htonl(rv);
249	tipc_cfg_respond(msg_sect, 2u, orig);
250}
251#endif
252
253static struct sk_buff *cfg_enable_bearer(void)
254{
255	struct tipc_bearer_config *args;
256
257	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_BEARER_CONFIG))
258		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
259
260	args = (struct tipc_bearer_config *)TLV_DATA(req_tlv_area);
261	if (tipc_enable_bearer(args->name,
262			       ntohl(args->detect_scope),
263			       ntohl(args->priority)))
264		return tipc_cfg_reply_error_string("unable to enable bearer");
265
266	return tipc_cfg_reply_none();
267}
268
269static struct sk_buff *cfg_disable_bearer(void)
270{
271	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_BEARER_NAME))
272		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
273
274	if (tipc_disable_bearer((char *)TLV_DATA(req_tlv_area)))
275		return tipc_cfg_reply_error_string("unable to disable bearer");
276
277	return tipc_cfg_reply_none();
278}
279
280static struct sk_buff *cfg_set_own_addr(void)
281{
282	u32 addr;
283
284	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
285		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
286
287	addr = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
288	if (addr == tipc_own_addr)
289		return tipc_cfg_reply_none();
290	if (!tipc_addr_node_valid(addr))
291		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
292						   " (node address)");
293	if (tipc_mode == TIPC_NET_MODE)
294		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
295						   " (cannot change node address once assigned)");
296	tipc_own_addr = addr;
297
298	/*
299	 * Must release all spinlocks before calling start_net() because
300	 * Linux version of TIPC calls eth_media_start() which calls
301	 * register_netdevice_notifier() which may block!
302	 *
303	 * Temporarily releasing the lock should be harmless for non-Linux TIPC,
304	 * but Linux version of eth_media_start() should really be reworked
305	 * so that it can be called with spinlocks held.
306	 */
307
308	spin_unlock_bh(&config_lock);
309	tipc_core_start_net();
310	spin_lock_bh(&config_lock);
311	return tipc_cfg_reply_none();
312}
313
314static struct sk_buff *cfg_set_remote_mng(void)
315{
316	u32 value;
317
318	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
319		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
320
321	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
322	tipc_remote_management = (value != 0);
323	return tipc_cfg_reply_none();
324}
325
326static struct sk_buff *cfg_set_max_publications(void)
327{
328	u32 value;
329
330	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
331		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
332
333	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
334	if (value != delimit(value, 1, 65535))
335		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
336						   " (max publications must be 1-65535)");
337	tipc_max_publications = value;
338	return tipc_cfg_reply_none();
339}
340
341static struct sk_buff *cfg_set_max_subscriptions(void)
342{
343	u32 value;
344
345	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
346		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
347
348	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
349	if (value != delimit(value, 1, 65535))
350		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
351						   " (max subscriptions must be 1-65535");
352	tipc_max_subscriptions = value;
353	return tipc_cfg_reply_none();
354}
355
356static struct sk_buff *cfg_set_max_ports(void)
357{
358	u32 value;
359
360	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
361		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
362	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
363	if (value == tipc_max_ports)
364		return tipc_cfg_reply_none();
365	if (value != delimit(value, 127, 65535))
366		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
367						   " (max ports must be 127-65535)");
368	if (tipc_mode != TIPC_NOT_RUNNING)
369		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
370			" (cannot change max ports while TIPC is active)");
371	tipc_max_ports = value;
372	return tipc_cfg_reply_none();
373}
374
375static struct sk_buff *cfg_set_max_zones(void)
376{
377	u32 value;
378
379	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
380		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
381	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
382	if (value == tipc_max_zones)
383		return tipc_cfg_reply_none();
384	if (value != delimit(value, 1, 255))
385		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
386						   " (max zones must be 1-255)");
387	if (tipc_mode == TIPC_NET_MODE)
388		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
389			" (cannot change max zones once TIPC has joined a network)");
390	tipc_max_zones = value;
391	return tipc_cfg_reply_none();
392}
393
394static struct sk_buff *cfg_set_max_clusters(void)
395{
396	u32 value;
397
398	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
399		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
400	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
401	if (value != delimit(value, 1, 1))
402		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
403						   " (max clusters fixed at 1)");
404	return tipc_cfg_reply_none();
405}
406
407static struct sk_buff *cfg_set_max_nodes(void)
408{
409	u32 value;
410
411	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
412		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
413	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
414	if (value == tipc_max_nodes)
415		return tipc_cfg_reply_none();
416	if (value != delimit(value, 8, 2047))
417		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
418						   " (max nodes must be 8-2047)");
419	if (tipc_mode == TIPC_NET_MODE)
420		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
421			" (cannot change max nodes once TIPC has joined a network)");
422	tipc_max_nodes = value;
423	return tipc_cfg_reply_none();
424}
425
426static struct sk_buff *cfg_set_max_slaves(void)
427{
428	u32 value;
429
430	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
431		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
432	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
433	if (value != 0)
434		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
435						   " (max secondary nodes fixed at 0)");
436	return tipc_cfg_reply_none();
437}
438
439static struct sk_buff *cfg_set_netid(void)
440{
441	u32 value;
442
443	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
444		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
445	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
446	if (value == tipc_net_id)
447		return tipc_cfg_reply_none();
448	if (value != delimit(value, 1, 9999))
449		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
450						   " (network id must be 1-9999)");
451	if (tipc_mode == TIPC_NET_MODE)
452		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
453			" (cannot change network id once TIPC has joined a network)");
454	tipc_net_id = value;
455	return tipc_cfg_reply_none();
456}
457
458struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area,
459				int request_space, int reply_headroom)
460{
461	struct sk_buff *rep_tlv_buf;
462
463	spin_lock_bh(&config_lock);
464
465	/* Save request and reply details in a well-known location */
466
467	req_tlv_area = request_area;
468	req_tlv_space = request_space;
469	rep_headroom = reply_headroom;
470
471	/* Check command authorization */
472
473	if (likely(orig_node == tipc_own_addr)) {
474		/* command is permitted */
475	} else if (cmd >= 0x8000) {
476		rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
477							  " (cannot be done remotely)");
478		goto exit;
479	} else if (!tipc_remote_management) {
480		rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NO_REMOTE);
481		goto exit;
482	}
483	else if (cmd >= 0x4000) {
484		u32 domain = 0;
485
486		if ((tipc_nametbl_translate(TIPC_ZM_SRV, 0, &domain) == 0) ||
487		    (domain != orig_node)) {
488			rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_ZONE_MSTR);
489			goto exit;
490		}
491	}
492
493	/* Call appropriate processing routine */
494
495	switch (cmd) {
496	case TIPC_CMD_NOOP:
497		rep_tlv_buf = tipc_cfg_reply_none();
498		break;
499	case TIPC_CMD_GET_NODES:
500		rep_tlv_buf = tipc_node_get_nodes(req_tlv_area, req_tlv_space);
501		break;
502	case TIPC_CMD_GET_LINKS:
503		rep_tlv_buf = tipc_node_get_links(req_tlv_area, req_tlv_space);
504		break;
505	case TIPC_CMD_SHOW_LINK_STATS:
506		rep_tlv_buf = tipc_link_cmd_show_stats(req_tlv_area, req_tlv_space);
507		break;
508	case TIPC_CMD_RESET_LINK_STATS:
509		rep_tlv_buf = tipc_link_cmd_reset_stats(req_tlv_area, req_tlv_space);
510		break;
511	case TIPC_CMD_SHOW_NAME_TABLE:
512		rep_tlv_buf = tipc_nametbl_get(req_tlv_area, req_tlv_space);
513		break;
514	case TIPC_CMD_GET_BEARER_NAMES:
515		rep_tlv_buf = tipc_bearer_get_names();
516		break;
517	case TIPC_CMD_GET_MEDIA_NAMES:
518		rep_tlv_buf = tipc_media_get_names();
519		break;
520	case TIPC_CMD_SHOW_PORTS:
521		rep_tlv_buf = tipc_port_get_ports();
522		break;
523#if 0
524	case TIPC_CMD_SHOW_PORT_STATS:
525		rep_tlv_buf = port_show_stats(req_tlv_area, req_tlv_space);
526		break;
527	case TIPC_CMD_RESET_PORT_STATS:
528		rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED);
529		break;
530#endif
531	case TIPC_CMD_SET_LOG_SIZE:
532		rep_tlv_buf = tipc_log_resize(req_tlv_area, req_tlv_space);
533		break;
534	case TIPC_CMD_DUMP_LOG:
535		rep_tlv_buf = tipc_log_dump();
536		break;
537	case TIPC_CMD_SET_LINK_TOL:
538	case TIPC_CMD_SET_LINK_PRI:
539	case TIPC_CMD_SET_LINK_WINDOW:
540		rep_tlv_buf = tipc_link_cmd_config(req_tlv_area, req_tlv_space, cmd);
541		break;
542	case TIPC_CMD_ENABLE_BEARER:
543		rep_tlv_buf = cfg_enable_bearer();
544		break;
545	case TIPC_CMD_DISABLE_BEARER:
546		rep_tlv_buf = cfg_disable_bearer();
547		break;
548	case TIPC_CMD_SET_NODE_ADDR:
549		rep_tlv_buf = cfg_set_own_addr();
550		break;
551	case TIPC_CMD_SET_REMOTE_MNG:
552		rep_tlv_buf = cfg_set_remote_mng();
553		break;
554	case TIPC_CMD_SET_MAX_PORTS:
555		rep_tlv_buf = cfg_set_max_ports();
556		break;
557	case TIPC_CMD_SET_MAX_PUBL:
558		rep_tlv_buf = cfg_set_max_publications();
559		break;
560	case TIPC_CMD_SET_MAX_SUBSCR:
561		rep_tlv_buf = cfg_set_max_subscriptions();
562		break;
563	case TIPC_CMD_SET_MAX_ZONES:
564		rep_tlv_buf = cfg_set_max_zones();
565		break;
566	case TIPC_CMD_SET_MAX_CLUSTERS:
567		rep_tlv_buf = cfg_set_max_clusters();
568		break;
569	case TIPC_CMD_SET_MAX_NODES:
570		rep_tlv_buf = cfg_set_max_nodes();
571		break;
572	case TIPC_CMD_SET_MAX_SLAVES:
573		rep_tlv_buf = cfg_set_max_slaves();
574		break;
575	case TIPC_CMD_SET_NETID:
576		rep_tlv_buf = cfg_set_netid();
577		break;
578	case TIPC_CMD_GET_REMOTE_MNG:
579		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_remote_management);
580		break;
581	case TIPC_CMD_GET_MAX_PORTS:
582		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_ports);
583		break;
584	case TIPC_CMD_GET_MAX_PUBL:
585		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_publications);
586		break;
587	case TIPC_CMD_GET_MAX_SUBSCR:
588		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_subscriptions);
589		break;
590	case TIPC_CMD_GET_MAX_ZONES:
591		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_zones);
592		break;
593	case TIPC_CMD_GET_MAX_CLUSTERS:
594		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_clusters);
595		break;
596	case TIPC_CMD_GET_MAX_NODES:
597		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_nodes);
598		break;
599	case TIPC_CMD_GET_MAX_SLAVES:
600		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_slaves);
601		break;
602	case TIPC_CMD_GET_NETID:
603		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_net_id);
604		break;
605	default:
606		rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
607							  " (unknown command)");
608		break;
609	}
610
611	/* Return reply buffer */
612exit:
613	spin_unlock_bh(&config_lock);
614	return rep_tlv_buf;
615}
616
617static void cfg_named_msg_event(void *userdata,
618				u32 port_ref,
619				struct sk_buff **buf,
620				const unchar *msg,
621				u32 size,
622				u32 importance,
623				struct tipc_portid const *orig,
624				struct tipc_name_seq const *dest)
625{
626	struct tipc_cfg_msg_hdr *req_hdr;
627	struct tipc_cfg_msg_hdr *rep_hdr;
628	struct sk_buff *rep_buf;
629
630	/* Validate configuration message header (ignore invalid message) */
631
632	req_hdr = (struct tipc_cfg_msg_hdr *)msg;
633	if ((size < sizeof(*req_hdr)) ||
634	    (size != TCM_ALIGN(ntohl(req_hdr->tcm_len))) ||
635	    (ntohs(req_hdr->tcm_flags) != TCM_F_REQUEST)) {
636		warn("Invalid configuration message discarded\n");
637		return;
638	}
639
640	/* Generate reply for request (if can't, return request) */
641
642	rep_buf = tipc_cfg_do_cmd(orig->node,
643				  ntohs(req_hdr->tcm_type),
644				  msg + sizeof(*req_hdr),
645				  size - sizeof(*req_hdr),
646				  BUF_HEADROOM + MAX_H_SIZE + sizeof(*rep_hdr));
647	if (rep_buf) {
648		skb_push(rep_buf, sizeof(*rep_hdr));
649		rep_hdr = (struct tipc_cfg_msg_hdr *)rep_buf->data;
650		memcpy(rep_hdr, req_hdr, sizeof(*rep_hdr));
651		rep_hdr->tcm_len = htonl(rep_buf->len);
652		rep_hdr->tcm_flags &= htons(~TCM_F_REQUEST);
653	} else {
654		rep_buf = *buf;
655		*buf = NULL;
656	}
657
658	/* NEED TO ADD CODE TO HANDLE FAILED SEND (SUCH AS CONGESTION) */
659	tipc_send_buf2port(port_ref, orig, rep_buf, rep_buf->len);
660}
661
662int tipc_cfg_init(void)
663{
664	struct tipc_name_seq seq;
665	int res;
666
667	memset(&mng, 0, sizeof(mng));
668	INIT_LIST_HEAD(&mng.link_subscribers);
669
670	res = tipc_attach(&mng.user_ref, NULL, NULL);
671	if (res)
672		goto failed;
673
674	res = tipc_createport(mng.user_ref, NULL, TIPC_CRITICAL_IMPORTANCE,
675			      NULL, NULL, NULL,
676			      NULL, cfg_named_msg_event, NULL,
677			      NULL, &mng.port_ref);
678	if (res)
679		goto failed;
680
681	seq.type = TIPC_CFG_SRV;
682	seq.lower = seq.upper = tipc_own_addr;
683	res = tipc_nametbl_publish_rsv(mng.port_ref, TIPC_ZONE_SCOPE, &seq);
684	if (res)
685		goto failed;
686
687	return 0;
688
689failed:
690	err("Unable to create configuration service\n");
691	tipc_detach(mng.user_ref);
692	mng.user_ref = 0;
693	return res;
694}
695
696void tipc_cfg_stop(void)
697{
698	if (mng.user_ref) {
699		tipc_detach(mng.user_ref);
700		mng.user_ref = 0;
701	}
702}
703