dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / lib / nwamd / routing_events.c
blob12be965f6a80200548117c193703d8252eb5b55d
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <arpa/inet.h>
27 #include <assert.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <net/if.h>
31 #include <net/route.h>
32 #include <pthread.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <strings.h>
37 #include <sys/fcntl.h>
38 #include <unistd.h>
40 #include <libnwam.h>
41 #include "events.h"
42 #include "ncp.h"
43 #include "ncu.h"
44 #include "util.h"
47 * routing_events.c - this file contains routines to retrieve routing socket
48 * events and package them for high level processing.
51 #define RTMBUFSZ sizeof (struct rt_msghdr) + \
52 (RTAX_MAX * sizeof (struct sockaddr_storage))
54 static void printaddrs(int, void *);
55 static char *printaddr(void **);
56 static void *getaddr(int, int, void *);
57 static void setaddr(int, int *, void *, struct sockaddr *);
59 union rtm_buf
61 /* Routing information. */
62 struct
64 struct rt_msghdr rtm;
65 struct sockaddr_storage addr[RTAX_MAX];
66 } r;
68 /* Interface information. */
69 struct
71 struct if_msghdr ifm;
72 struct sockaddr_storage addr[RTAX_MAX];
73 } im;
75 /* Interface address information. */
76 struct
78 struct ifa_msghdr ifa;
79 struct sockaddr_storage addr[RTAX_MAX];
80 } ia;
83 static int v4_sock = -1;
84 static int v6_sock = -1;
85 static pthread_t v4_routing, v6_routing;
86 static int seq = 0;
88 static const char *
89 rtmtype_str(int type)
91 static char typestr[12]; /* strlen("type ") + enough for an int */
93 switch (type) {
94 case RTM_NEWADDR:
95 return ("NEWADDR");
96 case RTM_DELADDR:
97 return ("DELADDR");
98 case RTM_CHGADDR:
99 return ("CHGADDR");
100 case RTM_FREEADDR:
101 return ("FREEADDR");
102 default:
103 (void) snprintf(typestr, sizeof (typestr), "type %d", type);
104 return (typestr);
108 /* ARGSUSED0 */
109 static void *
110 routing_events_v4(void *arg)
112 int n;
113 union rtm_buf buffer;
114 struct rt_msghdr *rtm;
115 struct ifa_msghdr *ifa;
116 char *addrs, *if_name;
117 struct sockaddr_dl *addr_dl;
118 struct sockaddr *addr, *netmask;
119 nwamd_event_t ip_event;
121 nlog(LOG_DEBUG, "v4 routing socket %d", v4_sock);
123 for (;;) {
124 rtm = &buffer.r.rtm;
125 n = read(v4_sock, &buffer, sizeof (buffer));
126 if (n == -1 && errno == EAGAIN) {
127 continue;
128 } else if (n == -1) {
129 nlog(LOG_ERR, "error reading routing socket "
130 "%d: %m", v4_sock);
131 /* Low likelihood. What's recovery path? */
132 continue;
135 if (rtm->rtm_msglen < n) {
136 nlog(LOG_ERR, "only read %d bytes from "
137 "routing socket but message claims to be "
138 "of length %d", rtm->rtm_msglen);
139 continue;
142 if (rtm->rtm_version != RTM_VERSION) {
143 nlog(LOG_ERR, "tossing routing message of "
144 "version %d type %d", rtm->rtm_version,
145 rtm->rtm_type);
146 continue;
149 if (rtm->rtm_msglen != n) {
150 nlog(LOG_DEBUG, "routing message of %d size came from "
151 "read of %d on socket %d", rtm->rtm_msglen,
152 n, v4_sock);
155 switch (rtm->rtm_type) {
156 case RTM_NEWADDR:
157 case RTM_DELADDR:
158 case RTM_CHGADDR:
159 case RTM_FREEADDR:
161 ifa = (void *)rtm;
162 addrs = (char *)ifa + sizeof (*ifa);
164 nlog(LOG_DEBUG, "v4 routing message %s: "
165 "index %d flags %x", rtmtype_str(rtm->rtm_type),
166 ifa->ifam_index, ifa->ifam_flags);
168 if ((addr = (struct sockaddr *)getaddr(RTA_IFA,
169 ifa->ifam_addrs, addrs)) == NULL)
170 break;
172 /* Ignore routing socket messages for 0.0.0.0 */
173 /*LINTED*/
174 if (((struct sockaddr_in *)addr)->sin_addr.s_addr
175 == INADDR_ANY) {
176 nlog(LOG_DEBUG, "routing_events_v4: "
177 "tossing message for 0.0.0.0");
178 break;
181 if ((netmask = (struct sockaddr *)getaddr(RTA_NETMASK,
182 ifa->ifam_addrs, addrs)) == NULL)
183 break;
185 if ((addr_dl = (struct sockaddr_dl *)getaddr
186 (RTA_IFP, ifa->ifam_addrs, addrs)) == NULL)
187 break;
189 * We don't use the lladdr in this structure so we can
190 * run over it.
192 addr_dl->sdl_data[addr_dl->sdl_nlen] = 0;
193 if_name = addr_dl->sdl_data; /* no lifnum */
195 if (ifa->ifam_index == 0) {
196 nlog(LOG_DEBUG, "tossing index 0 message");
197 break;
199 if (ifa->ifam_type != rtm->rtm_type) {
200 nlog(LOG_INFO,
201 "routing_events_v4: unhandled type %d",
202 ifa->ifam_type);
203 break;
206 printaddrs(ifa->ifam_addrs, addrs);
208 /* Create and enqueue IF_STATE event */
209 ip_event = nwamd_event_init_if_state(if_name,
210 ifa->ifam_flags,
211 (rtm->rtm_type == RTM_NEWADDR ||
212 rtm->rtm_type == RTM_CHGADDR ? B_TRUE : B_FALSE),
213 addr, netmask);
214 if (ip_event != NULL)
215 nwamd_event_enqueue(ip_event);
216 break;
219 /* NOTREACHED */
220 return (NULL);
223 /* ARGSUSED0 */
224 static void *
225 routing_events_v6(void *arg)
227 int n;
228 union rtm_buf buffer;
229 struct rt_msghdr *rtm;
230 struct ifa_msghdr *ifa;
231 char *addrs, *if_name;
232 struct sockaddr_dl *addr_dl;
233 struct sockaddr *addr, *netmask;
234 nwamd_event_t ip_event;
236 nlog(LOG_DEBUG, "v6 routing socket %d", v6_sock);
238 for (;;) {
240 rtm = &buffer.r.rtm;
241 n = read(v6_sock, &buffer, sizeof (buffer));
242 if (n == -1 && errno == EAGAIN) {
243 continue;
244 } else if (n == -1) {
245 nlog(LOG_ERR, "error reading routing socket "
246 "%d: %m", v6_sock);
247 /* Low likelihood. What's recovery path? */
248 continue;
251 if (rtm->rtm_msglen < n) {
252 nlog(LOG_ERR, "only read %d bytes from "
253 "routing socket but message claims to be "
254 "of length %d", rtm->rtm_msglen);
255 continue;
258 if (rtm->rtm_version != RTM_VERSION) {
259 nlog(LOG_ERR, "tossing routing message of "
260 "version %d type %d", rtm->rtm_version,
261 rtm->rtm_type);
262 continue;
265 if (rtm->rtm_msglen != n) {
266 nlog(LOG_DEBUG, "routing message of %d size came from "
267 "read of %d on socket %d", rtm->rtm_msglen,
268 n, v6_sock);
271 switch (rtm->rtm_type) {
272 case RTM_NEWADDR:
273 case RTM_DELADDR:
274 case RTM_CHGADDR:
275 case RTM_FREEADDR:
277 ifa = (void *)rtm;
278 addrs = (char *)ifa + sizeof (*ifa);
280 nlog(LOG_DEBUG, "v6 routing message %s: "
281 "index %d flags %x", rtmtype_str(rtm->rtm_type),
282 ifa->ifam_index, ifa->ifam_flags);
284 if ((addr = (struct sockaddr *)getaddr(RTA_IFA,
285 ifa->ifam_addrs, addrs)) == NULL)
286 break;
288 /* Ignore routing socket messages for :: & linklocal */
289 /*LINTED*/
290 if (IN6_IS_ADDR_UNSPECIFIED(
291 &((struct sockaddr_in6 *)addr)->sin6_addr)) {
292 nlog(LOG_INFO, "routing_events_v6: "
293 "tossing message for ::");
294 break;
296 /*LINTED*/
297 if (IN6_IS_ADDR_LINKLOCAL(
298 &((struct sockaddr_in6 *)addr)->sin6_addr)) {
299 nlog(LOG_INFO, "routing_events_v6: "
300 "tossing message for link local address");
301 break;
304 if ((netmask =
305 (struct sockaddr *)getaddr(RTA_NETMASK,
306 ifa->ifam_addrs, addrs)) == NULL)
307 break;
309 if ((addr_dl = (struct sockaddr_dl *)getaddr
310 (RTA_IFP, ifa->ifam_addrs, addrs)) == NULL)
311 break;
313 * We don't use the lladdr in this structure so we can
314 * run over it.
316 addr_dl->sdl_data[addr_dl->sdl_nlen] = 0;
317 if_name = addr_dl->sdl_data; /* no lifnum */
319 if (ifa->ifam_index == 0) {
320 nlog(LOG_DEBUG, "tossing index 0 message");
321 break;
323 if (ifa->ifam_type != rtm->rtm_type) {
324 nlog(LOG_DEBUG,
325 "routing_events_v6: unhandled type %d",
326 ifa->ifam_type);
327 break;
330 printaddrs(ifa->ifam_addrs, addrs);
332 /* Create and enqueue IF_STATE event */
333 ip_event = nwamd_event_init_if_state(if_name,
334 ifa->ifam_flags,
335 (rtm->rtm_type == RTM_NEWADDR ||
336 rtm->rtm_type == RTM_CHGADDR ? B_TRUE : B_FALSE),
337 addr, netmask);
338 if (ip_event != NULL)
339 nwamd_event_enqueue(ip_event);
340 break;
344 /* NOTREACHED */
345 return (NULL);
348 void
349 nwamd_routing_events_init(void)
351 pthread_attr_t attr;
354 * Initialize routing sockets here so that we know the routing threads
355 * (and any requests to add a route) will be working with a valid socket
356 * by the time we start handling events.
358 v4_sock = socket(AF_ROUTE, SOCK_RAW, AF_INET);
359 if (v4_sock == -1)
360 pfail("failed to open v4 routing socket: %m");
362 v6_sock = socket(AF_ROUTE, SOCK_RAW, AF_INET6);
363 if (v6_sock == -1)
364 pfail("failed to open v6 routing socket: %m");
366 (void) pthread_attr_init(&attr);
367 (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
368 if (pthread_create(&v4_routing, &attr, routing_events_v4, NULL) != 0 ||
369 pthread_create(&v6_routing, &attr, routing_events_v6, NULL) != 0)
370 pfail("routing thread creation failed");
371 (void) pthread_attr_destroy(&attr);
374 void
375 nwamd_routing_events_fini(void)
377 (void) pthread_cancel(v4_routing);
378 (void) pthread_cancel(v6_routing);
381 void
382 nwamd_add_route(struct sockaddr *dest, struct sockaddr *mask,
383 struct sockaddr *gateway, const char *ifname)
385 char rtbuf[RTMBUFSZ];
386 /* LINTED E_BAD_PTR_CAST_ALIGN */
387 struct rt_msghdr *rtm = (struct rt_msghdr *)rtbuf;
388 void *addrs = rtbuf + sizeof (struct rt_msghdr);
389 struct sockaddr_dl sdl;
390 int rlen, index;
391 int af;
393 af = gateway->sa_family;
395 /* retrieve the index value for the interface */
396 if ((index = if_nametoindex(ifname)) == 0) {
397 nlog(LOG_ERR, "nwamd_add_route: if_nametoindex failed on %s",
398 ifname);
399 return;
402 (void) bzero(&sdl, sizeof (struct sockaddr_dl));
403 sdl.sdl_family = AF_LINK;
404 sdl.sdl_index = index;
406 (void) bzero(rtm, RTMBUFSZ);
407 rtm->rtm_pid = getpid();
408 rtm->rtm_type = RTM_ADD;
409 rtm->rtm_flags = RTF_UP | RTF_STATIC | RTF_GATEWAY;
410 rtm->rtm_version = RTM_VERSION;
411 rtm->rtm_seq = ++seq;
412 rtm->rtm_msglen = sizeof (rtbuf);
413 setaddr(RTA_DST, &rtm->rtm_addrs, &addrs, dest);
414 setaddr(RTA_GATEWAY, &rtm->rtm_addrs, &addrs, gateway);
415 setaddr(RTA_NETMASK, &rtm->rtm_addrs, &addrs, mask);
416 setaddr(RTA_IFP, &rtm->rtm_addrs, &addrs, (struct sockaddr *)&sdl);
418 if ((rlen = write(af == AF_INET ? v4_sock : v6_sock,
419 rtbuf, rtm->rtm_msglen)) < 0) {
420 nlog(LOG_ERR, "nwamd_add_route: "
421 "got error %s writing to routing socket", strerror(errno));
422 } else if (rlen < rtm->rtm_msglen) {
423 nlog(LOG_ERR, "nwamd_add_route: "
424 "only wrote %d bytes of %d to routing socket\n",
425 rlen, rtm->rtm_msglen);
429 static char *
430 printaddr(void **address)
432 static char buffer[80];
433 sa_family_t family = *(sa_family_t *)*address;
434 struct sockaddr_in *s4 = *address;
435 struct sockaddr_in6 *s6 = *address;
436 struct sockaddr_dl *dl = *address;
438 switch (family) {
439 case AF_UNSPEC:
440 (void) inet_ntop(AF_UNSPEC, &s4->sin_addr, buffer,
441 sizeof (buffer));
442 *address = (char *)*address + sizeof (*s4);
443 break;
444 case AF_INET:
445 (void) inet_ntop(AF_INET, &s4->sin_addr, buffer,
446 sizeof (buffer));
447 *address = (char *)*address + sizeof (*s4);
448 break;
449 case AF_INET6:
450 (void) inet_ntop(AF_INET6, &s6->sin6_addr, buffer,
451 sizeof (buffer));
452 *address = (char *)*address + sizeof (*s6);
453 break;
454 case AF_LINK:
455 (void) snprintf(buffer, sizeof (buffer), "link %.*s",
456 dl->sdl_nlen, dl->sdl_data);
457 *address = (char *)*address + sizeof (*dl);
458 break;
459 default:
461 * We can't reliably update the size of this thing
462 * because we don't know what its type is. So bump
463 * it by a sockaddr_in and see what happens. The
464 * caller should really make sure this never happens.
466 *address = (char *)*address + sizeof (*s4);
467 (void) snprintf(buffer, sizeof (buffer),
468 "unknown address family %d", family);
469 break;
471 return (buffer);
474 static void
475 printaddrs(int mask, void *address)
477 if (mask == 0)
478 return;
479 if (mask & RTA_DST)
480 nlog(LOG_DEBUG, "destination address: %s", printaddr(&address));
481 if (mask & RTA_GATEWAY)
482 nlog(LOG_DEBUG, "gateway address: %s", printaddr(&address));
483 if (mask & RTA_NETMASK)
484 nlog(LOG_DEBUG, "netmask: %s", printaddr(&address));
485 if (mask & RTA_GENMASK)
486 nlog(LOG_DEBUG, "cloning mask: %s", printaddr(&address));
487 if (mask & RTA_IFP)
488 nlog(LOG_DEBUG, "interface name: %s", printaddr(&address));
489 if (mask & RTA_IFA)
490 nlog(LOG_DEBUG, "interface address: %s", printaddr(&address));
491 if (mask & RTA_AUTHOR)
492 nlog(LOG_DEBUG, "author: %s", printaddr(&address));
493 if (mask & RTA_BRD)
494 nlog(LOG_DEBUG, "broadcast address: %s", printaddr(&address));
497 static void
498 nextaddr(void **address)
500 sa_family_t family = *(sa_family_t *)*address;
502 switch (family) {
503 case AF_UNSPEC:
504 case AF_INET:
505 *address = (char *)*address + sizeof (struct sockaddr_in);
506 break;
507 case AF_INET6:
508 *address = (char *)*address + sizeof (struct sockaddr_in6);
509 break;
510 case AF_LINK:
511 *address = (char *)*address + sizeof (struct sockaddr_dl);
512 break;
513 default:
514 nlog(LOG_ERR, "unknown af (%d) while parsing rtm", family);
515 break;
519 static void *
520 getaddr(int addrid, int mask, void *addresses)
522 int i;
523 void *p = addresses;
525 if ((mask & addrid) == 0)
526 return (NULL);
528 for (i = 1; i < addrid; i <<= 1) {
529 if (i & mask)
530 nextaddr(&p);
532 return (p);
535 static void
536 setaddr(int addrid, int *maskp, void *addressesp, struct sockaddr *address)
538 struct sockaddr *p = *((struct sockaddr **)addressesp);
540 *maskp |= addrid;
542 switch (address->sa_family) {
543 case AF_INET:
544 (void) memcpy(p, address, sizeof (struct sockaddr_in));
545 break;
546 case AF_INET6:
547 (void) memcpy(p, address, sizeof (struct sockaddr_in6));
548 break;
549 case AF_LINK:
550 (void) memcpy(p, address, sizeof (struct sockaddr_dl));
551 break;
552 default:
553 nlog(LOG_ERR, "setaddr: unknown af (%d) while setting addr",
554 address->sa_family);
555 break;
557 nextaddr(addressesp);