config.c 14.5 KB
Newer Older
Per Liden's avatar
Per Liden committed
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
Per Liden's avatar
Per Liden committed
6
7
 * All rights reserved.
 *
Per Liden's avatar
Per Liden committed
8
 * Redistribution and use in source and binary forms, with or without
Per Liden's avatar
Per Liden committed
9
10
 * modification, are permitted provided that the following conditions are met:
 *
Per Liden's avatar
Per Liden committed
11
12
13
14
15
16
17
18
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the names of the copyright holders nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
Per Liden's avatar
Per Liden committed
19
 *
Per Liden's avatar
Per Liden committed
20
21
22
23
24
25
26
27
28
29
30
31
32
33
 * Alternatively, this software may be distributed under the terms of the
 * GNU General Public License ("GPL") version 2 as published by the Free
 * Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
Per Liden's avatar
Per Liden committed
34
35
36
37
38
39
40
41
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "core.h"
#include "port.h"
#include "name_table.h"
#include "config.h"

42
static u32 config_port_ref;
Per Liden's avatar
Per Liden committed
43

44
static DEFINE_SPINLOCK(config_lock);
Per Liden's avatar
Per Liden committed
45
46
47
48
49
50

static const void *req_tlv_area;	/* request message TLV area */
static int req_tlv_space;		/* request message TLV area size */
static int rep_headroom;		/* reply message headroom to use */


51
struct sk_buff *tipc_cfg_reply_alloc(int payload_size)
Per Liden's avatar
Per Liden committed
52
53
54
55
56
57
58
59
60
{
	struct sk_buff *buf;

	buf = alloc_skb(rep_headroom + payload_size, GFP_ATOMIC);
	if (buf)
		skb_reserve(buf, rep_headroom);
	return buf;
}

61
int tipc_cfg_append_tlv(struct sk_buff *buf, int tlv_type,
62
			void *tlv_data, int tlv_data_size)
Per Liden's avatar
Per Liden committed
63
{
64
	struct tlv_desc *tlv = (struct tlv_desc *)skb_tail_pointer(buf);
Per Liden's avatar
Per Liden committed
65
66
	int new_tlv_space = TLV_SPACE(tlv_data_size);

67
	if (skb_tailroom(buf) < new_tlv_space)
Per Liden's avatar
Per Liden committed
68
69
70
71
72
73
74
75
76
		return 0;
	skb_put(buf, new_tlv_space);
	tlv->tlv_type = htons(tlv_type);
	tlv->tlv_len  = htons(TLV_LENGTH(tlv_data_size));
	if (tlv_data_size && tlv_data)
		memcpy(TLV_DATA(tlv), tlv_data, tlv_data_size);
	return 1;
}

77
static struct sk_buff *tipc_cfg_reply_unsigned_type(u16 tlv_type, u32 value)
Per Liden's avatar
Per Liden committed
78
79
{
	struct sk_buff *buf;
Al Viro's avatar
Al Viro committed
80
	__be32 value_net;
Per Liden's avatar
Per Liden committed
81

82
	buf = tipc_cfg_reply_alloc(TLV_SPACE(sizeof(value)));
Per Liden's avatar
Per Liden committed
83
84
	if (buf) {
		value_net = htonl(value);
85
		tipc_cfg_append_tlv(buf, tlv_type, &value_net,
86
				    sizeof(value_net));
Per Liden's avatar
Per Liden committed
87
88
89
90
	}
	return buf;
}

91
92
93
94
95
static struct sk_buff *tipc_cfg_reply_unsigned(u32 value)
{
	return tipc_cfg_reply_unsigned_type(TIPC_TLV_UNSIGNED, value);
}

96
struct sk_buff *tipc_cfg_reply_string_type(u16 tlv_type, char *string)
Per Liden's avatar
Per Liden committed
97
98
99
100
{
	struct sk_buff *buf;
	int string_len = strlen(string) + 1;

101
	buf = tipc_cfg_reply_alloc(TLV_SPACE(string_len));
Per Liden's avatar
Per Liden committed
102
	if (buf)
103
		tipc_cfg_append_tlv(buf, tlv_type, string, string_len);
Per Liden's avatar
Per Liden committed
104
105
106
	return buf;
}

107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#define MAX_STATS_INFO 2000

static struct sk_buff *tipc_show_stats(void)
{
	struct sk_buff *buf;
	struct tlv_desc *rep_tlv;
	struct print_buf pb;
	int str_len;
	u32 value;

	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);

	value = ntohl(*(u32 *)TLV_DATA(req_tlv_area));
	if (value != 0)
		return tipc_cfg_reply_error_string("unsupported argument");

	buf = tipc_cfg_reply_alloc(TLV_SPACE(MAX_STATS_INFO));
	if (buf == NULL)
		return NULL;

	rep_tlv = (struct tlv_desc *)buf->data;
	tipc_printbuf_init(&pb, (char *)TLV_DATA(rep_tlv), MAX_STATS_INFO);

	tipc_printf(&pb, "TIPC version " TIPC_MOD_VER "\n");

	/* Use additional tipc_printf()'s to return more info ... */

	str_len = tipc_printbuf_validate(&pb);
	skb_put(buf, TLV_SPACE(str_len));
	TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);

	return buf;
}

Per Liden's avatar
Per Liden committed
142
143
144
145
146
static struct sk_buff *cfg_enable_bearer(void)
{
	struct tipc_bearer_config *args;

	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_BEARER_CONFIG))
147
		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
Per Liden's avatar
Per Liden committed
148
149
150

	args = (struct tipc_bearer_config *)TLV_DATA(req_tlv_area);
	if (tipc_enable_bearer(args->name,
151
			       ntohl(args->disc_domain),
Per Liden's avatar
Per Liden committed
152
			       ntohl(args->priority)))
153
		return tipc_cfg_reply_error_string("unable to enable bearer");
Per Liden's avatar
Per Liden committed
154

155
	return tipc_cfg_reply_none();
Per Liden's avatar
Per Liden committed
156
157
158
159
160
}

static struct sk_buff *cfg_disable_bearer(void)
{
	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_BEARER_NAME))
161
		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
Per Liden's avatar
Per Liden committed
162
163

	if (tipc_disable_bearer((char *)TLV_DATA(req_tlv_area)))
164
		return tipc_cfg_reply_error_string("unable to disable bearer");
Per Liden's avatar
Per Liden committed
165

166
	return tipc_cfg_reply_none();
Per Liden's avatar
Per Liden committed
167
168
169
170
171
172
173
}

static struct sk_buff *cfg_set_own_addr(void)
{
	u32 addr;

	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
174
		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
Per Liden's avatar
Per Liden committed
175

Al Viro's avatar
Al Viro committed
176
	addr = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
Per Liden's avatar
Per Liden committed
177
	if (addr == tipc_own_addr)
178
179
180
181
		return tipc_cfg_reply_none();
	if (!tipc_addr_node_valid(addr))
		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
						   " (node address)");
182
	if (tipc_own_addr)
183
184
		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
						   " (cannot change node address once assigned)");
185

186
	/*
187
188
189
190
191
192
	 * Must temporarily release configuration spinlock while switching into
	 * networking mode as it calls tipc_eth_media_start(), which may sleep.
	 * Releasing the lock is harmless as other locally-issued configuration
	 * commands won't occur until this one completes, and remotely-issued
	 * configuration commands can't be received until a local configuration
	 * command to enable the first bearer is received and processed.
193
	 */
Per Liden's avatar
Per Liden committed
194
195

	spin_unlock_bh(&config_lock);
196
	tipc_core_start_net(addr);
Per Liden's avatar
Per Liden committed
197
	spin_lock_bh(&config_lock);
198
	return tipc_cfg_reply_none();
Per Liden's avatar
Per Liden committed
199
200
201
202
203
204
205
}

static struct sk_buff *cfg_set_remote_mng(void)
{
	u32 value;

	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
206
		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
Per Liden's avatar
Per Liden committed
207

Al Viro's avatar
Al Viro committed
208
	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
Per Liden's avatar
Per Liden committed
209
	tipc_remote_management = (value != 0);
210
	return tipc_cfg_reply_none();
Per Liden's avatar
Per Liden committed
211
212
213
214
215
216
217
}

static struct sk_buff *cfg_set_max_publications(void)
{
	u32 value;

	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
218
		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
Per Liden's avatar
Per Liden committed
219

Al Viro's avatar
Al Viro committed
220
	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
221
	if (value < 1 || value > 65535)
222
223
		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
						   " (max publications must be 1-65535)");
Per Liden's avatar
Per Liden committed
224
	tipc_max_publications = value;
225
	return tipc_cfg_reply_none();
Per Liden's avatar
Per Liden committed
226
227
228
229
230
231
232
}

static struct sk_buff *cfg_set_max_subscriptions(void)
{
	u32 value;

	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
233
		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
Per Liden's avatar
Per Liden committed
234

Al Viro's avatar
Al Viro committed
235
	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
236
	if (value < 1 || value > 65535)
237
238
		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
						   " (max subscriptions must be 1-65535");
Per Liden's avatar
Per Liden committed
239
	tipc_max_subscriptions = value;
240
	return tipc_cfg_reply_none();
Per Liden's avatar
Per Liden committed
241
242
243
244
245
246
247
}

static struct sk_buff *cfg_set_max_ports(void)
{
	u32 value;

	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
248
		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
Al Viro's avatar
Al Viro committed
249
	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
250
251
	if (value == tipc_max_ports)
		return tipc_cfg_reply_none();
252
	if (value < 127 || value > 65535)
253
254
		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
						   " (max ports must be 127-65535)");
255
256
	return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
		" (cannot change max ports while TIPC is active)");
Per Liden's avatar
Per Liden committed
257
258
259
260
261
262
263
}

static struct sk_buff *cfg_set_netid(void)
{
	u32 value;

	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
264
		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
Al Viro's avatar
Al Viro committed
265
	value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
266
267
	if (value == tipc_net_id)
		return tipc_cfg_reply_none();
268
	if (value < 1 || value > 9999)
269
270
		return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
						   " (network id must be 1-9999)");
271
	if (tipc_own_addr)
272
		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
273
274
275
			" (cannot change network id once TIPC has joined a network)");
	tipc_net_id = value;
	return tipc_cfg_reply_none();
Per Liden's avatar
Per Liden committed
276
277
}

278
279
struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area,
				int request_space, int reply_headroom)
Per Liden's avatar
Per Liden committed
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
{
	struct sk_buff *rep_tlv_buf;

	spin_lock_bh(&config_lock);

	/* Save request and reply details in a well-known location */

	req_tlv_area = request_area;
	req_tlv_space = request_space;
	rep_headroom = reply_headroom;

	/* Check command authorization */

	if (likely(orig_node == tipc_own_addr)) {
		/* command is permitted */
	} else if (cmd >= 0x8000) {
296
297
		rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
							  " (cannot be done remotely)");
Per Liden's avatar
Per Liden committed
298
299
		goto exit;
	} else if (!tipc_remote_management) {
300
		rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NO_REMOTE);
Per Liden's avatar
Per Liden committed
301
		goto exit;
302
	} else if (cmd >= 0x4000) {
Per Liden's avatar
Per Liden committed
303
304
		u32 domain = 0;

305
		if ((tipc_nametbl_translate(TIPC_ZM_SRV, 0, &domain) == 0) ||
Per Liden's avatar
Per Liden committed
306
		    (domain != orig_node)) {
307
			rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_ZONE_MSTR);
Per Liden's avatar
Per Liden committed
308
309
310
311
312
313
314
315
			goto exit;
		}
	}

	/* Call appropriate processing routine */

	switch (cmd) {
	case TIPC_CMD_NOOP:
316
		rep_tlv_buf = tipc_cfg_reply_none();
Per Liden's avatar
Per Liden committed
317
318
		break;
	case TIPC_CMD_GET_NODES:
319
		rep_tlv_buf = tipc_node_get_nodes(req_tlv_area, req_tlv_space);
Per Liden's avatar
Per Liden committed
320
321
		break;
	case TIPC_CMD_GET_LINKS:
322
		rep_tlv_buf = tipc_node_get_links(req_tlv_area, req_tlv_space);
Per Liden's avatar
Per Liden committed
323
324
		break;
	case TIPC_CMD_SHOW_LINK_STATS:
325
		rep_tlv_buf = tipc_link_cmd_show_stats(req_tlv_area, req_tlv_space);
Per Liden's avatar
Per Liden committed
326
327
		break;
	case TIPC_CMD_RESET_LINK_STATS:
328
		rep_tlv_buf = tipc_link_cmd_reset_stats(req_tlv_area, req_tlv_space);
Per Liden's avatar
Per Liden committed
329
330
		break;
	case TIPC_CMD_SHOW_NAME_TABLE:
331
		rep_tlv_buf = tipc_nametbl_get(req_tlv_area, req_tlv_space);
Per Liden's avatar
Per Liden committed
332
333
		break;
	case TIPC_CMD_GET_BEARER_NAMES:
334
		rep_tlv_buf = tipc_bearer_get_names();
Per Liden's avatar
Per Liden committed
335
336
		break;
	case TIPC_CMD_GET_MEDIA_NAMES:
337
		rep_tlv_buf = tipc_media_get_names();
Per Liden's avatar
Per Liden committed
338
339
		break;
	case TIPC_CMD_SHOW_PORTS:
340
		rep_tlv_buf = tipc_port_get_ports();
Per Liden's avatar
Per Liden committed
341
342
		break;
	case TIPC_CMD_SET_LOG_SIZE:
343
		rep_tlv_buf = tipc_log_resize_cmd(req_tlv_area, req_tlv_space);
Per Liden's avatar
Per Liden committed
344
345
		break;
	case TIPC_CMD_DUMP_LOG:
346
		rep_tlv_buf = tipc_log_dump();
Per Liden's avatar
Per Liden committed
347
		break;
348
349
350
	case TIPC_CMD_SHOW_STATS:
		rep_tlv_buf = tipc_show_stats();
		break;
Per Liden's avatar
Per Liden committed
351
352
353
	case TIPC_CMD_SET_LINK_TOL:
	case TIPC_CMD_SET_LINK_PRI:
	case TIPC_CMD_SET_LINK_WINDOW:
354
		rep_tlv_buf = tipc_link_cmd_config(req_tlv_area, req_tlv_space, cmd);
Per Liden's avatar
Per Liden committed
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
		break;
	case TIPC_CMD_ENABLE_BEARER:
		rep_tlv_buf = cfg_enable_bearer();
		break;
	case TIPC_CMD_DISABLE_BEARER:
		rep_tlv_buf = cfg_disable_bearer();
		break;
	case TIPC_CMD_SET_NODE_ADDR:
		rep_tlv_buf = cfg_set_own_addr();
		break;
	case TIPC_CMD_SET_REMOTE_MNG:
		rep_tlv_buf = cfg_set_remote_mng();
		break;
	case TIPC_CMD_SET_MAX_PORTS:
		rep_tlv_buf = cfg_set_max_ports();
		break;
	case TIPC_CMD_SET_MAX_PUBL:
		rep_tlv_buf = cfg_set_max_publications();
		break;
	case TIPC_CMD_SET_MAX_SUBSCR:
		rep_tlv_buf = cfg_set_max_subscriptions();
		break;
	case TIPC_CMD_SET_NETID:
		rep_tlv_buf = cfg_set_netid();
		break;
	case TIPC_CMD_GET_REMOTE_MNG:
381
		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_remote_management);
Per Liden's avatar
Per Liden committed
382
383
		break;
	case TIPC_CMD_GET_MAX_PORTS:
384
		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_ports);
Per Liden's avatar
Per Liden committed
385
386
		break;
	case TIPC_CMD_GET_MAX_PUBL:
387
		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_publications);
Per Liden's avatar
Per Liden committed
388
389
		break;
	case TIPC_CMD_GET_MAX_SUBSCR:
390
		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_subscriptions);
Per Liden's avatar
Per Liden committed
391
392
		break;
	case TIPC_CMD_GET_NETID:
393
		rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_net_id);
Per Liden's avatar
Per Liden committed
394
		break;
395
396
397
398
	case TIPC_CMD_NOT_NET_ADMIN:
		rep_tlv_buf =
			tipc_cfg_reply_error_string(TIPC_CFG_NOT_NET_ADMIN);
		break;
399
400
	case TIPC_CMD_SET_MAX_ZONES:
	case TIPC_CMD_GET_MAX_ZONES:
401
402
	case TIPC_CMD_SET_MAX_SLAVES:
	case TIPC_CMD_GET_MAX_SLAVES:
403
404
	case TIPC_CMD_SET_MAX_CLUSTERS:
	case TIPC_CMD_GET_MAX_CLUSTERS:
405
406
	case TIPC_CMD_SET_MAX_NODES:
	case TIPC_CMD_GET_MAX_NODES:
407
408
409
		rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
							  " (obsolete command)");
		break;
Per Liden's avatar
Per Liden committed
410
	default:
411
412
		rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
							  " (unknown command)");
Per Liden's avatar
Per Liden committed
413
414
415
416
417
418
419
420
421
422
423
424
425
426
		break;
	}

	/* Return reply buffer */
exit:
	spin_unlock_bh(&config_lock);
	return rep_tlv_buf;
}

static void cfg_named_msg_event(void *userdata,
				u32 port_ref,
				struct sk_buff **buf,
				const unchar *msg,
				u32 size,
427
				u32 importance,
Per Liden's avatar
Per Liden committed
428
429
430
431
432
433
434
435
436
437
438
439
440
				struct tipc_portid const *orig,
				struct tipc_name_seq const *dest)
{
	struct tipc_cfg_msg_hdr *req_hdr;
	struct tipc_cfg_msg_hdr *rep_hdr;
	struct sk_buff *rep_buf;

	/* Validate configuration message header (ignore invalid message) */

	req_hdr = (struct tipc_cfg_msg_hdr *)msg;
	if ((size < sizeof(*req_hdr)) ||
	    (size != TCM_ALIGN(ntohl(req_hdr->tcm_len))) ||
	    (ntohs(req_hdr->tcm_flags) != TCM_F_REQUEST)) {
441
		warn("Invalid configuration message discarded\n");
Per Liden's avatar
Per Liden committed
442
443
444
445
446
		return;
	}

	/* Generate reply for request (if can't, return request) */

447
	rep_buf = tipc_cfg_do_cmd(orig->node,
448
				  ntohs(req_hdr->tcm_type),
449
450
451
				  msg + sizeof(*req_hdr),
				  size - sizeof(*req_hdr),
				  BUF_HEADROOM + MAX_H_SIZE + sizeof(*rep_hdr));
Per Liden's avatar
Per Liden committed
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
	if (rep_buf) {
		skb_push(rep_buf, sizeof(*rep_hdr));
		rep_hdr = (struct tipc_cfg_msg_hdr *)rep_buf->data;
		memcpy(rep_hdr, req_hdr, sizeof(*rep_hdr));
		rep_hdr->tcm_len = htonl(rep_buf->len);
		rep_hdr->tcm_flags &= htons(~TCM_F_REQUEST);
	} else {
		rep_buf = *buf;
		*buf = NULL;
	}

	/* NEED TO ADD CODE TO HANDLE FAILED SEND (SUCH AS CONGESTION) */
	tipc_send_buf2port(port_ref, orig, rep_buf, rep_buf->len);
}

467
int tipc_cfg_init(void)
Per Liden's avatar
Per Liden committed
468
469
470
471
{
	struct tipc_name_seq seq;
	int res;

472
	res = tipc_createport(NULL, TIPC_CRITICAL_IMPORTANCE,
Per Liden's avatar
Per Liden committed
473
474
			      NULL, NULL, NULL,
			      NULL, cfg_named_msg_event, NULL,
475
			      NULL, &config_port_ref);
Per Liden's avatar
Per Liden committed
476
477
478
479
480
	if (res)
		goto failed;

	seq.type = TIPC_CFG_SRV;
	seq.lower = seq.upper = tipc_own_addr;
481
	res = tipc_publish(config_port_ref, TIPC_ZONE_SCOPE, &seq);
Per Liden's avatar
Per Liden committed
482
483
484
485
486
487
488
489
490
491
	if (res)
		goto failed;

	return 0;

failed:
	err("Unable to create configuration service\n");
	return res;
}

492
void tipc_cfg_stop(void)
Per Liden's avatar
Per Liden committed
493
{
494
495
496
	if (config_port_ref) {
		tipc_deleteport(config_port_ref);
		config_port_ref = 0;
Per Liden's avatar
Per Liden committed
497
498
	}
}