1 /****************************************************************************
2 Copyright (c) 2012, Intel Corporation
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
8 1. Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
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.
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.
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.
31 ******************************************************************************/
33 * an MRP (MMRP, MVRP, MSRP) endpoint implementation of 802.1Q-2011
44 #include <sys/ioctl.h>
46 #include <sys/resource.h>
48 #include <sys/timerfd.h>
50 #include <sys/socket.h>
52 #include <netpacket/packet.h>
53 #include <netinet/in.h>
54 #include <arpa/inet.h>
55 #include <net/ethernet.h>
64 /* global mgmt parameters */
75 /* state machine controls */
79 /* if registration is FIXED or FORBIDDEN
80 * updates from MRP are discarded, and
81 * only IN and JOININ messages are sent
86 /* if participant role is 'SILENT' (or non-participant)
87 * applicant doesn't send any messages - configured per-attribute
90 #define VERSION_STR "0.0"
92 static const char *version_str =
93 "mrpd v" VERSION_STR "\n" "Copyright (c) 2012, Intel Corporation\n";
95 unsigned char STATION_ADDR[] = { 0x00, 0x88, 0x77, 0x66, 0x55, 0x44 };
97 /* global variables */
98 SOCKET control_socket;
99 extern SOCKET mmrp_socket;
100 extern SOCKET mvrp_socket;
101 extern SOCKET msrp_socket;
106 extern struct mmrp_database *MMRP_db;
107 extern struct mvrp_database *MVRP_db;
108 extern struct msrp_database *MSRP_db;
110 int mrpd_timer_create(void)
112 int t = timerfd_create(CLOCK_MONOTONIC, 0);
114 fcntl(t, F_SETFL, O_NONBLOCK);
118 void mrpd_timer_close(int t)
124 int mrpd_timer_start_interval(int timerfd,
125 unsigned long value_ms, unsigned long interval_ms)
128 struct itimerspec itimerspec_new;
129 struct itimerspec itimerspec_old;
130 unsigned long ns_per_ms = 1000000;
132 memset(&itimerspec_new, 0, sizeof(itimerspec_new));
133 memset(&itimerspec_old, 0, sizeof(itimerspec_old));
136 itimerspec_new.it_interval.tv_sec = interval_ms / 1000;
137 itimerspec_new.it_interval.tv_nsec =
138 (interval_ms % 1000) * ns_per_ms;
141 itimerspec_new.it_value.tv_sec = value_ms / 1000;
142 itimerspec_new.it_value.tv_nsec = (value_ms % 1000) * ns_per_ms;
144 rc = timerfd_settime(timerfd, 0, &itimerspec_new, &itimerspec_old);
149 int mrpd_timer_start(int timerfd, unsigned long value_ms)
151 return mrpd_timer_start_interval(timerfd, value_ms, 0);
154 int mrpd_timer_stop(int timerfd)
157 struct itimerspec itimerspec_new;
158 struct itimerspec itimerspec_old;
160 memset(&itimerspec_new, 0, sizeof(itimerspec_new));
161 memset(&itimerspec_old, 0, sizeof(itimerspec_old));
163 rc = timerfd_settime(timerfd, 0, &itimerspec_new, &itimerspec_old);
170 /* reclaim memory every 30 minutes */
171 return mrpd_timer_start(gc_timer, 30 * 60 * 1000);
174 int periodictimer_start()
176 /* periodictimer has expired. (10.7.5.23)
177 * PeriodicTransmission state machine generates periodic events
178 * period is one-per-sec
180 return mrpd_timer_start_interval(periodic_timer, 1000, 1000);
183 int periodictimer_stop()
185 /* periodictimer has expired. (10.7.5.23)
186 * PeriodicTransmission state machine generates periodic events
187 * period is one-per-sec
189 return mrpd_timer_stop(periodic_timer);
192 int init_local_ctl(void)
194 struct sockaddr_in addr;
199 sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
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);
209 rc = bind(sock_fd, (struct sockaddr *)&addr, addr_len);
214 control_socket = sock_fd;
225 mrpd_send_ctl_msg(struct sockaddr_in *client_addr, char *notify_data,
231 if (-1 == control_socket)
235 printf("CTL MSG:%s to CLNT %d\n", notify_data, client_addr->sin_port);
237 rc = sendto(control_socket, notify_data, notify_len,
238 0, (struct sockaddr *)client_addr, sizeof(struct sockaddr));
242 int process_ctl_msg(char *buf, int buflen, struct sockaddr_in *client)
247 * Inbound/output commands from/to a client:
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.
255 * BYE Client detaches from daemon
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
268 * ERC - error, unrecognized command
269 * ERP - error, unrecognized parameter
270 * ERI - error, internal
275 * M?? - query MMRP Registrar MAC Address database
276 * V?? - query MVRP Registrar VID database
277 * S?? - query MSRP Registrar database
279 * Registrar Responses (to ?? commands)
282 * MMT - Registered, Empty
283 * MLV - Registered, Leaving
284 * MNE - New attribute notification
285 * MJO - JOIN attribute notification
286 * MLV - LEAVE attribute notification
288 * VMT - Registered, Empty
289 * VLV - Registered, Leaving
291 * SMT - Registered, Empty
292 * SLV - Registered, Leaving
296 memset(respbuf, 0, sizeof(respbuf));
299 printf("CMD:%s from CLNT %d\n", buf, client->sin_port);
302 printf("buflen = %d!\b", buflen);
309 return mmrp_recv_cmd(buf, buflen, client);
312 return mvrp_recv_cmd(buf, buflen, client);
315 return msrp_recv_cmd(buf, buflen, client);
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));
336 struct sockaddr_in client_addr;
341 msgbuf = (char *)malloc(MAX_MRPD_CMDSZ);
345 memset(&msg, 0, sizeof(msg));
346 memset(&client_addr, 0, sizeof(client_addr));
347 memset(msgbuf, 0, MAX_MRPD_CMDSZ);
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);
356 bytes = recvmsg(control_socket, &msg, 0);
360 process_ctl_msg(msgbuf, bytes, &client_addr);
367 int mrpd_recvmsgbuf(int sock, char **buf)
369 struct sockaddr_ll client_addr;
374 *buf = (char *)malloc(MAX_FRAME_SIZE);
378 memset(&msg, 0, sizeof(msg));
379 memset(&client_addr, 0, sizeof(client_addr));
380 memset(*buf, 0, MAX_FRAME_SIZE);
382 iov.iov_len = MAX_FRAME_SIZE;
384 msg.msg_name = &client_addr;
385 msg.msg_namelen = sizeof(client_addr);
388 bytes = recvmsg(sock, &msg, 0);
393 mrpd_init_protocol_socket(u_int16_t etype, int *sock,
394 unsigned char *multicast_addr)
396 struct sockaddr_ll addr;
397 struct ifreq if_request;
400 struct packet_mreq multicast_req;
404 if (NULL == multicast_addr)
409 lsock = socket(PF_PACKET, SOCK_RAW, htons(etype));
413 memset(&if_request, 0, sizeof(if_request));
415 strncpy(if_request.ifr_name, interface, sizeof(if_request.ifr_name));
417 rc = ioctl(lsock, SIOCGIFHWADDR, &if_request);
423 memcpy(STATION_ADDR, if_request.ifr_hwaddr.sa_data,
424 sizeof(STATION_ADDR));
426 memset(&if_request, 0, sizeof(if_request));
428 strncpy(if_request.ifr_name, interface, sizeof(if_request.ifr_name));
430 rc = ioctl(lsock, SIOCGIFINDEX, &if_request);
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);
441 rc = bind(lsock, (struct sockaddr *)&addr, sizeof(addr));
447 rc = setsockopt(lsock, SOL_SOCKET, SO_BINDTODEVICE, interface,
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);
459 rc = setsockopt(lsock, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
460 &multicast_req, sizeof(multicast_req));
471 int mrpd_close_socket(SOCKET sock)
476 int mrpd_init_timers(struct mrp_database *mrp_db)
478 mrp_db->join_timer = mrpd_timer_create();
479 mrp_db->lv_timer = mrpd_timer_create();
480 mrp_db->lva_timer = mrpd_timer_create();
482 if (-1 == mrp_db->join_timer)
484 if (-1 == mrp_db->lv_timer)
486 if (-1 == mrp_db->lva_timer)
490 mrpd_timer_close(mrp_db->join_timer);
491 mrpd_timer_close(mrp_db->lv_timer);
492 mrpd_timer_close(mrp_db->lva_timer);
497 int handle_periodic(void)
500 periodictimer_start();
502 periodictimer_stop();
507 int init_timers(void)
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
515 periodic_timer = mrpd_timer_create();
516 gc_timer = mrpd_timer_create();
518 if (-1 == periodic_timer)
526 periodictimer_start();
533 int mrp_register_timers(struct mrp_database *mrp_db, fd_set * fds)
537 FD_SET(mrp_db->join_timer, fds);
538 FD_SET(mrp_db->lv_timer, fds);
539 FD_SET(mrp_db->lva_timer, fds);
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;
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
569 void process_events(void)
576 /* wait for events, demux the received packets, process packets */
579 FD_SET(control_socket, &fds);
581 max_fd = control_socket;
584 FD_SET(mmrp_socket, &fds);
585 if (mmrp_socket > max_fd)
586 max_fd = mmrp_socket;
591 rc = mrp_register_timers(&(MMRP_db->mrp_db), &fds);
596 FD_SET(mvrp_socket, &fds);
597 if (mvrp_socket > max_fd)
598 max_fd = mvrp_socket;
602 rc = mrp_register_timers(&(MVRP_db->mrp_db), &fds);
608 FD_SET(msrp_socket, &fds);
609 if (msrp_socket > max_fd)
610 max_fd = msrp_socket;
614 rc = mrp_register_timers(&(MSRP_db->mrp_db), &fds);
620 FD_SET(periodic_timer, &fds);
621 if (periodic_timer > max_fd)
622 max_fd = periodic_timer;
624 FD_SET(gc_timer, &fds);
625 if (gc_timer > max_fd)
631 rc = select(max_fd + 1, &sel_fds, NULL, NULL, NULL);
634 return; /* exit on error */
636 if (FD_ISSET(control_socket, &sel_fds))
640 (mmrp_socket, &sel_fds) mmrp_recv_msg();
642 (MMRP_db->mrp_db.lva_timer, &sel_fds) {
643 mmrp_event(MRP_EVENT_LVATIMER, NULL);
646 (MMRP_db->mrp_db.lv_timer, &sel_fds) {
647 mmrp_event(MRP_EVENT_LVTIMER, NULL);
650 (MMRP_db->mrp_db.join_timer, &sel_fds) {
651 mmrp_event(MRP_EVENT_TX, NULL);
656 (mvrp_socket, &sel_fds) mvrp_recv_msg();
658 (MVRP_db->mrp_db.lva_timer, &sel_fds) {
659 mvrp_event(MRP_EVENT_LVATIMER, NULL);
662 (MVRP_db->mrp_db.lv_timer, &sel_fds) {
663 mvrp_event(MRP_EVENT_LVTIMER, NULL);
666 (MVRP_db->mrp_db.join_timer, &sel_fds) {
667 mvrp_event(MRP_EVENT_TX, NULL);
672 (msrp_socket, &sel_fds) msrp_recv_msg();
674 (MSRP_db->mrp_db.lva_timer, &sel_fds) {
675 msrp_event(MRP_EVENT_LVATIMER, NULL);
678 (MSRP_db->mrp_db.lv_timer, &sel_fds) {
679 msrp_event(MRP_EVENT_LVTIMER, NULL);
682 (MSRP_db->mrp_db.join_timer, &sel_fds) {
683 msrp_event(MRP_EVENT_TX, NULL);
686 if (FD_ISSET(periodic_timer, &sel_fds)) {
688 mmrp_event(MRP_EVENT_PERIODIC, NULL);
691 mvrp_event(MRP_EVENT_PERIODIC, NULL);
694 msrp_event(MRP_EVENT_PERIODIC, NULL);
698 if (FD_ISSET(gc_timer, &sel_fds)) {
709 "usage: mrpd [-hdlmvsp] -i interface-name"
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);
724 int main(int argc, char *argv[])
734 mrpd_port = MRPD_PORT_DEFAULT;
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;
748 c = getopt(argc, argv, "hdlmvspi:");
775 ("only one interface per daemon is supported\n");
778 interface = strdup(optarg);
789 if (NULL == interface)
792 if (!mmrp_enable && !mvrp_enable && !msrp_enable)
795 /* daemonize before we start creating file descriptors */
806 rc = init_local_ctl();
810 rc = mmrp_init(mmrp_enable);
814 rc = mvrp_init(mvrp_enable);
818 rc = msrp_init(msrp_enable);
829 printf("Error starting. Run as sudo?\n");