1 /** $MirOS: src/sys/netinet/ip_carp.c,v 1.6 2007/05/29 10:23:08 tg Exp $ */
2 /* $OpenBSD: ip_carp.c,v 1.52 2004/05/16 02:06:10 mcbride Exp $ */
3
4 /*
5 * Copyright (c) 2002 Michael Shalayeff. All rights reserved.
6 * Copyright (c) 2003 Ryan McBride. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
21 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
26 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 * THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 /*
31 * TODO:
32 * - iface reconfigure
33 * - track iface ip address changes;
34 * - support for hardware checksum calculations;
35 *
36 */
37
38 #include "ether.h"
39
40 #include <sys/param.h>
41 #include <sys/proc.h>
42 #include <sys/systm.h>
43 #include <sys/mbuf.h>
44 #include <sys/socket.h>
45 #include <sys/ioctl.h>
46 #include <sys/errno.h>
47 #include <sys/device.h>
48 #include <sys/kernel.h>
49 #include <sys/sysctl.h>
50 #include <sys/syslog.h>
51
52 #include <machine/cpu.h>
53 #include <dev/rndvar.h>
54
55 #include <net/if.h>
56 #include <net/if_types.h>
57 #include <net/if_llc.h>
58 #include <net/route.h>
59 #include <net/netisr.h>
60
61 #if NFDDI > 0
62 #include <net/if_fddi.h>
63 #endif
64 #if NTOKEN > 0
65 #include <net/if_token.h>
66 #endif
67
68 #include <crypto/sha1.h>
69
70 #ifdef INET
71 #include <netinet/in.h>
72 #include <netinet/in_systm.h>
73 #include <netinet/in_var.h>
74 #include <netinet/ip.h>
75 #include <netinet/ip_var.h>
76 #include <netinet/if_ether.h>
77 #include <netinet/ip_ipsp.h>
78
79 #include <net/if_enc.h>
80 #endif
81
82 #ifdef INET6
83 #include <netinet/icmp6.h>
84 #include <netinet/ip6.h>
85 #include <netinet6/ip6_var.h>
86 #include <netinet6/nd6.h>
87 #include <net/if_dl.h>
88 #endif
89
90 #include "bpfilter.h"
91 #if NBPFILTER > 0
92 #include <net/bpf.h>
93 #endif
94
95 #include <netinet/ip_carp.h>
96
97 struct carp_softc {
98 struct arpcom sc_ac;
99 int if_flags; /* current flags to treat UP/DOWN */
100 struct ifnet *sc_ifp;
101 struct in_ifaddr *sc_ia; /* primary iface address */
102 struct ip_moptions sc_imo;
103 #ifdef INET6
104 struct in6_ifaddr *sc_ia6; /* primary iface address v6 */
105 struct ip6_moptions sc_im6o;
106 #endif /* INET6 */
107 TAILQ_ENTRY(carp_softc) sc_list;
108
109 enum { INIT = 0, BACKUP, MASTER } sc_state;
110
111 int sc_flags_backup;
112 int sc_suppress;
113
114 int sc_sendad_errors;
115 #define CARP_SENDAD_MAX_ERRORS 3
116 int sc_sendad_success;
117 #define CARP_SENDAD_MIN_SUCCESS 3
118
119 int sc_vhid;
120 int sc_advskew;
121 int sc_naddrs;
122 int sc_naddrs6;
123 int sc_advbase; /* seconds */
124 int sc_init_counter;
125 u_int64_t sc_counter;
126
127 /* authentication */
128 #define CARP_HMAC_PAD 64
129 unsigned char sc_key[CARP_KEY_LEN];
130 unsigned char sc_pad[CARP_HMAC_PAD];
131 SHA1_CTX sc_sha1;
132
133 struct timeout sc_ad_tmo; /* advertisement timeout */
134 struct timeout sc_md_tmo; /* master down timeout */
135 struct timeout sc_md6_tmo; /* master down timeout */
136
137 };
138
139 int carp_suppress_preempt = 0;
140 int carp_opts[CARPCTL_MAXID] = { 0, 1, 0, 0, 0 }; /* XXX for now */
141 struct carpstats carpstats;
142
143 struct carp_if {
144 TAILQ_HEAD(, carp_softc) vhif_vrs;
145 int vhif_nvrs;
146
147 struct ifnet *vhif_ifp;
148 };
149
150 #define CARP_LOG(s,a) if (carp_opts[CARPCTL_LOG]) \
151 log(LOG_INFO, "carp: " s "\n", (a));
152 #define CARP_LOG0(s) if (carp_opts[CARPCTL_LOG]) \
153 log(LOG_INFO, "carp: " s "\n");
154 #define CARP_LOG1(sc,s,a) if (carp_opts[CARPCTL_LOG]) \
155 log(LOG_INFO, "%s: " s "\n", (sc)->sc_ac.ac_if.if_xname, (a));
156
157 void carp_hmac_prepare(struct carp_softc *);
158 void carp_hmac_generate(struct carp_softc *, u_int32_t *,
159 unsigned char *);
160 int carp_hmac_verify(struct carp_softc *, u_int32_t *,
161 unsigned char *);
162 void carp_setroute(struct carp_softc *, int);
163 void carp_input_c(struct mbuf *, struct carp_header *, sa_family_t);
164 void carpattach(int);
165 void carpdetach(struct carp_softc *);
166 int carp_prepare_ad(struct mbuf *, struct carp_softc *,
167 struct carp_header *);
168 void carp_send_ad_all(void);
169 void carp_send_ad(void *);
170 void carp_send_arp(struct carp_softc *);
171 void carp_master_down(void *);
172 int carp_ioctl(struct ifnet *, u_long, caddr_t);
173 void carp_start(struct ifnet *);
174 void carp_setrun(struct carp_softc *, sa_family_t);
175 void carp_set_state(struct carp_softc *, int);
176 int carp_addrcount(struct carp_if *, struct in_ifaddr *, int);
177 enum { CARP_COUNT_MASTER, CARP_COUNT_RUNNING };
178
179 int carp_set_addr(struct carp_softc *, struct sockaddr_in *);
180 int carp_del_addr(struct carp_softc *, struct sockaddr_in *);
181 #ifdef INET6
182 void carp_send_na(struct carp_softc *);
183 int carp_set_addr6(struct carp_softc *, struct sockaddr_in6 *);
184 int carp_del_addr6(struct carp_softc *, struct sockaddr_in6 *);
185 #endif
186 int carp_clone_create(struct if_clone *, int);
187 int carp_clone_destroy(struct ifnet *);
188
189 struct if_clone carp_cloner =
190 IF_CLONE_INITIALIZER("carp", carp_clone_create, carp_clone_destroy);
191
192 static __inline u_int16_t
carp_cksum(struct mbuf * m,int len)193 carp_cksum(struct mbuf *m, int len)
194 {
195 return (in_cksum(m, len));
196 }
197
198 void
carp_hmac_prepare(struct carp_softc * sc)199 carp_hmac_prepare(struct carp_softc *sc)
200 {
201 u_int8_t version = CARP_VERSION, type = CARP_ADVERTISEMENT;
202 u_int8_t vhid = sc->sc_vhid & 0xff;
203 struct ifaddr *ifa;
204 int i;
205 #ifdef INET6
206 struct in6_addr in6;
207 #endif /* INET6 */
208
209 /* compute ipad from key */
210 bzero(sc->sc_pad, sizeof(sc->sc_pad));
211 bcopy(sc->sc_key, sc->sc_pad, sizeof(sc->sc_key));
212 for (i = 0; i < sizeof(sc->sc_pad); i++)
213 sc->sc_pad[i] ^= 0x36;
214
215 /* precompute first part of inner hash */
216 SHA1Init(&sc->sc_sha1);
217 SHA1Update(&sc->sc_sha1, sc->sc_pad, sizeof(sc->sc_pad));
218 SHA1Update(&sc->sc_sha1, (void *)&version, sizeof(version));
219 SHA1Update(&sc->sc_sha1, (void *)&type, sizeof(type));
220 SHA1Update(&sc->sc_sha1, (void *)&vhid, sizeof(vhid));
221 #ifdef INET
222 TAILQ_FOREACH(ifa, &sc->sc_ac.ac_if.if_addrlist, ifa_list) {
223 if (ifa->ifa_addr->sa_family == AF_INET)
224 SHA1Update(&sc->sc_sha1,
225 (void *)&ifatoia(ifa)->ia_addr.sin_addr.s_addr,
226 sizeof(struct in_addr));
227 }
228 #endif /* INET */
229 #ifdef INET6
230 TAILQ_FOREACH(ifa, &sc->sc_ac.ac_if.if_addrlist, ifa_list) {
231 if (ifa->ifa_addr->sa_family == AF_INET6) {
232 in6 = ifatoia6(ifa)->ia_addr.sin6_addr;
233 if (IN6_IS_ADDR_LINKLOCAL(&in6))
234 in6.s6_addr16[1] = 0;
235 SHA1Update(&sc->sc_sha1, (void *)&in6, sizeof(in6));
236 }
237 }
238 #endif /* INET6 */
239
240 /* convert ipad to opad */
241 for (i = 0; i < sizeof(sc->sc_pad); i++)
242 sc->sc_pad[i] ^= 0x36 ^ 0x5c;
243 }
244
245 void
carp_hmac_generate(struct carp_softc * sc,u_int32_t counter[2],unsigned char md[20])246 carp_hmac_generate(struct carp_softc *sc, u_int32_t counter[2],
247 unsigned char md[20])
248 {
249 SHA1_CTX sha1ctx;
250
251 /* fetch first half of inner hash */
252 bcopy(&sc->sc_sha1, &sha1ctx, sizeof(sha1ctx));
253
254 SHA1Update(&sha1ctx, (void *)counter, sizeof(sc->sc_counter));
255 SHA1Final(md, &sha1ctx);
256
257 /* outer hash */
258 SHA1Init(&sha1ctx);
259 SHA1Update(&sha1ctx, sc->sc_pad, sizeof(sc->sc_pad));
260 SHA1Update(&sha1ctx, md, 20);
261 SHA1Final(md, &sha1ctx);
262 }
263
264 int
carp_hmac_verify(struct carp_softc * sc,u_int32_t counter[2],unsigned char md[20])265 carp_hmac_verify(struct carp_softc *sc, u_int32_t counter[2],
266 unsigned char md[20])
267 {
268 unsigned char md2[20];
269
270 carp_hmac_generate(sc, counter, md2);
271
272 return (bcmp(md, md2, sizeof(md2)));
273 }
274
275 void
carp_setroute(struct carp_softc * sc,int cmd)276 carp_setroute(struct carp_softc *sc, int cmd)
277 {
278 struct ifaddr *ifa;
279 int s;
280
281 s = splnet();
282 TAILQ_FOREACH(ifa, &sc->sc_ac.ac_if.if_addrlist, ifa_list) {
283 if (ifa->ifa_addr->sa_family == AF_INET) {
284 int count = carp_addrcount(
285 (struct carp_if *)sc->sc_ifp->if_carp,
286 ifatoia(ifa), CARP_COUNT_MASTER);
287
288 if ((cmd == RTM_ADD && count == 1) ||
289 (cmd == RTM_DELETE && count == 0))
290 rtinit(ifa, cmd, RTF_UP | RTF_HOST);
291 }
292 #ifdef INET6
293 if (ifa->ifa_addr->sa_family == AF_INET6) {
294 if (cmd == RTM_ADD)
295 in6_ifaddloop(ifa);
296 else
297 in6_ifremloop(ifa);
298 }
299 #endif /* INET6 */
300 }
301 splx(s);
302 }
303
304 /*
305 * process input packet.
306 * we have rearranged checks order compared to the rfc,
307 * but it seems more efficient this way or not possible otherwise.
308 */
309 void
carp_input(struct mbuf * m,...)310 carp_input(struct mbuf *m, ...)
311 {
312 struct ip *ip = mtod(m, struct ip *);
313 struct carp_header *ch;
314 int iplen, len, hlen;
315 va_list ap;
316
317 va_start(ap, m);
318 hlen = va_arg(ap, int);
319 va_end(ap);
320
321 carpstats.carps_ipackets++;
322
323 if (!carp_opts[CARPCTL_ALLOW]) {
324 m_freem(m);
325 return;
326 }
327
328 /* check if received on a valid carp interface */
329 if (m->m_pkthdr.rcvif->if_carp == NULL) {
330 carpstats.carps_badif++;
331 CARP_LOG("packet received on non-carp interface: %s",
332 m->m_pkthdr.rcvif->if_xname);
333 m_freem(m);
334 return;
335 }
336
337 /* verify that the IP TTL is 255. */
338 if (ip->ip_ttl != CARP_DFLTTL) {
339 carpstats.carps_badttl++;
340 CARP_LOG("received ttl %d != 255", ip->ip_ttl);
341 m_freem(m);
342 return;
343 }
344
345 iplen = ip->ip_hl << 2;
346
347 if (m->m_pkthdr.len < iplen + sizeof(*ch)) {
348 carpstats.carps_badlen++;
349 CARP_LOG("received len %d < 36",
350 m->m_len - (int)sizeof(struct ip));
351 m_freem(m);
352 return;
353 }
354
355 if (iplen + sizeof(*ch) < m->m_len) {
356 if ((m = m_pullup2(m, iplen + sizeof(*ch))) == NULL) {
357 carpstats.carps_hdrops++;
358 /* CARP_LOG ? */
359 return;
360 }
361 ip = mtod(m, struct ip *);
362 }
363 ch = (void *)ip + iplen;
364
365 /*
366 * verify that the received packet length is
367 * equal to the CARP header
368 */
369 len = iplen + sizeof(*ch);
370 if (len > m->m_pkthdr.len) {
371 carpstats.carps_badlen++;
372 CARP_LOG("packet too short %d", m->m_pkthdr.len);
373 m_freem(m);
374 return;
375 }
376
377 if ((m = m_pullup2(m, len)) == NULL) {
378 carpstats.carps_hdrops++;
379 return;
380 }
381 ip = mtod(m, struct ip *);
382 ch = (void *)ip + iplen;
383
384 /* verify the CARP checksum */
385 m->m_data += iplen;
386 if (carp_cksum(m, len - iplen)) {
387 carpstats.carps_badsum++;
388 CARP_LOG0("checksum failed");
389 m_freem(m);
390 return;
391 }
392 m->m_data -= iplen;
393
394 carp_input_c(m, ch, AF_INET);
395 }
396
397 #ifdef INET6
398 int
carp6_input(struct mbuf ** mp,int * offp,int proto)399 carp6_input(struct mbuf **mp, int *offp, int proto)
400 {
401 struct mbuf *m = *mp;
402 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
403 struct carp_header *ch;
404 u_int len;
405
406 carpstats.carps_ipackets6++;
407
408 if (!carp_opts[CARPCTL_ALLOW]) {
409 m_freem(m);
410 return (IPPROTO_DONE);
411 }
412
413 /* check if received on a valid carp interface */
414 if (m->m_pkthdr.rcvif->if_carp == NULL) {
415 carpstats.carps_badif++;
416 CARP_LOG("packet received on non-carp interface: %s",
417 m->m_pkthdr.rcvif->if_xname);
418 m_freem(m);
419 return (IPPROTO_DONE);
420 }
421
422 /* verify that the IP TTL is 255 */
423 if (ip6->ip6_hlim != CARP_DFLTTL) {
424 carpstats.carps_badttl++;
425 CARP_LOG("received ttl %d != 255", ip6->ip6_hlim);
426 m_freem(m);
427 return (IPPROTO_DONE);
428 }
429
430 /* verify that we have a complete carp packet */
431 len = m->m_len;
432 IP6_EXTHDR_GET(ch, struct carp_header *, m, *offp, sizeof(*ch));
433 if (ch == NULL) {
434 carpstats.carps_badlen++;
435 CARP_LOG("packet size %u too small", len);
436 return (IPPROTO_DONE);
437 }
438
439
440 /* verify the CARP checksum */
441 m->m_data += *offp;
442 if (carp_cksum(m, sizeof(*ch))) {
443 carpstats.carps_badsum++;
444 CARP_LOG0("checksum failed");
445 m_freem(m);
446 return (IPPROTO_DONE);
447 }
448 m->m_data -= *offp;
449
450 carp_input_c(m, ch, AF_INET6);
451 return (IPPROTO_DONE);
452 }
453 #endif /* INET6 */
454
455 void
carp_input_c(struct mbuf * m,struct carp_header * ch,sa_family_t af)456 carp_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af)
457 {
458 struct carp_softc *sc;
459 struct ifnet *ifp = m->m_pkthdr.rcvif;
460 u_int64_t tmp_counter;
461 struct timeval sc_tv, ch_tv;
462
463 /* verify that the VHID is valid on the receiving interface */
464 TAILQ_FOREACH(sc, &((struct carp_if *)ifp->if_carp)->vhif_vrs, sc_list)
465 if (sc->sc_vhid == ch->carp_vhid)
466 break;
467 if (!sc || (sc->sc_ac.ac_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
468 (IFF_UP|IFF_RUNNING)) {
469 carpstats.carps_badvhid++;
470 m_freem(m);
471 return;
472 }
473
474 sc->sc_ac.ac_if.if_lastchange = time;
475 sc->sc_ac.ac_if.if_ipackets++;
476 sc->sc_ac.ac_if.if_ibytes += m->m_pkthdr.len;
477
478 #if NBPFILTER > 0
479 if (sc->sc_ac.ac_if.if_bpf) {
480 /*
481 * We need to prepend the address family as
482 * a four byte field. Cons up a dummy header
483 * to pacify bpf. This is safe because bpf
484 * will only read from the mbuf (i.e., it won't
485 * try to free it or keep a pointer to it).
486 */
487 struct mbuf m0;
488 u_int32_t af = htonl(af);
489
490 m0.m_next = m;
491 m0.m_len = sizeof(af);
492 m0.m_data = (char *)⁡
493 bpf_mtap(sc->sc_ac.ac_if.if_bpf, &m0);
494 }
495 #endif
496
497 /* verify the CARP version. */
498 if (ch->carp_version != CARP_VERSION) {
499 carpstats.carps_badver++;
500 sc->sc_ac.ac_if.if_ierrors++;
501 CARP_LOG1(sc, "invalid version %d", ch->carp_version);
502 m_freem(m);
503 return;
504 }
505
506 /* verify the hash */
507 if (carp_hmac_verify(sc, ch->carp_counter, ch->carp_md)) {
508 carpstats.carps_badauth++;
509 sc->sc_ac.ac_if.if_ierrors++;
510 CARP_LOG0("incorrect hash");
511 m_freem(m);
512 return;
513 }
514
515 tmp_counter = ntohl(ch->carp_counter[0]);
516 tmp_counter = tmp_counter<<32;
517 tmp_counter += ntohl(ch->carp_counter[1]);
518
519 /* XXX Replay protection goes here */
520
521 sc->sc_init_counter = 0;
522 sc->sc_counter = tmp_counter;
523
524
525 sc_tv.tv_sec = sc->sc_advbase;
526 if (carp_suppress_preempt && sc->sc_advskew < 240)
527 sc_tv.tv_usec = 240 * 1000000 / 256;
528 else
529 sc_tv.tv_usec = sc->sc_advskew * 1000000 / 256;
530 ch_tv.tv_sec = ch->carp_advbase;
531 ch_tv.tv_usec = ch->carp_advskew * 1000000 / 256;
532
533 switch (sc->sc_state) {
534 case INIT:
535 break;
536 case MASTER:
537 /*
538 * If we receive an advertisement from a master who's going to
539 * be more frequent than us, go into BACKUP state.
540 */
541 if (timercmp(&sc_tv, &ch_tv, >) ||
542 timercmp(&sc_tv, &ch_tv, ==)) {
543 timeout_del(&sc->sc_ad_tmo);
544 carp_set_state(sc, BACKUP);
545 carp_setrun(sc, 0);
546 carp_setroute(sc, RTM_DELETE);
547 }
548 break;
549 case BACKUP:
550 /*
551 * If we're pre-empting masters who advertise slower than us,
552 * and this one claims to be slower, treat him as down.
553 */
554 if (carp_opts[CARPCTL_PREEMPT] && timercmp(&sc_tv, &ch_tv, <)) {
555 carp_master_down(sc);
556 break;
557 }
558
559 /*
560 * If the master is going to advertise at such a low frequency
561 * that he's guaranteed to time out, we'd might as well just
562 * treat him as timed out now.
563 */
564 sc_tv.tv_sec = sc->sc_advbase * 3;
565 if (timercmp(&sc_tv, &ch_tv, <)) {
566 carp_master_down(sc);
567 break;
568 }
569
570 /*
571 * Otherwise, we reset the counter and wait for the next
572 * advertisement.
573 */
574 carp_setrun(sc, af);
575 break;
576 }
577
578 m_freem(m);
579 return;
580 }
581
582 int
carp_sysctl(int * name,u_int namelen,void * oldp,size_t * oldlenp,void * newp,size_t newlen)583 carp_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
584 size_t newlen)
585 {
586 /* All sysctl names at this level are terminal. */
587 if (namelen != 1)
588 return (ENOTDIR);
589
590 if (name[0] <= 0 || name[0] >= CARPCTL_MAXID)
591 return (ENOPROTOOPT);
592
593 return sysctl_int(oldp, oldlenp, newp, newlen, &carp_opts[name[0]]);
594 }
595
596 /*
597 * Interface side of the CARP implementation.
598 */
599
600 /* ARGSUSED */
601 void
carpattach(int n)602 carpattach(int n)
603 {
604 if_clone_attach(&carp_cloner);
605 }
606
607 int
carp_clone_create(ifc,unit)608 carp_clone_create(ifc, unit)
609 struct if_clone *ifc;
610 int unit;
611 {
612 extern int ifqmaxlen;
613 struct carp_softc *sc;
614 struct ifnet *ifp;
615
616 sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT);
617 if (!sc)
618 return (ENOMEM);
619 bzero(sc, sizeof(*sc));
620
621 sc->sc_flags_backup = 0;
622 sc->sc_suppress = 0;
623 sc->sc_advbase = CARP_DFLTINTV;
624 sc->sc_vhid = -1; /* required setting */
625 sc->sc_advskew = 0;
626 sc->sc_init_counter = 1;
627 sc->sc_naddrs = sc->sc_naddrs6 = 0;
628 #ifdef INET6
629 sc->sc_im6o.im6o_multicast_hlim = CARP_DFLTTL;
630 #endif /* INET6 */
631
632 timeout_set(&sc->sc_ad_tmo, carp_send_ad, sc);
633 timeout_set(&sc->sc_md_tmo, carp_master_down, sc);
634 timeout_set(&sc->sc_md6_tmo, carp_master_down, sc);
635
636 ifp = &sc->sc_ac.ac_if;
637 ifp->if_softc = sc;
638 snprintf(ifp->if_xname, sizeof ifp->if_xname, "%s%d", ifc->ifc_name,
639 unit);
640 ifp->if_mtu = ETHERMTU;
641 ifp->if_flags = 0;
642 ifp->if_ioctl = carp_ioctl;
643 ifp->if_output = looutput;
644 ifp->if_start = carp_start;
645 ifp->if_type = IFT_PROPVIRTUAL;
646 ifp->if_snd.ifq_maxlen = ifqmaxlen;
647 ifp->if_hdrlen = 0;
648 if_attach(ifp);
649 if_alloc_sadl(ifp);
650 #if NBPFILTER > 0
651 bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(u_int32_t));
652 #endif
653 return (0);
654 }
655
656 int
carp_clone_destroy(struct ifnet * ifp)657 carp_clone_destroy(struct ifnet *ifp)
658 {
659 struct carp_softc *sc = ifp->if_softc;
660 struct carp_if *cif;
661
662 timeout_del(&sc->sc_ad_tmo);
663 timeout_del(&sc->sc_md_tmo);
664 timeout_del(&sc->sc_md6_tmo);
665
666 if (sc->sc_ifp != NULL) {
667 cif = (struct carp_if *)sc->sc_ifp->if_carp;
668 TAILQ_REMOVE(&cif->vhif_vrs, sc, sc_list);
669 if (!--cif->vhif_nvrs) {
670 sc->sc_ifp->if_carp = NULL;
671 FREE(cif, M_IFADDR);
672 }
673 }
674
675 #if NBPFILTER > 0
676 bpfdetach(ifp);
677 #endif
678 if_detach(ifp);
679
680 return (0);
681 }
682
683 void
carpdetach(struct carp_softc * sc)684 carpdetach(struct carp_softc *sc)
685 {
686 struct ifaddr *ifa;
687
688 timeout_del(&sc->sc_ad_tmo);
689 timeout_del(&sc->sc_md_tmo);
690 timeout_del(&sc->sc_md6_tmo);
691
692 while ((ifa = TAILQ_FIRST(&sc->sc_ac.ac_if.if_addrlist)) != NULL)
693 if (ifa->ifa_addr->sa_family == AF_INET) {
694 struct in_ifaddr *ia = ifatoia(ifa);
695
696 carp_del_addr(sc, &ia->ia_addr);
697
698 /* ripped screaming from in_control(SIOCDIFADDR) */
699 in_ifscrub(&sc->sc_ac.ac_if, ia);
700 TAILQ_REMOVE(&sc->sc_ac.ac_if.if_addrlist,
701 ifa, ifa_list);
702 TAILQ_REMOVE(&in_ifaddr, ia, ia_list);
703 IFAFREE((&ia->ia_ifa));
704 }
705 }
706
707 /* Detach an interface from the carp. */
708 void
carp_ifdetach(struct ifnet * ifp)709 carp_ifdetach(struct ifnet *ifp)
710 {
711 struct carp_softc *sc;
712
713 TAILQ_FOREACH(sc, &((struct carp_if *)ifp->if_carp)->vhif_vrs, sc_list)
714 carpdetach(sc);
715 }
716
717 int
carp_prepare_ad(struct mbuf * m,struct carp_softc * sc,struct carp_header * ch)718 carp_prepare_ad(struct mbuf *m, struct carp_softc *sc, struct carp_header *ch)
719 {
720 struct m_tag *mtag;
721
722 if (sc->sc_init_counter) {
723 /* this could also be seconds since unix epoch */
724 sc->sc_counter = arc4random();
725 sc->sc_counter = sc->sc_counter << 32;
726 sc->sc_counter += arc4random();
727 } else if (sc->sc_counter == 0xffffffffffffffffULL) {
728 sc->sc_counter = 0;
729 } else
730 sc->sc_counter++;
731
732 ch->carp_counter[0] = htonl((sc->sc_counter>>32)&0xffffffff);
733 ch->carp_counter[1] = htonl(sc->sc_counter&0xffffffff);
734
735 carp_hmac_generate(sc, ch->carp_counter, ch->carp_md);
736
737 /* Tag packet for carp_output */
738 mtag = m_tag_get(PACKET_TAG_CARP,
739 sizeof(struct carp_softc *), M_NOWAIT);
740 if (mtag == NULL) {
741 m_freem(m);
742 sc->sc_ac.ac_if.if_oerrors++;
743 return (ENOMEM);
744 }
745 bcopy(&sc, (caddr_t)(mtag + 1), sizeof(struct carp_softc *));
746 m_tag_prepend(m, mtag);
747
748 return (0);
749 }
750
751 void
carp_send_ad_all(void)752 carp_send_ad_all(void)
753 {
754 struct ifnet *ifp;
755 struct carp_if *cif;
756 struct carp_softc *vh;
757
758 TAILQ_FOREACH(ifp, &ifnet, if_list) {
759 if (ifp->if_carp == NULL)
760 continue;
761
762 cif = (struct carp_if *)ifp->if_carp;
763 TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) {
764 if ((vh->sc_ac.ac_if.if_flags & (IFF_UP|IFF_RUNNING)) &&
765 vh->sc_state == MASTER)
766 carp_send_ad(vh);
767 }
768 }
769 }
770
771
772 void
carp_send_ad(void * v)773 carp_send_ad(void *v)
774 {
775 struct carp_header ch;
776 struct timeval tv;
777 struct carp_softc *sc = v;
778 struct carp_header *ch_ptr;
779 struct mbuf *m;
780 int len, advbase, advskew;
781
782 /* bow out if we've lost our UPness or RUNNINGuiness */
783 if ((sc->sc_ac.ac_if.if_flags &
784 (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
785 advbase = 255;
786 advskew = 255;
787 } else {
788 advbase = sc->sc_advbase;
789 if (!carp_suppress_preempt || sc->sc_advskew > 240)
790 advskew = sc->sc_advskew;
791 else
792 advskew = 240;
793 tv.tv_sec = advbase;
794 tv.tv_usec = advskew * 1000000 / 256;
795 }
796
797 ch.carp_version = CARP_VERSION;
798 ch.carp_type = CARP_ADVERTISEMENT;
799 ch.carp_vhid = sc->sc_vhid;
800 ch.carp_advbase = advbase;
801 ch.carp_advskew = advskew;
802 ch.carp_authlen = 7; /* XXX DEFINE */
803 ch.carp_pad1 = 0; /* must be zero */
804 ch.carp_cksum = 0;
805
806
807 #ifdef INET
808 if (sc->sc_ia) {
809 struct ip *ip;
810
811 MGETHDR(m, M_DONTWAIT, MT_HEADER);
812 if (m == NULL) {
813 sc->sc_ac.ac_if.if_oerrors++;
814 carpstats.carps_onomem++;
815 /* XXX maybe less ? */
816 if (advbase != 255 || advskew != 255)
817 timeout_add(&sc->sc_ad_tmo, tvtohz(&tv));
818 return;
819 }
820 len = sizeof(*ip) + sizeof(ch);
821 m->m_pkthdr.len = len;
822 m->m_pkthdr.rcvif = NULL;
823 m->m_len = len;
824 MH_ALIGN(m, m->m_len);
825 m->m_flags |= M_MCAST;
826 ip = mtod(m, struct ip *);
827 ip->ip_v = IPVERSION;
828 ip->ip_hl = sizeof(*ip) >> 2;
829 ip->ip_tos = IPTOS_LOWDELAY;
830 ip->ip_len = htons(len);
831 ip->ip_id = htons(ip_randomid());
832 ip->ip_off = htons(IP_DF);
833 ip->ip_ttl = CARP_DFLTTL;
834 ip->ip_p = IPPROTO_CARP;
835 ip->ip_sum = 0;
836 ip->ip_src.s_addr = sc->sc_ia->ia_addr.sin_addr.s_addr;
837 ip->ip_dst.s_addr = INADDR_CARP_GROUP;
838
839 ch_ptr = (void *)ip + sizeof(*ip);
840 bcopy(&ch, ch_ptr, sizeof(ch));
841 if (carp_prepare_ad(m, sc, ch_ptr))
842 return;
843
844 m->m_data += sizeof(*ip);
845 ch_ptr->carp_cksum = carp_cksum(m, len - sizeof(*ip));
846 m->m_data -= sizeof(*ip);
847
848 sc->sc_ac.ac_if.if_lastchange = time;
849 sc->sc_ac.ac_if.if_opackets++;
850 sc->sc_ac.ac_if.if_obytes += len;
851 carpstats.carps_opackets++;
852
853 if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL)) {
854 sc->sc_ac.ac_if.if_oerrors++;
855 if (sc->sc_sendad_errors < INT_MAX)
856 sc->sc_sendad_errors++;
857 if (sc->sc_sendad_errors == CARP_SENDAD_MAX_ERRORS) {
858 carp_suppress_preempt++;
859 if (carp_suppress_preempt == 1)
860 carp_send_ad_all();
861 }
862 sc->sc_sendad_success = 0;
863 } else {
864 if (sc->sc_sendad_errors >= CARP_SENDAD_MAX_ERRORS) {
865 if (++sc->sc_sendad_success >=
866 CARP_SENDAD_MIN_SUCCESS) {
867 carp_suppress_preempt--;
868 sc->sc_sendad_errors = 0;
869 }
870 } else
871 sc->sc_sendad_errors = 0;
872 }
873 }
874 #endif /* INET */
875 #ifdef INET6
876 if (sc->sc_ia6) {
877 struct ip6_hdr *ip6;
878
879 MGETHDR(m, M_DONTWAIT, MT_HEADER);
880 if (m == NULL) {
881 sc->sc_ac.ac_if.if_oerrors++;
882 carpstats.carps_onomem++;
883 /* XXX maybe less ? */
884 if (advbase != 255 || advskew != 255)
885 timeout_add(&sc->sc_ad_tmo, tvtohz(&tv));
886 return;
887 }
888 len = sizeof(*ip6) + sizeof(ch);
889 m->m_pkthdr.len = len;
890 m->m_pkthdr.rcvif = NULL;
891 m->m_len = len;
892 MH_ALIGN(m, m->m_len);
893 m->m_flags |= M_MCAST;
894 ip6 = mtod(m, struct ip6_hdr *);
895 bzero(ip6, sizeof(*ip6));
896 ip6->ip6_vfc |= IPV6_VERSION;
897 ip6->ip6_hlim = CARP_DFLTTL;
898 ip6->ip6_nxt = IPPROTO_CARP;
899 bcopy(&sc->sc_ia6->ia_addr.sin6_addr, &ip6->ip6_src,
900 sizeof(struct in6_addr));
901 /* set the multicast destination */
902
903 ip6->ip6_dst.s6_addr8[0] = 0xff;
904 ip6->ip6_dst.s6_addr8[1] = 0x02;
905 ip6->ip6_dst.s6_addr8[15] = 0x12;
906
907 ch_ptr = (void *)ip6 + sizeof(*ip6);
908 bcopy(&ch, ch_ptr, sizeof(ch));
909 if (carp_prepare_ad(m, sc, ch_ptr))
910 return;
911
912 m->m_data += sizeof(*ip6);
913 ch_ptr->carp_cksum = carp_cksum(m, len - sizeof(*ip6));
914 m->m_data -= sizeof(*ip6);
915
916 sc->sc_ac.ac_if.if_lastchange = time;
917 sc->sc_ac.ac_if.if_opackets++;
918 sc->sc_ac.ac_if.if_obytes += len;
919 carpstats.carps_opackets6++;
920
921 if (ip6_output(m, NULL, NULL, 0, &sc->sc_im6o, NULL)) {
922 sc->sc_ac.ac_if.if_oerrors++;
923 if (sc->sc_sendad_errors < INT_MAX)
924 sc->sc_sendad_errors++;
925 if (sc->sc_sendad_errors == CARP_SENDAD_MAX_ERRORS) {
926 carp_suppress_preempt++;
927 if (carp_suppress_preempt == 1)
928 carp_send_ad_all();
929 }
930 sc->sc_sendad_success = 0;
931 } else {
932 if (sc->sc_sendad_errors >= CARP_SENDAD_MAX_ERRORS) {
933 if (++sc->sc_sendad_success >=
934 CARP_SENDAD_MIN_SUCCESS) {
935 carp_suppress_preempt--;
936 sc->sc_sendad_errors = 0;
937 }
938 } else
939 sc->sc_sendad_errors = 0;
940 }
941 }
942 #endif /* INET6 */
943
944 if (advbase != 255 || advskew != 255)
945 timeout_add(&sc->sc_ad_tmo, tvtohz(&tv));
946 }
947
948 /*
949 * Broadcast a gratuitous ARP request containing
950 * the virtual router MAC address for each IP address
951 * associated with the virtual router.
952 */
953 void
carp_send_arp(struct carp_softc * sc)954 carp_send_arp(struct carp_softc *sc)
955 {
956 struct ifaddr *ifa;
957 in_addr_t in;
958
959 TAILQ_FOREACH(ifa, &sc->sc_ac.ac_if.if_addrlist, ifa_list) {
960
961 if (ifa->ifa_addr->sa_family != AF_INET)
962 continue;
963
964 in = ifatoia(ifa)->ia_addr.sin_addr.s_addr;
965 arprequest(sc->sc_ifp, &in, &in, sc->sc_ac.ac_enaddr);
966 DELAY(1000); /* XXX */
967 }
968 }
969
970 #ifdef INET6
971 void
carp_send_na(struct carp_softc * sc)972 carp_send_na(struct carp_softc *sc)
973 {
974 struct ifaddr *ifa;
975 struct in6_addr *in6;
976 static struct in6_addr mcast = IN6ADDR_LINKLOCAL_ALLNODES_INIT;
977
978 TAILQ_FOREACH(ifa, &sc->sc_ac.ac_if.if_addrlist, ifa_list) {
979
980 if (ifa->ifa_addr->sa_family != AF_INET6)
981 continue;
982
983 in6 = &ifatoia6(ifa)->ia_addr.sin6_addr;
984 nd6_na_output(sc->sc_ifp, &mcast, in6,
985 ND_NA_FLAG_OVERRIDE, 1, NULL);
986 DELAY(1000); /* XXX */
987 }
988 }
989 #endif /* INET6 */
990
991 int
carp_addrcount(struct carp_if * cif,struct in_ifaddr * ia,int type)992 carp_addrcount(struct carp_if *cif, struct in_ifaddr *ia, int type)
993 {
994 struct carp_softc *vh;
995 struct ifaddr *ifa;
996 int count = 0;
997
998 TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) {
999 if ((type == CARP_COUNT_RUNNING &&
1000 (vh->sc_ac.ac_if.if_flags & (IFF_UP|IFF_RUNNING)) ==
1001 (IFF_UP|IFF_RUNNING)) ||
1002 (type == CARP_COUNT_MASTER && vh->sc_state == MASTER)) {
1003 TAILQ_FOREACH(ifa, &vh->sc_ac.ac_if.if_addrlist,
1004 ifa_list) {
1005 if (ifa->ifa_addr->sa_family == AF_INET &&
1006 ia->ia_addr.sin_addr.s_addr ==
1007 ifatoia(ifa)->ia_addr.sin_addr.s_addr)
1008 count++;
1009 }
1010 }
1011 }
1012 return (count);
1013 }
1014
1015 int
carp_iamatch(void * v,struct in_ifaddr * ia,struct in_addr * isaddr,u_int8_t ** enaddr)1016 carp_iamatch(void *v, struct in_ifaddr *ia,
1017 struct in_addr *isaddr, u_int8_t **enaddr)
1018 {
1019 struct carp_if *cif = v;
1020 struct carp_softc *vh;
1021 int index, count = 0;
1022 struct ifaddr *ifa;
1023
1024 if (carp_opts[CARPCTL_ARPBALANCE]) {
1025 /*
1026 * XXX proof of concept implementation.
1027 * We use the source ip to decide which virtual host should
1028 * handle the request. If we're master of that virtual host,
1029 * then we respond, otherwise, just drop the arp packet on
1030 * the floor.
1031 */
1032 count = carp_addrcount(cif, ia, CARP_COUNT_RUNNING);
1033 if (count == 0) {
1034 /* should never reach this */
1035 return (0);
1036 }
1037
1038 /* this should be a hash, like pf_hash() */
1039 index = isaddr->s_addr % count;
1040 count = 0;
1041
1042 TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) {
1043 if ((vh->sc_ac.ac_if.if_flags & (IFF_UP|IFF_RUNNING)) ==
1044 (IFF_UP|IFF_RUNNING)) {
1045 TAILQ_FOREACH(ifa, &vh->sc_ac.ac_if.if_addrlist,
1046 ifa_list) {
1047 if (ifa->ifa_addr->sa_family ==
1048 AF_INET &&
1049 ia->ia_addr.sin_addr.s_addr ==
1050 ifatoia(ifa)->ia_addr.sin_addr.s_addr) {
1051 if (count == index) {
1052 if (vh->sc_state ==
1053 MASTER) {
1054 *enaddr = vh->sc_ac.ac_enaddr;
1055 return (1);
1056 } else
1057 return (0);
1058 }
1059 count++;
1060 }
1061 }
1062 }
1063 }
1064 } else {
1065 TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) {
1066 if ((vh->sc_ac.ac_if.if_flags & (IFF_UP|IFF_RUNNING)) ==
1067 (IFF_UP|IFF_RUNNING) && ia->ia_ifp ==
1068 &vh->sc_ac.ac_if) {
1069 *enaddr = vh->sc_ac.ac_enaddr;
1070 return (1);
1071 }
1072 }
1073 }
1074
1075 return (0);
1076 }
1077
1078 #ifdef INET6
1079 struct ifaddr *
carp_iamatch6(void * v,struct in6_addr * taddr)1080 carp_iamatch6(void *v, struct in6_addr *taddr)
1081 {
1082 struct carp_if *cif = v;
1083 struct carp_softc *vh;
1084 struct ifaddr *ifa;
1085
1086 TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) {
1087 TAILQ_FOREACH(ifa, &vh->sc_ac.ac_if.if_addrlist, ifa_list) {
1088 if (IN6_ARE_ADDR_EQUAL(taddr,
1089 &ifatoia6(ifa)->ia_addr.sin6_addr) &&
1090 ((vh->sc_ac.ac_if.if_flags &
1091 (IFF_UP|IFF_RUNNING)) == (IFF_UP|IFF_RUNNING)))
1092 return (ifa);
1093 }
1094 }
1095
1096 return (NULL);
1097 }
1098
1099 void *
carp_macmatch6(void * v,struct mbuf * m,struct in6_addr * taddr)1100 carp_macmatch6(void *v, struct mbuf *m, struct in6_addr *taddr)
1101 {
1102 struct m_tag *mtag;
1103 struct carp_if *cif = v;
1104 struct carp_softc *sc;
1105 struct ifaddr *ifa;
1106
1107
1108 TAILQ_FOREACH(sc, &cif->vhif_vrs, sc_list) {
1109 TAILQ_FOREACH(ifa, &sc->sc_ac.ac_if.if_addrlist, ifa_list) {
1110 if (IN6_ARE_ADDR_EQUAL(taddr,
1111 &ifatoia6(ifa)->ia_addr.sin6_addr) &&
1112 ((sc->sc_ac.ac_if.if_flags &
1113 (IFF_UP|IFF_RUNNING)) == (IFF_UP|IFF_RUNNING))) {
1114 mtag = m_tag_get(PACKET_TAG_CARP,
1115 sizeof(struct carp_softc *), M_NOWAIT);
1116 if (mtag == NULL) {
1117 /* better a bit than nothing */
1118 return (sc->sc_ac.ac_enaddr);
1119 }
1120 bcopy(&sc, (caddr_t)(mtag + 1),
1121 sizeof(struct carp_softc *));
1122 m_tag_prepend(m, mtag);
1123
1124 return (sc->sc_ac.ac_enaddr);
1125 }
1126 }
1127 }
1128
1129 return (NULL);
1130 }
1131 #endif /* INET6 */
1132
1133 struct ifnet *
carp_forus(void * v,void * dhost)1134 carp_forus(void *v, void *dhost)
1135 {
1136 struct carp_if *cif = v;
1137 struct carp_softc *vh;
1138 u_int8_t *ena = dhost;
1139
1140 if (ena[0] || ena[1] || ena[2] != 0x5e || ena[3] || ena[4] != 1)
1141 return (NULL);
1142
1143 TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list)
1144 if ((vh->sc_ac.ac_if.if_flags & (IFF_UP|IFF_RUNNING)) ==
1145 (IFF_UP|IFF_RUNNING) && vh->sc_state == MASTER &&
1146 !bcmp(dhost, vh->sc_ac.ac_enaddr, ETHER_ADDR_LEN))
1147 return (&vh->sc_ac.ac_if);
1148
1149 return (NULL);
1150 }
1151
1152 void
carp_master_down(void * v)1153 carp_master_down(void *v)
1154 {
1155 struct carp_softc *sc = v;
1156
1157 switch (sc->sc_state) {
1158 case INIT:
1159 printf("%s: master_down event in INIT state\n",
1160 sc->sc_ac.ac_if.if_xname);
1161 break;
1162 case MASTER:
1163 break;
1164 case BACKUP:
1165 carp_set_state(sc, MASTER);
1166 carp_send_ad(sc);
1167 carp_send_arp(sc);
1168 #ifdef INET6
1169 carp_send_na(sc);
1170 #endif /* INET6 */
1171 carp_setrun(sc, 0);
1172 carp_setroute(sc, RTM_ADD);
1173 break;
1174 }
1175 }
1176
1177 /*
1178 * When in backup state, af indicates whether to reset the master down timer
1179 * for v4 or v6. If it's set to zero, reset the ones which are already pending.
1180 */
1181 void
carp_setrun(struct carp_softc * sc,sa_family_t af)1182 carp_setrun(struct carp_softc *sc, sa_family_t af)
1183 {
1184 struct timeval tv;
1185
1186 if (sc->sc_ac.ac_if.if_flags & IFF_UP &&
1187 sc->sc_vhid > 0 && (sc->sc_naddrs || sc->sc_naddrs6))
1188 sc->sc_ac.ac_if.if_flags |= IFF_RUNNING;
1189 else {
1190 sc->sc_ac.ac_if.if_flags &= ~IFF_RUNNING;
1191 carp_setroute(sc, RTM_DELETE);
1192 return;
1193 }
1194
1195 switch (sc->sc_state) {
1196 case INIT:
1197 if (carp_opts[CARPCTL_PREEMPT] && !carp_suppress_preempt) {
1198 carp_send_ad(sc);
1199 carp_send_arp(sc);
1200 #ifdef INET6
1201 carp_send_na(sc);
1202 #endif /* INET6 */
1203 carp_set_state(sc, MASTER);
1204 carp_setroute(sc, RTM_ADD);
1205 } else {
1206 carp_set_state(sc, BACKUP);
1207 carp_setroute(sc, RTM_DELETE);
1208 carp_setrun(sc, 0);
1209 }
1210 break;
1211 case BACKUP:
1212 timeout_del(&sc->sc_ad_tmo);
1213 tv.tv_sec = 3 * sc->sc_advbase;
1214 tv.tv_usec = sc->sc_advskew * 1000000 / 256;
1215 switch (af) {
1216 #ifdef INET
1217 case AF_INET:
1218 timeout_add(&sc->sc_md_tmo, tvtohz(&tv));
1219 break;
1220 #endif /* INET */
1221 #ifdef INET6
1222 case AF_INET6:
1223 timeout_add(&sc->sc_md6_tmo, tvtohz(&tv));
1224 break;
1225 #endif /* INET6 */
1226 default:
1227 if (sc->sc_naddrs)
1228 timeout_add(&sc->sc_md_tmo, tvtohz(&tv));
1229 if (sc->sc_naddrs6)
1230 timeout_add(&sc->sc_md6_tmo, tvtohz(&tv));
1231 break;
1232 }
1233 break;
1234 case MASTER:
1235 tv.tv_sec = sc->sc_advbase;
1236 tv.tv_usec = sc->sc_advskew * 1000000 / 256;
1237 timeout_add(&sc->sc_ad_tmo, tvtohz(&tv));
1238 break;
1239 }
1240 }
1241
1242 int
carp_set_addr(struct carp_softc * sc,struct sockaddr_in * sin)1243 carp_set_addr(struct carp_softc *sc, struct sockaddr_in *sin)
1244 {
1245 struct ifnet *ifp;
1246 struct carp_if *cif;
1247 struct in_ifaddr *ia, *ia_if;
1248 struct ip_moptions *imo = &sc->sc_imo;
1249 struct in_addr addr;
1250 int own, error;
1251
1252 if (sin->sin_addr.s_addr == 0) {
1253 if (!(sc->sc_ac.ac_if.if_flags & IFF_UP))
1254 carp_set_state(sc, INIT);
1255 if (sc->sc_naddrs)
1256 sc->sc_ac.ac_if.if_flags |= IFF_UP;
1257 carp_setrun(sc, 0);
1258 return (0);
1259 }
1260
1261 /* we have to do it by hands to check we won't match on us */
1262 ia_if = NULL; own = 0;
1263 for (ia = TAILQ_FIRST(&in_ifaddr); ia; ia = TAILQ_NEXT(ia, ia_list)) {
1264
1265 /* and, yeah, we need a multicast-capable iface too */
1266 if (ia->ia_ifp != &sc->sc_ac.ac_if &&
1267 (ia->ia_ifp->if_flags & IFF_MULTICAST) &&
1268 (sin->sin_addr.s_addr & ia->ia_subnetmask) ==
1269 ia->ia_subnet) {
1270 if (!ia_if)
1271 ia_if = ia;
1272 if (sin->sin_addr.s_addr == ia->ia_addr.sin_addr.s_addr)
1273 own++;
1274 }
1275 }
1276
1277 if (!ia_if)
1278 return (EADDRNOTAVAIL);
1279 ia = ia_if;
1280 ifp = ia->ia_ifp;
1281
1282 if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0 ||
1283 (imo->imo_multicast_ifp && imo->imo_multicast_ifp != ifp))
1284 return (EADDRNOTAVAIL);
1285
1286 if (imo->imo_num_memberships == 0) {
1287 addr.s_addr = INADDR_CARP_GROUP;
1288 if ((imo->imo_membership[0] = in_addmulti(&addr, ifp)) == NULL)
1289 return (ENOBUFS);
1290 imo->imo_num_memberships++;
1291 imo->imo_multicast_ifp = ifp;
1292 imo->imo_multicast_ttl = CARP_DFLTTL;
1293 imo->imo_multicast_loop = 0;
1294 }
1295
1296 if (!ifp->if_carp) {
1297
1298 MALLOC(cif, struct carp_if *, sizeof(*cif), M_IFADDR, M_WAITOK);
1299 if (!cif) {
1300 error = ENOBUFS;
1301 goto cleanup;
1302 }
1303 if ((error = ifpromisc(ifp, 1))) {
1304 FREE(cif, M_IFADDR);
1305 goto cleanup;
1306 }
1307
1308 cif->vhif_ifp = ifp;
1309 TAILQ_INIT(&cif->vhif_vrs);
1310 ifp->if_carp = (caddr_t)cif;
1311
1312 } else {
1313 struct carp_softc *vr;
1314
1315 cif = (struct carp_if *)ifp->if_carp;
1316 TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list)
1317 if (vr != sc && vr->sc_vhid == sc->sc_vhid) {
1318 error = EINVAL;
1319 goto cleanup;
1320 }
1321 }
1322 sc->sc_ia = ia;
1323 sc->sc_ifp = ifp;
1324
1325 { /* XXX prevent endless loop if already in queue */
1326 struct carp_softc *vr, *after = NULL;
1327 int myself = 0;
1328 cif = (struct carp_if *)ifp->if_carp;
1329
1330 TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list) {
1331 if (vr == sc)
1332 myself = 1;
1333 if (vr->sc_vhid < sc->sc_vhid)
1334 after = vr;
1335 }
1336
1337 if (!myself) {
1338 /* We're trying to keep things in order */
1339 if (after == NULL) {
1340 TAILQ_INSERT_TAIL(&cif->vhif_vrs, sc, sc_list);
1341 } else {
1342 TAILQ_INSERT_AFTER(&cif->vhif_vrs, after, sc, sc_list);
1343 }
1344 cif->vhif_nvrs++;
1345 }
1346 }
1347
1348 sc->sc_naddrs++;
1349 sc->sc_ac.ac_if.if_flags |= IFF_UP;
1350 if (own)
1351 sc->sc_advskew = 0;
1352 carp_set_state(sc, INIT);
1353 carp_setrun(sc, 0);
1354
1355 return (0);
1356
1357 cleanup:
1358 in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
1359 return (error);
1360 }
1361
1362 int
carp_del_addr(struct carp_softc * sc,struct sockaddr_in * sin)1363 carp_del_addr(struct carp_softc *sc, struct sockaddr_in *sin)
1364 {
1365 int error = 0;
1366
1367 if (!--sc->sc_naddrs) {
1368 struct carp_if *cif = (struct carp_if *)sc->sc_ifp->if_carp;
1369 struct ip_moptions *imo = &sc->sc_imo;
1370
1371 timeout_del(&sc->sc_ad_tmo);
1372 sc->sc_ac.ac_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
1373 sc->sc_vhid = -1;
1374 in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
1375 imo->imo_multicast_ifp = NULL;
1376 TAILQ_REMOVE(&cif->vhif_vrs, sc, sc_list);
1377 if (!--cif->vhif_nvrs) {
1378 sc->sc_ifp->if_carp = NULL;
1379 FREE(cif, M_IFADDR);
1380 }
1381 }
1382
1383 return (error);
1384 }
1385
1386 #ifdef INET6
1387 int
carp_set_addr6(struct carp_softc * sc,struct sockaddr_in6 * sin6)1388 carp_set_addr6(struct carp_softc *sc, struct sockaddr_in6 *sin6)
1389 {
1390 struct ifnet *ifp;
1391 struct carp_if *cif;
1392 struct in6_ifaddr *ia, *ia_if;
1393 struct ip6_moptions *im6o = &sc->sc_im6o;
1394 struct in6_multi_mship *imm;
1395 struct sockaddr_in6 addr;
1396 int own, error;
1397
1398 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
1399 if (!(sc->sc_ac.ac_if.if_flags & IFF_UP))
1400 carp_set_state(sc, INIT);
1401 if (sc->sc_naddrs6)
1402 sc->sc_ac.ac_if.if_flags |= IFF_UP;
1403 carp_setrun(sc, 0);
1404 return (0);
1405 }
1406
1407 /* we have to do it by hands to check we won't match on us */
1408 ia_if = NULL; own = 0;
1409 for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
1410 int i;
1411
1412 for (i = 0; i < 4; i++) {
1413 if ((sin6->sin6_addr.s6_addr32[i] &
1414 ia->ia_prefixmask.sin6_addr.s6_addr32[i]) !=
1415 (ia->ia_addr.sin6_addr.s6_addr32[i] &
1416 ia->ia_prefixmask.sin6_addr.s6_addr32[i]))
1417 break;
1418 }
1419 /* and, yeah, we need a multicast-capable iface too */
1420 if (ia->ia_ifp != &sc->sc_ac.ac_if &&
1421 (ia->ia_ifp->if_flags & IFF_MULTICAST) &&
1422 (i == 4)) {
1423 if (!ia_if)
1424 ia_if = ia;
1425 if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
1426 &ia->ia_addr.sin6_addr))
1427 own++;
1428 }
1429 }
1430
1431 if (!ia_if)
1432 return (EADDRNOTAVAIL);
1433 ia = ia_if;
1434 ifp = ia->ia_ifp;
1435
1436 if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0 ||
1437 (im6o->im6o_multicast_ifp && im6o->im6o_multicast_ifp != ifp))
1438 return (EADDRNOTAVAIL);
1439
1440 if (!sc->sc_naddrs6) {
1441 im6o->im6o_multicast_ifp = ifp;
1442
1443 /* join CARP multicast address */
1444 bzero(&addr, sizeof(addr));
1445 addr.sin6_family = AF_INET6;
1446 addr.sin6_len = sizeof(addr);
1447 addr.sin6_addr.s6_addr16[0] = htons(0xff02);
1448 addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
1449 addr.sin6_addr.s6_addr8[15] = 0x12;
1450 if ((imm = in6_joingroup(ifp, &addr.sin6_addr, &error)) == NULL)
1451 goto cleanup;
1452 LIST_INSERT_HEAD(&im6o->im6o_memberships, imm, i6mm_chain);
1453
1454 /* join solicited multicast address */
1455 bzero(&addr.sin6_addr, sizeof(addr.sin6_addr));
1456 addr.sin6_addr.s6_addr16[0] = htons(0xff02);
1457 addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
1458 addr.sin6_addr.s6_addr32[1] = 0;
1459 addr.sin6_addr.s6_addr32[2] = htonl(1);
1460 addr.sin6_addr.s6_addr32[3] = sin6->sin6_addr.s6_addr32[3];
1461 addr.sin6_addr.s6_addr8[12] = 0xff;
1462 if ((imm = in6_joingroup(ifp, &addr.sin6_addr, &error)) == NULL)
1463 goto cleanup;
1464 LIST_INSERT_HEAD(&im6o->im6o_memberships, imm, i6mm_chain);
1465 }
1466
1467 if (!ifp->if_carp) {
1468 MALLOC(cif, struct carp_if *, sizeof(*cif), M_IFADDR, M_WAITOK);
1469 if (!cif) {
1470 error = ENOBUFS;
1471 goto cleanup;
1472 }
1473 if ((error = ifpromisc(ifp, 1))) {
1474 FREE(cif, M_IFADDR);
1475 goto cleanup;
1476 }
1477
1478 cif->vhif_ifp = ifp;
1479 TAILQ_INIT(&cif->vhif_vrs);
1480 ifp->if_carp = (caddr_t)cif;
1481
1482 } else {
1483 struct carp_softc *vr;
1484
1485 cif = (struct carp_if *)ifp->if_carp;
1486 TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list)
1487 if (vr != sc && vr->sc_vhid == sc->sc_vhid) {
1488 error = EINVAL;
1489 goto cleanup;
1490 }
1491 }
1492 sc->sc_ia6 = ia;
1493 sc->sc_ifp = ifp;
1494
1495 { /* XXX prevent endless loop if already in queue */
1496 struct carp_softc *vr, *after = NULL;
1497 int myself = 0;
1498 cif = (struct carp_if *)ifp->if_carp;
1499
1500 TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list) {
1501 if (vr == sc)
1502 myself = 1;
1503 if (vr->sc_vhid < sc->sc_vhid)
1504 after = vr;
1505 }
1506
1507 if (!myself) {
1508 /* We're trying to keep things in order */
1509 if (after == NULL) {
1510 TAILQ_INSERT_TAIL(&cif->vhif_vrs, sc, sc_list);
1511 } else {
1512 TAILQ_INSERT_AFTER(&cif->vhif_vrs, after, sc, sc_list);
1513 }
1514 cif->vhif_nvrs++;
1515 }
1516 }
1517
1518 sc->sc_naddrs6++;
1519 sc->sc_ac.ac_if.if_flags |= IFF_UP;
1520 if (own)
1521 sc->sc_advskew = 0;
1522 carp_set_state(sc, INIT);
1523 carp_setrun(sc, 0);
1524
1525 return (0);
1526
1527 cleanup:
1528 /* clean up multicast memberships */
1529 if (!sc->sc_naddrs6) {
1530 while (!LIST_EMPTY(&im6o->im6o_memberships)) {
1531 imm = LIST_FIRST(&im6o->im6o_memberships);
1532 LIST_REMOVE(imm, i6mm_chain);
1533 in6_leavegroup(imm);
1534 }
1535 }
1536 return (error);
1537 }
1538
1539 int
carp_del_addr6(struct carp_softc * sc,struct sockaddr_in6 * sin6)1540 carp_del_addr6(struct carp_softc *sc, struct sockaddr_in6 *sin6)
1541 {
1542 int error = 0;
1543
1544 if (!--sc->sc_naddrs6) {
1545 struct carp_if *cif = (struct carp_if *)sc->sc_ifp->if_carp;
1546 struct ip6_moptions *im6o = &sc->sc_im6o;
1547
1548 timeout_del(&sc->sc_ad_tmo);
1549 sc->sc_ac.ac_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
1550 sc->sc_vhid = -1;
1551 while (!LIST_EMPTY(&im6o->im6o_memberships)) {
1552 struct in6_multi_mship *imm =
1553 LIST_FIRST(&im6o->im6o_memberships);
1554
1555 LIST_REMOVE(imm, i6mm_chain);
1556 in6_leavegroup(imm);
1557 }
1558 im6o->im6o_multicast_ifp = NULL;
1559 TAILQ_REMOVE(&cif->vhif_vrs, sc, sc_list);
1560 if (!--cif->vhif_nvrs) {
1561 sc->sc_ifp->if_carp = NULL;
1562 FREE(cif, M_IFADDR);
1563 }
1564 }
1565
1566 return (error);
1567 }
1568
1569 #endif /* INET6 */
1570
1571 int
carp_ioctl(struct ifnet * ifp,u_long cmd,caddr_t addr)1572 carp_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr)
1573 {
1574 struct proc *p = curproc; /* XXX */
1575 struct carp_softc *sc = ifp->if_softc, *vr;
1576 struct carpreq carpr;
1577 struct ifaddr *ifa;
1578 struct ifreq *ifr;
1579 struct ifaliasreq *ifra;
1580 int error = 0;
1581
1582 ifa = (struct ifaddr *)addr;
1583 ifra = (struct ifaliasreq *)addr;
1584 ifr = (struct ifreq *)addr;
1585
1586 switch (cmd) {
1587 case SIOCSIFADDR:
1588 switch (ifa->ifa_addr->sa_family) {
1589 #ifdef INET
1590 case AF_INET:
1591 sc->sc_ac.ac_if.if_flags |= IFF_UP;
1592 bcopy(ifa->ifa_addr, ifa->ifa_dstaddr,
1593 sizeof(struct sockaddr));
1594 error = carp_set_addr(sc, satosin(ifa->ifa_addr));
1595 break;
1596 #endif /* INET */
1597 #ifdef INET6
1598 case AF_INET6:
1599 sc->sc_ac.ac_if.if_flags|= IFF_UP;
1600 error = carp_set_addr6(sc, satosin6(ifa->ifa_addr));
1601 break;
1602 #endif /* INET6 */
1603 default:
1604 error = EAFNOSUPPORT;
1605 break;
1606 }
1607 break;
1608
1609 case SIOCAIFADDR:
1610 switch (ifa->ifa_addr->sa_family) {
1611 #ifdef INET
1612 case AF_INET:
1613 sc->sc_ac.ac_if.if_flags |= IFF_UP;
1614 bcopy(ifa->ifa_addr, ifa->ifa_dstaddr,
1615 sizeof(struct sockaddr));
1616 error = carp_set_addr(sc, satosin(&ifra->ifra_addr));
1617 break;
1618 #endif /* INET */
1619 #ifdef INET6
1620 case AF_INET6:
1621 sc->sc_ac.ac_if.if_flags |= IFF_UP;
1622 error = carp_set_addr6(sc, satosin6(&ifra->ifra_addr));
1623 break;
1624 #endif /* INET6 */
1625 default:
1626 error = EAFNOSUPPORT;
1627 break;
1628 }
1629 break;
1630
1631 case SIOCDIFADDR:
1632 sc->sc_ac.ac_if.if_flags &= ~IFF_UP;
1633 switch (ifa->ifa_addr->sa_family) {
1634 #ifdef INET
1635 case AF_INET:
1636 error = carp_del_addr(sc, satosin(&ifra->ifra_addr));
1637 break;
1638 #endif /* INET */
1639 #ifdef INET6
1640 case AF_INET6:
1641 error = carp_del_addr6(sc, satosin6(&ifra->ifra_addr));
1642 break;
1643 #endif /* INET6 */
1644 default:
1645 error = EAFNOSUPPORT;
1646 break;
1647 }
1648 break;
1649
1650 case SIOCSIFFLAGS:
1651 if (sc->sc_ac.ac_if.if_flags & IFF_UP &&
1652 (ifr->ifr_flags & IFF_UP) == 0) {
1653 sc->sc_ac.ac_if.if_flags &= ~IFF_UP;
1654 timeout_del(&sc->sc_ad_tmo);
1655 timeout_del(&sc->sc_md_tmo);
1656 timeout_del(&sc->sc_md6_tmo);
1657 if (sc->sc_state == MASTER)
1658 carp_send_ad(sc);
1659 carp_set_state(sc, INIT);
1660 carp_setrun(sc, 0);
1661 }
1662 if (ifr->ifr_flags & IFF_UP &&
1663 (sc->sc_ac.ac_if.if_flags & IFF_UP) == 0) {
1664 sc->sc_ac.ac_if.if_flags |= IFF_UP;
1665 carp_set_state(sc, INIT);
1666 carp_setrun(sc, 0);
1667 }
1668 break;
1669
1670 case SIOCSVH:
1671 if ((error = suser(p, p->p_acflag)) != 0)
1672 break;
1673 if ((error = copyin(ifr->ifr_data, &carpr, sizeof carpr)))
1674 break;
1675 error = 1;
1676 if (sc->sc_state != INIT && carpr.carpr_state != sc->sc_state) {
1677 switch (carpr.carpr_state) {
1678 case BACKUP:
1679 timeout_del(&sc->sc_ad_tmo);
1680 carp_set_state(sc, BACKUP);
1681 carp_setrun(sc, 0);
1682 carp_setroute(sc, RTM_DELETE);
1683 break;
1684 case MASTER:
1685 carp_master_down(sc);
1686 break;
1687 default:
1688 break;
1689 }
1690 }
1691 if (carpr.carpr_vhid > 0) {
1692 if (carpr.carpr_vhid > 255) {
1693 error = EINVAL;
1694 break;
1695 }
1696 if (sc->sc_ifp) {
1697 struct carp_if *cif;
1698 cif = (struct carp_if *)sc->sc_ifp->if_carp;
1699 TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list)
1700 if (vr != sc &&
1701 vr->sc_vhid == carpr.carpr_vhid)
1702 return (EINVAL);
1703 }
1704 sc->sc_vhid = carpr.carpr_vhid;
1705 sc->sc_ac.ac_enaddr[0] = 0;
1706 sc->sc_ac.ac_enaddr[1] = 0;
1707 sc->sc_ac.ac_enaddr[2] = 0x5e;
1708 sc->sc_ac.ac_enaddr[3] = 0;
1709 sc->sc_ac.ac_enaddr[4] = 1;
1710 sc->sc_ac.ac_enaddr[5] = sc->sc_vhid;
1711 error--;
1712 }
1713 if (carpr.carpr_advbase > 0 || carpr.carpr_advskew > 0) {
1714 if (carpr.carpr_advskew >= 255) {
1715 error = EINVAL;
1716 break;
1717 }
1718 if (carpr.carpr_advbase > 255) {
1719 error = EINVAL;
1720 break;
1721 }
1722 sc->sc_advbase = carpr.carpr_advbase;
1723 sc->sc_advskew = carpr.carpr_advskew;
1724 error--;
1725 }
1726 bcopy(carpr.carpr_key, sc->sc_key, sizeof(sc->sc_key));
1727 if (error > 0)
1728 error = EINVAL;
1729 else {
1730 error = 0;
1731 carp_setrun(sc, 0);
1732 }
1733 break;
1734
1735 case SIOCGVH:
1736 bzero(&carpr, sizeof(carpr));
1737 carpr.carpr_state = sc->sc_state;
1738 carpr.carpr_vhid = sc->sc_vhid;
1739 carpr.carpr_advbase = sc->sc_advbase;
1740 carpr.carpr_advskew = sc->sc_advskew;
1741 if (suser(p, p->p_acflag) == 0)
1742 bcopy(sc->sc_key, carpr.carpr_key,
1743 sizeof(carpr.carpr_key));
1744 error = copyout(&carpr, ifr->ifr_data, sizeof(carpr));
1745 break;
1746
1747 default:
1748 error = EINVAL;
1749 }
1750
1751 carp_hmac_prepare(sc);
1752 return (error);
1753 }
1754
1755
1756 /*
1757 * Start output on carp interface. This function should never be called.
1758 */
1759 void
carp_start(struct ifnet * ifp)1760 carp_start(struct ifnet *ifp)
1761 {
1762 #ifdef DEBUG
1763 printf("%s: start called\n", ifp->if_xname);
1764 #endif
1765 }
1766
1767 int
carp_output(struct ifnet * ifp,struct mbuf * m,struct sockaddr * sa,struct rtentry * rt)1768 carp_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa,
1769 struct rtentry *rt)
1770 {
1771 struct m_tag *mtag;
1772 struct carp_softc *sc;
1773
1774 if (!sa)
1775 return (0);
1776
1777 switch (sa->sa_family) {
1778 #ifdef INET
1779 case AF_INET:
1780 break;
1781 #endif /* INET */
1782 #ifdef INET6
1783 case AF_INET6:
1784 break;
1785 #endif /* INET6 */
1786 default:
1787 return (0);
1788 }
1789
1790 mtag = m_tag_find(m, PACKET_TAG_CARP, NULL);
1791 if (mtag == NULL)
1792 return (0);
1793
1794 bcopy(mtag + 1, &sc, sizeof(struct carp_softc *));
1795
1796 /* Set the source MAC address to Virtual Router MAC Address */
1797 switch (ifp->if_type) {
1798 #if NETHER > 0
1799 case IFT_ETHER: {
1800 struct ether_header *eh;
1801
1802 eh = mtod(m, struct ether_header *);
1803 eh->ether_shost[0] = 0;
1804 eh->ether_shost[1] = 0;
1805 eh->ether_shost[2] = 0x5e;
1806 eh->ether_shost[3] = 0;
1807 eh->ether_shost[4] = 1;
1808 eh->ether_shost[5] = sc->sc_vhid;
1809 }
1810 break;
1811 #endif
1812 #if NFDDI > 0
1813 case IFT_FDDI: {
1814 struct fddi_header *fh;
1815
1816 fh = mtod(m, struct fddi_header *);
1817 fh->fddi_shost[0] = 0;
1818 fh->fddi_shost[1] = 0;
1819 fh->fddi_shost[2] = 0x5e;
1820 fh->fddi_shost[3] = 0;
1821 fh->fddi_shost[4] = 1;
1822 fh->fddi_shost[5] = sc->sc_vhid;
1823 }
1824 break;
1825 #endif
1826 #if NTOKEN > 0
1827 case IFT_ISO88025: {
1828 struct token_header *th;
1829
1830 th = mtod(m, struct token_header *);
1831 th->token_shost[0] = 3;
1832 th->token_shost[1] = 0;
1833 th->token_shost[2] = 0x40 >> (sc->sc_vhid - 1);
1834 th->token_shost[3] = 0x40000 >> (sc->sc_vhid - 1);
1835 th->token_shost[4] = 0;
1836 th->token_shost[5] = 0;
1837 }
1838 break;
1839 #endif
1840 default:
1841 printf("%s: carp is not supported for this interface type\n",
1842 ifp->if_xname);
1843 return (EOPNOTSUPP);
1844 }
1845
1846 return (0);
1847 }
1848
1849 void
carp_set_state(struct carp_softc * sc,int state)1850 carp_set_state(struct carp_softc *sc, int state)
1851 {
1852 if (sc->sc_state == state)
1853 return;
1854
1855 sc->sc_state = state;
1856 switch (state) {
1857 case BACKUP:
1858 sc->sc_ac.ac_if.if_link_state = LINK_STATE_DOWN;
1859 break;
1860 case MASTER:
1861 sc->sc_ac.ac_if.if_link_state = LINK_STATE_UP;
1862 break;
1863 default:
1864 sc->sc_ac.ac_if.if_link_state = LINK_STATE_UNKNOWN;
1865 break;
1866 }
1867 rt_ifmsg(&sc->sc_ac.ac_if);
1868 }
1869
1870 void
carp_carpdev_state(void * v)1871 carp_carpdev_state(void *v)
1872 {
1873 struct carp_if *cif = v;
1874 struct carp_softc *sc;
1875
1876 TAILQ_FOREACH(sc, &cif->vhif_vrs, sc_list) {
1877 if (sc->sc_ifp->if_link_state == LINK_STATE_DOWN ||
1878 !(sc->sc_ifp->if_flags & IFF_UP)) {
1879 sc->sc_flags_backup = sc->sc_ac.ac_if.if_flags;
1880 sc->sc_ac.ac_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
1881 timeout_del(&sc->sc_ad_tmo);
1882 timeout_del(&sc->sc_md_tmo);
1883 timeout_del(&sc->sc_md6_tmo);
1884 carp_set_state(sc, INIT);
1885 carp_setrun(sc, 0);
1886 if (!sc->sc_suppress) {
1887 carp_suppress_preempt++;
1888 if (carp_suppress_preempt == 1)
1889 carp_send_ad_all();
1890 }
1891 sc->sc_suppress = 1;
1892 } else {
1893 sc->sc_ac.ac_if.if_flags |= sc->sc_flags_backup;
1894 carp_set_state(sc, INIT);
1895 carp_setrun(sc, 0);
1896 if (sc->sc_suppress)
1897 carp_suppress_preempt--;
1898 sc->sc_suppress = 0;
1899 }
1900 }
1901 }
1902