config.c revision 7368ddf144afd79456fd853fa25f33e31da003a9
1/*
2 * net/tipc/config.c: TIPC configuration management code
3 *
4 * Copyright (c) 2002-2006, Ericsson AB
5 * Copyright (c) 2004-2007, 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};
60
61static struct manager mng = { 0};
62
63static DEFINE_SPINLOCK(config_lock);
64
65static const void *req_tlv_area;	/* request message TLV area */
66static int req_tlv_space;		/* request message TLV area size */
67static int rep_headroom;		/* reply message headroom to use */
68
69
70struct sk_buff *tipc_cfg_reply_alloc(int payload_size)
71{
72	struct sk_buff *buf;
73
74	buf = alloc_skb(rep_headroom + payload_size, GFP_ATOMIC);
75	if (buf)
76		skb_reserve(buf, rep_headroom);
77	return buf;
78}
79
80int tipc_cfg_append_tlv(struct sk_buff *buf, int tlv_type,
81			void *tlv_data, int tlv_data_size)
82{
83	struct tlv_desc *tlv = (struct tlv_desc *)skb_tail_pointer(buf);
84	int new_tlv_space = TLV_SPACE(tlv_data_size);
85
86	if (skb_tailroom(buf) < new_tlv_space) {
87		dbg("tipc_cfg_append_tlv unable to append TLV\n");
88		return 0;
89	}
90	skb_put(buf, new_tlv_space);
91	tlv->tlv_type = htons(tlv_type);
92	tlv->tlv_len  = htons(TLV_LENGTH(tlv_data_size));
93	if (tlv_data_size && tlv_data)
94		memcpy(TLV_DATA(tlv), tlv_data, tlv_data_size);
95	return 1;
96}
97
98struct sk_buff *tipc_cfg_reply_unsigned_type(u16 tlv_type, u32 value)
99{
100	struct sk_buff *buf;
101	__be32 value_net;
102
103	buf = tipc_cfg_reply_alloc(TLV_SPACE(sizeof(value)));
104	if (buf) {
105		value_net = htonl(value);
106		tipc_cfg_append_tlv(buf, tlv_type, &value_net,
107				    sizeof(value_net));
108	}
109	return buf;
110}
111
112struct sk_buff *tipc_cfg_reply_string_type(u16 tlv_type, char *string)
113{
114	struct sk_buff *buf;
115	int string_len = strlen(string) + 1;
116
117	buf = tipc_cfg_reply_alloc(TLV_SPACE(string_len));
118	if (buf)
119		tipc_cfg_append_tlv(buf, tlv_type, string, string_len);
120	return buf;
121}
122
123#define MAX_STATS_INFO 2000
124
125static struct sk_buff *tipc_show_stats(void)
126{
127	struct sk_buff *buf;
128	struct tlv_desc *rep_tlv;
129	struct print_buf pb;
130	int str_len;
131	u32 value;
132
133	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
134		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
135
136	value = ntohl(*(u32 *)TLV_DATA(req_tlv_area));
137	if (value != 0)
138		return tipc_cfg_reply_error_string("unsupported argument");
139
140	buf = tipc_cfg_reply_alloc(TLV_SPACE(MAX_STATS_INFO));
141	if (buf == NULL)
142		return NULL;
143
144	rep_tlv = (struct tlv_desc *)buf->data;
145	tipc_printbuf_init(&pb, (char *)TLV_DATA(rep_tlv), MAX_STATS_INFO);
146
147	tipc_printf(&pb, "TIPC version " TIPC_MOD_VER "\n");
148
149	/* Use additional tipc_printf()'s to return more info ... */
150
151	str_len = tipc_printbuf_validate(&pb);
152	skb_put(buf, TLV_SPACE(str_len));
153	TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
154
155	return buf;
156}
157
158static struct sk_buff *cfg_enable_bearer(void)
159{
160	struct tipc_bearer_config *args;
161
162	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_BEARER_CONFIG))
163		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
164
165	args = (struct tipc_bearer_config *)TLV_DATA(req_tlv_area);
166	if (tipc_enable_bearer(args->name,
167			       ntohl(args->detect_scope),
168			       ntohl(args->priority)))
169		return tipc_cfg_reply_error_string("unable to enable bearer");
170
171	return tipc_cfg_reply_none();
172}
173
174static struct sk_buff *cfg_disable_bearer(void)
175{
176	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_BEARER_NAME))
177		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
178
179	if (tipc_disable_bearer((char *)TLV_DATA(req_tlv_area)))
180		return tipc_cfg_reply_error_string("unable to disable bearer");
181
182	return tipc_cfg_reply_none();
183}
184
185static struct sk_buff *cfg_set_own_addr(void)
186{
187	u32 addr;
188
189	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
190		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
191
192	addr = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
193	if (addr == tipc_own_addr)
194		return tipc_cfg_reply_none();
195	if (!tipc_addr_node_valid(addr))
196		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
197						   " (node address)");
198	if (tipc_mode == TIPC_NET_MODE)
199		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
200						   " (cannot change node address once assigned)");
201
202	/*
203	 * Must release all spinlocks before calling start_net() because
204	 * Linux version of TIPC calls eth_media_start() which calls
205	 * register_netdevice_notifier() which may block!
206	 *
207	 * Temporarily releasing the lock should be harmless for non-Linux TIPC,
208	 * but Linux version of eth_media_start() should really be reworked
209	 * so that it can be called with spinlocks held.
210	 */
211
212	spin_unlock_bh(&config_lock);
213	tipc_core_start_net(addr);
214	spin_lock_bh(&config_lock);
215	return tipc_cfg_reply_none();
216}
217
218static struct sk_buff *cfg_set_remote_mng(void)
219{
220	u32 value;
221
222	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
223		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
224
225	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
226	tipc_remote_management = (value != 0);
227	return tipc_cfg_reply_none();
228}
229
230static struct sk_buff *cfg_set_max_publications(void)
231{
232	u32 value;
233
234	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
235		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
236
237	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
238	if (value != delimit(value, 1, 65535))
239		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
240						   " (max publications must be 1-65535)");
241	tipc_max_publications = value;
242	return tipc_cfg_reply_none();
243}
244
245static struct sk_buff *cfg_set_max_subscriptions(void)
246{
247	u32 value;
248
249	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
250		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
251
252	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
253	if (value != delimit(value, 1, 65535))
254		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
255						   " (max subscriptions must be 1-65535");
256	tipc_max_subscriptions = value;
257	return tipc_cfg_reply_none();
258}
259
260static struct sk_buff *cfg_set_max_ports(void)
261{
262	u32 value;
263
264	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
265		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
266	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
267	if (value == tipc_max_ports)
268		return tipc_cfg_reply_none();
269	if (value != delimit(value, 127, 65535))
270		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
271						   " (max ports must be 127-65535)");
272	if (tipc_mode != TIPC_NOT_RUNNING)
273		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
274			" (cannot change max ports while TIPC is active)");
275	tipc_max_ports = value;
276	return tipc_cfg_reply_none();
277}
278
279static struct sk_buff *cfg_set_max_zones(void)
280{
281	u32 value;
282
283	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
284		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
285	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
286	if (value == tipc_max_zones)
287		return tipc_cfg_reply_none();
288	if (value != delimit(value, 1, 255))
289		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
290						   " (max zones must be 1-255)");
291	if (tipc_mode == TIPC_NET_MODE)
292		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
293			" (cannot change max zones once TIPC has joined a network)");
294	tipc_max_zones = value;
295	return tipc_cfg_reply_none();
296}
297
298static struct sk_buff *cfg_set_max_clusters(void)
299{
300	u32 value;
301
302	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
303		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
304	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
305	if (value != delimit(value, 1, 1))
306		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
307						   " (max clusters fixed at 1)");
308	return tipc_cfg_reply_none();
309}
310
311static struct sk_buff *cfg_set_max_nodes(void)
312{
313	u32 value;
314
315	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
316		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
317	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
318	if (value == tipc_max_nodes)
319		return tipc_cfg_reply_none();
320	if (value != delimit(value, 8, 2047))
321		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
322						   " (max nodes must be 8-2047)");
323	if (tipc_mode == TIPC_NET_MODE)
324		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
325			" (cannot change max nodes once TIPC has joined a network)");
326	tipc_max_nodes = value;
327	return tipc_cfg_reply_none();
328}
329
330static struct sk_buff *cfg_set_max_slaves(void)
331{
332	u32 value;
333
334	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
335		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
336	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
337	if (value != 0)
338		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
339						   " (max secondary nodes fixed at 0)");
340	return tipc_cfg_reply_none();
341}
342
343static struct sk_buff *cfg_set_netid(void)
344{
345	u32 value;
346
347	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
348		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
349	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
350	if (value == tipc_net_id)
351		return tipc_cfg_reply_none();
352	if (value != delimit(value, 1, 9999))
353		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
354						   " (network id must be 1-9999)");
355	if (tipc_mode == TIPC_NET_MODE)
356		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
357			" (cannot change network id once TIPC has joined a network)");
358	tipc_net_id = value;
359	return tipc_cfg_reply_none();
360}
361
362struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area,
363				int request_space, int reply_headroom)
364{
365	struct sk_buff *rep_tlv_buf;
366
367	spin_lock_bh(&config_lock);
368
369	/* Save request and reply details in a well-known location */
370
371	req_tlv_area = request_area;
372	req_tlv_space = request_space;
373	rep_headroom = reply_headroom;
374
375	/* Check command authorization */
376
377	if (likely(orig_node == tipc_own_addr)) {
378		/* command is permitted */
379	} else if (cmd >= 0x8000) {
380		rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
381							  " (cannot be done remotely)");
382		goto exit;
383	} else if (!tipc_remote_management) {
384		rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NO_REMOTE);
385		goto exit;
386	}
387	else if (cmd >= 0x4000) {
388		u32 domain = 0;
389
390		if ((tipc_nametbl_translate(TIPC_ZM_SRV, 0, &domain) == 0) ||
391		    (domain != orig_node)) {
392			rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_ZONE_MSTR);
393			goto exit;
394		}
395	}
396
397	/* Call appropriate processing routine */
398
399	switch (cmd) {
400	case TIPC_CMD_NOOP:
401		rep_tlv_buf = tipc_cfg_reply_none();
402		break;
403	case TIPC_CMD_GET_NODES:
404		rep_tlv_buf = tipc_node_get_nodes(req_tlv_area, req_tlv_space);
405		break;
406	case TIPC_CMD_GET_LINKS:
407		rep_tlv_buf = tipc_node_get_links(req_tlv_area, req_tlv_space);
408		break;
409	case TIPC_CMD_SHOW_LINK_STATS:
410		rep_tlv_buf = tipc_link_cmd_show_stats(req_tlv_area, req_tlv_space);
411		break;
412	case TIPC_CMD_RESET_LINK_STATS:
413		rep_tlv_buf = tipc_link_cmd_reset_stats(req_tlv_area, req_tlv_space);
414		break;
415	case TIPC_CMD_SHOW_NAME_TABLE:
416		rep_tlv_buf = tipc_nametbl_get(req_tlv_area, req_tlv_space);
417		break;
418	case TIPC_CMD_GET_BEARER_NAMES:
419		rep_tlv_buf = tipc_bearer_get_names();
420		break;
421	case TIPC_CMD_GET_MEDIA_NAMES:
422		rep_tlv_buf = tipc_media_get_names();
423		break;
424	case TIPC_CMD_SHOW_PORTS:
425		rep_tlv_buf = tipc_port_get_ports();
426		break;
427	case TIPC_CMD_SET_LOG_SIZE:
428		rep_tlv_buf = tipc_log_resize_cmd(req_tlv_area, req_tlv_space);
429		break;
430	case TIPC_CMD_DUMP_LOG:
431		rep_tlv_buf = tipc_log_dump();
432		break;
433	case TIPC_CMD_SHOW_STATS:
434		rep_tlv_buf = tipc_show_stats();
435		break;
436	case TIPC_CMD_SET_LINK_TOL:
437	case TIPC_CMD_SET_LINK_PRI:
438	case TIPC_CMD_SET_LINK_WINDOW:
439		rep_tlv_buf = tipc_link_cmd_config(req_tlv_area, req_tlv_space, cmd);
440		break;
441	case TIPC_CMD_ENABLE_BEARER:
442		rep_tlv_buf = cfg_enable_bearer();
443		break;
444	case TIPC_CMD_DISABLE_BEARER:
445		rep_tlv_buf = cfg_disable_bearer();
446		break;
447	case TIPC_CMD_SET_NODE_ADDR:
448		rep_tlv_buf = cfg_set_own_addr();
449		break;
450	case TIPC_CMD_SET_REMOTE_MNG:
451		rep_tlv_buf = cfg_set_remote_mng();
452		break;
453	case TIPC_CMD_SET_MAX_PORTS:
454		rep_tlv_buf = cfg_set_max_ports();
455		break;
456	case TIPC_CMD_SET_MAX_PUBL:
457		rep_tlv_buf = cfg_set_max_publications();
458		break;
459	case TIPC_CMD_SET_MAX_SUBSCR:
460		rep_tlv_buf = cfg_set_max_subscriptions();
461		break;
462	case TIPC_CMD_SET_MAX_ZONES:
463		rep_tlv_buf = cfg_set_max_zones();
464		break;
465	case TIPC_CMD_SET_MAX_CLUSTERS:
466		rep_tlv_buf = cfg_set_max_clusters();
467		break;
468	case TIPC_CMD_SET_MAX_NODES:
469		rep_tlv_buf = cfg_set_max_nodes();
470		break;
471	case TIPC_CMD_SET_MAX_SLAVES:
472		rep_tlv_buf = cfg_set_max_slaves();
473		break;
474	case TIPC_CMD_SET_NETID:
475		rep_tlv_buf = cfg_set_netid();
476		break;
477	case TIPC_CMD_GET_REMOTE_MNG:
478		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_remote_management);
479		break;
480	case TIPC_CMD_GET_MAX_PORTS:
481		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_ports);
482		break;
483	case TIPC_CMD_GET_MAX_PUBL:
484		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_publications);
485		break;
486	case TIPC_CMD_GET_MAX_SUBSCR:
487		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_subscriptions);
488		break;
489	case TIPC_CMD_GET_MAX_ZONES:
490		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_zones);
491		break;
492	case TIPC_CMD_GET_MAX_CLUSTERS:
493		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_clusters);
494		break;
495	case TIPC_CMD_GET_MAX_NODES:
496		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_nodes);
497		break;
498	case TIPC_CMD_GET_MAX_SLAVES:
499		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_slaves);
500		break;
501	case TIPC_CMD_GET_NETID:
502		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_net_id);
503		break;
504	case TIPC_CMD_NOT_NET_ADMIN:
505		rep_tlv_buf =
506			tipc_cfg_reply_error_string(TIPC_CFG_NOT_NET_ADMIN);
507		break;
508	default:
509		rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
510							  " (unknown command)");
511		break;
512	}
513
514	/* Return reply buffer */
515exit:
516	spin_unlock_bh(&config_lock);
517	return rep_tlv_buf;
518}
519
520static void cfg_named_msg_event(void *userdata,
521				u32 port_ref,
522				struct sk_buff **buf,
523				const unchar *msg,
524				u32 size,
525				u32 importance,
526				struct tipc_portid const *orig,
527				struct tipc_name_seq const *dest)
528{
529	struct tipc_cfg_msg_hdr *req_hdr;
530	struct tipc_cfg_msg_hdr *rep_hdr;
531	struct sk_buff *rep_buf;
532
533	/* Validate configuration message header (ignore invalid message) */
534
535	req_hdr = (struct tipc_cfg_msg_hdr *)msg;
536	if ((size < sizeof(*req_hdr)) ||
537	    (size != TCM_ALIGN(ntohl(req_hdr->tcm_len))) ||
538	    (ntohs(req_hdr->tcm_flags) != TCM_F_REQUEST)) {
539		warn("Invalid configuration message discarded\n");
540		return;
541	}
542
543	/* Generate reply for request (if can't, return request) */
544
545	rep_buf = tipc_cfg_do_cmd(orig->node,
546				  ntohs(req_hdr->tcm_type),
547				  msg + sizeof(*req_hdr),
548				  size - sizeof(*req_hdr),
549				  BUF_HEADROOM + MAX_H_SIZE + sizeof(*rep_hdr));
550	if (rep_buf) {
551		skb_push(rep_buf, sizeof(*rep_hdr));
552		rep_hdr = (struct tipc_cfg_msg_hdr *)rep_buf->data;
553		memcpy(rep_hdr, req_hdr, sizeof(*rep_hdr));
554		rep_hdr->tcm_len = htonl(rep_buf->len);
555		rep_hdr->tcm_flags &= htons(~TCM_F_REQUEST);
556	} else {
557		rep_buf = *buf;
558		*buf = NULL;
559	}
560
561	/* NEED TO ADD CODE TO HANDLE FAILED SEND (SUCH AS CONGESTION) */
562	tipc_send_buf2port(port_ref, orig, rep_buf, rep_buf->len);
563}
564
565int tipc_cfg_init(void)
566{
567	struct tipc_name_seq seq;
568	int res;
569
570	res = tipc_attach(&mng.user_ref, NULL, NULL);
571	if (res)
572		goto failed;
573
574	res = tipc_createport(mng.user_ref, NULL, TIPC_CRITICAL_IMPORTANCE,
575			      NULL, NULL, NULL,
576			      NULL, cfg_named_msg_event, NULL,
577			      NULL, &mng.port_ref);
578	if (res)
579		goto failed;
580
581	seq.type = TIPC_CFG_SRV;
582	seq.lower = seq.upper = tipc_own_addr;
583	res = tipc_nametbl_publish_rsv(mng.port_ref, TIPC_ZONE_SCOPE, &seq);
584	if (res)
585		goto failed;
586
587	return 0;
588
589failed:
590	err("Unable to create configuration service\n");
591	tipc_detach(mng.user_ref);
592	mng.user_ref = 0;
593	return res;
594}
595
596void tipc_cfg_stop(void)
597{
598	if (mng.user_ref) {
599		tipc_detach(mng.user_ref);
600		mng.user_ref = 0;
601	}
602}
603