1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include "defs.h"
28 #include "tables.h"
29
30 #include <sys/sysmacros.h>
31
32 #include <dhcpagent_ipc.h>
33 #include <dhcpagent_util.h>
34
35 static boolean_t verify_opt_len(struct nd_opt_hdr *opt, int optlen,
36 struct phyint *pi, struct sockaddr_in6 *from);
37
38 static void incoming_rs(struct phyint *pi, struct nd_router_solicit *rs,
39 int len, struct sockaddr_in6 *from);
40
41 void incoming_ra(struct phyint *pi, struct nd_router_advert *ra,
42 int len, struct sockaddr_in6 *from, boolean_t loopback);
43 static void incoming_prefix_opt(struct phyint *pi, uchar_t *opt,
44 struct sockaddr_in6 *from, boolean_t loopback);
45 static void incoming_prefix_onlink(struct phyint *pi, uchar_t *opt);
46 void incoming_prefix_onlink_process(struct prefix *pr,
47 uchar_t *opt);
48 static void incoming_prefix_stateful(struct phyint *, uchar_t *);
49 static boolean_t incoming_prefix_addrconf(struct phyint *pi,
50 uchar_t *opt, struct sockaddr_in6 *from,
51 boolean_t loopback);
52 boolean_t incoming_prefix_addrconf_process(struct phyint *pi,
53 struct prefix *pr, uchar_t *opt,
54 struct sockaddr_in6 *from, boolean_t loopback,
55 boolean_t new_prefix);
56 static void incoming_mtu_opt(struct phyint *pi, uchar_t *opt,
57 struct sockaddr_in6 *from);
58 static void incoming_lla_opt(struct phyint *pi, uchar_t *opt,
59 struct sockaddr_in6 *from, int isrouter);
60
61 static void verify_ra_consistency(struct phyint *pi,
62 struct nd_router_advert *ra,
63 int len, struct sockaddr_in6 *from);
64 static void verify_prefix_opt(struct phyint *pi, uchar_t *opt,
65 char *frombuf);
66 static void verify_mtu_opt(struct phyint *pi, uchar_t *opt,
67 char *frombuf);
68
69 static void update_ra_flag(const struct phyint *pi,
70 const struct sockaddr_in6 *from, int isrouter);
71
72 /*
73 * Return a pointer to the specified option buffer.
74 * If not found return NULL.
75 */
76 static void *
find_ancillary(struct msghdr * msg,int cmsg_type)77 find_ancillary(struct msghdr *msg, int cmsg_type)
78 {
79 struct cmsghdr *cmsg;
80
81 for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL;
82 cmsg = CMSG_NXTHDR(msg, cmsg)) {
83 if (cmsg->cmsg_level == IPPROTO_IPV6 &&
84 cmsg->cmsg_type == cmsg_type) {
85 return (CMSG_DATA(cmsg));
86 }
87 }
88 return (NULL);
89 }
90
91 void
in_data(struct phyint * pi)92 in_data(struct phyint *pi)
93 {
94 struct sockaddr_in6 from;
95 struct icmp6_hdr *icmp;
96 struct nd_router_solicit *rs;
97 struct nd_router_advert *ra;
98 static uint64_t in_packet[(IP_MAXPACKET + 1)/8];
99 static uint64_t ancillary_data[(IP_MAXPACKET + 1)/8];
100 int len;
101 char abuf[INET6_ADDRSTRLEN];
102 const char *msgbuf;
103 struct msghdr msg;
104 struct iovec iov;
105 uchar_t *opt;
106 uint_t hoplimit;
107
108 iov.iov_base = (char *)in_packet;
109 iov.iov_len = sizeof (in_packet);
110 msg.msg_iov = &iov;
111 msg.msg_iovlen = 1;
112 msg.msg_name = (struct sockaddr *)&from;
113 msg.msg_namelen = sizeof (from);
114 msg.msg_control = ancillary_data;
115 msg.msg_controllen = sizeof (ancillary_data);
116
117 if ((len = recvmsg(pi->pi_sock, &msg, 0)) < 0) {
118 logperror_pi(pi, "in_data: recvfrom");
119 return;
120 }
121 if (len == 0)
122 return;
123
124 if (inet_ntop(AF_INET6, (void *)&from.sin6_addr,
125 abuf, sizeof (abuf)) == NULL)
126 msgbuf = "Unspecified Router";
127 else
128 msgbuf = abuf;
129
130 /* Ignore packets > 64k or control buffers that don't fit */
131 if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) {
132 if (debug & D_PKTBAD) {
133 logmsg(LOG_DEBUG, "Truncated message: msg_flags 0x%x "
134 "from %s\n", msg.msg_flags, msgbuf);
135 }
136 return;
137 }
138
139 icmp = (struct icmp6_hdr *)in_packet;
140
141 if (len < ICMP6_MINLEN) {
142 logmsg(LOG_INFO, "Too short ICMP packet: %d bytes "
143 "from %s on %s\n",
144 len, msgbuf, pi->pi_name);
145 return;
146 }
147
148 opt = find_ancillary(&msg, IPV6_HOPLIMIT);
149 if (opt == NULL) {
150 /* Unknown hoplimit - must drop */
151 logmsg(LOG_INFO, "Unknown hop limit from %s on %s\n",
152 msgbuf, pi->pi_name);
153 return;
154 }
155 hoplimit = *(uint_t *)opt;
156 opt = find_ancillary(&msg, IPV6_RTHDR);
157 if (opt != NULL) {
158 /* Can't allow routing headers in ND messages */
159 logmsg(LOG_INFO, "ND message with routing header "
160 "from %s on %s\n",
161 msgbuf, pi->pi_name);
162 return;
163 }
164 switch (icmp->icmp6_type) {
165 case ND_ROUTER_SOLICIT:
166 if (!pi->pi_AdvSendAdvertisements)
167 return;
168 if (pi->pi_flags & IFF_NORTEXCH) {
169 if (debug & D_PKTIN) {
170 logmsg(LOG_DEBUG, "Ignore received RS packet "
171 "on %s (no route exchange on interface)\n",
172 pi->pi_name);
173 }
174 return;
175 }
176
177 /*
178 * Assumes that the kernel has verified the AH (if present)
179 * and the ICMP checksum.
180 */
181 if (hoplimit != IPV6_MAX_HOPS) {
182 logmsg(LOG_DEBUG, "RS hop limit: %d from %s on %s\n",
183 hoplimit, msgbuf, pi->pi_name);
184 return;
185 }
186
187 if (icmp->icmp6_code != 0) {
188 logmsg(LOG_INFO, "RS code: %d from %s on %s\n",
189 icmp->icmp6_code, msgbuf, pi->pi_name);
190 return;
191 }
192
193 if (len < sizeof (struct nd_router_solicit)) {
194 logmsg(LOG_INFO, "RS too short: %d bytes "
195 "from %s on %s\n",
196 len, msgbuf, pi->pi_name);
197 return;
198 }
199 rs = (struct nd_router_solicit *)icmp;
200 if (len > sizeof (struct nd_router_solicit)) {
201 if (!verify_opt_len((struct nd_opt_hdr *)&rs[1],
202 len - sizeof (struct nd_router_solicit), pi, &from))
203 return;
204 }
205 if (debug & D_PKTIN) {
206 print_route_sol("Received valid solicit from ", pi,
207 rs, len, &from);
208 }
209 incoming_rs(pi, rs, len, &from);
210 break;
211
212 case ND_ROUTER_ADVERT:
213 if (IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr)) {
214 /*
215 * Router advt. must have address!
216 * Logging the news and returning.
217 */
218 logmsg(LOG_DEBUG,
219 "Router's address unspecified in advertisement\n");
220 return;
221 }
222 if (pi->pi_flags & IFF_NORTEXCH) {
223 if (debug & D_PKTIN) {
224 logmsg(LOG_DEBUG, "Ignore received RA packet "
225 "on %s (no route exchange on interface)\n",
226 pi->pi_name);
227 }
228 return;
229 }
230
231 /*
232 * Assumes that the kernel has verified the AH (if present)
233 * and the ICMP checksum.
234 */
235 if (!IN6_IS_ADDR_LINKLOCAL(&from.sin6_addr)) {
236 logmsg(LOG_DEBUG, "RA from %s - not link local on %s\n",
237 msgbuf, pi->pi_name);
238 return;
239 }
240
241 if (hoplimit != IPV6_MAX_HOPS) {
242 logmsg(LOG_INFO, "RA hop limit: %d from %s on %s\n",
243 hoplimit, msgbuf, pi->pi_name);
244 return;
245 }
246
247 if (icmp->icmp6_code != 0) {
248 logmsg(LOG_INFO, "RA code: %d from %s on %s\n",
249 icmp->icmp6_code, msgbuf, pi->pi_name);
250 return;
251 }
252
253 if (len < sizeof (struct nd_router_advert)) {
254 logmsg(LOG_INFO, "RA too short: %d bytes "
255 "from %s on %s\n",
256 len, msgbuf, pi->pi_name);
257 return;
258 }
259 ra = (struct nd_router_advert *)icmp;
260 if (len > sizeof (struct nd_router_advert)) {
261 if (!verify_opt_len((struct nd_opt_hdr *)&ra[1],
262 len - sizeof (struct nd_router_advert), pi, &from))
263 return;
264 }
265 if (debug & D_PKTIN) {
266 print_route_adv("Received valid advert from ", pi,
267 ra, len, &from);
268 }
269 if (pi->pi_AdvSendAdvertisements)
270 verify_ra_consistency(pi, ra, len, &from);
271 else
272 incoming_ra(pi, ra, len, &from, _B_FALSE);
273 break;
274 }
275 }
276
277 /*
278 * Process a received router solicitation.
279 * Check for source link-layer address option and check if it
280 * is time to advertise.
281 */
282 static void
incoming_rs(struct phyint * pi,struct nd_router_solicit * rs,int len,struct sockaddr_in6 * from)283 incoming_rs(struct phyint *pi, struct nd_router_solicit *rs, int len,
284 struct sockaddr_in6 *from)
285 {
286 struct nd_opt_hdr *opt;
287 int optlen;
288
289 /* Process any options */
290 len -= sizeof (struct nd_router_solicit);
291 opt = (struct nd_opt_hdr *)&rs[1];
292 while (len >= sizeof (struct nd_opt_hdr)) {
293 optlen = opt->nd_opt_len * 8;
294 switch (opt->nd_opt_type) {
295 case ND_OPT_SOURCE_LINKADDR:
296 incoming_lla_opt(pi, (uchar_t *)opt,
297 from, NDF_ISROUTER_OFF);
298 break;
299 default:
300 break;
301 }
302 opt = (struct nd_opt_hdr *)((char *)opt + optlen);
303 len -= optlen;
304 }
305 /* Simple algorithm: treat unicast and multicast RSs the same */
306 check_to_advertise(pi, RECEIVED_SOLICIT);
307 }
308
309 /*
310 * Function that sends commands to dhcpagent daemon.
311 */
312 int
dhcp_op(struct phyint * pi,int type)313 dhcp_op(struct phyint *pi, int type)
314 {
315 dhcp_ipc_request_t *request;
316 dhcp_ipc_reply_t *reply = NULL;
317 int error;
318
319 request = dhcp_ipc_alloc_request(type | DHCP_V6, pi->pi_name, NULL, 0,
320 DHCP_TYPE_NONE);
321 if (request == NULL) {
322 logmsg(LOG_ERR, "dhcp_op: out of memory\n");
323 /* make sure we try again next time there's a chance */
324 if (type != DHCP_RELEASE) {
325 pi->pi_ra_flags &=
326 ~ND_RA_FLAG_MANAGED & ~ND_RA_FLAG_OTHER;
327 }
328 return (DHCP_IPC_E_MEMORY);
329 }
330
331 error = dhcp_ipc_make_request(request, &reply, 0);
332 free(request);
333 if (error != 0) {
334 logmsg(LOG_ERR, "could not send request to dhcpagent: "
335 "%s: %s\n", pi->pi_name, dhcp_ipc_strerror(error));
336 return (error);
337 }
338
339 error = reply->return_code;
340 free(reply);
341
342 return (error);
343 }
344
345 /*
346 * Start up DHCPv6 on a given physical interface. Does not wait for
347 * a message to be returned from the daemon.
348 */
349 void
start_dhcp(struct phyint * pi)350 start_dhcp(struct phyint *pi)
351 {
352 int error;
353 int type;
354
355 if (dhcp_start_agent(DHCP_IPC_MAX_WAIT) == -1) {
356 logmsg(LOG_ERR, "unable to start %s\n", DHCP_AGENT_PATH);
357 /* make sure we try again next time there's a chance */
358 pi->pi_ra_flags &= ~ND_RA_FLAG_MANAGED & ~ND_RA_FLAG_OTHER;
359 return;
360 }
361
362 else if (pi->pi_ra_flags & ND_RA_FLAG_MANAGED)
363 type = DHCP_START;
364 else
365 type = DHCP_INFORM;
366
367 error = dhcp_op(pi, type);
368 /*
369 * Timeout is considered to be "success" because we don't wait for DHCP
370 * to do its exchange.
371 */
372 if (error != DHCP_IPC_SUCCESS && error != DHCP_IPC_E_RUNNING &&
373 error != DHCP_IPC_E_TIMEOUT) {
374 logmsg(LOG_ERR, "Error in dhcpagent: %s: %s\n",
375 pi->pi_name, dhcp_ipc_strerror(error));
376 }
377 }
378
379 /*
380 * Release the acquired DHCPv6 lease on a given physical interface.
381 * Does not wait for a message to be returned from the daemon.
382 */
383 void
release_dhcp(struct phyint * pi)384 release_dhcp(struct phyint *pi)
385 {
386 int error;
387 int type;
388
389 type = DHCP_RELEASE;
390 retry:
391 error = dhcp_op(pi, type);
392 if (error != DHCP_IPC_SUCCESS && error != DHCP_IPC_E_RUNNING &&
393 error != DHCP_IPC_E_TIMEOUT) {
394 if (type == DHCP_RELEASE && error == DHCP_IPC_E_OUTSTATE) {
395 /*
396 * Drop the dhcp control if we cannot release it.
397 */
398 type = DHCP_DROP;
399 goto retry;
400 }
401 logmsg(LOG_ERR, "Error in dhcpagent: %s: %s\n",
402 pi->pi_name, dhcp_ipc_strerror(error));
403 }
404 }
405
406 /*
407 * Process a received router advertisement.
408 * Called both when packets arrive as well as when we send RAs.
409 * In the latter case 'loopback' is set.
410 */
411 void
incoming_ra(struct phyint * pi,struct nd_router_advert * ra,int len,struct sockaddr_in6 * from,boolean_t loopback)412 incoming_ra(struct phyint *pi, struct nd_router_advert *ra, int len,
413 struct sockaddr_in6 *from, boolean_t loopback)
414 {
415 struct nd_opt_hdr *opt;
416 int optlen;
417 struct lifreq lifr;
418 boolean_t set_needed = _B_FALSE;
419 struct router *dr;
420 uint16_t router_lifetime;
421 uint_t reachable, retrans;
422 boolean_t reachable_time_changed = _B_FALSE;
423 boolean_t slla_opt_present = _B_FALSE;
424
425 if (no_loopback && loopback)
426 return;
427
428 bzero(&lifr, sizeof (lifr));
429 (void) strlcpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name));
430
431 if (ra->nd_ra_curhoplimit != CURHOP_UNSPECIFIED &&
432 ra->nd_ra_curhoplimit != pi->pi_CurHopLimit) {
433 pi->pi_CurHopLimit = ra->nd_ra_curhoplimit;
434 lifr.lifr_ifinfo.lir_maxhops = pi->pi_CurHopLimit;
435 set_needed = _B_TRUE;
436 }
437
438 reachable = ntohl(ra->nd_ra_reachable);
439 if (reachable != 0 &&
440 reachable != pi->pi_BaseReachableTime) {
441 pi->pi_BaseReachableTime = reachable;
442 reachable_time_changed = _B_TRUE;
443 }
444
445 if (pi->pi_reach_time_since_random < MIN_REACH_RANDOM_INTERVAL ||
446 reachable_time_changed) {
447 phyint_reach_random(pi, _B_FALSE);
448 set_needed = _B_TRUE;
449 }
450 lifr.lifr_ifinfo.lir_reachtime = pi->pi_ReachableTime;
451
452 retrans = ntohl(ra->nd_ra_retransmit);
453 if (retrans != 0 &&
454 pi->pi_RetransTimer != retrans) {
455 pi->pi_RetransTimer = retrans;
456 lifr.lifr_ifinfo.lir_reachretrans = pi->pi_RetransTimer;
457 set_needed = _B_TRUE;
458 }
459
460 if (set_needed) {
461 if (ioctl(pi->pi_sock, SIOCSLIFLNKINFO, (char *)&lifr) < 0) {
462 logperror_pi(pi, "incoming_ra: SIOCSLIFLNKINFO");
463 return;
464 }
465 }
466
467 /*
468 * If the "managed" flag is set, then just assume that the "other" flag
469 * is set as well. It's not legal to get addresses alone without
470 * getting other data.
471 */
472 if (ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED)
473 ra->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER;
474
475 /*
476 * If either the "managed" or "other" bits have turned on, then it's
477 * now time to invoke DHCP. If only the "other" bit is set, then don't
478 * get addresses via DHCP; only "other" data. If "managed" is set,
479 * then we must always get both addresses and "other" data.
480 */
481 if (pi->pi_autoconf && pi->pi_stateful &&
482 (ra->nd_ra_flags_reserved & ~pi->pi_ra_flags &
483 (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER))) {
484 if (debug & D_DHCP) {
485 logmsg(LOG_DEBUG,
486 "incoming_ra: trigger dhcp %s on %s\n",
487 (ra->nd_ra_flags_reserved & ~pi->pi_ra_flags &
488 ND_RA_FLAG_MANAGED) ? "MANAGED" : "OTHER",
489 pi->pi_name);
490 }
491 pi->pi_ra_flags |= ra->nd_ra_flags_reserved;
492 start_dhcp(pi);
493 }
494
495 /* Skip default router code if sent from ourselves */
496 if (!loopback) {
497 /* Find and update or add default router in list */
498 dr = router_lookup(pi, from->sin6_addr);
499 router_lifetime = ntohs(ra->nd_ra_router_lifetime);
500 if (dr == NULL) {
501 if (router_lifetime != 0) {
502 dr = router_create(pi, from->sin6_addr,
503 MILLISEC * router_lifetime);
504 timer_schedule(dr->dr_lifetime);
505 }
506 } else {
507 dr->dr_lifetime = MILLISEC * router_lifetime;
508 if (dr->dr_lifetime != 0)
509 timer_schedule(dr->dr_lifetime);
510 if ((dr->dr_lifetime != 0 && !dr->dr_inkernel) ||
511 (dr->dr_lifetime == 0 && dr->dr_inkernel))
512 router_update_k(dr);
513 }
514 }
515 /* Process any options */
516 len -= sizeof (struct nd_router_advert);
517 opt = (struct nd_opt_hdr *)&ra[1];
518 while (len >= sizeof (struct nd_opt_hdr)) {
519 optlen = opt->nd_opt_len * 8;
520 switch (opt->nd_opt_type) {
521 case ND_OPT_PREFIX_INFORMATION:
522 incoming_prefix_opt(pi, (uchar_t *)opt, from,
523 loopback);
524 break;
525 case ND_OPT_MTU:
526 incoming_mtu_opt(pi, (uchar_t *)opt, from);
527 break;
528 case ND_OPT_SOURCE_LINKADDR:
529 /* skip lla option if sent from ourselves! */
530 if (!loopback) {
531 incoming_lla_opt(pi, (uchar_t *)opt,
532 from, NDF_ISROUTER_ON);
533 slla_opt_present = _B_TRUE;
534 }
535 break;
536 default:
537 break;
538 }
539 opt = (struct nd_opt_hdr *)((char *)opt + optlen);
540 len -= optlen;
541 }
542 if (!loopback && !slla_opt_present)
543 update_ra_flag(pi, from, NDF_ISROUTER_ON);
544 /* Stop sending solicitations */
545 check_to_solicit(pi, SOLICIT_DONE);
546 }
547
548 /*
549 * Process a received prefix option.
550 * Unless addrconf is turned off we process both the addrconf and the
551 * onlink aspects of the prefix option.
552 *
553 * Note that when a flag (onlink or auto) is turned off we do nothing -
554 * the prefix will time out.
555 */
556 static void
incoming_prefix_opt(struct phyint * pi,uchar_t * opt,struct sockaddr_in6 * from,boolean_t loopback)557 incoming_prefix_opt(struct phyint *pi, uchar_t *opt,
558 struct sockaddr_in6 *from, boolean_t loopback)
559 {
560 struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt;
561 boolean_t good_prefix = _B_TRUE;
562
563 if (8 * po->nd_opt_pi_len != sizeof (*po)) {
564 char abuf[INET6_ADDRSTRLEN];
565
566 (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
567 abuf, sizeof (abuf));
568 logmsg(LOG_INFO, "prefix option from %s on %s wrong size "
569 "(%d bytes)\n",
570 abuf, pi->pi_name,
571 8 * (int)po->nd_opt_pi_len);
572 return;
573 }
574 if (IN6_IS_ADDR_LINKLOCAL(&po->nd_opt_pi_prefix)) {
575 char abuf[INET6_ADDRSTRLEN];
576
577 (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
578 abuf, sizeof (abuf));
579 logmsg(LOG_INFO, "RA from %s on %s contains link-local prefix "
580 "- ignored\n",
581 abuf, pi->pi_name);
582 return;
583 }
584 if ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) &&
585 pi->pi_stateless && pi->pi_autoconf) {
586 good_prefix = incoming_prefix_addrconf(pi, opt, from, loopback);
587 }
588 if ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) &&
589 good_prefix) {
590 incoming_prefix_onlink(pi, opt);
591 }
592 if (pi->pi_stateful && pi->pi_autoconf)
593 incoming_prefix_stateful(pi, opt);
594 }
595
596 /*
597 * Process prefix options with the onlink flag set.
598 *
599 * If there are no routers ndpd will add an onlink
600 * default route which will allow communication
601 * between neighbors.
602 *
603 * This function needs to loop to find the same prefix multiple times
604 * as if a failover happened earlier, the addresses belonging to
605 * a different interface may be found here on this interface.
606 */
607 static void
incoming_prefix_onlink(struct phyint * pi,uchar_t * opt)608 incoming_prefix_onlink(struct phyint *pi, uchar_t *opt)
609 {
610 struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt;
611 int plen;
612 struct prefix *pr;
613 uint32_t validtime; /* Without 2 hour rule */
614 boolean_t found_one = _B_FALSE;
615
616 plen = po->nd_opt_pi_prefix_len;
617 for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) {
618 if (pr->pr_prefix_len == plen &&
619 prefix_equal(po->nd_opt_pi_prefix, pr->pr_prefix, plen)) {
620 /* Exclude static prefixes */
621 if (pr->pr_state & PR_STATIC)
622 continue;
623 found_one = _B_TRUE;
624 incoming_prefix_onlink_process(pr, opt);
625 }
626 }
627
628 validtime = ntohl(po->nd_opt_pi_valid_time);
629 /*
630 * If we have found a matching prefix already or validtime
631 * is zero, we have nothing to do.
632 */
633 if (validtime == 0 || found_one)
634 return;
635 pr = prefix_create(pi, po->nd_opt_pi_prefix, plen, 0);
636 if (pr == NULL)
637 return;
638 incoming_prefix_onlink_process(pr, opt);
639 }
640
641 void
incoming_prefix_onlink_process(struct prefix * pr,uchar_t * opt)642 incoming_prefix_onlink_process(struct prefix *pr, uchar_t *opt)
643 {
644 struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt;
645 uint32_t validtime; /* Without 2 hour rule */
646 char abuf[INET6_ADDRSTRLEN];
647
648 validtime = ntohl(po->nd_opt_pi_valid_time);
649 if (validtime != 0)
650 pr->pr_state |= PR_ONLINK;
651 else
652 pr->pr_state &= ~PR_ONLINK;
653
654 /*
655 * Convert from seconds to milliseconds avoiding overflow.
656 * If the lifetime in the packet is e.g. PREFIX_INFINITY - 1
657 * (4 billion seconds - about 130 years) we will in fact time
658 * out the prefix after 4 billion milliseconds - 46 days).
659 * Thus the longest lifetime (apart from infinity) is 46 days.
660 * Note that this ensures that PREFIX_INFINITY still means "forever".
661 */
662 if (pr->pr_flags & IFF_TEMPORARY) {
663 pr->pr_OnLinkLifetime = pr->pr_ValidLifetime;
664 } else {
665 if (validtime >= PREFIX_INFINITY / MILLISEC)
666 pr->pr_OnLinkLifetime = PREFIX_INFINITY - 1;
667 else
668 pr->pr_OnLinkLifetime = validtime * MILLISEC;
669 }
670 pr->pr_OnLinkFlag = _B_TRUE;
671 if (debug & (D_PREFIX|D_TMP)) {
672 logmsg(LOG_DEBUG, "incoming_prefix_onlink_process(%s, %s/%u) "
673 "onlink %u state 0x%x, kstate 0x%x\n",
674 pr->pr_name, inet_ntop(AF_INET6, (void *)&pr->pr_prefix,
675 abuf, sizeof (abuf)), pr->pr_prefix_len,
676 pr->pr_OnLinkLifetime, pr->pr_state, pr->pr_kernel_state);
677 }
678
679 if (pr->pr_kernel_state != pr->pr_state) {
680 prefix_update_k(pr);
681 }
682
683 if (pr->pr_OnLinkLifetime != 0)
684 timer_schedule(pr->pr_OnLinkLifetime);
685 }
686
687 /*
688 * Process all prefix options by locating the DHCPv6-configured interfaces, and
689 * applying the netmasks as needed.
690 */
691 static void
incoming_prefix_stateful(struct phyint * pi,uchar_t * opt)692 incoming_prefix_stateful(struct phyint *pi, uchar_t *opt)
693 {
694 struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt;
695 struct prefix *pr;
696 boolean_t foundpref;
697 char abuf[INET6_ADDRSTRLEN];
698
699 /* Make sure it's a valid prefix. */
700 if (ntohl(po->nd_opt_pi_valid_time) == 0) {
701 if (debug & D_DHCP)
702 logmsg(LOG_DEBUG, "incoming_prefix_stateful: ignoring "
703 "prefix with no valid time\n");
704 return;
705 }
706
707 if (debug & D_DHCP)
708 logmsg(LOG_DEBUG, "incoming_prefix_stateful(%s, %s/%d)\n",
709 pi->pi_name, inet_ntop(AF_INET6,
710 (void *)&po->nd_opt_pi_prefix, abuf, sizeof (abuf)),
711 po->nd_opt_pi_prefix_len);
712 foundpref = _B_FALSE;
713 for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) {
714 if (prefix_equal(po->nd_opt_pi_prefix, pr->pr_prefix,
715 po->nd_opt_pi_prefix_len)) {
716 if ((pr->pr_flags & IFF_DHCPRUNNING) &&
717 pr->pr_prefix_len != po->nd_opt_pi_prefix_len) {
718 pr->pr_prefix_len = po->nd_opt_pi_prefix_len;
719 if (pr->pr_flags & IFF_UP) {
720 if (debug & D_DHCP)
721 logmsg(LOG_DEBUG,
722 "incoming_prefix_stateful:"
723 " set mask on DHCP %s\n",
724 pr->pr_name);
725 prefix_update_dhcp(pr);
726 }
727 }
728 if (pr->pr_prefix_len == po->nd_opt_pi_prefix_len &&
729 (!(pr->pr_state & PR_STATIC) ||
730 (pr->pr_flags & IFF_DHCPRUNNING)))
731 foundpref = _B_TRUE;
732 }
733 }
734 /*
735 * If there's no matching DHCPv6 prefix present, then create an empty
736 * one so that we'll be able to configure it later.
737 */
738 if (!foundpref) {
739 pr = prefix_create(pi, po->nd_opt_pi_prefix,
740 po->nd_opt_pi_prefix_len, IFF_DHCPRUNNING);
741 if (pr != NULL) {
742 pr->pr_state = PR_STATIC;
743 if (debug & D_DHCP)
744 logmsg(LOG_DEBUG,
745 "incoming_prefix_stateful: created dummy "
746 "prefix for later\n");
747 }
748 }
749 }
750
751 /*
752 * Process prefix options with the autonomous flag set.
753 * Returns false if this prefix results in a bad address (duplicate)
754 * This function needs to loop to find the same prefix multiple times
755 * as if a failover happened earlier, the addresses belonging to
756 * a different interface may be found here on this interface.
757 */
758 static boolean_t
incoming_prefix_addrconf(struct phyint * pi,uchar_t * opt,struct sockaddr_in6 * from,boolean_t loopback)759 incoming_prefix_addrconf(struct phyint *pi, uchar_t *opt,
760 struct sockaddr_in6 *from, boolean_t loopback)
761 {
762 struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt;
763 int plen;
764 struct prefix *pr;
765 uint32_t validtime, preftime; /* In seconds */
766 char abuf[INET6_ADDRSTRLEN];
767 char pbuf[INET6_ADDRSTRLEN];
768 boolean_t found_pub = _B_FALSE;
769 boolean_t found_tmp = _B_FALSE;
770 boolean_t ret;
771
772 validtime = ntohl(po->nd_opt_pi_valid_time);
773 preftime = ntohl(po->nd_opt_pi_preferred_time);
774 plen = po->nd_opt_pi_prefix_len;
775
776 /* Sanity checks */
777 if (validtime < preftime) {
778 (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
779 abuf, sizeof (abuf));
780 (void) inet_ntop(AF_INET6,
781 (void *)&po->nd_opt_pi_prefix,
782 pbuf, sizeof (pbuf));
783 logmsg(LOG_WARNING, "prefix option %s/%u from %s on %s: "
784 "valid %u < pref %u ignored\n",
785 pbuf, plen, abuf, pi->pi_name,
786 validtime, preftime);
787 return (_B_FALSE);
788 }
789
790 for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) {
791 if (pr->pr_prefix_len == plen &&
792 prefix_equal(po->nd_opt_pi_prefix, pr->pr_prefix, plen)) {
793
794 /* Exclude static prefixes and DHCP */
795 if ((pr->pr_state & PR_STATIC) ||
796 (pr->pr_flags & IFF_DHCPRUNNING))
797 continue;
798 if (pr->pr_flags & IFF_TEMPORARY) {
799 /*
800 * If this address is deprecated and its token
801 * doesn't match the current tmp token, we want
802 * to create a new address with the current
803 * token. So don't count this addr as a match.
804 */
805 if (!((pr->pr_flags & IFF_DEPRECATED) &&
806 !token_equal(pi->pi_tmp_token,
807 pr->pr_address, TMP_TOKEN_BITS)))
808 found_tmp = _B_TRUE;
809 } else {
810 found_pub = _B_TRUE;
811 }
812 (void) incoming_prefix_addrconf_process(pi, pr, opt,
813 from, loopback, _B_FALSE);
814 }
815 }
816
817 /*
818 * If we have found a matching prefix (for public and, if temp addrs
819 * are enabled, for temporary) already or validtime is zero, we have
820 * nothing to do.
821 */
822 if (validtime == 0 ||
823 (found_pub && (!pi->pi_TmpAddrsEnabled || found_tmp)))
824 return (_B_TRUE);
825
826 if (!found_pub) {
827 pr = prefix_create(pi, po->nd_opt_pi_prefix, plen, 0);
828 if (pr == NULL)
829 return (_B_TRUE);
830 ret = incoming_prefix_addrconf_process(pi, pr, opt, from,
831 loopback, _B_TRUE);
832 }
833 /*
834 * if processing of the public address failed,
835 * don't bother with the temporary address.
836 */
837 if (ret == _B_FALSE)
838 return (_B_FALSE);
839
840 if (pi->pi_TmpAddrsEnabled && !found_tmp) {
841 pr = prefix_create(pi, po->nd_opt_pi_prefix, plen,
842 IFF_TEMPORARY);
843 if (pr == NULL)
844 return (_B_TRUE);
845 ret = incoming_prefix_addrconf_process(pi, pr, opt, from,
846 loopback, _B_TRUE);
847 }
848
849 return (ret);
850 }
851
852 boolean_t
incoming_prefix_addrconf_process(struct phyint * pi,struct prefix * pr,uchar_t * opt,struct sockaddr_in6 * from,boolean_t loopback,boolean_t new_prefix)853 incoming_prefix_addrconf_process(struct phyint *pi, struct prefix *pr,
854 uchar_t *opt, struct sockaddr_in6 *from, boolean_t loopback,
855 boolean_t new_prefix)
856 {
857 struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt;
858 char abuf[INET6_ADDRSTRLEN];
859 char pbuf[INET6_ADDRSTRLEN];
860 uint32_t validtime, preftime; /* In seconds */
861 uint32_t recorded_validtime; /* In seconds */
862 int plen;
863 struct prefix *other_pr;
864
865 validtime = ntohl(po->nd_opt_pi_valid_time);
866 preftime = ntohl(po->nd_opt_pi_preferred_time);
867 plen = po->nd_opt_pi_prefix_len;
868 if (!new_prefix) {
869 /*
870 * Check 2 hour rule on valid lifetime.
871 * Follows: RFC 2462
872 * If we advertised this prefix ourselves we skip
873 * these checks. They are also skipped if we did not
874 * previously do addrconf on this prefix.
875 */
876 recorded_validtime = pr->pr_ValidLifetime / MILLISEC;
877
878 if (loopback || !(pr->pr_state & PR_AUTO) ||
879 validtime >= MIN_VALID_LIFETIME ||
880 /* LINTED - statement has no consequent */
881 validtime >= recorded_validtime) {
882 /* OK */
883 } else if (recorded_validtime < MIN_VALID_LIFETIME &&
884 validtime < recorded_validtime) {
885 /* Ignore the prefix */
886 (void) inet_ntop(AF_INET6,
887 (void *)&from->sin6_addr,
888 abuf, sizeof (abuf));
889 (void) inet_ntop(AF_INET6,
890 (void *)&po->nd_opt_pi_prefix,
891 pbuf, sizeof (pbuf));
892 logmsg(LOG_INFO, "prefix option %s/%u from %s on %s: "
893 "too short valid lifetime %u stored %u "
894 "- ignored\n",
895 pbuf, plen, abuf, pi->pi_name,
896 validtime, recorded_validtime);
897 return (_B_TRUE);
898 } else {
899 /*
900 * If the router clock runs slower than the
901 * host by 1 second over 2 hours then this
902 * test will set the lifetime back to 2 hours
903 * once i.e. a lifetime decrementing in
904 * realtime might cause the prefix to live an
905 * extra 2 hours on the host.
906 */
907 (void) inet_ntop(AF_INET6,
908 (void *)&from->sin6_addr,
909 abuf, sizeof (abuf));
910 (void) inet_ntop(AF_INET6,
911 (void *)&po->nd_opt_pi_prefix,
912 pbuf, sizeof (pbuf));
913 logmsg(LOG_INFO, "prefix option %s/%u from %s on %s: "
914 "valid time %u stored %u rounded up "
915 "to %u\n",
916 pbuf, plen, abuf, pi->pi_name,
917 validtime, recorded_validtime,
918 MIN_VALID_LIFETIME);
919 validtime = MIN_VALID_LIFETIME;
920 }
921 }
922
923 /*
924 * For RFC3041 addresses, need to take token lifetime
925 * into account, too.
926 */
927 if (pr->pr_flags & IFF_TEMPORARY) {
928 uint_t cur_tpreftime =
929 pi->pi_TmpPreferredLifetime - pi->pi_TmpDesyncFactor;
930
931 if (new_prefix) {
932 validtime = MIN(validtime, pi->pi_TmpValidLifetime);
933 preftime = MIN(preftime, cur_tpreftime);
934 } else {
935 uint_t cur_vexp, cur_pexp, curtime;
936 curtime = getcurrenttime() / MILLISEC;
937
938 cur_vexp = pr->pr_CreateTime + pi->pi_TmpValidLifetime;
939 cur_pexp = pr->pr_CreateTime + cur_tpreftime;
940 if (curtime > cur_vexp)
941 validtime = 0;
942 else if ((curtime + validtime) > cur_vexp)
943 validtime = cur_vexp - curtime;
944 /*
945 * If this is an existing address which was deprecated
946 * because of a bad token, we don't want to update its
947 * preferred lifetime!
948 */
949 if ((pr->pr_PreferredLifetime == 0) &&
950 !token_equal(pr->pr_address, pi->pi_tmp_token,
951 TMP_TOKEN_BITS))
952 preftime = 0;
953 else if (curtime > cur_pexp)
954 preftime = 0;
955 else if ((curtime + preftime) > cur_pexp)
956 preftime = cur_pexp - curtime;
957 }
958 if ((preftime != 0) && (preftime <= pi->pi_TmpRegenAdvance)) {
959 (void) inet_ntop(AF_INET6,
960 (void *)&from->sin6_addr,
961 abuf, sizeof (abuf));
962 (void) inet_ntop(AF_INET6,
963 (void *)&po->nd_opt_pi_prefix,
964 pbuf, sizeof (pbuf));
965 logmsg(LOG_WARNING, "prefix opt %s/%u from %s on %s: "
966 "preferred lifetime(%d) <= TmpRegenAdvance(%d)\n",
967 pbuf, plen, abuf, pi->pi_name, preftime,
968 pi->pi_TmpRegenAdvance);
969 if (new_prefix) {
970 prefix_update_ipadm_addrobj(pr, _B_FALSE);
971 prefix_delete(pr);
972 }
973 return (_B_TRUE);
974 }
975 }
976 if (debug & D_TMP)
977 logmsg(LOG_DEBUG, "calculated lifetimes(%s, 0x%llx): v %d, "
978 "p %d\n", pr->pr_name, pr->pr_flags, validtime, preftime);
979
980 if (!(pr->pr_state & PR_AUTO)) {
981 int i, tokenlen;
982 in6_addr_t *token;
983 /*
984 * Form a new local address if the lengths match.
985 */
986 if (pr->pr_flags & IFF_TEMPORARY) {
987 if (IN6_IS_ADDR_UNSPECIFIED(&pi->pi_tmp_token)) {
988 if (!tmptoken_create(pi)) {
989 prefix_delete(pr);
990 return (_B_TRUE);
991 }
992 }
993 tokenlen = TMP_TOKEN_BITS;
994 token = &pi->pi_tmp_token;
995 } else {
996 tokenlen = pi->pi_token_length;
997 token = &pi->pi_token;
998 }
999 if (pr->pr_prefix_len + tokenlen != IPV6_ABITS) {
1000 (void) inet_ntop(AF_INET6,
1001 (void *)&from->sin6_addr,
1002 abuf, sizeof (abuf));
1003 (void) inet_ntop(AF_INET6,
1004 (void *)&po->nd_opt_pi_prefix,
1005 pbuf, sizeof (pbuf));
1006 logmsg(LOG_INFO, "prefix option %s/%u from %s on %s: "
1007 "mismatched length %d token length %d\n",
1008 pbuf, plen, abuf, pi->pi_name,
1009 pr->pr_prefix_len, tokenlen);
1010 return (_B_TRUE);
1011 }
1012 for (i = 0; i < 16; i++) {
1013 /*
1014 * prefix_create ensures that pr_prefix has all-zero
1015 * bits after prefixlen.
1016 */
1017 pr->pr_address.s6_addr[i] = pr->pr_prefix.s6_addr[i] |
1018 token->s6_addr[i];
1019 }
1020 /*
1021 * Check if any other physical interface has the same
1022 * address configured already
1023 */
1024 if ((other_pr = prefix_lookup_addr_match(pr)) != NULL) {
1025 /*
1026 * Delete this prefix structure as kernel
1027 * does not allow duplicated addresses
1028 */
1029 logmsg(LOG_ERR, "incoming_prefix_addrconf_process: "
1030 "Duplicate prefix %s received on interface %s\n",
1031 inet_ntop(AF_INET6, &po->nd_opt_pi_prefix, abuf,
1032 sizeof (abuf)), pi->pi_name);
1033 logmsg(LOG_ERR, "incoming_prefix_addrconf_process: "
1034 "Prefix already exists in interface %s\n",
1035 other_pr->pr_physical->pi_name);
1036 if (new_prefix) {
1037 prefix_update_ipadm_addrobj(pr, _B_FALSE);
1038 prefix_delete(pr);
1039 return (_B_FALSE);
1040 }
1041 /* Ignore for addrconf purposes */
1042 validtime = preftime = 0;
1043 }
1044 if ((pr->pr_flags & IFF_TEMPORARY) && new_prefix) {
1045 pr->pr_CreateTime = getcurrenttime() / MILLISEC;
1046 if (debug & D_TMP)
1047 logmsg(LOG_DEBUG,
1048 "created tmp addr(%s v %d p %d)\n",
1049 pr->pr_name, validtime, preftime);
1050 }
1051 }
1052
1053 if (validtime != 0)
1054 pr->pr_state |= PR_AUTO;
1055 else
1056 pr->pr_state &= ~(PR_AUTO|PR_DEPRECATED);
1057 if (preftime != 0 || !(pr->pr_state & PR_AUTO))
1058 pr->pr_state &= ~PR_DEPRECATED;
1059 else
1060 pr->pr_state |= PR_DEPRECATED;
1061
1062 /*
1063 * Convert from seconds to milliseconds avoiding overflow.
1064 * If the lifetime in the packet is e.g. PREFIX_INFINITY - 1
1065 * (4 billion seconds - about 130 years) we will in fact time
1066 * out the prefix after 4 billion milliseconds - 46 days).
1067 * Thus the longest lifetime (apart from infinity) is 46 days.
1068 * Note that this ensures that PREFIX_INFINITY still means "forever".
1069 */
1070 if (validtime >= PREFIX_INFINITY / MILLISEC)
1071 pr->pr_ValidLifetime = PREFIX_INFINITY - 1;
1072 else
1073 pr->pr_ValidLifetime = validtime * MILLISEC;
1074 if (preftime >= PREFIX_INFINITY / MILLISEC)
1075 pr->pr_PreferredLifetime = PREFIX_INFINITY - 1;
1076 else
1077 pr->pr_PreferredLifetime = preftime * MILLISEC;
1078 pr->pr_AutonomousFlag = _B_TRUE;
1079
1080 if (debug & D_PREFIX) {
1081 logmsg(LOG_DEBUG, "incoming_prefix_addrconf_process(%s, %s/%u) "
1082 "valid %u pref %u\n",
1083 pr->pr_physical->pi_name,
1084 inet_ntop(AF_INET6, (void *)&pr->pr_prefix,
1085 abuf, sizeof (abuf)), pr->pr_prefix_len,
1086 pr->pr_ValidLifetime, pr->pr_PreferredLifetime);
1087 }
1088
1089 if (pr->pr_state & PR_AUTO) {
1090 /* Take the min of the two timeouts by calling it twice */
1091 if (pr->pr_ValidLifetime != 0)
1092 timer_schedule(pr->pr_ValidLifetime);
1093 if (pr->pr_PreferredLifetime != 0)
1094 timer_schedule(pr->pr_PreferredLifetime);
1095 }
1096 if (pr->pr_kernel_state != pr->pr_state) {
1097 /* Log a message when an addrconf prefix goes away */
1098 if ((pr->pr_kernel_state & PR_AUTO) &&
1099 !(pr->pr_state & PR_AUTO)) {
1100 char abuf[INET6_ADDRSTRLEN];
1101
1102 logmsg(LOG_WARNING, "Address removed due to zero "
1103 "valid lifetime %s\n",
1104 inet_ntop(AF_INET6, (void *)&pr->pr_address,
1105 abuf, sizeof (abuf)));
1106 }
1107 prefix_update_k(pr);
1108 }
1109 return (_B_TRUE);
1110 }
1111
1112 /*
1113 * Process an MTU option received in a router advertisement.
1114 */
1115 static void
incoming_mtu_opt(struct phyint * pi,uchar_t * opt,struct sockaddr_in6 * from)1116 incoming_mtu_opt(struct phyint *pi, uchar_t *opt,
1117 struct sockaddr_in6 *from)
1118 {
1119 struct nd_opt_mtu *mo = (struct nd_opt_mtu *)opt;
1120 struct lifreq lifr;
1121 uint32_t mtu;
1122
1123 if (8 * mo->nd_opt_mtu_len != sizeof (*mo)) {
1124 char abuf[INET6_ADDRSTRLEN];
1125
1126 (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
1127 abuf, sizeof (abuf));
1128 logmsg(LOG_INFO, "mtu option from %s on %s wrong size "
1129 "(%d bytes)\n",
1130 abuf, pi->pi_name,
1131 8 * (int)mo->nd_opt_mtu_len);
1132 return;
1133 }
1134 mtu = ntohl(mo->nd_opt_mtu_mtu);
1135 if (pi->pi_LinkMTU == mtu)
1136 return; /* No change */
1137 if (mtu > pi->pi_mtu) {
1138 /* Can't exceed physical MTU */
1139 char abuf[INET6_ADDRSTRLEN];
1140
1141 (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
1142 abuf, sizeof (abuf));
1143 logmsg(LOG_INFO, "mtu option from %s on %s too large "
1144 "MTU %d - %d\n", abuf, pi->pi_name, mtu, pi->pi_mtu);
1145 return;
1146 }
1147 if (mtu < IPV6_MIN_MTU) {
1148 char abuf[INET6_ADDRSTRLEN];
1149
1150 (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
1151 abuf, sizeof (abuf));
1152 logmsg(LOG_INFO, "mtu option from %s on %s too small "
1153 "MTU (%d)\n", abuf, pi->pi_name, mtu);
1154 return;
1155 }
1156
1157 pi->pi_LinkMTU = mtu;
1158 bzero(&lifr, sizeof (lifr));
1159 (void) strlcpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name));
1160 lifr.lifr_ifinfo.lir_maxmtu = pi->pi_LinkMTU;
1161 if (ioctl(pi->pi_sock, SIOCSLIFLNKINFO, (char *)&lifr) < 0) {
1162 logperror_pi(pi, "incoming_mtu_opt: SIOCSLIFLNKINFO");
1163 return;
1164 }
1165 }
1166
1167 /*
1168 * Process a source link-layer address option received in a router
1169 * advertisement or solicitation.
1170 */
1171 static void
incoming_lla_opt(struct phyint * pi,uchar_t * opt,struct sockaddr_in6 * from,int isrouter)1172 incoming_lla_opt(struct phyint *pi, uchar_t *opt,
1173 struct sockaddr_in6 *from, int isrouter)
1174 {
1175 struct nd_opt_lla *lo = (struct nd_opt_lla *)opt;
1176 struct lifreq lifr;
1177 struct sockaddr_in6 *sin6;
1178 int max_content_len;
1179
1180 /*
1181 * Get our link-layer address length. We may not have one, in which
1182 * case we can just bail.
1183 */
1184 if (phyint_get_lla(pi, &lifr) != 0)
1185 return;
1186
1187 /*
1188 * Can't remove padding since it is link type specific.
1189 * However, we check against the length of our link-layer address.
1190 * Note: assumes that all links have a fixed length address.
1191 */
1192 max_content_len = lo->nd_opt_lla_len * 8 - sizeof (struct nd_opt_hdr);
1193 if (max_content_len < lifr.lifr_nd.lnr_hdw_len ||
1194 (max_content_len >= 8 &&
1195 max_content_len - 7 > lifr.lifr_nd.lnr_hdw_len)) {
1196 char abuf[INET6_ADDRSTRLEN];
1197
1198 (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
1199 abuf, sizeof (abuf));
1200 logmsg(LOG_INFO, "lla option from %s on %s too long with bad "
1201 "physaddr length (%d vs. %d bytes)\n", abuf, pi->pi_name,
1202 max_content_len, lifr.lifr_nd.lnr_hdw_len);
1203 return;
1204 }
1205
1206 bcopy(lo->nd_opt_lla_hdw_addr, lifr.lifr_nd.lnr_hdw_addr,
1207 lifr.lifr_nd.lnr_hdw_len);
1208
1209 sin6 = (struct sockaddr_in6 *)&lifr.lifr_nd.lnr_addr;
1210 bzero(sin6, sizeof (struct sockaddr_in6));
1211 sin6->sin6_family = AF_INET6;
1212 sin6->sin6_addr = from->sin6_addr;
1213
1214 /*
1215 * Set IsRouter flag if RA; clear if RS.
1216 */
1217 lifr.lifr_nd.lnr_state_create = ND_STALE;
1218 lifr.lifr_nd.lnr_state_same_lla = ND_UNCHANGED;
1219 lifr.lifr_nd.lnr_state_diff_lla = ND_STALE;
1220 lifr.lifr_nd.lnr_flags = isrouter;
1221 (void) strlcpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name));
1222 if (ioctl(pi->pi_sock, SIOCLIFSETND, (char *)&lifr) < 0) {
1223 logperror_pi(pi, "incoming_lla_opt: SIOCLIFSETND");
1224 return;
1225 }
1226 }
1227
1228 /*
1229 * Verify the content of the received router advertisement against our
1230 * own configuration as specified in RFC 2461.
1231 */
1232 static void
verify_ra_consistency(struct phyint * pi,struct nd_router_advert * ra,int len,struct sockaddr_in6 * from)1233 verify_ra_consistency(struct phyint *pi, struct nd_router_advert *ra, int len,
1234 struct sockaddr_in6 *from)
1235 {
1236 char frombuf[INET6_ADDRSTRLEN];
1237 struct nd_opt_hdr *opt;
1238 int optlen;
1239 uint_t reachable, retrans;
1240 boolean_t pktflag, myflag;
1241
1242 (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
1243 frombuf, sizeof (frombuf));
1244
1245 if (ra->nd_ra_curhoplimit != 0 &&
1246 pi->pi_AdvCurHopLimit != 0 &&
1247 ra->nd_ra_curhoplimit != pi->pi_AdvCurHopLimit) {
1248 logmsg(LOG_INFO, "RA from %s on %s inconsistent cur hop "
1249 "limit:\n\treceived %d configuration %d\n",
1250 frombuf, pi->pi_name,
1251 ra->nd_ra_curhoplimit, pi->pi_AdvCurHopLimit);
1252 }
1253
1254 reachable = ntohl(ra->nd_ra_reachable);
1255 if (reachable != 0 && pi->pi_AdvReachableTime != 0 &&
1256 reachable != pi->pi_AdvReachableTime) {
1257 logmsg(LOG_INFO, "RA from %s on %s inconsistent reachable "
1258 "time:\n\treceived %d configuration %d\n",
1259 frombuf, pi->pi_name,
1260 reachable, pi->pi_AdvReachableTime);
1261 }
1262
1263 retrans = ntohl(ra->nd_ra_retransmit);
1264 if (retrans != 0 && pi->pi_AdvRetransTimer != 0 &&
1265 retrans != pi->pi_AdvRetransTimer) {
1266 logmsg(LOG_INFO, "RA from %s on %s inconsistent retransmit "
1267 "timer:\n\treceived %d configuration %d\n",
1268 frombuf, pi->pi_name,
1269 retrans, pi->pi_AdvRetransTimer);
1270 }
1271
1272 pktflag = ((ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) != 0);
1273 myflag = (pi->pi_AdvManagedFlag != 0);
1274 if (pktflag != myflag) {
1275 logmsg(LOG_INFO, "RA from %s on %s inconsistent managed "
1276 "flag:\n\treceived %s configuration %s\n",
1277 frombuf, pi->pi_name,
1278 (pktflag ? "ON" : "OFF"),
1279 (myflag ? "ON" : "OFF"));
1280 }
1281 pktflag = ((ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) != 0);
1282 myflag = (pi->pi_AdvOtherConfigFlag != 0);
1283 if (pktflag != myflag) {
1284 logmsg(LOG_INFO, "RA from %s on %s inconsistent other config "
1285 "flag:\n\treceived %s configuration %s\n",
1286 frombuf, pi->pi_name,
1287 (pktflag ? "ON" : "OFF"),
1288 (myflag ? "ON" : "OFF"));
1289 }
1290
1291 /* Process any options */
1292 len -= sizeof (struct nd_router_advert);
1293 opt = (struct nd_opt_hdr *)&ra[1];
1294 while (len >= sizeof (struct nd_opt_hdr)) {
1295 optlen = opt->nd_opt_len * 8;
1296 switch (opt->nd_opt_type) {
1297 case ND_OPT_PREFIX_INFORMATION:
1298 verify_prefix_opt(pi, (uchar_t *)opt, frombuf);
1299 break;
1300 case ND_OPT_MTU:
1301 verify_mtu_opt(pi, (uchar_t *)opt, frombuf);
1302 break;
1303 default:
1304 break;
1305 }
1306 opt = (struct nd_opt_hdr *)((char *)opt + optlen);
1307 len -= optlen;
1308 }
1309 }
1310
1311 /*
1312 * Verify that the lifetimes and onlink/auto flags are consistent
1313 * with our settings.
1314 */
1315 static void
verify_prefix_opt(struct phyint * pi,uchar_t * opt,char * frombuf)1316 verify_prefix_opt(struct phyint *pi, uchar_t *opt, char *frombuf)
1317 {
1318 struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt;
1319 int plen;
1320 struct adv_prefix *adv_pr;
1321 uint32_t validtime, preftime;
1322 char prefixbuf[INET6_ADDRSTRLEN];
1323 int pktflag, myflag;
1324
1325 if (8 * po->nd_opt_pi_len != sizeof (*po)) {
1326 logmsg(LOG_INFO, "RA prefix option from %s on %s wrong size "
1327 "(%d bytes)\n",
1328 frombuf, pi->pi_name,
1329 8 * (int)po->nd_opt_pi_len);
1330 return;
1331 }
1332 if (IN6_IS_ADDR_LINKLOCAL(&po->nd_opt_pi_prefix)) {
1333 logmsg(LOG_INFO, "RA from %s on %s contains link-local "
1334 "prefix - ignored\n",
1335 frombuf, pi->pi_name);
1336 return;
1337 }
1338 plen = po->nd_opt_pi_prefix_len;
1339 adv_pr = adv_prefix_lookup(pi, po->nd_opt_pi_prefix, plen);
1340 if (adv_pr == NULL)
1341 return;
1342
1343 /* Ignore prefixes which we do not advertise */
1344 if (!adv_pr->adv_pr_AdvAutonomousFlag && !adv_pr->adv_pr_AdvOnLinkFlag)
1345 return;
1346 (void) inet_ntop(AF_INET6, (void *)&adv_pr->adv_pr_prefix,
1347 prefixbuf, sizeof (prefixbuf));
1348 pktflag = ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) != 0);
1349 myflag = (adv_pr->adv_pr_AdvAutonomousFlag != 0);
1350 if (pktflag != myflag) {
1351 logmsg(LOG_INFO,
1352 "RA from %s on %s inconsistent autonomous flag for \n\t"
1353 "prefix %s/%u: received %s configuration %s\n",
1354 frombuf, pi->pi_name, prefixbuf, adv_pr->adv_pr_prefix_len,
1355 (pktflag ? "ON" : "OFF"),
1356 (myflag ? "ON" : "OFF"));
1357 }
1358
1359 pktflag = ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) != 0);
1360 myflag = (adv_pr->adv_pr_AdvOnLinkFlag != 0);
1361 if (pktflag != myflag) {
1362 logmsg(LOG_INFO, "RA from %s on %s inconsistent on link flag "
1363 "for \n\tprefix %s/%u: received %s configuration %s\n",
1364 frombuf, pi->pi_name, prefixbuf, adv_pr->adv_pr_prefix_len,
1365 (pktflag ? "ON" : "OFF"),
1366 (myflag ? "ON" : "OFF"));
1367 }
1368 validtime = ntohl(po->nd_opt_pi_valid_time);
1369 preftime = ntohl(po->nd_opt_pi_preferred_time);
1370
1371 /*
1372 * Take into account variation for lifetimes decrementing
1373 * in real time. Allow +/- 10 percent and +/- 10 seconds.
1374 */
1375 #define LOWER_LIMIT(val) ((val) - (val)/10 - 10)
1376 #define UPPER_LIMIT(val) ((val) + (val)/10 + 10)
1377 if (adv_pr->adv_pr_AdvValidRealTime) {
1378 if (adv_pr->adv_pr_AdvValidExpiration > 0 &&
1379 (validtime <
1380 LOWER_LIMIT(adv_pr->adv_pr_AdvValidExpiration) ||
1381 validtime >
1382 UPPER_LIMIT(adv_pr->adv_pr_AdvValidExpiration))) {
1383 logmsg(LOG_INFO, "RA from %s on %s inconsistent valid "
1384 "lifetime for\n\tprefix %s/%u: received %d "
1385 "configuration %d\n",
1386 frombuf, pi->pi_name, prefixbuf,
1387 adv_pr->adv_pr_prefix_len,
1388 validtime, adv_pr->adv_pr_AdvValidExpiration);
1389 }
1390 } else {
1391 if (validtime != adv_pr->adv_pr_AdvValidLifetime) {
1392 logmsg(LOG_INFO, "RA from %s on %s inconsistent valid "
1393 "lifetime for\n\tprefix %s/%u: received %d "
1394 "configuration %d\n",
1395 frombuf, pi->pi_name, prefixbuf,
1396 adv_pr->adv_pr_prefix_len,
1397 validtime, adv_pr->adv_pr_AdvValidLifetime);
1398 }
1399 }
1400
1401 if (adv_pr->adv_pr_AdvPreferredRealTime) {
1402 if (adv_pr->adv_pr_AdvPreferredExpiration > 0 &&
1403 (preftime <
1404 LOWER_LIMIT(adv_pr->adv_pr_AdvPreferredExpiration) ||
1405 preftime >
1406 UPPER_LIMIT(adv_pr->adv_pr_AdvPreferredExpiration))) {
1407 logmsg(LOG_INFO, "RA from %s on %s inconsistent "
1408 "preferred lifetime for\n\tprefix %s/%u: "
1409 "received %d configuration %d\n",
1410 frombuf, pi->pi_name, prefixbuf,
1411 adv_pr->adv_pr_prefix_len,
1412 preftime, adv_pr->adv_pr_AdvPreferredExpiration);
1413 }
1414 } else {
1415 if (preftime != adv_pr->adv_pr_AdvPreferredLifetime) {
1416 logmsg(LOG_INFO, "RA from %s on %s inconsistent "
1417 "preferred lifetime for\n\tprefix %s/%u: "
1418 "received %d configuration %d\n",
1419 frombuf, pi->pi_name, prefixbuf,
1420 adv_pr->adv_pr_prefix_len,
1421 preftime, adv_pr->adv_pr_AdvPreferredLifetime);
1422 }
1423 }
1424 }
1425
1426 /*
1427 * Verify the received MTU against our own configuration.
1428 */
1429 static void
verify_mtu_opt(struct phyint * pi,uchar_t * opt,char * frombuf)1430 verify_mtu_opt(struct phyint *pi, uchar_t *opt, char *frombuf)
1431 {
1432 struct nd_opt_mtu *mo = (struct nd_opt_mtu *)opt;
1433 uint32_t mtu;
1434
1435 if (8 * mo->nd_opt_mtu_len != sizeof (*mo)) {
1436 logmsg(LOG_INFO, "mtu option from %s on %s wrong size "
1437 "(%d bytes)\n",
1438 frombuf, pi->pi_name,
1439 8 * (int)mo->nd_opt_mtu_len);
1440 return;
1441 }
1442 mtu = ntohl(mo->nd_opt_mtu_mtu);
1443 if (pi->pi_AdvLinkMTU != 0 &&
1444 pi->pi_AdvLinkMTU != mtu) {
1445 logmsg(LOG_INFO, "RA from %s on %s inconsistent MTU: "
1446 "received %d configuration %d\n",
1447 frombuf, pi->pi_name,
1448 mtu, pi->pi_AdvLinkMTU);
1449 }
1450 }
1451
1452 /*
1453 * Verify that all options have a non-zero length and that
1454 * the options fit within the total length of the packet (optlen).
1455 */
1456 static boolean_t
verify_opt_len(struct nd_opt_hdr * opt,int optlen,struct phyint * pi,struct sockaddr_in6 * from)1457 verify_opt_len(struct nd_opt_hdr *opt, int optlen,
1458 struct phyint *pi, struct sockaddr_in6 *from)
1459 {
1460 while (optlen > 0) {
1461 if (opt->nd_opt_len == 0) {
1462 char abuf[INET6_ADDRSTRLEN];
1463
1464 (void) inet_ntop(AF_INET6,
1465 (void *)&from->sin6_addr,
1466 abuf, sizeof (abuf));
1467
1468 logmsg(LOG_INFO, "Zero length option type 0x%x "
1469 "from %s on %s\n",
1470 opt->nd_opt_type, abuf, pi->pi_name);
1471 return (_B_FALSE);
1472 }
1473 optlen -= 8 * opt->nd_opt_len;
1474 if (optlen < 0) {
1475 char abuf[INET6_ADDRSTRLEN];
1476
1477 (void) inet_ntop(AF_INET6,
1478 (void *)&from->sin6_addr,
1479 abuf, sizeof (abuf));
1480
1481 logmsg(LOG_INFO, "Too large option: type 0x%x len %u "
1482 "from %s on %s\n",
1483 opt->nd_opt_type, opt->nd_opt_len,
1484 abuf, pi->pi_name);
1485 return (_B_FALSE);
1486 }
1487 opt = (struct nd_opt_hdr *)((char *)opt +
1488 8 * opt->nd_opt_len);
1489 }
1490 return (_B_TRUE);
1491 }
1492
1493 /*
1494 * Update IsRouter Flag for Host turning into a router or vice-versa.
1495 */
1496 static void
update_ra_flag(const struct phyint * pi,const struct sockaddr_in6 * from,int isrouter)1497 update_ra_flag(const struct phyint *pi, const struct sockaddr_in6 *from,
1498 int isrouter)
1499 {
1500 struct lifreq lifr;
1501 char abuf[INET6_ADDRSTRLEN];
1502 struct sockaddr_in6 *sin6;
1503
1504 /* check if valid flag is being set */
1505 if ((isrouter != NDF_ISROUTER_ON) &&
1506 (isrouter != NDF_ISROUTER_OFF)) {
1507 logmsg(LOG_ERR, "update_ra_flag: Invalid IsRouter "
1508 "flag %d\n", isrouter);
1509 return;
1510 }
1511
1512 sin6 = (struct sockaddr_in6 *)&lifr.lifr_nd.lnr_addr;
1513 bzero(sin6, sizeof (*sin6));
1514 sin6->sin6_family = AF_INET6;
1515 sin6->sin6_addr = from->sin6_addr;
1516
1517 (void) strlcpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name));
1518
1519 if (ioctl(pi->pi_sock, SIOCLIFGETND, (char *)&lifr) < 0) {
1520 if (errno == ESRCH) {
1521 if (debug & D_IFSCAN) {
1522 logmsg(LOG_DEBUG,
1523 "update_ra_flag: SIOCLIFGETND: nce doesn't exist, not setting IFF_ROUTER");
1524 }
1525 } else {
1526 logperror_pi(pi, "update_ra_flag: SIOCLIFGETND");
1527 }
1528 } else {
1529 /*
1530 * The lif_nd_req structure has three state values to be used
1531 * when changing/updating nces :
1532 * lnr_state_create, lnr_state_same_lla, and lnr_state_diff_lla.
1533 *
1534 * In this case, we're updating an nce, without changing lla;
1535 * so we set lnr_state_same_lla to ND_UNCHANGED, indicating that
1536 * nce's state should not be affected by our flag change.
1537 *
1538 * The kernel implementation also expects the lnr_state_create
1539 * field be always set, before processing ioctl request for NCE
1540 * update.
1541 * We use the state as STALE, while addressing the possibility
1542 * of NCE deletion when ioctl with SIOCLIFGETND argument
1543 * in earlier step is returned - further in such case we don't
1544 * want to re-create the entry in the reachable state.
1545 */
1546 lifr.lifr_nd.lnr_state_create = ND_STALE;
1547 lifr.lifr_nd.lnr_state_same_lla = ND_UNCHANGED;
1548 lifr.lifr_nd.lnr_flags = isrouter;
1549 if ((ioctl(pi->pi_sock, SIOCLIFSETND, (char *)&lifr)) < 0) {
1550 logperror_pi(pi, "update_ra_flag: SIOCLIFSETND");
1551 } else {
1552 (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
1553 abuf, sizeof (abuf));
1554 logmsg(LOG_INFO, "update_ra_flag: IsRouter flag "
1555 "updated for %s\n", abuf);
1556 }
1557 }
1558 }
1559