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