1 : /*
2 : * TIPC Linux kernel implementation
3 : * Copyright (c) 2001-2003 Ericsson Research Canada
4 : * Copyright (c) 2003 OSDL, Inc.
5 : *
6 : * This file is based on the original source code done by Jon Maloy
7 : * (jon.maloy@ericsson.com) for TIPC version 0.96, available from
8 : * http://tipc.sourceforge.net
9 : ***************************************************************************
10 : * This program is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License as published by
12 : * the Free Software Foundation; either version 2 of the License, or
13 : * (at your option) any later version.
14 : *
15 : * This program is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU General Public License
21 : * along with this program; if not, write to the Free Software
22 : * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 : ***************************************************************************
24 : * Alphabetical list of people who have worked on this file:
25 : * - Mark Haverkamp (markh@osdl.org)
26 : * - Mika Kukkonen (mika@osdl.org)
27 : * - Rusty Lynch (rusty@linux.intel.com)
28 : */
29 :
30 : #include "debug.h"
31 : #include "msg_buf.h"
32 : #include "message.h"
33 : #include "port.h"
34 : #include "link.h"
35 : #include "manager.h"
36 : #include "media.h"
37 : #include "name_table.h"
38 : #include "name_subscription.h"
39 : #include "reference.h"
40 : #include "local.h"
41 :
42 : extern void __tipc_subscribe2network(tipc_id_t tipc_userid,
43 : tipc_network_subscription_argv const
44 : *uargs, tipc_id_t * subscriptionid,
45 : unsigned int *initialcount);
46 : extern void __tipc_unsubscribe2network(tipc_id_t id);
47 :
48 : typedef struct Manager {
49 : tipc_id_t userid;
50 : tipc_id_t portid;
51 : tipc_id_t subscrid;
52 : tipc_id_t conn_portid;
53 : struct {
54 : uint nodes;
55 : uint links;
56 : LinkProbe parked;
57 : LinkRequest zone_req;
58 : LinkRequest node_req;
59 : } zones[16];
60 : LinkRequest pilot_reqs[16];
61 : uint name_subscriptions;
62 : uint network_subscriptions;
63 : uint link_subscriptions;
64 : } Manager;
65 :
66 : static struct Manager manager;
67 :
68 : uint
69 : set_user_error(uint errorcode, const char *file, const uint line)
70 0 : {
71 0 : char err_txt[512] = { 0, };
72 :
73 0 : switch (errorcode) {
74 : case tipc_invalid_message:
75 : {
76 0 : sprintf(err_txt,
77 : "TIPC: User Error: Attempt to send invalid message at.\n");
78 0 : break;
79 : }
80 : case tipc_oversized_message:
81 : {
82 0 : sprintf(err_txt,
83 : "TIPC: User Error: Sending oversized msg or more than 128 sections.\n");
84 0 : break;
85 : }
86 : case tipc_too_many_sections:
87 : {
88 0 : sprintf(err_txt,
89 : "TIPC: User Error: Attempt to send more than 128 sections.\n");
90 0 : break;
91 : }
92 : case tipc_del_no_port:
93 : {
94 : /* Let this one pass without crashing the Capsule. It is not acceptable
95 : when the capsule is the Java VM. */
96 0 : return 0;
97 : }
98 : case tipc_invalid_reference:
99 : {
100 0 : sprintf(err_txt,
101 : "TIPC: User Error: Attempt to access non-existing port or subscription.\n");
102 0 : break;
103 : }
104 : case tipc_invalid_args:
105 : {
106 0 : sprintf(err_txt,
107 : "TIPC: User Error: Kernel call with illegal argument vector.\n");
108 0 : break;
109 : }
110 : case tipc_illegal_operation:
111 : {
112 0 : sprintf(err_txt,
113 : "TIPC: User Error: Attempt to access port in wrong state.\n");
114 0 : break;
115 : }
116 : case tipc_publishing_connected_port:
117 : {
118 0 : sprintf(err_txt,
119 : "TIPC: User Error: Publishing port name from connected port.\n");
120 0 : break;
121 : }
122 : case tipc_connecting_published_port:
123 : {
124 0 : sprintf(err_txt,
125 : "TIPC: User Error: Attempt to connect published port.\n");
126 0 : break;
127 : }
128 : case tipc_connecting_connected_port:
129 : {
130 0 : sprintf(err_txt,
131 : "TIPC: User Error: Attempt to connect already connected port.\n");
132 0 : break;
133 : }
134 : default:
135 : {
136 0 : sprintf(err_txt,
137 : "TIPC: User Error: User error, unknown code %i",
138 : errorcode);
139 : }
140 : }
141 0 : strncat(err_txt, "Detected at: ", sizeof (err_txt) - strlen(err_txt));
142 0 : strncat(err_txt, file, sizeof (err_txt) - strlen(err_txt));
143 0 : sprintf(err_txt + strlen(err_txt), " line %u\n", line);
144 0 : err("%s\n", err_txt);
145 0 : return 1;
146 : }
147 :
148 : void
149 : manager_cancelLinkReq(LinkRequest * r)
150 0 : {
151 0 : if (r->timerRef)
152 0 : os_cancelTimer(r->timerRef);
153 0 : memset(r, 0, sizeof (*r));
154 : }
155 :
156 : void
157 : manager_sendLinkRequest(LinkRequest * r)
158 0 : {
159 0 : struct tipc_link_addr addr;
160 :
161 0 : r->timerRef = 0;
162 0 : if (r->addr) { /* Pilot request goes forever */
163 0 : if ((r->timerCount++ >= 10) || (!tipc_node_id(r->addr)
164 : &&
165 : (zone_linkcount
166 : (tipc_zone_id(r->addr)) >=
167 : 2))) {
168 0 : memset(r, 0, sizeof (*r));
169 0 : return;
170 : }
171 : }
172 : assert(r->media);
173 0 : addr.media = r->media;
174 0 : addr.orig = tipc_my_addr;
175 0 : addr.dest = r->addr;
176 : memcpy(&addr.dest_media, &r->media_addr,
177 0 : sizeof (struct tipc_media_addr));
178 0 : r->media->api->send_req(&addr);
179 0 : r->timerRef =
180 : os_setTimer((TimeoutHandler) manager_sendLinkRequest, (void *) r,
181 : 4000);
182 : }
183 :
184 : void
185 : manager_requestLink(LinkRequest * r, tipc_net_addr_t addr,
186 : struct tipc_media *b,
187 : const struct tipc_media_addr *media_addr)
188 0 : {
189 0 : if (r->timerRef)
190 0 : return; /* Duplicate request */
191 0 : memset(r, 0, sizeof (*r));
192 : assert(b);
193 0 : r->addr = addr;
194 0 : r->media = b;
195 0 : memcpy(&r->media_addr, media_addr, sizeof (*media_addr));
196 0 : manager_sendLinkRequest(r);
197 : }
198 :
199 : void
200 : tipc_manager_link_setup(const tipc_net_addr_t addr)
201 0 : {
202 0 : uint z = tipc_zone_id(addr);
203 0 : uint ownLinks = zone_linkcount(z);
204 :
205 0 : if (ownLinks >= 2)
206 0 : return;
207 0 : if (manager.zones[z].nodes) {
208 0 : uint addr_htonl = htonl(addr);
209 0 : tipc_portname dest = { 1, TIPC_GET_MEDIA_INFO };
210 0 : uint router = ownLinks ? 0 : tipc_cluster_getrouter(addr);
211 0 : tipc_message_section msg;
212 :
213 0 : msg.data = (__u8 *) & addr_htonl;
214 0 : msg.size = 4u;
215 0 : __tipc_send2name(manager.portid, &dest, router, 1u, &msg);
216 : }
217 : }
218 :
219 : void
220 : manager_link_event(TipcLinkEvent * event)
221 4 : {
222 4 : tipc_net_addr_t addr = event->addr;
223 4 : uint z = tipc_zone_id(addr);
224 4 : uint linkCount = zone_linkcount(z);
225 4 : Link *link = link_findByName((const char *) &event->name);
226 4 : uint up = event->up;
227 :
228 : assert(z);
229 4 : event->discard(event);
230 4 : if (tipc_zone_id(addr) == tipc_my_zone.id)
231 0 : return;
232 0 : if (!up) { /* Set up new link if necessary */
233 0 : manager.zones[z].links--;
234 0 : link_delete(link);
235 0 : if (--linkCount < 2) {
236 0 : os_setTimer((TimeoutHandler) tipc_manager_link_setup,
237 : (void *) (z << 24), 2000);
238 : }
239 : } else {
240 0 : LinkRequest *r = &manager.zones[tipc_zone_id(addr)].node_req;
241 :
242 0 : if (r->addr == addr) {
243 0 : manager_cancelLinkReq(r);
244 0 : manager_forwardLinkProbe(&manager.
245 : zones[tipc_zone_id(addr)].
246 : parked);
247 : }
248 0 : manager.zones[z].links++;
249 0 : if (linkCount >= 2) {
250 0 : manager_cancelLinkReq(&manager.
251 : zones[tipc_zone_id(addr)].
252 : zone_req);
253 0 : if (linkCount > 2) { /* Link entropy check */
254 0 : tipc_portname dest =
255 0 : { 1, TIPC_CHECK_LINK_COUNT };
256 0 : tipc_message_section msg = { 0, 0 };
257 0 : uint i = linkCount;
258 :
259 0 : while (i--) {
260 0 : __tipc_send2name(manager.portid, &dest,
261 : addr, 1u, &msg);
262 0 : addr = tipc_network_nextnode(addr);
263 : }
264 : }
265 : }
266 : }
267 : info("-----> There is now %u links to zone %u\n",
268 0 : manager.zones[z].links, z);
269 : }
270 :
271 : void
272 : manager_network_event(void *userdata,
273 : tipc_id_t subscriptionid, tipc_net_addr_t node, int up)
274 2 : {
275 : /* A new zone available ? */
276 2 : if (tipc_zone_id(node) != tipc_my_zone.id) {
277 0 : uint zone = tipc_zone_id(node);
278 :
279 0 : if (!up) {
280 0 : manager.zones[zone].nodes--;
281 0 : return;
282 : }
283 0 : if ((!manager.zones[zone].nodes++)
284 : || (zone_linkcount(zone) < 2)) {
285 0 : tipc_manager_link_setup(zone << 24);
286 : }
287 : } else {
288 : /* Indicate to remote network subscribers */
289 : }
290 : }
291 :
292 : void
293 : manager_forwardLinkProbe(const LinkProbe * p)
294 0 : {
295 0 : struct tipc_media *b = media_find_by_name(p->cfg.media_name);
296 0 : uint linksToOtherZone =
297 0 : zone_linkcount(tipc_zone_id(ntohl(p->cfg.addr)));
298 0 : uint zoneSize = tipc_availablenodes(tipc_my_zone.id << 24);
299 0 : uint hopCount = ntohl(p->hopCount);
300 0 : uint foundLinks = ntohl(p->foundLinks);
301 0 : Link *link = 0;
302 0 : LinkProbe probe;
303 :
304 0 : memcpy(&probe, p, sizeof (LinkProbe));
305 0 : link = link_find(ntohl(probe.cfg.addr), b->id);
306 0 : if (link)
307 0 : probe.foundLinks = htonl(++foundLinks);
308 0 : if (ntohl(probe.foundLinks) >= 2)
309 0 : return;
310 0 : if (linksToOtherZone < ntohl(probe.lowestLinkCountThisTour)) {
311 0 : probe.lowestLinkCountThisTour = htonl(linksToOtherZone);
312 : }
313 :
314 : /* Has the probe completed a zone tour ? */
315 0 : if (!(++hopCount % zoneSize)) {
316 0 : probe.lowestLinkCount = probe.lowestLinkCountThisTour;
317 0 : probe.lowestLinkCountThisTour = ~0u;
318 0 : probe.foundLinks = 0;
319 : }
320 0 : if (hopCount < (10 * zoneSize)) {
321 0 : tipc_net_addr_t next = tipc_network_nextnode(tipc_my_addr);
322 0 : tipc_portname dest = { 1, TIPC_FORWARD_LINK_REQUEST };
323 0 : tipc_message_section msg;
324 :
325 0 : msg.data = (__u8 *) & probe;
326 0 : msg.size = sizeof (LinkProbe);
327 0 : probe.hopCount = htonl(hopCount);
328 0 : __tipc_send2name(manager.portid, &dest, next, 1u, &msg);
329 : }
330 : }
331 :
332 : void
333 : tipc_manager_link_req(struct tipc_media *b, const tipc_net_addr_t orig,
334 : const tipc_net_addr_t dest,
335 : struct tipc_media_addr *media_addr)
336 0 : {
337 : /* A general request to unspecified destination ? */
338 0 : if (!dest) {
339 0 : LinkRequest *r = &manager.zones[tipc_zone_id(orig)].node_req;
340 0 : LinkProbe *probe = &manager.zones[tipc_zone_id(orig)].parked;
341 :
342 0 : if (r->addr || tipc_availablenodes(orig & 0xff000000))
343 0 : return;
344 0 : media_add_link(b, orig, media_addr); /* Create pilot link */
345 :
346 : /* Prepare a probe to be forwarded later */
347 0 : memset(probe, 0, sizeof (probe));
348 0 : probe->cfg.addr = htonl(orig);
349 0 : probe->lowestLinkCountThisTour = ~0u;
350 : memcpy(&probe->cfg.media_addr, media_addr,
351 0 : sizeof (struct tipc_media_addr));
352 0 : strcpy(probe->cfg.media_name, b->name);
353 0 : manager_requestLink(r, orig, b, (const struct tipc_media_addr *)
354 : media_addr);
355 : }
356 :
357 : /* A scoped request to this zone ? */
358 0 : else if (!tipc_node_id(dest)) {
359 0 : LinkProbe probe;
360 :
361 0 : memset(&probe, 0, sizeof (probe));
362 0 : probe.cfg.addr = htonl(orig);
363 0 : probe.lowestLinkCountThisTour = ~0u;
364 : memcpy(&probe.cfg.media_addr, media_addr,
365 0 : sizeof (struct tipc_media_addr));
366 0 : strcpy(probe.cfg.media_name, b->name);
367 : assert(!tipc_cluster_id(dest));
368 0 : manager_forwardLinkProbe(&probe);
369 : }
370 :
371 : /* A specific request to this node ? */
372 : else {
373 0 : LinkRequest *r = &manager.zones[tipc_zone_id(orig)].node_req;
374 0 : tipc_portname name = { 1, TIPC_LINK_REQUEST_ACCEPTED };
375 0 : tipc_message_section msg = { 0, 0 };
376 0 : Link *link = 0;
377 :
378 0 : link = link_find(orig, b->id);
379 : assert(dest == tipc_my_addr);
380 0 : manager_cancelLinkReq(&manager.zones[tipc_zone_id(orig)].
381 : zone_req);
382 :
383 0 : if (zone_linkcount(tipc_zone_id(orig)) < 2) {
384 : /* Race condition: mutual link requests. Needs special treatment: */
385 0 : if (link || ((r->addr == orig) && (dest < orig))) {
386 0 : name.instance = TIPC_LINK_REQUEST_REJECTED;
387 0 : } else if (!link) {
388 0 : media_add_link(b, orig, media_addr);
389 : }
390 0 : } else if (!link) {
391 0 : name.instance = TIPC_DROP_LINK_REQUEST;
392 : } else
393 0 : return; /* Duplicate of accepted request. Ignore */
394 0 : __tipc_send2name(manager.portid, &name, orig, 1u, &msg);
395 : }
396 : }
397 :
398 : uint
399 : tipc_createLink(const tipc_create_link_argv * argv)
400 0 : {
401 0 : struct tipc_media *b = media_find_by_name(argv->media_name);
402 0 : uint i = 0;
403 0 : LinkRequest *r = &manager.pilot_reqs[i];
404 :
405 0 : while (r->media) {
406 0 : r = &manager.pilot_reqs[++i];
407 : }
408 0 : if ((i > 15) || (!b))
409 0 : return 1;
410 0 : manager_requestLink(r, 0, b, &argv->peer_addr);
411 0 : return 0;
412 : }
413 :
414 : void
415 : manager_name_subscr_event(TipcNameEvent * ev)
416 0 : {
417 0 : if (!ev->cancelled) {
418 0 : tipc_command_result_msg rmsg;
419 0 : tipc_message_section msg =
420 0 : { (const __u8 *) &rmsg, sizeof (rmsg) };
421 0 : memset(&rmsg, 0, sizeof (rmsg));
422 0 : rmsg.command = htonl(TIPC_NAME_SUBSCRIBE);
423 0 : rmsg.result_len = htonl(sizeof (rmsg.result.name_event));
424 0 : rmsg.retval = 0;
425 : memcpy(&rmsg.userdata, &ev->subscription->userArea,
426 0 : sizeof (rmsg.userdata));
427 0 : rmsg.result.name_event.event = htonl(ev->event);
428 0 : rmsg.result.name_event.type = htonl(ev->subscription->type);
429 0 : rmsg.result.name_event.found_lower = htonl(ev->foundlower);
430 0 : rmsg.result.name_event.found_upper = htonl(ev->foundupper);
431 0 : __tipc_send((tipc_id_t) ev->subscription->userArea[7], 1u,
432 : &msg);
433 0 : if (ev->event == tipc_subscription_timeout) {
434 0 : tipc_nameUnsubscribe((uint) ev->subscription->
435 : subscrRef);
436 0 : __tipc_deleteport((tipc_id_t) ev->subscription->
437 : userArea[7]);
438 : }
439 : }
440 0 : ev->discard(ev);
441 : }
442 :
443 : void
444 : manager_name_subscr_port_event(void *userdata,
445 : tipc_id_t portid, tipc_msg_error_code reason)
446 0 : {
447 0 : int connected = 0;
448 :
449 0 : tipc_isconnected(portid, &connected);
450 0 : if (connected)
451 0 : tipc_disconnect(portid);
452 0 : __tipc_deleteport(portid);
453 0 : tipc_nameUnsubscribe((uint) userdata);
454 0 : manager.name_subscriptions--;
455 : }
456 :
457 : void
458 : manager_netw_subscr_event(TipcNetworkEvent * ev)
459 0 : {
460 0 : if (!ev->cancelled) {
461 0 : tipc_command_result_msg rmsg;
462 0 : tipc_message_section msg =
463 0 : { (const __u8 *) &rmsg, sizeof (rmsg) };
464 0 : memset(&rmsg, 0, sizeof (rmsg));
465 0 : rmsg.command = htonl(TIPC_NETWORK_SUBSCRIBE);
466 0 : rmsg.result_len = htonl(sizeof (rmsg.result.network_event));
467 0 : rmsg.retval = 0;
468 : memcpy(&rmsg.userdata, &ev->subscription->userArea,
469 0 : sizeof (rmsg.userdata));
470 0 : rmsg.result.network_event.up = htonl(ev->up);
471 0 : rmsg.result.network_event.addr = htonl(ev->addr);
472 0 : __tipc_send((tipc_id_t) ev->subscription->userArea[7], 1u,
473 : &msg);
474 : }
475 0 : ev->discard(ev);
476 : }
477 :
478 : void
479 : manager_netw_subscr_port_event(void *userdata,
480 : tipc_id_t portid, tipc_msg_error_code reason)
481 0 : {
482 0 : int connected = 0;
483 :
484 0 : tipc_isconnected(portid, &connected);
485 0 : if (connected)
486 0 : __tipc_disconnect(portid);
487 0 : __tipc_deleteport(portid);
488 0 : tipc_networkUnsubscribe((uint) userdata);
489 : }
490 :
491 : void
492 : manager_link_subscr_event(TipcLinkEvent * ev)
493 0 : {
494 0 : spin_lock_bh(&tipc_big_lock);
495 0 : if (!ev->cancelled) {
496 0 : tipc_command_result_msg rmsg;
497 0 : tipc_message_section msg =
498 0 : { (const __u8 *) &rmsg, sizeof (rmsg) };
499 0 : memset(&rmsg, 0, sizeof (rmsg));
500 0 : rmsg.command = htonl(TIPC_LINK_SUBSCRIBE);
501 0 : rmsg.result_len = htonl(sizeof (rmsg.result.link_event));
502 0 : rmsg.retval = 0;
503 : memcpy(&rmsg.userdata, &ev->subscription->userArea,
504 0 : sizeof (rmsg.userdata));
505 0 : rmsg.result.link_event.up = htonl(ev->up);
506 0 : rmsg.result.link_event.addr = htonl(ev->addr);
507 : memcpy(&rmsg.result.link_event.link_name, &ev->name,
508 0 : sizeof (ev->name));
509 0 : __tipc_send((tipc_id_t) ev->subscription->userArea[7], 1u,
510 : &msg);
511 : }
512 0 : ev->discard(ev);
513 0 : spin_unlock_bh(&tipc_big_lock);
514 : }
515 :
516 : void
517 : manager_link_subscr_port_event(void *userdata,
518 : tipc_id_t portid, tipc_msg_error_code reason)
519 0 : {
520 0 : int connected = 0;
521 :
522 0 : __tipc_isconnected(portid, &connected);
523 0 : if (connected)
524 0 : __tipc_disconnect(portid);
525 0 : __tipc_deleteport(portid);
526 0 : tipc_linkUnsubscribe((uint) userdata);
527 : }
528 :
529 : void
530 : manager_respond(tipc_message_section * const rmsg,
531 : uint section_count, tipc_portreference const *origin)
532 24 : {
533 24 : if (origin) {
534 24 : __tipc_send2port(manager.portid, origin, section_count, rmsg);
535 : } else {
536 0 : __tipc_send(manager.conn_portid, section_count, rmsg);
537 : }
538 : }
539 :
540 : void
541 : manager_command_event(const unsigned char *octets,
542 : unsigned int size, tipc_portreference const *origin)
543 24 : {
544 24 : const tipc_command_msg *msg = (const tipc_command_msg *) octets;
545 24 : uint retval = htonl(1);
546 24 : const __u8 *failure_info = "Illegal arguments";
547 24 : uint result_len = htonl(strlen(failure_info) + 1);
548 24 : uint remains = 0;
549 24 : tipc_message_section rmsg[5] = { {octets, 20}, /* Command and user data */
550 : {(unsigned char *) &retval, 4u},
551 : {(unsigned char *) &result_len, 4u},
552 : {(unsigned char *) &remains, 4u},
553 24 : {failure_info, ntohl(result_len)}
554 24 : };
555 24 : uint command = ntohl(msg->command);
556 :
557 24 : if (size == sizeof (tipc_command_msg)) {
558 24 : switch (command) {
559 : case TIPC_CREATE_LINK:
560 : {
561 0 : retval =
562 : htonl(tipc_createLink
563 : (&msg->argv.create_link));
564 0 : if (!retval) {
565 0 : result_len = 0;
566 0 : __tipc_send(manager.conn_portid, 4u,
567 : rmsg);
568 : }
569 0 : break;
570 : }
571 : case TIPC_GET_LINKS:
572 : {
573 2 : const tipc_net_addr_t scope =
574 4 : ntohl(msg->argv.scope);
575 2 : if (tipc_valid_addr(scope)) {
576 2 : rmsg[4].data =
577 : tipc_network_getlinks(scope);
578 2 : rmsg[4].size =
579 : rmsg[4].data ? strlen(rmsg[4].
580 : data) + 1 : 0;
581 2 : retval = 0;
582 2 : result_len = htonl(rmsg[4].size);
583 2 : manager_respond(rmsg, 5u, origin);
584 : }
585 2 : break;
586 : }
587 : case TIPC_GET_LINK_STATISTICS:
588 : {
589 8 : char *stat_buf =
590 8 : kmalloc(STAT_BUF_SIZE, GFP_ATOMIC);
591 8 : if (stat_buf == NULL)
592 8 : break;
593 8 : tipc_linkStatistics(msg->argv.link_name,
594 : stat_buf, STAT_BUF_SIZE);
595 8 : rmsg[4].data = stat_buf;
596 8 : rmsg[4].size = strlen(stat_buf) + 1;
597 8 : result_len = htonl(rmsg[4].size);
598 8 : retval = 0;
599 8 : manager_respond(rmsg, 5u, origin);
600 8 : kfree(stat_buf);
601 8 : break;
602 : }
603 : case TIPC_RESET_LINK_STATISTICS:
604 : {
605 0 : tipc_resetLinkStatistics(msg->argv.link_name);
606 0 : retval = 0;
607 0 : result_len = 0;
608 0 : manager_respond(rmsg, 5u, origin);
609 0 : break;
610 : }
611 : case TIPC_BLOCK_LINK:
612 : {
613 0 : retval =
614 : htonl(tipc_blockLink(msg->argv.link_name));
615 0 : if (!retval) {
616 0 : result_len = 0;
617 0 : __tipc_send(manager.conn_portid, 4u,
618 : rmsg);
619 : }
620 0 : break;
621 : }
622 : case TIPC_UNBLOCK_LINK:
623 : {
624 0 : retval =
625 : htonl(tipc_unblockLink
626 : (msg->argv.link_name));
627 0 : if (!retval) {
628 0 : result_len = 0;
629 0 : __tipc_send(manager.conn_portid, 4u,
630 : rmsg);
631 : }
632 0 : break;
633 : }
634 : case TIPC_REMOVE_LINK:
635 : {
636 0 : retval =
637 : htonl(tipc_removeLink(msg->argv.link_name));
638 0 : if (!retval) {
639 0 : result_len = 0;
640 0 : __tipc_send(manager.conn_portid, 4u,
641 : rmsg);
642 : }
643 0 : break;
644 : }
645 : case TIPC_GET_PEER_ADDRESS:
646 : {
647 0 : const struct tipc_media_addr *addr =
648 0 : tipc_getPeerAddress(msg->argv.link_name);
649 0 : rmsg[4].data = (const char *) addr;
650 0 : rmsg[4].size = sizeof (struct tipc_media_addr);
651 0 : result_len = htonl(rmsg[4].size);
652 0 : retval = 0;
653 0 : manager_respond(rmsg, 5u, origin);
654 0 : break;
655 : }
656 : case TIPC_SET_LINK_TOLERANCE:
657 : {
658 0 : tipc_configure_link_argv a;
659 :
660 : memcpy(&a, &msg->argv.configure_link,
661 0 : sizeof (a));
662 0 : a.value = ntohl(a.value);
663 0 : retval = htonl(tipc_setLinkTolerance(&a));
664 0 : if (!retval) {
665 0 : result_len = 0;
666 0 : __tipc_send(manager.conn_portid, 4u,
667 : rmsg);
668 : }
669 0 : break;
670 : }
671 : case TIPC_SET_LINK_PRIORITY:
672 : {
673 0 : tipc_configure_link_argv a;
674 :
675 : memcpy(&a, &msg->argv.configure_link,
676 0 : sizeof (a));
677 0 : a.value = ntohl(a.value);
678 0 : retval = htonl(tipc_setLinkPriority(&a));
679 0 : if (!retval) {
680 0 : result_len = 0;
681 0 : __tipc_send(manager.conn_portid, 4u,
682 : rmsg);
683 : }
684 0 : break;
685 : }
686 : case TIPC_SET_LINK_WINDOW:
687 : {
688 0 : tipc_configure_link_argv a;
689 :
690 : memcpy(&a, &msg->argv.configure_link,
691 0 : sizeof (a));
692 0 : a.value = ntohl(a.value);
693 0 : retval = htonl(tipc_setLinkWindow(&a));
694 0 : if (!retval) {
695 0 : result_len = 0;
696 0 : __tipc_send(manager.conn_portid, 4u,
697 : rmsg);
698 : }
699 0 : break;
700 : }
701 : case TIPC_GET_NODES:
702 : {
703 2 : const tipc_net_addr_t scope =
704 4 : ntohl(msg->argv.scope);
705 2 : if (tipc_valid_addr(scope)) {
706 2 : struct tipc_node_list *s =
707 2 : tipc_network_getnodes(scope);
708 2 : uint count = s->count;
709 2 : uint p = 0;
710 :
711 2 : rmsg[4].data =
712 : (const __u8 *) &s->nodes[0];
713 2 : rmsg[4].size =
714 : count * sizeof (s->nodes[0]);
715 2 : retval = 0;
716 2 : result_len = htonl(rmsg[4].size);
717 8 : for (; p < count; p++) {
718 6 : s->nodes[p].addr =
719 6 : htonl(s->nodes[p].addr);
720 6 : s->nodes[p].available =
721 : htonl(s->nodes[p].
722 6 : available);
723 : }
724 2 : manager_respond(rmsg, 5u, origin);
725 : }
726 2 : break;
727 : }
728 : case TIPC_GET_MEDIAS:
729 : {
730 2 : char *medias =
731 2 : kmalloc(STAT_BUF_SIZE, GFP_ATOMIC);
732 2 : if (medias == NULL)
733 2 : break;
734 2 : rmsg[4].data =
735 : (const __u8 *) media_name_list(medias);
736 2 : rmsg[4].size =
737 : strlen((const char *) rmsg[4].data) + 1;
738 2 : retval = 0;
739 2 : result_len = htonl(rmsg[4].size);
740 2 : manager_respond(rmsg, 5u, origin);
741 2 : kfree(medias);
742 :
743 2 : break;
744 : }
745 : case TIPC_GET_MEDIA_TYPES:
746 : {
747 2 : char *medias =
748 2 : kmalloc(STAT_BUF_SIZE, GFP_ATOMIC);
749 2 : if (medias == NULL)
750 2 : break;
751 :
752 2 : strcpy(medias, "<ethernet>\n<udp>\n");
753 2 : rmsg[4].data = (const __u8 *) medias;
754 2 : rmsg[4].size =
755 : strlen((const char *) rmsg[4].data) + 1;
756 2 : retval = 0;
757 2 : result_len = htonl(rmsg[4].size);
758 2 : manager_respond(rmsg, 5u, origin);
759 2 : kfree(medias);
760 :
761 2 : break;
762 : }
763 : case TIPC_ENABLE_MEDIA:
764 : {
765 0 : tipc_enable_media_argv argv;
766 :
767 : memcpy(&argv, &msg->argv.enable_media,
768 0 : sizeof (argv));
769 0 : argv.priority =
770 0 : ntohl(msg->argv.enable_media.priority);
771 0 : retval =
772 : htonl(media_enable_by_name
773 : ((const char *) &argv.name));
774 0 : if (!retval) {
775 0 : result_len = 0;
776 0 : __tipc_send(manager.conn_portid, 4u,
777 : rmsg);
778 : }
779 :
780 0 : break;
781 : }
782 : case TIPC_DISABLE_MEDIA:
783 : {
784 0 : retval =
785 : htonl(media_disable_by_name
786 : (msg->argv.media_name));
787 0 : if (!retval) {
788 0 : result_len = 0;
789 0 : __tipc_send(manager.conn_portid, 4u,
790 : rmsg);
791 : }
792 :
793 0 : break;
794 : }
795 : case TIPC_GET_PORTS:
796 : {
797 2 : TipcPortList *list = tipc_getPorts();
798 :
799 2 : rmsg[4].data = (const __u8 *) &list->ports;
800 2 : rmsg[4].size = list->count * sizeof (uint);
801 2 : retval = 0;
802 2 : result_len = htonl(rmsg[4].size);
803 2 : manager_respond(rmsg, 5u, origin);
804 2 : break;
805 : }
806 : case TIPC_GET_PORT_STATISTICS:
807 : {
808 6 : char *pstats =
809 6 : kmalloc(STAT_BUF_SIZE, GFP_ATOMIC);
810 6 : if (pstats == NULL) {
811 6 : break;
812 : }
813 6 : rmsg[4].data =
814 : tipc_portStatistics(*(uint *) & msg->argv.
815 : port_ref, pstats,
816 : STAT_BUF_SIZE);
817 6 : rmsg[4].size = strlen(rmsg[4].data) + 1;
818 6 : retval = 0;
819 6 : result_len = htonl(rmsg[4].size);
820 6 : manager_respond(rmsg, 5u, origin);
821 6 : kfree(pstats);
822 6 : break;
823 : }
824 : case TIPC_RESET_PORT_STATISTICS:
825 : {
826 0 : retval = 0;
827 0 : result_len = 0;
828 0 : manager_respond(rmsg, 4u, origin);
829 0 : break;
830 : }
831 : case TIPC_GET_NAME_TABLE:
832 : {
833 0 : tipc_get_name_table_argv argv;
834 :
835 0 : argv.type =
836 0 : ntohl(msg->argv.get_name_table.type);
837 0 : argv.depth =
838 0 : ntohl(msg->argv.get_name_table.depth);
839 0 : if (argv.depth > 2)
840 0 : break;
841 : #ifdef CONFIG_TIPC_DBG_BUF
842 : rmsg[4].data =
843 : (const __u8 *) tipc_getNameTable(&argv);
844 : rmsg[4].size =
845 : strlen((const char *) rmsg[4].data);
846 : #endif
847 0 : retval = 0;
848 0 : result_len = htonl(rmsg[4].size);
849 0 : manager_respond(rmsg, 5u, origin);
850 0 : break;
851 : }
852 : case TIPC_GET_ROUTING_TABLE:
853 : {
854 : #if 0
855 : tipc_net_addr_t scope = ntohl(msg->argv.scope);
856 : TipcRouteList *l;
857 : uint i = 0;
858 :
859 : if (!tipc_valid_addr(scope))
860 : break;
861 : l = tipc_getRoutes(scope);
862 : for (; l && (i < l->count); i++) {
863 : l->routes[i].dest =
864 : htonl(l->routes[i].dest);
865 : l->routes[i].router =
866 : htonl(l->routes[i].router);
867 : }
868 : rmsg[4].data = (const __u8 *) &l->routes;
869 : rmsg[4].size = l->count * sizeof (l->routes);
870 : #endif
871 0 : rmsg[4].data =
872 : "TIPC_GET_ROUTING_TABLE not implemented";
873 0 : rmsg[4].size = strlen(rmsg[4].data) + 1;
874 0 : retval = 0;
875 0 : result_len = htonl(rmsg[4].size);
876 0 : manager_respond(rmsg, 5u, origin);
877 : break;
878 : }
879 : default:{
880 : }
881 : }
882 : }
883 24 : if (retval) {
884 0 : manager_respond(rmsg, 5u, origin);
885 : }
886 : }
887 :
888 : void
889 : manager_connection_message_event(void *userdata,
890 : tipc_id_t portid,
891 : const unsigned char *octets,
892 : unsigned int size, void **dummy)
893 0 : {
894 0 : spin_lock_bh(&tipc_big_lock);
895 0 : manager_command_event(octets, size, 0);
896 0 : spin_unlock_bh(&tipc_big_lock);
897 : }
898 :
899 : void
900 : manager_named_message_event(void *userdata,
901 : tipc_id_t portid,
902 : const unsigned char *octets,
903 : unsigned int size,
904 : tipc_portreference const *origin,
905 : tipc_portname const *destination,
906 : tipc_msg_importance importance, void **dummy)
907 24 : {
908 24 : tipc_net_addr_t orig = origin->node;
909 24 : const tipc_command_msg *msg = (const tipc_command_msg *) octets;
910 24 : uint retval = htonl(1);
911 24 : const __u8 *failure_info = "Illegal arguments";
912 24 : uint result_len = htonl(strlen(failure_info) + 1);
913 24 : uint remains = 0;
914 24 : tipc_message_section rmsg[5] = { {octets, 20}, /* Command and user data */
915 : {(unsigned char *) &retval, 4u},
916 : {(unsigned char *) &result_len, 4u},
917 : {(unsigned char *) &remains, 4u},
918 24 : {failure_info, ntohl(result_len)}
919 24 : };
920 24 : uint command = ntohl(msg->command);
921 :
922 72 : spin_lock_bh(&tipc_big_lock);
923 24 : if ((size == sizeof (tipc_command_msg)) || (command <= 306)) {
924 24 : switch (command) {
925 : case TIPC_NAME_SUBSCRIBE:
926 : {
927 0 : TipcNameSubscription *s;
928 0 : TipcNameSubscribeArgv argv;
929 :
930 0 : if (manager.name_subscriptions > 1000)
931 0 : break;
932 0 : argv.type =
933 0 : ntohl(msg->argv.name_subscribe.type);
934 0 : argv.lower =
935 0 : ntohl(msg->argv.name_subscribe.lower);
936 0 : argv.upper =
937 0 : ntohl(msg->argv.name_subscribe.upper);
938 0 : argv.timeout =
939 0 : ntohl(msg->argv.name_subscribe.timeout);
940 0 : argv.handleEvent = manager_name_subscr_event;
941 0 : s = tipc_nameSubscribe(&argv);
942 0 : if (s) {
943 0 : tipc_createport_argv a;
944 0 : void *ev = (void *)
945 0 : manager_name_subscr_port_event;
946 :
947 0 : retval = 0;
948 : memcpy(&s->userArea, &msg->userdata,
949 0 : sizeof (msg->userdata));
950 0 : a.userdata = (void *) s->subscrRef;
951 0 : a.importance = tipc_high_importance;
952 0 : a.connected_error_cb =
953 : (tipc_connected_error_event) ev;
954 0 : a.named_message_cb =
955 : (tipc_named_message_event) ev;
956 0 : a.connected_message_cb =
957 : (tipc_connected_message_event) ev;
958 0 : a.continue_event_cb = 0;
959 0 : __tipc_createport(manager.userid, &a,
960 : (uint *) & s->
961 : userArea[7]);
962 0 : __tipc_connect2port(s->userArea[7],
963 : origin);
964 0 : __tipc_send(s->userArea[7], 4u, rmsg); /* Establish connection */
965 0 : manager.name_subscriptions++;
966 : }
967 0 : break;
968 : }
969 : case TIPC_NETWORK_SUBSCRIBE:
970 : {
971 0 : TipcNetworkSubscription *s;
972 0 : TipcNetworkSubscribeArgv argv;
973 :
974 0 : if (manager.network_subscriptions > 200)
975 0 : break;
976 0 : argv.addr = ntohl(msg->argv.scope);
977 0 : argv.handleEvent = manager_netw_subscr_event;
978 0 : s = tipc_networkSubscribe(&argv);
979 0 : if (s) {
980 0 : tipc_createport_argv a;
981 0 : void *ev = (void *)
982 0 : manager_netw_subscr_port_event;
983 :
984 0 : retval = 0;
985 : memcpy(&s->userArea, &msg->userdata,
986 0 : sizeof (msg->userdata));
987 0 : a.userdata = (void *) s->subscrRef;
988 0 : a.importance = tipc_high_importance;
989 0 : a.connected_error_cb =
990 : (tipc_connected_error_event) ev;
991 0 : a.named_message_cb =
992 : (tipc_named_message_event) ev;
993 0 : a.connected_message_cb =
994 : (tipc_connected_message_event) ev;
995 0 : a.continue_event_cb = 0;
996 0 : __tipc_createport(manager.userid, &a,
997 : (uint *) & s->
998 : userArea[7]);
999 0 : __tipc_connect2port(s->userArea[7],
1000 : origin);
1001 0 : __tipc_send(s->userArea[7], 4u, rmsg); /* Establish connection */
1002 0 : manager.network_subscriptions++;
1003 : }
1004 0 : break;
1005 : }
1006 : case TIPC_LINK_SUBSCRIBE:
1007 : {
1008 0 : TipcLinkSubscription *s;
1009 0 : TipcLinkSubscribeArgv argv;
1010 :
1011 0 : if (manager.link_subscriptions > 60)
1012 0 : break;
1013 0 : argv.handleEvent = manager_link_subscr_event;
1014 0 : s = tipc_linkSubscribe(&argv);
1015 0 : if (s) {
1016 0 : tipc_createport_argv a;
1017 0 : void *ev = (void *)
1018 0 : manager_link_subscr_port_event;
1019 :
1020 0 : retval = 0;
1021 0 : result_len = 0;
1022 : memcpy(&s->userArea, &msg->userdata,
1023 0 : sizeof (msg->userdata));
1024 0 : a.userdata = (void *) s->subscrRef;
1025 0 : a.importance = tipc_high_importance;
1026 0 : a.connected_error_cb =
1027 : (tipc_connected_error_event) ev;
1028 0 : a.named_message_cb =
1029 : (tipc_named_message_event) ev;
1030 0 : a.connected_message_cb =
1031 : (tipc_connected_message_event) ev;
1032 0 : a.continue_event_cb = 0;
1033 0 : __tipc_createport(manager.userid, &a,
1034 : (uint *) & s->
1035 : userArea[7]);
1036 0 : __tipc_connect2port(s->userArea[7],
1037 : origin);
1038 0 : __tipc_send(s->userArea[7], 4u, rmsg); /* Establish connection */
1039 0 : manager.link_subscriptions++;
1040 : }
1041 0 : break;
1042 : }
1043 : case TIPC_BLOCK_LINK:
1044 : case TIPC_UNBLOCK_LINK:
1045 : case TIPC_REMOVE_LINK:
1046 : case TIPC_CREATE_LINK:
1047 : case TIPC_SET_LINK_TOLERANCE:
1048 : case TIPC_SET_LINK_PRIORITY:
1049 : case TIPC_SET_LINK_WINDOW:
1050 : case TIPC_ENABLE_MEDIA:
1051 : case TIPC_DISABLE_MEDIA:
1052 : {
1053 0 : int connected;
1054 :
1055 0 : __tipc_isconnected(manager.conn_portid,
1056 : &connected);
1057 0 : if (connected) {
1058 0 : rmsg[4].data =
1059 : "Access denied: Manager connection exists\n";
1060 0 : rmsg[4].size = strlen(rmsg[4].data) + 1;
1061 0 : result_len = htonl(rmsg[4].size);
1062 0 : retval = 1;
1063 0 : break;
1064 : }
1065 : assert(origin);
1066 0 : __tipc_connect2port(manager.conn_portid,
1067 : origin);
1068 : }
1069 : case TIPC_GET_LINKS:
1070 : case TIPC_GET_LINK_STATISTICS:
1071 : case TIPC_RESET_LINK_STATISTICS:
1072 : case TIPC_GET_PEER_ADDRESS:
1073 : case TIPC_GET_NODES:
1074 : case TIPC_GET_MEDIAS:
1075 : case TIPC_GET_MEDIA_TYPES:
1076 : case TIPC_GET_PORTS:
1077 : case TIPC_GET_PORT_STATISTICS:
1078 : case TIPC_RESET_PORT_STATISTICS:
1079 : case TIPC_GET_NAME_TABLE:
1080 : case TIPC_GET_ROUTING_TABLE:
1081 : {
1082 24 : manager_command_event(octets, size, origin);
1083 24 : retval = 0; /* Send no response from here */
1084 24 : break;
1085 : }
1086 : /* Core internal calls related to inter zone link configuration: */
1087 : case TIPC_GET_MEDIA_INFO:
1088 : {
1089 0 : const tipc_net_addr_t addr =
1090 0 : ntohl(*(const tipc_net_addr_t *) octets);
1091 0 : Link *link = link_select(addr, 0);
1092 0 : tipc_portname dest = { 1, TIPC_MEDIA_ADDRESS };
1093 0 : LinkConfigInfo cfg;
1094 0 : tipc_message_section msg;
1095 :
1096 0 : msg.data = (__u8 *) & cfg;
1097 0 : msg.size = sizeof (cfg);
1098 0 : if (!link)
1099 0 : break;
1100 : memcpy(&cfg.media_addr, &link->rep.mediaAddr,
1101 0 : sizeof (struct tipc_media_addr));
1102 0 : strcpy(cfg.media_name, link->media->name);
1103 0 : cfg.addr = htonl(addr);
1104 0 : __tipc_send2name(manager.portid, &dest,
1105 : origin->node, 1u, &msg);
1106 0 : retval = 0;
1107 0 : break;
1108 : }
1109 : case TIPC_MEDIA_ADDRESS:
1110 : {
1111 0 : const LinkConfigInfo *cfg =
1112 0 : (const LinkConfigInfo *) octets;
1113 0 : tipc_net_addr_t addr =
1114 0 : 0xff000000 & ntohl(cfg->addr);
1115 0 : LinkRequest *r =
1116 0 : &manager.zones[tipc_zone_id(addr)].zone_req;
1117 0 : manager_requestLink(r, addr,
1118 : media_find_by_name(cfg->
1119 : media_name),
1120 : &cfg->media_addr);
1121 0 : retval = 0;
1122 0 : break;
1123 : }
1124 : case TIPC_FORWARD_LINK_REQUEST:
1125 : {
1126 0 : const LinkProbe *probe =
1127 0 : (const LinkProbe *) octets;
1128 0 : tipc_net_addr_t addr = ntohl(probe->cfg.addr);
1129 0 : uint maxLinks = ntohl(probe->lowestLinkCount);
1130 0 : struct tipc_media *b =
1131 0 : media_find_by_name(probe->cfg.media_name);
1132 0 : LinkRequest *r =
1133 0 : &manager.zones[tipc_zone_id(addr)].node_req;
1134 0 : Link *link = 0;
1135 :
1136 0 : retval = 0;
1137 0 : if (r->addr == probe->cfg.addr)
1138 0 : break; /* Duplicate request. Drop. */
1139 0 : link = link_find(addr, b->id);
1140 0 : if ((!link)
1141 : && ((!r->addr)
1142 : && (zone_linkcount(tipc_zone_id(addr))
1143 : <= maxLinks))) {
1144 : memcpy(&manager.
1145 : zones[tipc_zone_id(addr)].
1146 : parked, probe,
1147 0 : sizeof (LinkProbe));
1148 0 : manager_requestLink(r, addr, b,
1149 : &probe->cfg.
1150 : media_addr);
1151 0 : break;
1152 : }
1153 0 : manager_forwardLinkProbe(probe);
1154 0 : break;
1155 : }
1156 : case TIPC_LINK_REQUEST_REJECTED:
1157 : {
1158 0 : LinkRequest *r =
1159 0 : &manager.zones[tipc_zone_id(orig)].node_req;
1160 0 : if (r->addr == orig) {
1161 0 : manager_cancelLinkReq(r);
1162 0 : manager_forwardLinkProbe(&manager.
1163 : zones
1164 : [tipc_zone_id
1165 : (orig)].
1166 : parked);
1167 : }
1168 0 : retval = 0;
1169 0 : break;
1170 : }
1171 : case TIPC_LINK_REQUEST_ACCEPTED:
1172 : {
1173 0 : LinkRequest *r =
1174 0 : &manager.zones[tipc_zone_id(orig)].node_req;
1175 0 : if (r->addr == orig) {
1176 0 : media_add_link(r->media, orig,
1177 : (struct tipc_media_addr
1178 : *)
1179 : &r->media_addr);
1180 0 : manager_cancelLinkReq(r);
1181 0 : manager_forwardLinkProbe(&manager.
1182 : zones
1183 : [tipc_zone_id
1184 : (orig)].
1185 : parked);
1186 : }
1187 0 : retval = 0;
1188 0 : break;
1189 : }
1190 : case TIPC_DROP_LINK_REQUEST:
1191 : {
1192 0 : LinkRequest *r =
1193 0 : &manager.zones[tipc_zone_id(orig)].node_req;
1194 0 : if (r->addr == orig) {
1195 0 : manager_cancelLinkReq(r);
1196 : }
1197 0 : retval = 0;
1198 0 : break;
1199 : }
1200 : case TIPC_CHECK_LINK_COUNT:
1201 : {
1202 0 : if (zone_linkcount(tipc_zone_id(orig)) > 2) {
1203 : /* Both endpoints have > 2 inter zone links => common link can be removed: */
1204 0 : Link *link = link_select(orig, 0);
1205 :
1206 0 : if (link) {
1207 0 : info("Removing extra link to %u-%u-%u.\n", TIPC_ADDR_SPLIT(orig));
1208 0 : link_reset(link);
1209 : }
1210 : }
1211 0 : retval = 0;
1212 : break;
1213 : }
1214 : default:{
1215 : }
1216 : }
1217 : }
1218 24 : if (retval)
1219 0 : __tipc_send2port(manager.portid, origin, 5u, rmsg);
1220 72 : spin_unlock_bh(&tipc_big_lock);
1221 : }
1222 :
1223 : int
1224 : tipc_manager_start(void)
1225 1 : {
1226 1 : memset(&manager, 0, sizeof (manager));
1227 1 : __tipc_attach(&manager.userid, 0, 0);
1228 : {
1229 1 : tipc_createport_argv a = { 0, tipc_non_rejectable, 0, 0,
1230 : manager_named_message_event, 0, 0
1231 1 : };
1232 1 : tipc_portname_sequence seq = { 0, tipc_my_addr, tipc_my_addr };
1233 1 : tipc_portname_sequence iseq = { 1, TIPC_GET_MEDIA_INFO,
1234 : TIPC_CHECK_LINK_COUNT
1235 1 : };
1236 :
1237 1 : __tipc_createport(manager.userid, &a, &manager.portid);
1238 1 : __tipc_publish_namesequence(manager.portid, 1u, tipc_zone_scope,
1239 : &seq);
1240 1 : __tipc_publish_namesequence(manager.portid, 1u, tipc_zone_scope,
1241 : &iseq);
1242 :
1243 : /* Prepare the manager connection port */
1244 1 : a.connected_message_cb = manager_connection_message_event;
1245 1 : __tipc_createport(manager.userid, &a, &manager.conn_portid);
1246 : }
1247 : {
1248 1 : uint dummy;
1249 1 : tipc_network_subscription_argv s =
1250 1 : { 0, 0, manager_network_event };
1251 1 : __tipc_subscribe2network(manager.userid, &s, &manager.subscrid,
1252 : &dummy);
1253 : }
1254 : {
1255 1 : TipcLinkSubscribeArgv argv = { 0, manager_link_event };
1256 :
1257 1 : tipc_linkSubscribe(&argv);
1258 : }
1259 1 : return 0;
1260 : }
1261 :
1262 : void
1263 : tipc_manager_stop(void)
1264 0 : {
1265 0 : if (manager.userid)
1266 0 : __tipc_detach(manager.userid);
1267 : }
|