1 #include <err.h>
2 #include <errno.h>
3 #include <libgen.h>
4 #include <limits.h>
5 #include <linux/qrtr.h>
6 #include <linux/netlink.h>
7 #include <linux/rtnetlink.h>
8 #include <stdbool.h>
9 #include <stdint.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <sys/types.h>
14 #include <sys/socket.h>
15 #include <unistd.h>
16 
17 #include "addr.h"
18 #include "hash.h"
19 #include "list.h"
20 #include "map.h"
21 #include "ns.h"
22 #include "util.h"
23 #include "waiter.h"
24 
25 #include "libqrtr.h"
26 #include "logging.h"
27 
28 static const char *ctrl_pkt_strings[] = {
29 	[QRTR_TYPE_HELLO]	= "hello",
30 	[QRTR_TYPE_BYE]		= "bye",
31 	[QRTR_TYPE_NEW_SERVER]	= "new-server",
32 	[QRTR_TYPE_DEL_SERVER]	= "del-server",
33 	[QRTR_TYPE_DEL_CLIENT]	= "del-client",
34 	[QRTR_TYPE_RESUME_TX]	= "resume-tx",
35 	[QRTR_TYPE_EXIT]	= "exit",
36 	[QRTR_TYPE_PING]	= "ping",
37 	[QRTR_TYPE_NEW_LOOKUP]	= "new-lookup",
38 	[QRTR_TYPE_DEL_LOOKUP]	= "del-lookup",
39 };
40 
41 #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
42 
43 struct context {
44 	int sock;
45 
46 	int local_node;
47 
48 	struct sockaddr_qrtr bcast_sq;
49 
50 	struct list lookups;
51 };
52 
53 struct server_filter {
54 	unsigned int service;
55 	unsigned int instance;
56 	unsigned int ifilter;
57 };
58 
59 struct lookup {
60 	unsigned int service;
61 	unsigned int instance;
62 
63 	struct sockaddr_qrtr sq;
64 	struct list_item li;
65 };
66 
67 struct server {
68 	unsigned int service;
69 	unsigned int instance;
70 
71 	unsigned int node;
72 	unsigned int port;
73 	struct map_item mi;
74 	struct list_item qli;
75 };
76 
77 struct node {
78 	unsigned int id;
79 
80 	struct map_item mi;
81 	struct map services;
82 };
83 
84 static struct map nodes;
85 
86 static void server_mi_free(struct map_item *mi);
87 
node_get(unsigned int node_id)88 static struct node *node_get(unsigned int node_id)
89 {
90 	struct map_item *mi;
91 	struct node *node;
92 	int rc;
93 
94 	mi = map_get(&nodes, hash_u32(node_id));
95 	if (mi)
96 		return container_of(mi, struct node, mi);
97 
98 	node = calloc(1, sizeof(*node));
99 	if (!node)
100 		return NULL;
101 
102 	node->id = node_id;
103 
104 	rc = map_create(&node->services);
105 	if (rc)
106 		LOGE_AND_EXIT("unable to create map");
107 
108 	rc = map_put(&nodes, hash_u32(node_id), &node->mi);
109 	if (rc) {
110 		map_destroy(&node->services);
111 		free(node);
112 		return NULL;
113 	}
114 
115 	return node;
116 }
117 
server_match(const struct server * srv,const struct server_filter * f)118 static int server_match(const struct server *srv, const struct server_filter *f)
119 {
120 	unsigned int ifilter = f->ifilter;
121 
122 	if (f->service != 0 && srv->service != f->service)
123 		return 0;
124 	if (!ifilter && f->instance)
125 		ifilter = ~0;
126 	return (srv->instance & ifilter) == f->instance;
127 }
128 
server_query(const struct server_filter * f,struct list * list)129 static int server_query(const struct server_filter *f, struct list *list)
130 {
131 	struct map_entry *node_me;
132 	struct map_entry *me;
133 	struct node *node;
134 	int count = 0;
135 
136 	list_init(list);
137 	map_for_each(&nodes, node_me) {
138 		node = map_iter_data(node_me, struct node, mi);
139 
140 		map_for_each(&node->services, me) {
141 			struct server *srv;
142 
143 			srv = map_iter_data(me, struct server, mi);
144 			if (!server_match(srv, f))
145 				continue;
146 
147 			list_append(list, &srv->qli);
148 			++count;
149 		}
150 	}
151 
152 	return count;
153 }
154 
service_announce_new(struct context * ctx,struct sockaddr_qrtr * dest,struct server * srv)155 static int service_announce_new(struct context *ctx,
156 				struct sockaddr_qrtr *dest,
157 				struct server *srv)
158 {
159 	struct qrtr_ctrl_pkt cmsg;
160 	int rc;
161 
162 	LOGD("advertising new server [%d:%x]@[%d:%d]\n",
163 		srv->service, srv->instance, srv->node, srv->port);
164 
165 	cmsg.cmd = cpu_to_le32(QRTR_TYPE_NEW_SERVER);
166 	cmsg.server.service = cpu_to_le32(srv->service);
167 	cmsg.server.instance = cpu_to_le32(srv->instance);
168 	cmsg.server.node = cpu_to_le32(srv->node);
169 	cmsg.server.port = cpu_to_le32(srv->port);
170 
171 	rc = sendto(ctx->sock, &cmsg, sizeof(cmsg), 0,
172 		    (struct sockaddr *)dest, sizeof(*dest));
173 	if (rc < 0)
174 		PLOGW("sendto()");
175 
176 	return rc;
177 }
178 
service_announce_del(struct context * ctx,struct sockaddr_qrtr * dest,struct server * srv)179 static int service_announce_del(struct context *ctx,
180 				struct sockaddr_qrtr *dest,
181 				struct server *srv)
182 {
183 	struct qrtr_ctrl_pkt cmsg;
184 	int rc;
185 
186 	LOGD("advertising removal of server [%d:%x]@[%d:%d]\n",
187 		srv->service, srv->instance, srv->node, srv->port);
188 
189 	cmsg.cmd = cpu_to_le32(QRTR_TYPE_DEL_SERVER);
190 	cmsg.server.service = cpu_to_le32(srv->service);
191 	cmsg.server.instance = cpu_to_le32(srv->instance);
192 	cmsg.server.node = cpu_to_le32(srv->node);
193 	cmsg.server.port = cpu_to_le32(srv->port);
194 
195 	rc = sendto(ctx->sock, &cmsg, sizeof(cmsg), 0,
196 		    (struct sockaddr *)dest, sizeof(*dest));
197 	if (rc < 0)
198 		PLOGW("sendto()");
199 
200 	return rc;
201 }
202 
lookup_notify(struct context * ctx,struct sockaddr_qrtr * to,struct server * srv,bool new)203 static int lookup_notify(struct context *ctx, struct sockaddr_qrtr *to,
204 			 struct server *srv, bool new)
205 {
206 	struct qrtr_ctrl_pkt pkt = {};
207 	int rc;
208 
209 	pkt.cmd = new ? QRTR_TYPE_NEW_SERVER : QRTR_TYPE_DEL_SERVER;
210 	if (srv) {
211 		pkt.server.service = cpu_to_le32(srv->service);
212 		pkt.server.instance = cpu_to_le32(srv->instance);
213 		pkt.server.node = cpu_to_le32(srv->node);
214 		pkt.server.port = cpu_to_le32(srv->port);
215 	}
216 
217 	rc = sendto(ctx->sock, &pkt, sizeof(pkt), 0,
218 		    (struct sockaddr *)to, sizeof(*to));
219 	if (rc < 0)
220 		PLOGW("send lookup result failed");
221 	return rc;
222 }
223 
annouce_servers(struct context * ctx,struct sockaddr_qrtr * sq)224 static int annouce_servers(struct context *ctx, struct sockaddr_qrtr *sq)
225 {
226 	struct map_entry *me;
227 	struct server *srv;
228 	struct node *node;
229 	int rc;
230 
231 	node = node_get(ctx->local_node);
232 	if (!node)
233 		return 0;
234 
235 	map_for_each(&node->services, me) {
236 		srv = map_iter_data(me, struct server, mi);
237 
238 		rc = service_announce_new(ctx, sq, srv);
239 		if (rc < 0)
240 			return rc;
241 	}
242 
243 	return 0;
244 }
245 
server_add(unsigned int service,unsigned int instance,unsigned int node_id,unsigned int port)246 static struct server *server_add(unsigned int service, unsigned int instance,
247 	unsigned int node_id, unsigned int port)
248 {
249 	struct map_item *mi;
250 	struct server *srv;
251 	struct node *node;
252 	int rc;
253 
254 	if (!service || !port)
255 		return NULL;
256 
257 	srv = calloc(1, sizeof(*srv));
258 	if (srv == NULL)
259 		return NULL;
260 
261 	srv->service = service;
262 	srv->instance = instance;
263 	srv->node = node_id;
264 	srv->port = port;
265 
266 	node = node_get(node_id);
267 	if (!node)
268 		goto err;
269 
270 	rc = map_reput(&node->services, hash_u32(port), &srv->mi, &mi);
271 	if (rc)
272 		goto err;
273 
274 	LOGD("add server [%d:%x]@[%d:%d]\n", srv->service, srv->instance,
275 		srv->node, srv->port);
276 
277 	if (mi) { /* we replaced someone */
278 		struct server *old = container_of(mi, struct server, mi);
279 		free(old);
280 	}
281 
282 	return srv;
283 
284 err:
285 	free(srv);
286 	return NULL;
287 }
288 
server_del(struct context * ctx,struct node * node,unsigned int port)289 static int server_del(struct context *ctx, struct node *node, unsigned int port)
290 {
291 	struct lookup *lookup;
292 	struct list_item *li;
293 	struct map_item *mi;
294 	struct server *srv;
295 
296 	mi = map_get(&node->services, hash_u32(port));
297 	if (!mi)
298 		return -ENOENT;
299 
300 	srv = container_of(mi, struct server, mi);
301 	map_remove(&node->services, srv->mi.key);
302 
303 	/* Broadcast the removal of local services */
304 	if (srv->node == ctx->local_node)
305 		service_announce_del(ctx, &ctx->bcast_sq, srv);
306 
307 	/* Announce the service's disappearance to observers */
308 	list_for_each(&ctx->lookups, li) {
309 		lookup = container_of(li, struct lookup, li);
310 		if (lookup->service && lookup->service != srv->service)
311 			continue;
312 		if (lookup->instance && lookup->instance != srv->instance)
313 			continue;
314 
315 		lookup_notify(ctx, &lookup->sq, srv, false);
316 	}
317 
318 	free(srv);
319 
320 	return 0;
321 }
322 
ctrl_cmd_hello(struct context * ctx,struct sockaddr_qrtr * sq,const void * buf,size_t len)323 static int ctrl_cmd_hello(struct context *ctx, struct sockaddr_qrtr *sq,
324 			  const void *buf, size_t len)
325 {
326 	int rc;
327 
328 	rc = sendto(ctx->sock, buf, len, 0, (void *)sq, sizeof(*sq));
329 	if (rc > 0)
330 		rc = annouce_servers(ctx, sq);
331 
332 	return rc;
333 }
334 
ctrl_cmd_bye(struct context * ctx,struct sockaddr_qrtr * from)335 static int ctrl_cmd_bye(struct context *ctx, struct sockaddr_qrtr *from)
336 {
337 	struct qrtr_ctrl_pkt pkt;
338 	struct sockaddr_qrtr sq;
339 	struct node *local_node;
340 	struct map_entry *me;
341 	struct server *srv;
342 	struct node *node;
343 	int rc;
344 
345 	node = node_get(from->sq_node);
346 	if (!node)
347 		return 0;
348 
349 	map_for_each(&node->services, me) {
350 		srv = map_iter_data(me, struct server, mi);
351 
352 		server_del(ctx, node, srv->port);
353 	}
354 
355 	/* Advertise the removal of this client to all local services */
356 	local_node = node_get(ctx->local_node);
357 	if (!local_node)
358 		return 0;
359 
360 	memset(&pkt, 0, sizeof(pkt));
361 	pkt.cmd = QRTR_TYPE_BYE;
362 	pkt.client.node = from->sq_node;
363 
364 	map_for_each(&local_node->services, me) {
365 		srv = map_iter_data(me, struct server, mi);
366 
367 		sq.sq_family = AF_QIPCRTR;
368 		sq.sq_node = srv->node;
369 		sq.sq_port = srv->port;
370 
371 		rc = sendto(ctx->sock, &pkt, sizeof(pkt), 0,
372 				(struct sockaddr *)&sq, sizeof(sq));
373 		if (rc < 0)
374 			PLOGW("bye propagation failed");
375 	}
376 
377 	return 0;
378 }
379 
ctrl_cmd_del_client(struct context * ctx,struct sockaddr_qrtr * from,unsigned node_id,unsigned port)380 static int ctrl_cmd_del_client(struct context *ctx, struct sockaddr_qrtr *from,
381 			       unsigned node_id, unsigned port)
382 {
383 	struct qrtr_ctrl_pkt pkt;
384 	struct sockaddr_qrtr sq;
385 	struct node *local_node;
386 	struct list_item *tmp;
387 	struct lookup *lookup;
388 	struct list_item *li;
389 	struct map_entry *me;
390 	struct server *srv;
391 	struct node *node;
392 	int rc;
393 
394 	/* Don't accept spoofed messages */
395 	if (from->sq_node != node_id)
396 		return -EINVAL;
397 
398 	/* Local DEL_CLIENT messages comes from the port being closed */
399 	if (from->sq_node == ctx->local_node && from->sq_port != port)
400 		return -EINVAL;
401 
402 	/* Remove any lookups by this client */
403 	list_for_each_safe(&ctx->lookups, li, tmp) {
404 		lookup = container_of(li, struct lookup, li);
405 		if (lookup->sq.sq_node != node_id)
406 			continue;
407 		if (lookup->sq.sq_port != port)
408 			continue;
409 
410 		list_remove(&ctx->lookups, &lookup->li);
411 		free(lookup);
412 	}
413 
414 	/* Remove the server belonging to this port*/
415 	node = node_get(node_id);
416 	if (node)
417 		server_del(ctx, node, port);
418 
419 	/* Advertise the removal of this client to all local services */
420 	local_node = node_get(ctx->local_node);
421 	if (!local_node)
422 		return 0;
423 
424 	pkt.cmd = QRTR_TYPE_DEL_CLIENT;
425 	pkt.client.node = node_id;
426 	pkt.client.port = port;
427 
428 	map_for_each(&local_node->services, me) {
429 		srv = map_iter_data(me, struct server, mi);
430 
431 		sq.sq_family = AF_QIPCRTR;
432 		sq.sq_node = srv->node;
433 		sq.sq_port = srv->port;
434 
435 		rc = sendto(ctx->sock, &pkt, sizeof(pkt), 0,
436 				(struct sockaddr *)&sq, sizeof(sq));
437 		if (rc < 0)
438 			PLOGW("del_client propagation failed");
439 	}
440 
441 	return 0;
442 }
443 
ctrl_cmd_new_server(struct context * ctx,struct sockaddr_qrtr * from,unsigned int service,unsigned int instance,unsigned int node_id,unsigned int port)444 static int ctrl_cmd_new_server(struct context *ctx, struct sockaddr_qrtr *from,
445 			       unsigned int service, unsigned int instance,
446 			       unsigned int node_id, unsigned int port)
447 {
448 	struct lookup *lookup;
449 	struct list_item *li;
450 	struct server *srv;
451 	int rc = 0;
452 
453 	/* Ignore specified node and port for local servers*/
454 	if (from->sq_node == ctx->local_node) {
455 		node_id = from->sq_node;
456 		port = from->sq_port;
457 	}
458 
459 	/* Don't accept spoofed messages */
460 	if (from->sq_node != node_id)
461 		return -EINVAL;
462 
463 	srv = server_add(service, instance, node_id, port);
464 	if (!srv)
465 		return -EINVAL;
466 
467 	if (srv->node == ctx->local_node)
468 		rc = service_announce_new(ctx, &ctx->bcast_sq, srv);
469 
470 	list_for_each(&ctx->lookups, li) {
471 		lookup = container_of(li, struct lookup, li);
472 		if (lookup->service && lookup->service != service)
473 			continue;
474 		if (lookup->instance && lookup->instance != instance)
475 			continue;
476 
477 		lookup_notify(ctx, &lookup->sq, srv, true);
478 	}
479 
480 	return rc;
481 }
482 
ctrl_cmd_del_server(struct context * ctx,struct sockaddr_qrtr * from,unsigned int service __unused,unsigned int instance __unused,unsigned int node_id,unsigned int port)483 static int ctrl_cmd_del_server(struct context *ctx, struct sockaddr_qrtr *from,
484 			       unsigned int service __unused,
485 			       unsigned int instance __unused,
486 			       unsigned int node_id, unsigned int port)
487 {
488 	struct node *node;
489 
490 	/* Ignore specified node and port for local servers*/
491 	if (from->sq_node == ctx->local_node) {
492 		node_id = from->sq_node;
493 		port = from->sq_port;
494 	}
495 
496 	/* Don't accept spoofed messages */
497 	if (from->sq_node != node_id)
498 		return -EINVAL;
499 
500 	/* Local servers may only unregister themselves */
501 	if (from->sq_node == ctx->local_node && from->sq_port != port)
502 		return -EINVAL;
503 
504 	node = node_get(node_id);
505 	if (!node)
506 		return -ENOENT;
507 
508 	return server_del(ctx, node, port);
509 }
510 
ctrl_cmd_new_lookup(struct context * ctx,struct sockaddr_qrtr * from,unsigned int service,unsigned int instance)511 static int ctrl_cmd_new_lookup(struct context *ctx, struct sockaddr_qrtr *from,
512 			       unsigned int service, unsigned int instance)
513 {
514 	struct server_filter filter;
515 	struct list reply_list;
516 	struct lookup *lookup;
517 	struct list_item *li;
518 	struct server *srv;
519 
520 	/* Accept only local observers */
521 	if (from->sq_node != ctx->local_node)
522 		return -EINVAL;
523 
524 	lookup = calloc(1, sizeof(*lookup));
525 	if (!lookup)
526 		return -EINVAL;
527 
528 	lookup->sq = *from;
529 	lookup->service = service;
530 	lookup->instance = instance;
531 	list_append(&ctx->lookups, &lookup->li);
532 
533 	memset(&filter, 0, sizeof(filter));
534 	filter.service = service;
535 	filter.instance = instance;
536 
537 	server_query(&filter, &reply_list);
538 	list_for_each(&reply_list, li) {
539 		srv = container_of(li, struct server, qli);
540 
541 		lookup_notify(ctx, from, srv, true);
542 	}
543 
544 	lookup_notify(ctx, from, NULL, true);
545 
546 	return 0;
547 }
548 
ctrl_cmd_del_lookup(struct context * ctx,struct sockaddr_qrtr * from,unsigned int service,unsigned int instance)549 static int ctrl_cmd_del_lookup(struct context *ctx, struct sockaddr_qrtr *from,
550 			       unsigned int service, unsigned int instance)
551 {
552 	struct lookup *lookup;
553 	struct list_item *tmp;
554 	struct list_item *li;
555 
556 	list_for_each_safe(&ctx->lookups, li, tmp) {
557 		lookup = container_of(li, struct lookup, li);
558 		if (lookup->sq.sq_node != from->sq_node)
559 			continue;
560 		if (lookup->sq.sq_port != from->sq_port)
561 			continue;
562 		if (lookup->service != service)
563 			continue;
564 		if (lookup->instance && lookup->instance != instance)
565 			continue;
566 
567 		list_remove(&ctx->lookups, &lookup->li);
568 		free(lookup);
569 	}
570 
571 	return 0;
572 }
573 
ctrl_port_fn(void * vcontext,struct waiter_ticket * tkt)574 static void ctrl_port_fn(void *vcontext, struct waiter_ticket *tkt)
575 {
576 	struct context *ctx = vcontext;
577 	struct sockaddr_qrtr sq;
578 	int sock = ctx->sock;
579 	struct qrtr_ctrl_pkt *msg;
580 	unsigned int cmd;
581 	char buf[4096];
582 	socklen_t sl;
583 	ssize_t len;
584 	int rc;
585 
586 	sl = sizeof(sq);
587 	len = recvfrom(sock, buf, sizeof(buf), 0, (void *)&sq, &sl);
588 	if (len <= 0) {
589 		PLOGW("recvfrom()");
590 		close(sock);
591 		ctx->sock = -1;
592 		goto out;
593 	}
594 	msg = (void *)buf;
595 
596 	if (len < 4) {
597 		LOGW("short packet from %d:%d", sq.sq_node, sq.sq_port);
598 		goto out;
599 	}
600 
601 	cmd = le32_to_cpu(msg->cmd);
602 	if (cmd < ARRAY_SIZE(ctrl_pkt_strings) && ctrl_pkt_strings[cmd])
603 		LOGD("%s from %d:%d\n", ctrl_pkt_strings[cmd], sq.sq_node, sq.sq_port);
604 	else
605 		LOGD("UNK (%08x) from %d:%d\n", cmd, sq.sq_node, sq.sq_port);
606 
607 	rc = 0;
608 	switch (cmd) {
609 	case QRTR_TYPE_HELLO:
610 		rc = ctrl_cmd_hello(ctx, &sq, buf, len);
611 		break;
612 	case QRTR_TYPE_BYE:
613 		rc = ctrl_cmd_bye(ctx, &sq);
614 		break;
615 	case QRTR_TYPE_DEL_CLIENT:
616 		rc = ctrl_cmd_del_client(ctx, &sq,
617 					 le32_to_cpu(msg->client.node),
618 					 le32_to_cpu(msg->client.port));
619 		break;
620 	case QRTR_TYPE_NEW_SERVER:
621 		rc = ctrl_cmd_new_server(ctx, &sq,
622 					 le32_to_cpu(msg->server.service),
623 					 le32_to_cpu(msg->server.instance),
624 					 le32_to_cpu(msg->server.node),
625 					 le32_to_cpu(msg->server.port));
626 		break;
627 	case QRTR_TYPE_DEL_SERVER:
628 		rc = ctrl_cmd_del_server(ctx, &sq,
629 					 le32_to_cpu(msg->server.service),
630 					 le32_to_cpu(msg->server.instance),
631 					 le32_to_cpu(msg->server.node),
632 					 le32_to_cpu(msg->server.port));
633 		break;
634 	case QRTR_TYPE_EXIT:
635 	case QRTR_TYPE_PING:
636 	case QRTR_TYPE_RESUME_TX:
637 		break;
638 	case QRTR_TYPE_NEW_LOOKUP:
639 		rc = ctrl_cmd_new_lookup(ctx, &sq,
640 					 le32_to_cpu(msg->server.service),
641 					 le32_to_cpu(msg->server.instance));
642 		break;
643 	case QRTR_TYPE_DEL_LOOKUP:
644 		rc = ctrl_cmd_del_lookup(ctx, &sq,
645 					 le32_to_cpu(msg->server.service),
646 					 le32_to_cpu(msg->server.instance));
647 		break;
648 	}
649 
650 	if (rc < 0)
651 		LOGW("failed while handling packet from %d:%d",
652 		      sq.sq_node, sq.sq_port);
653 out:
654 	waiter_ticket_clear(tkt);
655 }
656 
say_hello(struct context * ctx)657 static int say_hello(struct context *ctx)
658 {
659 	struct qrtr_ctrl_pkt pkt;
660 	int rc;
661 
662 	memset(&pkt, 0, sizeof(pkt));
663 	pkt.cmd = cpu_to_le32(QRTR_TYPE_HELLO);
664 
665 	rc = sendto(ctx->sock, &pkt, sizeof(pkt), 0,
666 		    (struct sockaddr *)&ctx->bcast_sq, sizeof(ctx->bcast_sq));
667 	if (rc < 0)
668 		return rc;
669 
670 	return 0;
671 }
672 
server_mi_free(struct map_item * mi)673 static void server_mi_free(struct map_item *mi)
674 {
675 	free(container_of(mi, struct server, mi));
676 }
677 
node_mi_free(struct map_item * mi)678 static void node_mi_free(struct map_item *mi)
679 {
680 	struct node *node = container_of(mi, struct node, mi);
681 
682 	map_clear(&node->services, server_mi_free);
683 	map_destroy(&node->services);
684 
685 	free(node);
686 }
687 
go_dormant(int sock)688 static void go_dormant(int sock)
689 {
690 	close(sock);
691 
692 	for (;;)
693 		sleep(UINT_MAX);
694 }
695 
usage(const char * progname)696 static void usage(const char *progname)
697 {
698 	fprintf(stderr, "%s [-f] [-s] [<node-id>]\n", progname);
699 	exit(1);
700 }
701 
main(int argc,char ** argv)702 int main(int argc, char **argv)
703 {
704 	struct waiter_ticket *tkt;
705 	struct sockaddr_qrtr sq;
706 	struct context ctx;
707 	unsigned long addr = (unsigned long)-1;
708 	struct waiter *w;
709 	socklen_t sl = sizeof(sq);
710 	bool foreground = false;
711 	bool use_syslog = false;
712 	bool verbose_log = false;
713 	char *ep;
714 	int opt;
715 	int rc;
716 	const char *progname = basename(argv[0]);
717 
718 	while ((opt = getopt(argc, argv, "fsv")) != -1) {
719 		switch (opt) {
720 		case 'f':
721 			foreground = true;
722 			break;
723 		case 's':
724 			use_syslog = true;
725 			break;
726 		case 'v':
727 			verbose_log = true;
728 			break;
729 		default:
730 			usage(progname);
731 		}
732 	}
733 
734 	qlog_setup(progname, use_syslog);
735 	if (verbose_log)
736 		qlog_set_min_priority(LOG_DEBUG);
737 
738 	if (optind < argc) {
739 		addr = strtoul(argv[optind], &ep, 10);
740 		if (argv[1][0] == '\0' || *ep != '\0' || addr >= UINT_MAX)
741 			usage(progname);
742 
743 		qrtr_set_address(addr);
744 		optind++;
745 	}
746 
747 	if (optind != argc)
748 		usage(progname);
749 
750 	w = waiter_create();
751 	if (w == NULL)
752 		LOGE_AND_EXIT("unable to create waiter");
753 
754 	list_init(&ctx.lookups);
755 
756 	rc = map_create(&nodes);
757 	if (rc)
758 		LOGE_AND_EXIT("unable to create node map");
759 
760 	ctx.sock = socket(AF_QIPCRTR, SOCK_DGRAM, 0);
761 	if (ctx.sock < 0)
762 		PLOGE_AND_EXIT("unable to create control socket");
763 
764 	rc = getsockname(ctx.sock, (void*)&sq, &sl);
765 	if (rc < 0)
766 		PLOGE_AND_EXIT("getsockname()");
767 	sq.sq_port = QRTR_PORT_CTRL;
768 	ctx.local_node = sq.sq_node;
769 
770 	rc = bind(ctx.sock, (void *)&sq, sizeof(sq));
771 	if (rc < 0) {
772 		if (errno == EADDRINUSE) {
773 			PLOGE("nameserver already running, going dormant");
774 			go_dormant(ctx.sock);
775 		}
776 
777 		PLOGE_AND_EXIT("bind control socket");
778 	}
779 
780 	ctx.bcast_sq.sq_family = AF_QIPCRTR;
781 	ctx.bcast_sq.sq_node = QRTR_NODE_BCAST;
782 	ctx.bcast_sq.sq_port = QRTR_PORT_CTRL;
783 
784 	rc = say_hello(&ctx);
785 	if (rc)
786 		PLOGE_AND_EXIT("unable to say hello");
787 
788 	/* If we're going to background, fork and exit parent */
789 	if (!foreground && fork() != 0) {
790 		close(ctx.sock);
791 		exit(0);
792 	}
793 
794 	tkt = waiter_add_fd(w, ctx.sock);
795 	waiter_ticket_callback(tkt, ctrl_port_fn, &ctx);
796 
797 	while (ctx.sock >= 0)
798 		waiter_wait(w);
799 
800 	puts("exiting cleanly");
801 
802 	waiter_destroy(w);
803 
804 	map_clear(&nodes, node_mi_free);
805 	map_destroy(&nodes);
806 
807 	return 0;
808 }
809