]> bbs.cooldavid.org Git - net-next-2.6.git/blob - net/tipc/config.c
c429b0d488a33644529d291eb794382b77539e18
[net-next-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 "config.h"
47 #include "discover.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 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 struct 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
125 static 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
158 static 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
174 static 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
185 static 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
218 static 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
230 static 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
245 static 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
260 static 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
279 static 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
298 static 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
311 static 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
330 static 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
343 static 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
362 struct 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 */
515 exit:
516         spin_unlock_bh(&config_lock);
517         return rep_tlv_buf;
518 }
519
520 static 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
565 int 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
589 failed:
590         err("Unable to create configuration service\n");
591         tipc_detach(mng.user_ref);
592         mng.user_ref = 0;
593         return res;
594 }
595
596 void tipc_cfg_stop(void)
597 {
598         if (mng.user_ref) {
599                 tipc_detach(mng.user_ref);
600                 mng.user_ref = 0;
601         }
602 }