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 *)&af;
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