mrpd: comment cleanup
[profile/ivi/OpenAVB.git] / daemons / mrpd / mrpd.c
1 /****************************************************************************
2   Copyright (c) 2012, Intel Corporation
3   All rights reserved.
4
5   Redistribution and use in source and binary forms, with or without
6   modification, are permitted provided that the following conditions are met:
7
8    1. Redistributions of source code must retain the above copyright notice,
9       this list of conditions and the following disclaimer.
10
11    2. Redistributions in binary form must reproduce the above copyright
12       notice, this list of conditions and the following disclaimer in the
13       documentation and/or other materials provided with the distribution.
14
15    3. Neither the name of the Intel Corporation nor the names of its
16       contributors may be used to endorse or promote products derived from
17       this software without specific prior written permission.
18
19   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29   POSSIBILITY OF SUCH DAMAGE.
30
31 ******************************************************************************/
32 /*
33  * an MRP (MMRP, MVRP, MSRP) endpoint implementation of 802.1Q-2011
34  */
35 #include <unistd.h>
36 #include <fcntl.h>
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <stddef.h>
40 #include <string.h>
41 #include <syslog.h>
42 #include <signal.h>
43 #include <errno.h>
44 #include <sys/ioctl.h>
45 #include <sys/time.h>
46 #include <sys/resource.h>
47 #include <sys/mman.h>
48 #include <sys/timerfd.h>
49 #include <sys/user.h>
50 #include <sys/socket.h>
51 #include <linux/if.h>
52 #include <netpacket/packet.h>
53 #include <netinet/in.h>
54 #include <arpa/inet.h>
55 #include <net/ethernet.h>
56 #include <sys/un.h>
57
58 #include "mrpd.h"
59 #include "mrp.h"
60 #include "mvrp.h"
61 #include "msrp.h"
62 #include "mmrp.h"
63
64 /* global mgmt parameters */
65 int daemonize;
66 int mmrp_enable;
67 int mvrp_enable;
68 int msrp_enable;
69 int logging_enable;
70 int mrpd_port;
71
72 char *interface;
73 int interface_fd;
74
75 /* state machine controls */
76 int periodic_enable;
77 int registration;
78
79 /* if registration is FIXED or FORBIDDEN
80  * updates from MRP are discarded, and
81  * only IN and JOININ messages are sent
82  */
83
84 int participant;
85
86 /* if participant role is 'SILENT' (or non-participant)
87  * applicant doesn't send any messages - configured per-attribute
88  */
89
90 #define VERSION_STR     "0.0"
91
92 static const char *version_str =
93     "mrpd v" VERSION_STR "\n" "Copyright (c) 2012, Intel Corporation\n";
94
95 unsigned char STATION_ADDR[] = { 0x00, 0x88, 0x77, 0x66, 0x55, 0x44 };
96
97 /* global variables */
98 SOCKET control_socket;
99 extern SOCKET mmrp_socket;
100 extern SOCKET mvrp_socket;
101 extern SOCKET msrp_socket;
102
103 int periodic_timer;
104 int gc_timer;
105
106 extern struct mmrp_database *MMRP_db;
107 extern struct mvrp_database *MVRP_db;
108 extern struct msrp_database *MSRP_db;
109
110 int mrpd_timer_create(void)
111 {
112         int t = timerfd_create(CLOCK_MONOTONIC, 0);
113         if (-1 != t)
114                 fcntl(t, F_SETFL, O_NONBLOCK);
115         return t;
116 }
117
118 void mrpd_timer_close(int t)
119 {
120         if (-1 != t)
121                 close(t);
122 }
123
124 int mrpd_timer_start_interval(int timerfd,
125                               unsigned long value_ms, unsigned long interval_ms)
126 {
127         int rc;
128         struct itimerspec itimerspec_new;
129         struct itimerspec itimerspec_old;
130         unsigned long ns_per_ms = 1000000;
131
132         memset(&itimerspec_new, 0, sizeof(itimerspec_new));
133         memset(&itimerspec_old, 0, sizeof(itimerspec_old));
134
135         if (interval_ms) {
136                 itimerspec_new.it_interval.tv_sec = interval_ms / 1000;
137                 itimerspec_new.it_interval.tv_nsec =
138                     (interval_ms % 1000) * ns_per_ms;
139         }
140
141         itimerspec_new.it_value.tv_sec = value_ms / 1000;
142         itimerspec_new.it_value.tv_nsec = (value_ms % 1000) * ns_per_ms;
143
144         rc = timerfd_settime(timerfd, 0, &itimerspec_new, &itimerspec_old);
145
146         return (rc);
147 }
148
149 int mrpd_timer_start(int timerfd, unsigned long value_ms)
150 {
151         return mrpd_timer_start_interval(timerfd, value_ms, 0);
152 }
153
154 int mrpd_timer_stop(int timerfd)
155 {
156         int rc;
157         struct itimerspec itimerspec_new;
158         struct itimerspec itimerspec_old;
159
160         memset(&itimerspec_new, 0, sizeof(itimerspec_new));
161         memset(&itimerspec_old, 0, sizeof(itimerspec_old));
162
163         rc = timerfd_settime(timerfd, 0, &itimerspec_new, &itimerspec_old);
164
165         return (rc);
166 }
167
168 int gctimer_start()
169 {
170         /* reclaim memory every 30 minutes */
171         return mrpd_timer_start(gc_timer, 30 * 60 * 1000);
172 }
173
174 int periodictimer_start()
175 {
176         /* periodictimer has expired. (10.7.5.23)
177          * PeriodicTransmission state machine generates periodic events
178          * period is one-per-sec
179          */
180         return mrpd_timer_start_interval(periodic_timer, 1000, 1000);
181 }
182
183 int periodictimer_stop()
184 {
185         /* periodictimer has expired. (10.7.5.23)
186          * PeriodicTransmission state machine generates periodic events
187          * period is one-per-sec
188          */
189         return mrpd_timer_stop(periodic_timer);
190 }
191
192 int init_local_ctl(void)
193 {
194         struct sockaddr_in addr;
195         socklen_t addr_len;
196         int sock_fd = -1;
197         int rc;
198
199         sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
200         if (sock_fd < 0)
201                 goto out;
202
203         memset(&addr, 0, sizeof(addr));
204         addr.sin_family = AF_INET;
205         addr.sin_port = htons(mrpd_port);
206         inet_aton("127.0.0.1", (struct in_addr *)&addr.sin_addr.s_addr);
207         addr_len = sizeof(addr);
208
209         rc = bind(sock_fd, (struct sockaddr *)&addr, addr_len);
210
211         if (rc < 0)
212                 goto out;
213
214         control_socket = sock_fd;
215
216         return 0;
217  out:
218         if (sock_fd != -1)
219                 close(sock_fd);
220
221         return -1;
222 }
223
224 int
225 mrpd_send_ctl_msg(struct sockaddr_in *client_addr, char *notify_data,
226                   int notify_len)
227 {
228
229         int rc;
230
231         if (-1 == control_socket)
232                 return 0;
233
234         if (logging_enable)
235                 printf("CTL MSG:%s to CLNT %d\n", notify_data, client_addr->sin_port);
236
237         rc = sendto(control_socket, notify_data, notify_len,
238                     0, (struct sockaddr *)client_addr, sizeof(struct sockaddr));
239         return rc;
240 }
241
242 int process_ctl_msg(char *buf, int buflen, struct sockaddr_in *client)
243 {
244
245         char respbuf[8];
246         /*
247          * Inbound/output commands from/to a client:
248          *
249          * When sent from a client, indicates an operation on the
250          * internal attribute databases. When sent by the daemon to
251          * a client, indicates an event such as a new attribute arrival,
252          * or a leaveall timer to force clients to re-advertise continued
253          * interest in an attribute.
254          *
255          * BYE   Client detaches from daemon
256          *
257          * M+? - JOIN_MT a MAC address or service declaration
258          * M++   JOIN_IN a MAC Address (XXX: MMRP doesn't use 'New' though?)
259          * M-- - LV a MAC address or service declaration
260          * V+? - JOIN_MT a VID (VLAN ID)
261          * V++ - JOIN_IN a VID (VLAN ID)
262          * V-- - LV a VID (VLAN ID)
263          * S+? - JOIN_MT a Stream
264          * S++ - JOIN_IN a Stream
265          * S-- - LV a Stream
266          *
267          * Outbound messages
268          * ERC - error, unrecognized command
269          * ERP - error, unrecognized parameter
270          * ERI - error, internal
271          * OK+ - success
272          *
273          * Registrar Commands
274          *
275          * M?? - query MMRP Registrar MAC Address database
276          * V?? - query MVRP Registrar VID database
277          * S?? - query MSRP Registrar database
278          *
279          * Registrar Responses (to ?? commands)
280          *
281          * MIN - Registered
282          * MMT - Registered, Empty
283          * MLV - Registered, Leaving
284          * MNE - New attribute notification
285          * MJO - JOIN attribute notification
286          * MLV - LEAVE attribute notification
287          * VIN - Registered
288          * VMT - Registered, Empty
289          * VLV - Registered, Leaving
290          * SIN - Registered
291          * SMT - Registered, Empty
292          * SLV - Registered, Leaving
293          *
294          */
295
296         memset(respbuf, 0, sizeof(respbuf));
297
298         if (logging_enable)
299                 printf("CMD:%s from CLNT %d\n", buf, client->sin_port);
300
301         if (buflen < 3) {
302                 printf("buflen = %d!\b", buflen);
303
304                 return -1;
305         }
306
307         switch (buf[0]) {
308         case 'M':
309                 return mmrp_recv_cmd(buf, buflen, client);
310                 break;
311         case 'V':
312                 return mvrp_recv_cmd(buf, buflen, client);
313                 break;
314         case 'S':
315                 return msrp_recv_cmd(buf, buflen, client);
316                 break;
317         case 'B':
318                 mmrp_bye(client);
319                 mvrp_bye(client);
320                 msrp_bye(client);
321                 break;
322         default:
323                 printf("unrecognized command %s\n", buf);
324                 snprintf(respbuf, sizeof(respbuf) - 1, "ERC %s", buf);
325                 mrpd_send_ctl_msg(client, respbuf, sizeof(respbuf));
326                 return -1;
327                 break;
328         }
329
330         return 0;
331 }
332
333 int recv_ctl_msg()
334 {
335         char *msgbuf;
336         struct sockaddr_in client_addr;
337         struct msghdr msg;
338         struct iovec iov;
339         int bytes = 0;
340
341         msgbuf = (char *)malloc(MAX_MRPD_CMDSZ);
342         if (NULL == msgbuf)
343                 return -1;
344
345         memset(&msg, 0, sizeof(msg));
346         memset(&client_addr, 0, sizeof(client_addr));
347         memset(msgbuf, 0, MAX_MRPD_CMDSZ);
348
349         iov.iov_len = MAX_MRPD_CMDSZ;
350         iov.iov_base = msgbuf;
351         msg.msg_name = &client_addr;
352         msg.msg_namelen = sizeof(client_addr);
353         msg.msg_iov = &iov;
354         msg.msg_iovlen = 1;
355
356         bytes = recvmsg(control_socket, &msg, 0);
357         if (bytes <= 0)
358                 goto out;
359
360         process_ctl_msg(msgbuf, bytes, &client_addr);
361  out:
362         free(msgbuf);
363
364         return -1;
365 }
366
367 int mrpd_recvmsgbuf(int sock, char **buf)
368 {
369         struct sockaddr_ll client_addr;
370         struct msghdr msg;
371         struct iovec iov;
372         int bytes = 0;
373
374         *buf = (char *)malloc(MAX_FRAME_SIZE);
375         if (NULL == *buf)
376                 return -1;
377
378         memset(&msg, 0, sizeof(msg));
379         memset(&client_addr, 0, sizeof(client_addr));
380         memset(*buf, 0, MAX_FRAME_SIZE);
381
382         iov.iov_len = MAX_FRAME_SIZE;
383         iov.iov_base = *buf;
384         msg.msg_name = &client_addr;
385         msg.msg_namelen = sizeof(client_addr);
386         msg.msg_iov = &iov;
387         msg.msg_iovlen = 1;
388         bytes = recvmsg(sock, &msg, 0);
389         return bytes;
390 }
391
392 int
393 mrpd_init_protocol_socket(u_int16_t etype, int *sock,
394                           unsigned char *multicast_addr)
395 {
396         struct sockaddr_ll addr;
397         struct ifreq if_request;
398         int lsock;
399         int rc;
400         struct packet_mreq multicast_req;
401
402         if (NULL == sock)
403                 return -1;
404         if (NULL == multicast_addr)
405                 return -1;
406
407         *sock = -1;
408
409         lsock = socket(PF_PACKET, SOCK_RAW, htons(etype));
410         if (lsock < 0)
411                 return -1;
412
413         memset(&if_request, 0, sizeof(if_request));
414
415         strncpy(if_request.ifr_name, interface, sizeof(if_request.ifr_name));
416
417         rc = ioctl(lsock, SIOCGIFHWADDR, &if_request);
418         if (rc < 0) {
419                 close(lsock);
420                 return -1;
421         }
422
423         memcpy(STATION_ADDR, if_request.ifr_hwaddr.sa_data,
424                sizeof(STATION_ADDR));
425
426         memset(&if_request, 0, sizeof(if_request));
427
428         strncpy(if_request.ifr_name, interface, sizeof(if_request.ifr_name));
429
430         rc = ioctl(lsock, SIOCGIFINDEX, &if_request);
431         if (rc < 0) {
432                 close(lsock);
433                 return -1;
434         }
435
436         memset(&addr, 0, sizeof(addr));
437         addr.sll_ifindex = if_request.ifr_ifindex;
438         addr.sll_family = AF_PACKET;
439         addr.sll_protocol = htons(etype);
440
441         rc = bind(lsock, (struct sockaddr *)&addr, sizeof(addr));
442         if (0 != rc) {
443                 close(lsock);
444                 return -1;
445         }
446
447         rc = setsockopt(lsock, SOL_SOCKET, SO_BINDTODEVICE, interface,
448                         strlen(interface));
449         if (0 != rc) {
450                 close(lsock);
451                 return -1;
452         }
453
454         multicast_req.mr_ifindex = if_request.ifr_ifindex;
455         multicast_req.mr_type = PACKET_MR_MULTICAST;
456         multicast_req.mr_alen = 6;
457         memcpy(multicast_req.mr_address, multicast_addr, 6);
458
459         rc = setsockopt(lsock, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
460                         &multicast_req, sizeof(multicast_req));
461         if (0 != rc) {
462                 close(lsock);
463                 return -1;
464         }
465
466         *sock = lsock;
467
468         return 0;
469 }
470
471 int mrpd_close_socket(SOCKET sock)
472 {
473         return close(sock);
474 }
475
476 int mrpd_init_timers(struct mrp_database *mrp_db)
477 {
478         mrp_db->join_timer = mrpd_timer_create();
479         mrp_db->lv_timer = mrpd_timer_create();
480         mrp_db->lva_timer = mrpd_timer_create();
481
482         if (-1 == mrp_db->join_timer)
483                 goto out;
484         if (-1 == mrp_db->lv_timer)
485                 goto out;
486         if (-1 == mrp_db->lva_timer)
487                 goto out;
488         return 0;
489  out:
490         mrpd_timer_close(mrp_db->join_timer);
491         mrpd_timer_close(mrp_db->lv_timer);
492         mrpd_timer_close(mrp_db->lva_timer);
493
494         return -1;
495 }
496
497 int handle_periodic(void)
498 {
499         if (periodic_enable)
500                 periodictimer_start();
501         else
502                 periodictimer_stop();
503
504         return 0;
505 }
506
507 int init_timers(void)
508 {
509         /*
510          * primarily whether to schedule the periodic timer as the
511          * rest are self-scheduling as a side-effect of state transitions
512          * of the various attributes
513          */
514
515         periodic_timer = mrpd_timer_create();
516         gc_timer = mrpd_timer_create();
517
518         if (-1 == periodic_timer)
519                 goto out;
520         if (-1 == gc_timer)
521                 goto out;
522
523         gctimer_start();
524
525         if (periodic_enable)
526                 periodictimer_start();
527
528         return 0;
529  out:
530         return -1;
531 }
532
533 int mrp_register_timers(struct mrp_database *mrp_db, fd_set * fds)
534 {
535         int max_fd;
536
537         FD_SET(mrp_db->join_timer, fds);
538         FD_SET(mrp_db->lv_timer, fds);
539         FD_SET(mrp_db->lva_timer, fds);
540
541         max_fd = mrp_db->join_timer;
542         if (mrp_db->lv_timer > max_fd)
543                 max_fd = mrp_db->lv_timer;
544         if (mrp_db->lva_timer > max_fd)
545                 max_fd = mrp_db->lva_timer;
546
547         return max_fd;
548 }
549
550 int mrpd_reclaim()
551 {
552
553         /*
554          * if the local applications have neither registered interest
555          * by joining, and the remote node has quit advertising the attribute
556          * and allowing it to go into the MT state, delete the attribute 
557          */
558
559         mmrp_reclaim();
560         mvrp_reclaim();
561         msrp_reclaim();
562
563         gctimer_start();
564
565         return 0;
566
567 }
568
569 void process_events(void)
570 {
571
572         fd_set fds, sel_fds;
573         int rc;
574         int max_fd;
575
576         /* wait for events, demux the received packets, process packets */
577
578         FD_ZERO(&fds);
579         FD_SET(control_socket, &fds);
580
581         max_fd = control_socket;
582
583         if (mmrp_enable) {
584                 FD_SET(mmrp_socket, &fds);
585                 if (mmrp_socket > max_fd)
586                         max_fd = mmrp_socket;
587
588                 if (NULL == MMRP_db)
589                         return;
590
591                 rc = mrp_register_timers(&(MMRP_db->mrp_db), &fds);
592                 if (rc > max_fd)
593                         max_fd = rc;
594         }
595         if (mvrp_enable) {
596                 FD_SET(mvrp_socket, &fds);
597                 if (mvrp_socket > max_fd)
598                         max_fd = mvrp_socket;
599
600                 if (NULL == MVRP_db)
601                         return;
602                 rc = mrp_register_timers(&(MVRP_db->mrp_db), &fds);
603                 if (rc > max_fd)
604                         max_fd = rc;
605
606         }
607         if (msrp_enable) {
608                 FD_SET(msrp_socket, &fds);
609                 if (msrp_socket > max_fd)
610                         max_fd = msrp_socket;
611
612                 if (NULL == MSRP_db)
613                         return;
614                 rc = mrp_register_timers(&(MSRP_db->mrp_db), &fds);
615                 if (rc > max_fd)
616                         max_fd = rc;
617
618         }
619
620         FD_SET(periodic_timer, &fds);
621         if (periodic_timer > max_fd)
622                 max_fd = periodic_timer;
623
624         FD_SET(gc_timer, &fds);
625         if (gc_timer > max_fd)
626                 max_fd = gc_timer;
627
628         do {
629
630                 sel_fds = fds;
631                 rc = select(max_fd + 1, &sel_fds, NULL, NULL, NULL);
632
633                 if (-1 == rc)
634                         return; /* exit on error */
635                 else {
636                         if (FD_ISSET(control_socket, &sel_fds))
637                                 recv_ctl_msg();
638                         if (mmrp_enable) {
639                                 if FD_ISSET
640                                         (mmrp_socket, &sel_fds) mmrp_recv_msg();
641                                 if FD_ISSET
642                                         (MMRP_db->mrp_db.lva_timer, &sel_fds) {
643                                         mmrp_event(MRP_EVENT_LVATIMER, NULL);
644                                         }
645                                 if FD_ISSET
646                                         (MMRP_db->mrp_db.lv_timer, &sel_fds) {
647                                         mmrp_event(MRP_EVENT_LVTIMER, NULL);
648                                         }
649                                 if FD_ISSET
650                                         (MMRP_db->mrp_db.join_timer, &sel_fds) {
651                                         mmrp_event(MRP_EVENT_TX, NULL);
652                                         }
653                         }
654                         if (mvrp_enable) {
655                                 if FD_ISSET
656                                         (mvrp_socket, &sel_fds) mvrp_recv_msg();
657                                 if FD_ISSET
658                                         (MVRP_db->mrp_db.lva_timer, &sel_fds) {
659                                         mvrp_event(MRP_EVENT_LVATIMER, NULL);
660                                         }
661                                 if FD_ISSET
662                                         (MVRP_db->mrp_db.lv_timer, &sel_fds) {
663                                         mvrp_event(MRP_EVENT_LVTIMER, NULL);
664                                         }
665                                 if FD_ISSET
666                                         (MVRP_db->mrp_db.join_timer, &sel_fds) {
667                                         mvrp_event(MRP_EVENT_TX, NULL);
668                                         }
669                         }
670                         if (msrp_enable) {
671                                 if FD_ISSET
672                                         (msrp_socket, &sel_fds) msrp_recv_msg();
673                                 if FD_ISSET
674                                         (MSRP_db->mrp_db.lva_timer, &sel_fds) {
675                                         msrp_event(MRP_EVENT_LVATIMER, NULL);
676                                         }
677                                 if FD_ISSET
678                                         (MSRP_db->mrp_db.lv_timer, &sel_fds) {
679                                         msrp_event(MRP_EVENT_LVTIMER, NULL);
680                                         }
681                                 if FD_ISSET
682                                         (MSRP_db->mrp_db.join_timer, &sel_fds) {
683                                         msrp_event(MRP_EVENT_TX, NULL);
684                                         }
685                         }
686                         if (FD_ISSET(periodic_timer, &sel_fds)) {
687                                 if (mmrp_enable) {
688                                         mmrp_event(MRP_EVENT_PERIODIC, NULL);
689                                 }
690                                 if (mvrp_enable) {
691                                         mvrp_event(MRP_EVENT_PERIODIC, NULL);
692                                 }
693                                 if (msrp_enable) {
694                                         msrp_event(MRP_EVENT_PERIODIC, NULL);
695                                 }
696                                 handle_periodic();
697                         }
698                         if (FD_ISSET(gc_timer, &sel_fds)) {
699                                 mrpd_reclaim();
700                         }
701                 }
702         } while (1);
703 }
704
705 void usage(void)
706 {
707         fprintf(stderr,
708                 "\n"
709                 "usage: mrpd [-hdlmvsp] -i interface-name"
710                 "\n"
711                 "options:\n"
712                 "    -h  show this message\n"
713                 "    -d  run daemon in the background\n"
714                 "    -l  enable logging (ignored in daemon mode)\n"
715                 "    -p  enable periodic timer\n"
716                 "    -m  enable MMRP Registrar and Participant\n"
717                 "    -v  enable MVRP Registrar and Participant\n"
718                 "    -s  enable MSRP Registrar and Participant\n"
719                 "    -i  specify interface to monitor\n"
720                 "\n" "%s" "\n", version_str);
721         exit(1);
722 }
723
724 int main(int argc, char *argv[])
725 {
726         int c;
727         int rc = 0;
728
729         daemonize = 0;
730         mmrp_enable = 0;
731         mvrp_enable = 0;
732         msrp_enable = 0;
733         logging_enable = 0;
734         mrpd_port = MRPD_PORT_DEFAULT;
735         interface = NULL;
736         interface_fd = -1;
737         periodic_enable = 0;
738         registration = MRP_REGISTRAR_CTL_NORMAL;        /* default */
739         participant = MRP_APPLICANT_CTL_NORMAL; /* default */
740         control_socket = INVALID_SOCKET;
741         mmrp_socket = INVALID_SOCKET;
742         mvrp_socket = INVALID_SOCKET;
743         msrp_socket = INVALID_SOCKET;
744         periodic_timer = -1;
745         gc_timer = -1;
746
747         for (;;) {
748                 c = getopt(argc, argv, "hdlmvspi:");
749
750                 if (c < 0)
751                         break;
752
753                 switch (c) {
754                 case 'm':
755                         mmrp_enable = 1;
756                         break;
757                 case 'v':
758                         mvrp_enable = 1;
759                         break;
760                 case 's':
761                         msrp_enable = 1;
762                         break;
763                 case 'l':
764                         logging_enable = 1;
765                         break;
766                 case 'd':
767                         daemonize = 1;
768                         break;
769                 case 'p':
770                         periodic_enable = 1;
771                         break;
772                 case 'i':
773                         if (interface) {
774                                 printf
775                                     ("only one interface per daemon is supported\n");
776                                 usage();
777                         }
778                         interface = strdup(optarg);
779                         break;
780                 case 'h':
781                 default:
782                         usage();
783                         break;
784                 }
785         }
786         if (optind < argc)
787                 usage();
788
789         if (NULL == interface)
790                 usage();
791
792         if (!mmrp_enable && !mvrp_enable && !msrp_enable)
793                 usage();
794
795         /* daemonize before we start creating file descriptors */
796
797         if (daemonize) {
798                 rc = daemon(1, 0);
799                 if (rc)
800                         goto out;
801         }
802         rc = mrp_init();
803         if (rc)
804                 goto out;
805
806         rc = init_local_ctl();
807         if (rc)
808                 goto out;
809
810         rc = mmrp_init(mmrp_enable);
811         if (rc)
812                 goto out;
813
814         rc = mvrp_init(mvrp_enable);
815         if (rc)
816                 goto out;
817
818         rc = msrp_init(msrp_enable);
819         if (rc)
820                 goto out;
821
822         rc = init_timers();
823         if (rc)
824                 goto out;
825
826         process_events();
827  out:
828         if (rc)
829                 printf("Error starting. Run as sudo?\n");
830
831         return rc;
832
833 }