Annotation of sys/netinet/ip_carp.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: ip_carp.c,v 1.147 2007/06/23 16:15:26 reyk Exp $ */
2:
3: /*
4: * Copyright (c) 2002 Michael Shalayeff. All rights reserved.
5: * Copyright (c) 2003 Ryan McBride. All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: *
16: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19: * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
20: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22: * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25: * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26: * THE POSSIBILITY OF SUCH DAMAGE.
27: */
28:
29: /*
30: * TODO:
31: * - iface reconfigure
32: * - support for hardware checksum calculations;
33: *
34: */
35:
36: #include "ether.h"
37:
38: #include <sys/param.h>
39: #include <sys/proc.h>
40: #include <sys/systm.h>
41: #include <sys/mbuf.h>
42: #include <sys/socket.h>
43: #include <sys/socketvar.h>
44: #include <sys/ioctl.h>
45: #include <sys/errno.h>
46: #include <sys/device.h>
47: #include <sys/kernel.h>
48: #include <sys/sysctl.h>
49: #include <sys/syslog.h>
50:
51: #include <machine/cpu.h>
52:
53: #include <net/if.h>
54: #include <net/if_types.h>
55: #include <net/if_llc.h>
56: #include <net/route.h>
57: #include <net/netisr.h>
58:
59: /* for arc4random() */
60: #include <dev/rndvar.h>
61:
62: #if NFDDI > 0
63: #include <net/if_fddi.h>
64: #endif
65:
66: #include <crypto/sha1.h>
67:
68: #ifdef INET
69: #include <netinet/in.h>
70: #include <netinet/in_systm.h>
71: #include <netinet/in_var.h>
72: #include <netinet/ip.h>
73: #include <netinet/ip_var.h>
74: #include <netinet/if_ether.h>
75: #include <netinet/ip_ipsp.h>
76:
77: #include <net/if_enc.h>
78: #include <net/if_dl.h>
79: #endif
80:
81: #ifdef INET6
82: #include <netinet/icmp6.h>
83: #include <netinet/ip6.h>
84: #include <netinet6/ip6_var.h>
85: #include <netinet6/nd6.h>
86: #include <netinet6/in6_ifattach.h>
87: #endif
88:
89: #include "bpfilter.h"
90: #if NBPFILTER > 0
91: #include <net/bpf.h>
92: #endif
93:
94: #include <netinet/ip_carp.h>
95:
96: struct carp_mc_entry {
97: LIST_ENTRY(carp_mc_entry) mc_entries;
98: union {
99: struct ether_multi *mcu_enm;
100: } mc_u;
101: struct sockaddr_storage mc_addr;
102: };
103: #define mc_enm mc_u.mcu_enm
104:
105: enum { HMAC_ORIG=0, HMAC_NOV6LL=1, HMAC_MAX=2 };
106:
107: struct carp_softc {
108: struct arpcom sc_ac;
109: #define sc_if sc_ac.ac_if
110: #define sc_carpdev sc_ac.ac_if.if_carpdev
111: void *ah_cookie;
112: void *lh_cookie;
113: struct ip_moptions sc_imo;
114: #ifdef INET6
115: struct ip6_moptions sc_im6o;
116: #endif /* INET6 */
117: TAILQ_ENTRY(carp_softc) sc_list;
118:
119: enum { INIT = 0, BACKUP, MASTER } sc_state;
120:
121: int sc_suppress;
122: int sc_bow_out;
123:
124: int sc_sendad_errors;
125: #define CARP_SENDAD_MAX_ERRORS 3
126: int sc_sendad_success;
127: #define CARP_SENDAD_MIN_SUCCESS 3
128:
129: char sc_carplladdr[ETHER_ADDR_LEN];
130: char sc_curlladdr[ETHER_ADDR_LEN];
131: int sc_vhid;
132: int sc_advskew;
133: int sc_naddrs;
134: int sc_naddrs6;
135: int sc_advbase; /* seconds */
136: int sc_init_counter;
137: u_int64_t sc_counter;
138:
139: /* authentication */
140: #define CARP_HMAC_PAD 64
141: unsigned char sc_key[CARP_KEY_LEN];
142: unsigned char sc_pad[CARP_HMAC_PAD];
143:
144: SHA1_CTX sc_sha1[HMAC_MAX];
145: u_int32_t sc_hashkey[2];
146: u_int32_t sc_lsmask; /* load sharing mask */
147: int sc_lscount; /* # load sharing interfaces (max 32) */
148:
149: struct timeout sc_ad_tmo; /* advertisement timeout */
150: struct timeout sc_md_tmo; /* master down timeout */
151: struct timeout sc_md6_tmo; /* master down timeout */
152: int sc_delayed_arp; /* delayed ARP request countdown */
153:
154: LIST_HEAD(__carp_mchead, carp_mc_entry) carp_mc_listhead;
155: };
156:
157: int carp_opts[CARPCTL_MAXID] = { 0, 1, 0, 0, 0 }; /* XXX for now */
158: struct carpstats carpstats;
159:
160: struct carp_if {
161: TAILQ_HEAD(, carp_softc) vhif_vrs;
162: int vhif_nvrs;
163:
164: struct ifnet *vhif_ifp;
165: };
166:
167: #define CARP_LOG(sc, s) \
168: if (carp_opts[CARPCTL_LOG]) { \
169: if (sc) \
170: log(LOG_INFO, "%s: ", \
171: (sc)->sc_if.if_xname); \
172: else \
173: log(LOG_INFO, "carp: "); \
174: addlog s; \
175: addlog("\n"); \
176: }
177:
178: void carp_hmac_prepare(struct carp_softc *);
179: void carp_hmac_prepare_ctx(struct carp_softc *, u_int8_t);
180: void carp_hmac_generate(struct carp_softc *, u_int32_t *,
181: unsigned char *, u_int8_t);
182: int carp_hmac_verify(struct carp_softc *, u_int32_t *,
183: unsigned char *);
184: void carp_setroute(struct carp_softc *, int);
185: void carp_proto_input_c(struct mbuf *, struct carp_header *, sa_family_t);
186: void carpattach(int);
187: void carpdetach(struct carp_softc *);
188: int carp_prepare_ad(struct mbuf *, struct carp_softc *,
189: struct carp_header *);
190: void carp_send_ad_all(void);
191: void carp_send_ad(void *);
192: void carp_send_arp(struct carp_softc *);
193: void carp_master_down(void *);
194: int carp_ioctl(struct ifnet *, u_long, caddr_t);
195: void carp_ifgroup_ioctl(struct ifnet *, u_long, caddr_t);
196: void carp_ifgattr_ioctl(struct ifnet *, u_long, caddr_t);
197: void carp_start(struct ifnet *);
198: void carp_setrun(struct carp_softc *, sa_family_t);
199: void carp_set_state(struct carp_softc *, int);
200: int carp_addrcount(struct carp_if *, struct ifaddr *, int);
201: enum { CARP_COUNT_MASTER, CARP_COUNT_RUNNING, CARP_COUNT_LINK0 };
202: void carp_multicast_cleanup(struct carp_softc *);
203: int carp_set_ifp(struct carp_softc *, struct ifnet *);
204: void carp_set_enaddr(struct carp_softc *);
205: void carp_addr_updated(void *);
206: u_int32_t carp_hash(struct carp_softc *, u_char *);
207: int carp_set_addr(struct carp_softc *, struct sockaddr_in *);
208: int carp_join_multicast(struct carp_softc *);
209: #ifdef INET6
210: void carp_send_na(struct carp_softc *);
211: int carp_set_addr6(struct carp_softc *, struct sockaddr_in6 *);
212: int carp_join_multicast6(struct carp_softc *);
213: #endif
214: int carp_clone_create(struct if_clone *, int);
215: int carp_clone_destroy(struct ifnet *);
216: int carp_ether_addmulti(struct carp_softc *, struct ifreq *);
217: int carp_ether_delmulti(struct carp_softc *, struct ifreq *);
218: void carp_ether_purgemulti(struct carp_softc *);
219: int carp_group_demote_count(struct carp_softc *);
220: void carp_update_lsmask(struct carp_softc *);
221:
222: struct if_clone carp_cloner =
223: IF_CLONE_INITIALIZER("carp", carp_clone_create, carp_clone_destroy);
224:
225: #define carp_cksum(_m, _l) ((u_int16_t)in_cksum((_m), (_l)))
226:
227: void
228: carp_hmac_prepare(struct carp_softc *sc)
229: {
230: u_int8_t i;
231:
232: for (i=0; i < HMAC_MAX; i++)
233: carp_hmac_prepare_ctx(sc, i);
234: }
235:
236: void
237: carp_hmac_prepare_ctx(struct carp_softc *sc, u_int8_t ctx)
238: {
239: u_int8_t version = CARP_VERSION, type = CARP_ADVERTISEMENT;
240: u_int8_t vhid = sc->sc_vhid & 0xff;
241: SHA1_CTX sha1ctx;
242: u_int32_t kmd[5];
243: struct ifaddr *ifa;
244: int i, found;
245: struct in_addr last, cur, in;
246: #ifdef INET6
247: struct in6_addr last6, cur6, in6;
248: #endif /* INET6 */
249:
250: /* compute ipad from key */
251: bzero(sc->sc_pad, sizeof(sc->sc_pad));
252: bcopy(sc->sc_key, sc->sc_pad, sizeof(sc->sc_key));
253: for (i = 0; i < sizeof(sc->sc_pad); i++)
254: sc->sc_pad[i] ^= 0x36;
255:
256: /* precompute first part of inner hash */
257: SHA1Init(&sc->sc_sha1[ctx]);
258: SHA1Update(&sc->sc_sha1[ctx], sc->sc_pad, sizeof(sc->sc_pad));
259: SHA1Update(&sc->sc_sha1[ctx], (void *)&version, sizeof(version));
260: SHA1Update(&sc->sc_sha1[ctx], (void *)&type, sizeof(type));
261:
262: /* generate a key for the arpbalance hash, before the vhid is hashed */
263: bcopy(&sc->sc_sha1[ctx], &sha1ctx, sizeof(sha1ctx));
264: SHA1Final((unsigned char *)kmd, &sha1ctx);
265: sc->sc_hashkey[0] = kmd[0] ^ kmd[1];
266: sc->sc_hashkey[1] = kmd[2] ^ kmd[3];
267:
268: /* the rest of the precomputation */
269: if (bcmp(sc->sc_ac.ac_enaddr, sc->sc_carplladdr, ETHER_ADDR_LEN) != 0)
270: SHA1Update(&sc->sc_sha1[ctx], sc->sc_ac.ac_enaddr,
271: ETHER_ADDR_LEN);
272:
273: SHA1Update(&sc->sc_sha1[ctx], (void *)&vhid, sizeof(vhid));
274:
275: /* Hash the addresses from smallest to largest, not interface order */
276: #ifdef INET
277: cur.s_addr = 0;
278: do {
279: found = 0;
280: last = cur;
281: cur.s_addr = 0xffffffff;
282: TAILQ_FOREACH(ifa, &sc->sc_if.if_addrlist, ifa_list) {
283: in.s_addr = ifatoia(ifa)->ia_addr.sin_addr.s_addr;
284: if (ifa->ifa_addr->sa_family == AF_INET &&
285: ntohl(in.s_addr) > ntohl(last.s_addr) &&
286: ntohl(in.s_addr) < ntohl(cur.s_addr)) {
287: cur.s_addr = in.s_addr;
288: found++;
289: }
290: }
291: if (found)
292: SHA1Update(&sc->sc_sha1[ctx],
293: (void *)&cur, sizeof(cur));
294: } while (found);
295: #endif /* INET */
296: #ifdef INET6
297: memset(&cur6, 0x00, sizeof(cur6));
298: do {
299: found = 0;
300: last6 = cur6;
301: memset(&cur6, 0xff, sizeof(cur6));
302: TAILQ_FOREACH(ifa, &sc->sc_if.if_addrlist, ifa_list) {
303: in6 = ifatoia6(ifa)->ia_addr.sin6_addr;
304: if (IN6_IS_SCOPE_EMBED(&in6)) {
305: if (ctx == HMAC_NOV6LL)
306: continue;
307: in6.s6_addr16[1] = 0;
308: }
309: if (ifa->ifa_addr->sa_family == AF_INET6 &&
310: memcmp(&in6, &last6, sizeof(in6)) > 0 &&
311: memcmp(&in6, &cur6, sizeof(in6)) < 0) {
312: cur6 = in6;
313: found++;
314: }
315: }
316: if (found)
317: SHA1Update(&sc->sc_sha1[ctx],
318: (void *)&cur6, sizeof(cur6));
319: } while (found);
320: #endif /* INET6 */
321:
322: /* convert ipad to opad */
323: for (i = 0; i < sizeof(sc->sc_pad); i++)
324: sc->sc_pad[i] ^= 0x36 ^ 0x5c;
325: }
326:
327: void
328: carp_hmac_generate(struct carp_softc *sc, u_int32_t counter[2],
329: unsigned char md[20], u_int8_t ctx)
330: {
331: SHA1_CTX sha1ctx;
332:
333: /* fetch first half of inner hash */
334: bcopy(&sc->sc_sha1[ctx], &sha1ctx, sizeof(sha1ctx));
335:
336: SHA1Update(&sha1ctx, (void *)counter, sizeof(sc->sc_counter));
337: SHA1Final(md, &sha1ctx);
338:
339: /* outer hash */
340: SHA1Init(&sha1ctx);
341: SHA1Update(&sha1ctx, sc->sc_pad, sizeof(sc->sc_pad));
342: SHA1Update(&sha1ctx, md, 20);
343: SHA1Final(md, &sha1ctx);
344: }
345:
346: int
347: carp_hmac_verify(struct carp_softc *sc, u_int32_t counter[2],
348: unsigned char md[20])
349: {
350: unsigned char md2[20];
351: u_int8_t i;
352:
353: for (i=0; i < HMAC_MAX; i++) {
354: carp_hmac_generate(sc, counter, md2, i);
355: if (!bcmp(md, md2, sizeof(md2)))
356: return (0);
357: }
358: return (1);
359: }
360:
361: void
362: carp_setroute(struct carp_softc *sc, int cmd)
363: {
364: struct ifaddr *ifa;
365: int s;
366:
367: /* XXX this mess needs fixing */
368:
369: s = splsoftnet();
370: TAILQ_FOREACH(ifa, &sc->sc_if.if_addrlist, ifa_list) {
371: switch (ifa->ifa_addr->sa_family) {
372: case AF_INET: {
373: int count = 0, error;
374: struct sockaddr sa;
375: struct rtentry *rt;
376: struct radix_node_head *rnh;
377: struct radix_node *rn;
378: struct rt_addrinfo info;
379: int hr_otherif, nr_ourif;
380: struct sockaddr_rtlabel sa_rl;
381: const char *label;
382:
383: /*
384: * Avoid screwing with the routes if there are other
385: * carp interfaces which are master and have the same
386: * address.
387: */
388: if (sc->sc_carpdev != NULL &&
389: sc->sc_carpdev->if_carp != NULL) {
390: count = carp_addrcount(
391: (struct carp_if *)sc->sc_carpdev->if_carp,
392: ifa, CARP_COUNT_MASTER);
393: if ((cmd == RTM_ADD && count != 1) ||
394: (cmd == RTM_DELETE && count != 0))
395: continue;
396: }
397:
398: /* Remove the existing host route, if any */
399: bzero(&info, sizeof(info));
400: info.rti_info[RTAX_DST] = ifa->ifa_addr;
401: info.rti_flags = RTF_HOST;
402: error = rtrequest1(RTM_DELETE, &info, NULL, 0);
403: rt_missmsg(RTM_DELETE, &info, info.rti_flags, NULL,
404: error, 0);
405:
406:
407: /* Check for our address on another interface */
408: /* XXX cries for proper API */
409: rnh = rt_gettable(ifa->ifa_addr->sa_family, 0);
410: rn = rnh->rnh_matchaddr(ifa->ifa_addr, rnh);
411: rt = (struct rtentry *)rn;
412: hr_otherif = (rt && rt->rt_ifp != &sc->sc_if &&
413: rt->rt_flags & (RTF_CLONING|RTF_CLONED));
414:
415: /* Check for a network route on our interface */
416: bcopy(ifa->ifa_addr, &sa, sizeof(sa));
417: satosin(&sa)->sin_addr.s_addr = satosin(ifa->ifa_netmask
418: )->sin_addr.s_addr & satosin(&sa)->sin_addr.s_addr;
419: rt = (struct rtentry *)rt_lookup(&sa,
420: ifa->ifa_netmask, 0);
421: nr_ourif = (rt && rt->rt_ifp == &sc->sc_if);
422:
423: /* Restore the route label */
424: bzero(&sa_rl, sizeof(sa_rl));
425: if (rt && rt->rt_labelid) {
426: sa_rl.sr_len = sizeof(sa_rl);
427: sa_rl.sr_family = AF_UNSPEC;
428: label = rtlabel_id2name(rt->rt_labelid);
429: if (label != NULL)
430: strlcpy(sa_rl.sr_label, label,
431: sizeof(sa_rl.sr_label));
432: }
433:
434: switch (cmd) {
435: case RTM_ADD:
436: if (hr_otherif) {
437: ifa->ifa_rtrequest = NULL;
438: ifa->ifa_flags &= ~RTF_CLONING;
439: bzero(&info, sizeof(info));
440: info.rti_info[RTAX_DST] = ifa->ifa_addr;
441: info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr;
442: info.rti_flags = RTF_UP | RTF_HOST;
443: error = rtrequest1(RTM_ADD, &info, NULL, 0);
444: rt_missmsg(RTM_ADD, &info, info.rti_flags, NULL,
445: error, 0);
446: }
447: if (!hr_otherif || nr_ourif || !rt) {
448: if (nr_ourif && !(rt->rt_flags &
449: RTF_CLONING)) {
450: bzero(&info, sizeof(info));
451: info.rti_info[RTAX_DST] = &sa;
452: info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
453: error = rtrequest1(RTM_DELETE, &info, NULL, 0);
454: rt_missmsg(RTM_DELETE, &info, info.rti_flags, NULL,
455: error, 0);
456: }
457:
458: ifa->ifa_rtrequest = arp_rtrequest;
459: ifa->ifa_flags |= RTF_CLONING;
460:
461: bzero(&info, sizeof(info));
462: info.rti_info[RTAX_DST] = &sa;
463: info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr;
464: info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
465: info.rti_info[RTAX_LABEL] =
466: (struct sockaddr *)&sa_rl;
467: error = rtrequest1(RTM_ADD, &info, NULL, 0);
468: if (error == 0)
469: ifa->ifa_flags |= IFA_ROUTE;
470: rt_missmsg(RTM_ADD, &info, info.rti_flags, NULL,
471: error, 0);
472: }
473: break;
474: case RTM_DELETE:
475: break;
476: default:
477: break;
478: }
479: break;
480: }
481:
482: #ifdef INET6
483: case AF_INET6:
484: if (cmd == RTM_ADD)
485: in6_ifaddloop(ifa);
486: else
487: in6_ifremloop(ifa);
488: break;
489: #endif /* INET6 */
490: default:
491: break;
492: }
493: }
494: splx(s);
495: }
496:
497: /*
498: * process input packet.
499: * we have rearranged checks order compared to the rfc,
500: * but it seems more efficient this way or not possible otherwise.
501: */
502: void
503: carp_proto_input(struct mbuf *m, ...)
504: {
505: struct ip *ip = mtod(m, struct ip *);
506: struct carp_softc *sc = NULL;
507: struct carp_header *ch;
508: int iplen, len, hlen;
509: va_list ap;
510:
511: va_start(ap, m);
512: hlen = va_arg(ap, int);
513: va_end(ap);
514:
515: carpstats.carps_ipackets++;
516:
517: if (!carp_opts[CARPCTL_ALLOW]) {
518: m_freem(m);
519: return;
520: }
521:
522: /* check if received on a valid carp interface */
523: if (m->m_pkthdr.rcvif->if_type != IFT_CARP) {
524: carpstats.carps_badif++;
525: CARP_LOG(sc, ("packet received on non-carp interface: %s",
526: m->m_pkthdr.rcvif->if_xname));
527: m_freem(m);
528: return;
529: }
530:
531: /* verify that the IP TTL is 255. */
532: if (ip->ip_ttl != CARP_DFLTTL) {
533: carpstats.carps_badttl++;
534: CARP_LOG(sc, ("received ttl %d != %d on %s", ip->ip_ttl,
535: CARP_DFLTTL, m->m_pkthdr.rcvif->if_xname));
536: m_freem(m);
537: return;
538: }
539:
540: /*
541: * verify that the received packet length is
542: * equal to the CARP header
543: */
544: iplen = ip->ip_hl << 2;
545: len = iplen + sizeof(*ch);
546: if (len > m->m_pkthdr.len) {
547: carpstats.carps_badlen++;
548: CARP_LOG(sc, ("packet too short %d on %s", m->m_pkthdr.len,
549: m->m_pkthdr.rcvif->if_xname));
550: m_freem(m);
551: return;
552: }
553:
554: if ((m = m_pullup2(m, len)) == NULL) {
555: carpstats.carps_hdrops++;
556: return;
557: }
558: ip = mtod(m, struct ip *);
559: ch = (void *)ip + iplen;
560:
561: /* verify the CARP checksum */
562: m->m_data += iplen;
563: if (carp_cksum(m, len - iplen)) {
564: carpstats.carps_badsum++;
565: CARP_LOG(sc, ("checksum failed on %s",
566: m->m_pkthdr.rcvif->if_xname));
567: m_freem(m);
568: return;
569: }
570: m->m_data -= iplen;
571:
572: carp_proto_input_c(m, ch, AF_INET);
573: }
574:
575: #ifdef INET6
576: int
577: carp6_proto_input(struct mbuf **mp, int *offp, int proto)
578: {
579: struct mbuf *m = *mp;
580: struct carp_softc *sc = NULL;
581: struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
582: struct carp_header *ch;
583: u_int len;
584:
585: carpstats.carps_ipackets6++;
586:
587: if (!carp_opts[CARPCTL_ALLOW]) {
588: m_freem(m);
589: return (IPPROTO_DONE);
590: }
591:
592: /* check if received on a valid carp interface */
593: if (m->m_pkthdr.rcvif->if_type != IFT_CARP) {
594: carpstats.carps_badif++;
595: CARP_LOG(sc, ("packet received on non-carp interface: %s",
596: m->m_pkthdr.rcvif->if_xname));
597: m_freem(m);
598: return (IPPROTO_DONE);
599: }
600:
601: /* verify that the IP TTL is 255 */
602: if (ip6->ip6_hlim != CARP_DFLTTL) {
603: carpstats.carps_badttl++;
604: CARP_LOG(sc, ("received ttl %d != %d on %s", ip6->ip6_hlim,
605: CARP_DFLTTL, m->m_pkthdr.rcvif->if_xname));
606: m_freem(m);
607: return (IPPROTO_DONE);
608: }
609:
610: /* verify that we have a complete carp packet */
611: len = m->m_len;
612: IP6_EXTHDR_GET(ch, struct carp_header *, m, *offp, sizeof(*ch));
613: if (ch == NULL) {
614: carpstats.carps_badlen++;
615: CARP_LOG(sc, ("packet size %u too small", len));
616: return (IPPROTO_DONE);
617: }
618:
619:
620: /* verify the CARP checksum */
621: m->m_data += *offp;
622: if (carp_cksum(m, sizeof(*ch))) {
623: carpstats.carps_badsum++;
624: CARP_LOG(sc, ("checksum failed, on %s",
625: m->m_pkthdr.rcvif->if_xname));
626: m_freem(m);
627: return (IPPROTO_DONE);
628: }
629: m->m_data -= *offp;
630:
631: carp_proto_input_c(m, ch, AF_INET6);
632: return (IPPROTO_DONE);
633: }
634: #endif /* INET6 */
635:
636: void
637: carp_proto_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af)
638: {
639: struct carp_softc *sc;
640: u_int64_t tmp_counter;
641: struct timeval sc_tv, ch_tv;
642:
643: TAILQ_FOREACH(sc, &((struct carp_if *)
644: m->m_pkthdr.rcvif->if_carpdev->if_carp)->vhif_vrs, sc_list)
645: if (sc->sc_vhid == ch->carp_vhid)
646: break;
647:
648: if (!sc || (sc->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
649: (IFF_UP|IFF_RUNNING)) {
650: carpstats.carps_badvhid++;
651: m_freem(m);
652: return;
653: }
654:
655: /*
656: * Check if our own advertisement was duplicated
657: * from a non simplex interface.
658: * XXX If there is no address on our physical interface
659: * there is no way to distinguish our ads from the ones
660: * another carp host might have sent us.
661: */
662: if ((sc->sc_carpdev->if_flags & IFF_SIMPLEX) == 0) {
663: struct sockaddr sa;
664: struct ifaddr *ifa;
665:
666: bzero(&sa, sizeof(sa));
667: sa.sa_family = af;
668: ifa = ifaof_ifpforaddr(&sa, sc->sc_carpdev);
669:
670: if (ifa && af == AF_INET) {
671: struct ip *ip = mtod(m, struct ip *);
672: if (ip->ip_src.s_addr ==
673: ifatoia(ifa)->ia_addr.sin_addr.s_addr) {
674: m_freem(m);
675: return;
676: }
677: }
678: #ifdef INET6
679: if (ifa && af == AF_INET6) {
680: struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
681: struct in6_addr in6_src, in6_found;
682:
683: in6_src = ip6->ip6_src;
684: in6_found = ifatoia6(ifa)->ia_addr.sin6_addr;
685: if (IN6_IS_SCOPE_EMBED(&in6_src))
686: in6_src.s6_addr16[1] = 0;
687: if (IN6_IS_SCOPE_EMBED(&in6_found))
688: in6_found.s6_addr16[1] = 0;
689: if (IN6_ARE_ADDR_EQUAL(&in6_src, &in6_found)) {
690: m_freem(m);
691: return;
692: }
693: }
694: #endif /* INET6 */
695: }
696:
697: getmicrotime(&sc->sc_if.if_lastchange);
698: sc->sc_if.if_ipackets++;
699: sc->sc_if.if_ibytes += m->m_pkthdr.len;
700:
701: /* verify the CARP version. */
702: if (ch->carp_version != CARP_VERSION) {
703: carpstats.carps_badver++;
704: sc->sc_if.if_ierrors++;
705: CARP_LOG(sc, ("invalid version %d != %d",
706: ch->carp_version, CARP_VERSION));
707: m_freem(m);
708: return;
709: }
710:
711: /* verify the hash */
712: if (carp_hmac_verify(sc, ch->carp_counter, ch->carp_md)) {
713: carpstats.carps_badauth++;
714: sc->sc_if.if_ierrors++;
715: CARP_LOG(sc, ("incorrect hash"));
716: m_freem(m);
717: return;
718: }
719:
720: tmp_counter = ntohl(ch->carp_counter[0]);
721: tmp_counter = tmp_counter<<32;
722: tmp_counter += ntohl(ch->carp_counter[1]);
723:
724: /* XXX Replay protection goes here */
725:
726: sc->sc_init_counter = 0;
727: sc->sc_counter = tmp_counter;
728:
729:
730: sc_tv.tv_sec = sc->sc_advbase;
731: if (carp_group_demote_count(sc) && sc->sc_advskew < 240)
732: sc_tv.tv_usec = 240 * 1000000 / 256;
733: else
734: sc_tv.tv_usec = sc->sc_advskew * 1000000 / 256;
735: ch_tv.tv_sec = ch->carp_advbase;
736: ch_tv.tv_usec = ch->carp_advskew * 1000000 / 256;
737:
738: switch (sc->sc_state) {
739: case INIT:
740: break;
741: case MASTER:
742: /*
743: * If we receive an advertisement from a master who's going to
744: * be more frequent than us, go into BACKUP state.
745: */
746: if (timercmp(&sc_tv, &ch_tv, >) ||
747: (timercmp(&sc_tv, &ch_tv, ==) &&
748: ch->carp_demote <=
749: (carp_group_demote_count(sc) & 0xff))) {
750: timeout_del(&sc->sc_ad_tmo);
751: carp_set_state(sc, BACKUP);
752: carp_setrun(sc, 0);
753: carp_setroute(sc, RTM_DELETE);
754: }
755: break;
756: case BACKUP:
757: /*
758: * If we're pre-empting masters who advertise slower than us,
759: * and this one claims to be slower, treat him as down.
760: */
761: if (carp_opts[CARPCTL_PREEMPT] && timercmp(&sc_tv, &ch_tv, <)) {
762: carp_master_down(sc);
763: break;
764: }
765:
766: /*
767: * Take over masters advertising with a higher demote count,
768: * regardless of CARPCTL_PREEMPT.
769: */
770: if (ch->carp_demote > (carp_group_demote_count(sc) & 0xff)) {
771: carp_master_down(sc);
772: break;
773: }
774:
775: /*
776: * If the master is going to advertise at such a low frequency
777: * that he's guaranteed to time out, we'd might as well just
778: * treat him as timed out now.
779: */
780: sc_tv.tv_sec = sc->sc_advbase * 3;
781: if (timercmp(&sc_tv, &ch_tv, <)) {
782: carp_master_down(sc);
783: break;
784: }
785:
786: /*
787: * Otherwise, we reset the counter and wait for the next
788: * advertisement.
789: */
790: carp_setrun(sc, af);
791: break;
792: }
793:
794: m_freem(m);
795: return;
796: }
797:
798: int
799: carp_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
800: size_t newlen)
801: {
802: /* All sysctl names at this level are terminal. */
803: if (namelen != 1)
804: return (ENOTDIR);
805:
806: if (name[0] <= 0 || name[0] >= CARPCTL_MAXID)
807: return (ENOPROTOOPT);
808:
809: return sysctl_int(oldp, oldlenp, newp, newlen, &carp_opts[name[0]]);
810: }
811:
812: /*
813: * Interface side of the CARP implementation.
814: */
815:
816: /* ARGSUSED */
817: void
818: carpattach(int n)
819: {
820: struct ifg_group *ifg;
821:
822: if ((ifg = if_creategroup("carp")) != NULL)
823: ifg->ifg_refcnt++; /* keep around even if empty */
824: if_clone_attach(&carp_cloner);
825: }
826:
827: int
828: carp_clone_create(ifc, unit)
829: struct if_clone *ifc;
830: int unit;
831: {
832: struct carp_softc *sc;
833: struct ifnet *ifp;
834:
835: sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT);
836: if (!sc)
837: return (ENOMEM);
838: bzero(sc, sizeof(*sc));
839:
840: sc->sc_suppress = 0;
841: sc->sc_advbase = CARP_DFLTINTV;
842: sc->sc_vhid = -1; /* required setting */
843: sc->sc_advskew = 0;
844: sc->sc_init_counter = 1;
845: sc->sc_naddrs = sc->sc_naddrs6 = 0;
846: #ifdef INET6
847: sc->sc_im6o.im6o_multicast_hlim = CARP_DFLTTL;
848: #endif /* INET6 */
849:
850: timeout_set(&sc->sc_ad_tmo, carp_send_ad, sc);
851: timeout_set(&sc->sc_md_tmo, carp_master_down, sc);
852: timeout_set(&sc->sc_md6_tmo, carp_master_down, sc);
853:
854: LIST_INIT(&sc->carp_mc_listhead);
855: ifp = &sc->sc_if;
856: ifp->if_softc = sc;
857: snprintf(ifp->if_xname, sizeof ifp->if_xname, "%s%d", ifc->ifc_name,
858: unit);
859: ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
860: ifp->if_ioctl = carp_ioctl;
861: ifp->if_start = carp_start;
862: ifp->if_output = carp_output;
863: ifp->if_type = IFT_CARP;
864: ifp->if_addrlen = ETHER_ADDR_LEN;
865: ifp->if_hdrlen = ETHER_HDR_LEN;
866: ifp->if_mtu = ETHERMTU;
867: IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
868: IFQ_SET_READY(&ifp->if_snd);
869: if_attach(ifp);
870:
871: if_alloc_sadl(ifp);
872: LIST_INIT(&sc->sc_ac.ac_multiaddrs);
873: #if NBPFILTER > 0
874: bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, ETHER_HDR_LEN);
875: #endif
876: return (0);
877: }
878:
879: int
880: carp_clone_destroy(struct ifnet *ifp)
881: {
882: carpdetach(ifp->if_softc);
883: ether_ifdetach(ifp);
884: if_detach(ifp);
885: free(ifp->if_softc, M_DEVBUF);
886:
887: return (0);
888: }
889:
890: void
891: carpdetach(struct carp_softc *sc)
892: {
893: struct carp_if *cif;
894: int s;
895:
896: timeout_del(&sc->sc_ad_tmo);
897: timeout_del(&sc->sc_md_tmo);
898: timeout_del(&sc->sc_md6_tmo);
899:
900: if (sc->sc_suppress)
901: carp_group_demote_adj(&sc->sc_if, -1);
902: sc->sc_suppress = 0;
903:
904: if (sc->sc_sendad_errors >= CARP_SENDAD_MAX_ERRORS)
905: carp_group_demote_adj(&sc->sc_if, -1);
906: sc->sc_sendad_errors = 0;
907:
908: carp_set_state(sc, INIT);
909: sc->sc_if.if_flags &= ~IFF_UP;
910: carp_setrun(sc, 0);
911: carp_multicast_cleanup(sc);
912:
913: s = splnet();
914: if (sc->sc_carpdev != NULL) {
915: if (sc->lh_cookie != NULL)
916: hook_disestablish(sc->sc_carpdev->if_linkstatehooks,
917: sc->lh_cookie);
918: cif = (struct carp_if *)sc->sc_carpdev->if_carp;
919: TAILQ_REMOVE(&cif->vhif_vrs, sc, sc_list);
920: if (!--cif->vhif_nvrs) {
921: ifpromisc(sc->sc_carpdev, 0);
922: sc->sc_carpdev->if_carp = NULL;
923: FREE(cif, M_IFADDR);
924: }
925: }
926: sc->sc_carpdev = NULL;
927: splx(s);
928: }
929:
930: /* Detach an interface from the carp. */
931: void
932: carp_ifdetach(struct ifnet *ifp)
933: {
934: struct carp_softc *sc, *nextsc;
935: struct carp_if *cif = (struct carp_if *)ifp->if_carp;
936:
937: for (sc = TAILQ_FIRST(&cif->vhif_vrs); sc; sc = nextsc) {
938: nextsc = TAILQ_NEXT(sc, sc_list);
939: carpdetach(sc);
940: }
941: }
942:
943: int
944: carp_prepare_ad(struct mbuf *m, struct carp_softc *sc, struct carp_header *ch)
945: {
946: if (sc->sc_init_counter) {
947: /* this could also be seconds since unix epoch */
948: sc->sc_counter = arc4random();
949: sc->sc_counter = sc->sc_counter << 32;
950: sc->sc_counter += arc4random();
951: } else
952: sc->sc_counter++;
953:
954: ch->carp_counter[0] = htonl((sc->sc_counter>>32)&0xffffffff);
955: ch->carp_counter[1] = htonl(sc->sc_counter&0xffffffff);
956:
957: /*
958: * For the time being, do not include the IPv6 linklayer addresses
959: * in the HMAC.
960: */
961: carp_hmac_generate(sc, ch->carp_counter, ch->carp_md, HMAC_NOV6LL);
962:
963: return (0);
964: }
965:
966: void
967: carp_send_ad_all(void)
968: {
969: struct ifnet *ifp;
970: struct carp_if *cif;
971: struct carp_softc *vh;
972:
973: TAILQ_FOREACH(ifp, &ifnet, if_list) {
974: if (ifp->if_carp == NULL || ifp->if_type == IFT_CARP)
975: continue;
976:
977: cif = (struct carp_if *)ifp->if_carp;
978: TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) {
979: if ((vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) ==
980: (IFF_UP|IFF_RUNNING) && vh->sc_state == MASTER)
981: carp_send_ad(vh);
982: }
983: }
984: }
985:
986:
987: void
988: carp_send_ad(void *v)
989: {
990: struct carp_header ch;
991: struct timeval tv;
992: struct carp_softc *sc = v;
993: struct carp_header *ch_ptr;
994: struct mbuf *m;
995: int error, len, advbase, advskew, s;
996: struct ifaddr *ifa;
997: struct sockaddr sa;
998:
999: s = splsoftnet();
1000:
1001: if (sc->sc_carpdev == NULL) {
1002: sc->sc_if.if_oerrors++;
1003: goto retry_later;
1004: }
1005:
1006: /* bow out if we've gone to backup (the carp interface is going down) */
1007: if (sc->sc_bow_out) {
1008: sc->sc_bow_out = 0;
1009: advbase = 255;
1010: advskew = 255;
1011: } else {
1012: advbase = sc->sc_advbase;
1013: if (!carp_group_demote_count(sc) || sc->sc_advskew > 240)
1014: advskew = sc->sc_advskew;
1015: else
1016: advskew = 240;
1017: tv.tv_sec = advbase;
1018: tv.tv_usec = advskew * 1000000 / 256;
1019: }
1020:
1021: ch.carp_version = CARP_VERSION;
1022: ch.carp_type = CARP_ADVERTISEMENT;
1023: ch.carp_vhid = sc->sc_vhid;
1024: ch.carp_demote = carp_group_demote_count(sc) & 0xff;
1025: ch.carp_advbase = advbase;
1026: ch.carp_advskew = advskew;
1027: ch.carp_authlen = 7; /* XXX DEFINE */
1028: ch.carp_cksum = 0;
1029:
1030:
1031: #ifdef INET
1032: if (sc->sc_naddrs) {
1033: struct ip *ip;
1034:
1035: MGETHDR(m, M_DONTWAIT, MT_HEADER);
1036: if (m == NULL) {
1037: sc->sc_if.if_oerrors++;
1038: carpstats.carps_onomem++;
1039: /* XXX maybe less ? */
1040: goto retry_later;
1041: }
1042: len = sizeof(*ip) + sizeof(ch);
1043: m->m_pkthdr.len = len;
1044: m->m_pkthdr.rcvif = NULL;
1045: m->m_len = len;
1046: MH_ALIGN(m, m->m_len);
1047: m->m_flags |= M_MCAST;
1048: ip = mtod(m, struct ip *);
1049: ip->ip_v = IPVERSION;
1050: ip->ip_hl = sizeof(*ip) >> 2;
1051: ip->ip_tos = IPTOS_LOWDELAY;
1052: ip->ip_len = htons(len);
1053: ip->ip_id = htons(ip_randomid());
1054: ip->ip_off = htons(IP_DF);
1055: ip->ip_ttl = CARP_DFLTTL;
1056: ip->ip_p = IPPROTO_CARP;
1057: ip->ip_sum = 0;
1058:
1059: bzero(&sa, sizeof(sa));
1060: sa.sa_family = AF_INET;
1061: ifa = ifaof_ifpforaddr(&sa, sc->sc_carpdev);
1062: if (ifa == NULL)
1063: ip->ip_src.s_addr = 0;
1064: else
1065: ip->ip_src.s_addr =
1066: ifatoia(ifa)->ia_addr.sin_addr.s_addr;
1067: ip->ip_dst.s_addr = INADDR_CARP_GROUP;
1068:
1069: ch_ptr = (void *)ip + sizeof(*ip);
1070: bcopy(&ch, ch_ptr, sizeof(ch));
1071: if (carp_prepare_ad(m, sc, ch_ptr))
1072: goto retry_later;
1073:
1074: m->m_data += sizeof(*ip);
1075: ch_ptr->carp_cksum = carp_cksum(m, len - sizeof(*ip));
1076: m->m_data -= sizeof(*ip);
1077:
1078: getmicrotime(&sc->sc_if.if_lastchange);
1079: sc->sc_if.if_opackets++;
1080: sc->sc_if.if_obytes += len;
1081: carpstats.carps_opackets++;
1082:
1083: error = ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo,
1084: NULL);
1085: if (error) {
1086: if (error == ENOBUFS)
1087: carpstats.carps_onomem++;
1088: else
1089: CARP_LOG(sc, ("ip_output failed: %d", error));
1090: sc->sc_if.if_oerrors++;
1091: if (sc->sc_sendad_errors < INT_MAX)
1092: sc->sc_sendad_errors++;
1093: if (sc->sc_sendad_errors == CARP_SENDAD_MAX_ERRORS)
1094: carp_group_demote_adj(&sc->sc_if, 1);
1095: sc->sc_sendad_success = 0;
1096: } else {
1097: if (sc->sc_sendad_errors >= CARP_SENDAD_MAX_ERRORS) {
1098: if (++sc->sc_sendad_success >=
1099: CARP_SENDAD_MIN_SUCCESS) {
1100: carp_group_demote_adj(&sc->sc_if, -1);
1101: sc->sc_sendad_errors = 0;
1102: }
1103: } else
1104: sc->sc_sendad_errors = 0;
1105: }
1106: if (sc->sc_delayed_arp > 0)
1107: sc->sc_delayed_arp--;
1108: if (sc->sc_delayed_arp == 0) {
1109: carp_send_arp(sc);
1110: sc->sc_delayed_arp = -1;
1111: }
1112: }
1113: #endif /* INET */
1114: #ifdef INET6
1115: if (sc->sc_naddrs6) {
1116: struct ip6_hdr *ip6;
1117:
1118: MGETHDR(m, M_DONTWAIT, MT_HEADER);
1119: if (m == NULL) {
1120: sc->sc_if.if_oerrors++;
1121: carpstats.carps_onomem++;
1122: /* XXX maybe less ? */
1123: goto retry_later;
1124: }
1125: len = sizeof(*ip6) + sizeof(ch);
1126: m->m_pkthdr.len = len;
1127: m->m_pkthdr.rcvif = NULL;
1128: m->m_len = len;
1129: MH_ALIGN(m, m->m_len);
1130: m->m_flags |= M_MCAST;
1131: ip6 = mtod(m, struct ip6_hdr *);
1132: bzero(ip6, sizeof(*ip6));
1133: ip6->ip6_vfc |= IPV6_VERSION;
1134: ip6->ip6_hlim = CARP_DFLTTL;
1135: ip6->ip6_nxt = IPPROTO_CARP;
1136:
1137: /* set the source address */
1138: bzero(&sa, sizeof(sa));
1139: sa.sa_family = AF_INET6;
1140: ifa = ifaof_ifpforaddr(&sa, sc->sc_carpdev);
1141: if (ifa == NULL) /* This should never happen with IPv6 */
1142: bzero(&ip6->ip6_src, sizeof(struct in6_addr));
1143: else
1144: bcopy(ifatoia6(ifa)->ia_addr.sin6_addr.s6_addr,
1145: &ip6->ip6_src, sizeof(struct in6_addr));
1146: /* set the multicast destination */
1147:
1148: ip6->ip6_dst.s6_addr8[0] = 0xff;
1149: ip6->ip6_dst.s6_addr8[1] = 0x02;
1150: ip6->ip6_dst.s6_addr8[15] = 0x12;
1151:
1152: ch_ptr = (void *)ip6 + sizeof(*ip6);
1153: bcopy(&ch, ch_ptr, sizeof(ch));
1154: if (carp_prepare_ad(m, sc, ch_ptr))
1155: goto retry_later;
1156:
1157: m->m_data += sizeof(*ip6);
1158: ch_ptr->carp_cksum = carp_cksum(m, len - sizeof(*ip6));
1159: m->m_data -= sizeof(*ip6);
1160:
1161: getmicrotime(&sc->sc_if.if_lastchange);
1162: sc->sc_if.if_opackets++;
1163: sc->sc_if.if_obytes += len;
1164: carpstats.carps_opackets6++;
1165:
1166: error = ip6_output(m, NULL, NULL, 0, &sc->sc_im6o, NULL, NULL);
1167: if (error) {
1168: if (error == ENOBUFS)
1169: carpstats.carps_onomem++;
1170: else
1171: CARP_LOG(sc, ("ip6_output failed: %d", error));
1172: sc->sc_if.if_oerrors++;
1173: if (sc->sc_sendad_errors < INT_MAX)
1174: sc->sc_sendad_errors++;
1175: if (sc->sc_sendad_errors == CARP_SENDAD_MAX_ERRORS)
1176: carp_group_demote_adj(&sc->sc_if, 1);
1177: sc->sc_sendad_success = 0;
1178: } else {
1179: if (sc->sc_sendad_errors >= CARP_SENDAD_MAX_ERRORS) {
1180: if (++sc->sc_sendad_success >=
1181: CARP_SENDAD_MIN_SUCCESS) {
1182: carp_group_demote_adj(&sc->sc_if, -1);
1183: sc->sc_sendad_errors = 0;
1184: }
1185: } else
1186: sc->sc_sendad_errors = 0;
1187: }
1188: }
1189: #endif /* INET6 */
1190:
1191: retry_later:
1192: splx(s);
1193: if (advbase != 255 || advskew != 255)
1194: timeout_add(&sc->sc_ad_tmo, tvtohz(&tv));
1195: }
1196:
1197: /*
1198: * Broadcast a gratuitous ARP request containing
1199: * the virtual router MAC address for each IP address
1200: * associated with the virtual router.
1201: */
1202: void
1203: carp_send_arp(struct carp_softc *sc)
1204: {
1205: struct ifaddr *ifa;
1206: in_addr_t in;
1207: int s = splsoftnet();
1208:
1209: TAILQ_FOREACH(ifa, &sc->sc_if.if_addrlist, ifa_list) {
1210:
1211: if (ifa->ifa_addr->sa_family != AF_INET)
1212: continue;
1213:
1214: if (carp_addrcount((struct carp_if *)sc->sc_carpdev->if_carp,
1215: ifa, CARP_COUNT_LINK0))
1216: continue;
1217:
1218: in = ifatoia(ifa)->ia_addr.sin_addr.s_addr;
1219: arprequest(sc->sc_carpdev, &in, &in, sc->sc_ac.ac_enaddr);
1220: DELAY(1000); /* XXX */
1221: }
1222: splx(s);
1223: }
1224:
1225: #ifdef INET6
1226: void
1227: carp_send_na(struct carp_softc *sc)
1228: {
1229: struct ifaddr *ifa;
1230: struct in6_addr *in6;
1231: static struct in6_addr mcast = IN6ADDR_LINKLOCAL_ALLNODES_INIT;
1232: int s = splsoftnet();
1233:
1234: TAILQ_FOREACH(ifa, &sc->sc_if.if_addrlist, ifa_list) {
1235:
1236: if (ifa->ifa_addr->sa_family != AF_INET6)
1237: continue;
1238:
1239: in6 = &ifatoia6(ifa)->ia_addr.sin6_addr;
1240: nd6_na_output(sc->sc_carpdev, &mcast, in6,
1241: ND_NA_FLAG_OVERRIDE, 1, NULL);
1242: DELAY(1000); /* XXX */
1243: }
1244: splx(s);
1245: }
1246: #endif /* INET6 */
1247:
1248: /*
1249: * Based on bridge_hash() in if_bridge.c
1250: */
1251: #define mix(a,b,c) \
1252: do { \
1253: a -= b; a -= c; a ^= (c >> 13); \
1254: b -= c; b -= a; b ^= (a << 8); \
1255: c -= a; c -= b; c ^= (b >> 13); \
1256: a -= b; a -= c; a ^= (c >> 12); \
1257: b -= c; b -= a; b ^= (a << 16); \
1258: c -= a; c -= b; c ^= (b >> 5); \
1259: a -= b; a -= c; a ^= (c >> 3); \
1260: b -= c; b -= a; b ^= (a << 10); \
1261: c -= a; c -= b; c ^= (b >> 15); \
1262: } while (0)
1263:
1264: u_int32_t
1265: carp_hash(struct carp_softc *sc, u_char *src)
1266: {
1267: u_int32_t a = 0x9e3779b9, b = sc->sc_hashkey[0], c = sc->sc_hashkey[1];
1268:
1269: c += sc->sc_key[3] << 24;
1270: c += sc->sc_key[2] << 16;
1271: c += sc->sc_key[1] << 8;
1272: c += sc->sc_key[0];
1273: b += src[5] << 8;
1274: b += src[4];
1275: a += src[3] << 24;
1276: a += src[2] << 16;
1277: a += src[1] << 8;
1278: a += src[0];
1279:
1280: mix(a, b, c);
1281: return (c);
1282: }
1283:
1284: int
1285: carp_addrcount(struct carp_if *cif, struct ifaddr *ifa0, int type)
1286: {
1287: struct carp_softc *vh;
1288: struct ifaddr *ifa;
1289: int count = 0;
1290:
1291: TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) {
1292: switch (type) {
1293: case CARP_COUNT_RUNNING:
1294: if ((vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
1295: (IFF_UP|IFF_RUNNING))
1296: continue;
1297: break;
1298: case CARP_COUNT_MASTER:
1299: if (vh->sc_state != MASTER)
1300: continue;
1301: break;
1302: case CARP_COUNT_LINK0:
1303: if (!(vh->sc_if.if_flags & IFF_LINK0) ||
1304: (vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
1305: (IFF_UP|IFF_RUNNING))
1306: continue;
1307: break;
1308: }
1309: TAILQ_FOREACH(ifa, &vh->sc_if.if_addrlist, ifa_list) {
1310: if (ifa->ifa_addr->sa_family == AF_INET &&
1311: ifa0->ifa_addr->sa_family == AF_INET &&
1312: ifatoia(ifa0)->ia_addr.sin_addr.s_addr ==
1313: ifatoia(ifa)->ia_addr.sin_addr.s_addr)
1314: count++;
1315: #ifdef INET6
1316: if (ifa->ifa_addr->sa_family == AF_INET6 &&
1317: ifa0->ifa_addr->sa_family == AF_INET6 &&
1318: IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa0), IFA_IN6(ifa)))
1319: count++;
1320: #endif
1321: }
1322: }
1323: return (count);
1324: }
1325:
1326: void
1327: carp_update_lsmask(struct carp_softc *sc)
1328: {
1329: struct carp_softc *curvh, *vh, *sc0 = NULL;
1330: struct carp_if *cif;
1331: struct ifaddr *ifa, *ifa0 = NULL;
1332: int cur, last, count, found;
1333:
1334: if (!sc->sc_carpdev)
1335: return;
1336: cif = (struct carp_if *)sc->sc_carpdev->if_carp;
1337:
1338: /*
1339: * Take the first IPv4 address from the LINK0 carp interface
1340: * to determine the load sharing group.
1341: * Fallback on the first IPv6 address.
1342: */
1343: TAILQ_FOREACH(sc0, &cif->vhif_vrs, sc_list)
1344: if (sc0->sc_if.if_flags & IFF_LINK0)
1345: break;
1346: if (sc0 == NULL)
1347: return;
1348:
1349: TAILQ_FOREACH(ifa0, &sc0->sc_if.if_addrlist, ifa_list)
1350: if (ifa0->ifa_addr->sa_family == AF_INET)
1351: break;
1352: #ifdef INET6
1353: if (ifa0 == NULL)
1354: TAILQ_FOREACH(ifa0, &sc0->sc_if.if_addrlist, ifa_list)
1355: if (ifa0->ifa_addr->sa_family == AF_INET6 &&
1356: !IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa0)))
1357: break;
1358: #endif
1359: if (ifa0 == NULL)
1360: return;
1361: /*
1362: * Calculate the load sharing mask w/ all carp interfaces
1363: * that share the first address of the LINK0 interface.
1364: * Sort by virtual host ID.
1365: */
1366: sc0->sc_lsmask = 0;
1367: cur = 0;
1368: curvh = NULL;
1369: count = 0;
1370: do {
1371: found = 0;
1372: last = cur;
1373: cur = 255;
1374: TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) {
1375: if ((vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
1376: (IFF_UP|IFF_RUNNING))
1377: continue;
1378: TAILQ_FOREACH(ifa, &vh->sc_if.if_addrlist, ifa_list) {
1379: if (ifa->ifa_addr->sa_family == AF_INET &&
1380: ifa0->ifa_addr->sa_family == AF_INET &&
1381: ifatoia(ifa0)->ia_addr.sin_addr.s_addr ==
1382: ifatoia(ifa)->ia_addr.sin_addr.s_addr)
1383: break;
1384: #ifdef INET6
1385: if (ifa->ifa_addr->sa_family == AF_INET6 &&
1386: ifa0->ifa_addr->sa_family == AF_INET6 &&
1387: IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa0), IFA_IN6(ifa)))
1388: break;
1389: #endif
1390: }
1391: if (ifa && vh->sc_vhid > last && vh->sc_vhid < cur) {
1392: cur = vh->sc_vhid;
1393: curvh = vh;
1394: found++;
1395: }
1396: }
1397: if (found) {
1398: if (curvh->sc_state == MASTER &&
1399: count < sizeof(sc0->sc_lsmask) * 8)
1400: sc0->sc_lsmask |= 1 << count;
1401: count++;
1402: }
1403: } while (found);
1404:
1405: sc0->sc_lscount = count;
1406: if (count == 0)
1407: return;
1408:
1409: CARP_LOG(sc, ("carp_update_lsmask: %x", sc0->sc_lsmask))
1410: }
1411:
1412: int
1413: carp_iamatch(struct in_ifaddr *ia, u_char *src,
1414: u_int32_t *count, u_int32_t index)
1415: {
1416: struct carp_softc *sc = ia->ia_ifp->if_softc;
1417:
1418: /*
1419: * If the asked address is found on a LINK0 interface
1420: * don't answer the arp reply unless we are MASTER on it.
1421: */
1422: if (!(sc->sc_if.if_flags & IFF_LINK0) && sc->sc_carpdev &&
1423: carp_addrcount((struct carp_if *)sc->sc_carpdev->if_carp,
1424: (struct ifaddr *)ia, CARP_COUNT_LINK0))
1425: return (0);
1426:
1427: if (carp_opts[CARPCTL_ARPBALANCE]) {
1428: /*
1429: * We use the source ip to decide which virtual host should
1430: * handle the request. If we're master of that virtual host,
1431: * then we respond, otherwise, just drop the arp packet on
1432: * the floor.
1433: */
1434:
1435: /* Count the eligible carp interfaces with this address */
1436: if (*count == 0)
1437: *count = carp_addrcount(
1438: (struct carp_if *)ia->ia_ifp->if_carpdev->if_carp,
1439: (struct ifaddr *)ia, CARP_COUNT_RUNNING);
1440:
1441: /* This should never happen, but... */
1442: if (*count == 0)
1443: return (0);
1444:
1445: if (carp_hash(sc, src) % *count == index - 1 &&
1446: sc->sc_state == MASTER) {
1447: return (1);
1448: }
1449: } else {
1450: if (sc->sc_state == MASTER)
1451: return (1);
1452: }
1453:
1454: return (0);
1455: }
1456:
1457: #ifdef INET6
1458: int
1459: carp_iamatch6(struct ifnet *ifp, struct ifaddr *ifa)
1460: {
1461: struct carp_softc *sc = ifp->if_softc;
1462:
1463: /*
1464: * If the asked address is found on a LINK0 interface
1465: * don't answer the arp request unless we are MASTER on it.
1466: */
1467: if (!(sc->sc_if.if_flags & IFF_LINK0) && sc->sc_carpdev &&
1468: carp_addrcount((struct carp_if *)sc->sc_carpdev->if_carp,
1469: ifa, CARP_COUNT_LINK0))
1470: return (0);
1471:
1472: if (sc->sc_state == MASTER)
1473: return (1);
1474:
1475: return (0);
1476: }
1477: #endif /* INET6 */
1478:
1479: struct ifnet *
1480: carp_ourether(void *v, struct ether_header *eh, u_char iftype, int src)
1481: {
1482: struct carp_if *cif = (struct carp_if *)v;
1483: struct carp_softc *vh;
1484: u_int8_t *ena;
1485:
1486: if (src)
1487: ena = (u_int8_t *)&eh->ether_shost;
1488: else
1489: ena = (u_int8_t *)&eh->ether_dhost;
1490:
1491: TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) {
1492: if ((vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
1493: (IFF_UP|IFF_RUNNING))
1494: continue;
1495: if ((vh->sc_state == MASTER || vh->sc_if.if_flags & IFF_LINK0)
1496: && !bcmp(ena, vh->sc_ac.ac_enaddr, ETHER_ADDR_LEN))
1497: return (&vh->sc_if);
1498: }
1499: return (NULL);
1500: }
1501:
1502: int
1503: carp_input(struct mbuf *m, u_int8_t *shost, u_int8_t *dhost, u_int16_t etype)
1504: {
1505: struct ether_header eh;
1506: struct carp_if *cif = (struct carp_if *)m->m_pkthdr.rcvif->if_carp;
1507: struct ifnet *ifp;
1508:
1509: bcopy(shost, &eh.ether_shost, sizeof(eh.ether_shost));
1510: bcopy(dhost, &eh.ether_dhost, sizeof(eh.ether_dhost));
1511: eh.ether_type = etype;
1512:
1513: if ((ifp = carp_ourether(cif, &eh, m->m_pkthdr.rcvif->if_type, 0)))
1514: ;
1515: else if (m->m_flags & (M_BCAST|M_MCAST)) {
1516: struct carp_softc *vh;
1517: struct mbuf *m0;
1518:
1519: /*
1520: * XXX Should really check the list of multicast addresses
1521: * for each CARP interface _before_ copying.
1522: */
1523: TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) {
1524: m0 = m_copym2(m, 0, M_COPYALL, M_DONTWAIT);
1525: if (m0 == NULL)
1526: continue;
1527: m0->m_pkthdr.rcvif = &vh->sc_if;
1528: ether_input(&vh->sc_if, &eh, m0);
1529: }
1530: return (1);
1531: }
1532:
1533: if (ifp == NULL)
1534: return (1);
1535:
1536: m->m_pkthdr.rcvif = ifp;
1537:
1538: #if NBPFILTER > 0
1539: if (ifp->if_bpf)
1540: bpf_mtap_hdr(ifp->if_bpf, (char *)&eh, ETHER_HDR_LEN, m,
1541: BPF_DIRECTION_IN);
1542: #endif
1543: ifp->if_ipackets++;
1544: ether_input(ifp, &eh, m);
1545:
1546: return (0);
1547: }
1548:
1549: int
1550: carp_lsdrop(struct mbuf *m, sa_family_t af, u_int32_t *src, u_int32_t *dst)
1551: {
1552: struct carp_softc *sc = m->m_pkthdr.rcvif->if_softc;
1553: int match;
1554: u_int32_t fold;
1555:
1556: /*
1557: * Never drop carp advertisements.
1558: * XXX Bad idea to pass all broadcast / multicast traffic?
1559: */
1560: if (m->m_flags & (M_BCAST|M_MCAST))
1561: return (0);
1562:
1563: fold = src[0] ^ dst[0];
1564: #ifdef INET6
1565: if (af == AF_INET6) {
1566: int i;
1567: for (i = 1; i < 4; i++)
1568: fold ^= src[i] ^ dst[i];
1569: }
1570: #endif
1571: if (sc->sc_lscount == 0) /* just to be safe */
1572: return (1);
1573: match = (1 << (ntohl(fold) % sc->sc_lscount)) & sc->sc_lsmask;
1574:
1575: return (!match);
1576: }
1577:
1578: void
1579: carp_master_down(void *v)
1580: {
1581: struct carp_softc *sc = v;
1582:
1583: switch (sc->sc_state) {
1584: case INIT:
1585: printf("%s: master_down event in INIT state\n",
1586: sc->sc_if.if_xname);
1587: break;
1588: case MASTER:
1589: break;
1590: case BACKUP:
1591: carp_set_state(sc, MASTER);
1592: carp_send_ad(sc);
1593: carp_send_arp(sc);
1594: /* Schedule a delayed ARP request to deal w/ some L3 switches */
1595: sc->sc_delayed_arp = 2;
1596: #ifdef INET6
1597: carp_send_na(sc);
1598: #endif /* INET6 */
1599: carp_setrun(sc, 0);
1600: carp_setroute(sc, RTM_ADD);
1601: break;
1602: }
1603: }
1604:
1605: /*
1606: * When in backup state, af indicates whether to reset the master down timer
1607: * for v4 or v6. If it's set to zero, reset the ones which are already pending.
1608: */
1609: void
1610: carp_setrun(struct carp_softc *sc, sa_family_t af)
1611: {
1612: struct timeval tv;
1613:
1614: if (sc->sc_carpdev == NULL) {
1615: sc->sc_if.if_flags &= ~IFF_RUNNING;
1616: carp_set_state(sc, INIT);
1617: return;
1618: }
1619:
1620: if (sc->sc_if.if_flags & IFF_UP && sc->sc_vhid > 0 &&
1621: (sc->sc_naddrs || sc->sc_naddrs6) && !sc->sc_suppress) {
1622: sc->sc_if.if_flags |= IFF_RUNNING;
1623: } else {
1624: sc->sc_if.if_flags &= ~IFF_RUNNING;
1625: carp_setroute(sc, RTM_DELETE);
1626: return;
1627: }
1628:
1629: switch (sc->sc_state) {
1630: case INIT:
1631: carp_set_state(sc, BACKUP);
1632: carp_setroute(sc, RTM_DELETE);
1633: carp_setrun(sc, 0);
1634: break;
1635: case BACKUP:
1636: timeout_del(&sc->sc_ad_tmo);
1637: tv.tv_sec = 3 * sc->sc_advbase;
1638: tv.tv_usec = sc->sc_advskew * 1000000 / 256;
1639: sc->sc_delayed_arp = -1;
1640: switch (af) {
1641: #ifdef INET
1642: case AF_INET:
1643: timeout_add(&sc->sc_md_tmo, tvtohz(&tv));
1644: break;
1645: #endif /* INET */
1646: #ifdef INET6
1647: case AF_INET6:
1648: timeout_add(&sc->sc_md6_tmo, tvtohz(&tv));
1649: break;
1650: #endif /* INET6 */
1651: default:
1652: if (sc->sc_naddrs)
1653: timeout_add(&sc->sc_md_tmo, tvtohz(&tv));
1654: if (sc->sc_naddrs6)
1655: timeout_add(&sc->sc_md6_tmo, tvtohz(&tv));
1656: break;
1657: }
1658: break;
1659: case MASTER:
1660: tv.tv_sec = sc->sc_advbase;
1661: tv.tv_usec = sc->sc_advskew * 1000000 / 256;
1662: timeout_add(&sc->sc_ad_tmo, tvtohz(&tv));
1663: break;
1664: }
1665: }
1666:
1667: void
1668: carp_multicast_cleanup(struct carp_softc *sc)
1669: {
1670: struct ip_moptions *imo = &sc->sc_imo;
1671: #ifdef INET6
1672: struct ip6_moptions *im6o = &sc->sc_im6o;
1673: #endif
1674: u_int16_t n = imo->imo_num_memberships;
1675:
1676: /* Clean up our own multicast memberships */
1677: while (n-- > 0) {
1678: if (imo->imo_membership[n] != NULL) {
1679: in_delmulti(imo->imo_membership[n]);
1680: imo->imo_membership[n] = NULL;
1681: }
1682: }
1683: imo->imo_num_memberships = 0;
1684: imo->imo_multicast_ifp = NULL;
1685:
1686: #ifdef INET6
1687: while (!LIST_EMPTY(&im6o->im6o_memberships)) {
1688: struct in6_multi_mship *imm =
1689: LIST_FIRST(&im6o->im6o_memberships);
1690:
1691: LIST_REMOVE(imm, i6mm_chain);
1692: in6_leavegroup(imm);
1693: }
1694: im6o->im6o_multicast_ifp = NULL;
1695: #endif
1696:
1697: /* And any other multicast memberships */
1698: carp_ether_purgemulti(sc);
1699: }
1700:
1701: int
1702: carp_set_ifp(struct carp_softc *sc, struct ifnet *ifp)
1703: {
1704: struct carp_if *cif, *ncif = NULL;
1705: struct carp_softc *vr, *after = NULL;
1706: int myself = 0, error = 0;
1707: int s;
1708:
1709: if (ifp == sc->sc_carpdev)
1710: return (0);
1711:
1712: if (ifp != NULL) {
1713: if ((ifp->if_flags & IFF_MULTICAST) == 0)
1714: return (EADDRNOTAVAIL);
1715:
1716: if (ifp->if_type == IFT_CARP)
1717: return (EINVAL);
1718:
1719: if (ifp->if_carp == NULL) {
1720: MALLOC(ncif, struct carp_if *, sizeof(*cif),
1721: M_IFADDR, M_NOWAIT);
1722: if (ncif == NULL)
1723: return (ENOBUFS);
1724: if ((error = ifpromisc(ifp, 1))) {
1725: FREE(ncif, M_IFADDR);
1726: return (error);
1727: }
1728:
1729: ncif->vhif_ifp = ifp;
1730: TAILQ_INIT(&ncif->vhif_vrs);
1731: } else {
1732: cif = (struct carp_if *)ifp->if_carp;
1733: TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list)
1734: if (vr != sc && vr->sc_vhid == sc->sc_vhid)
1735: return (EINVAL);
1736: }
1737:
1738: /* detach from old interface */
1739: if (sc->sc_carpdev != NULL)
1740: carpdetach(sc);
1741:
1742: /* join multicast groups */
1743: if (sc->sc_naddrs < 0 &&
1744: (error = carp_join_multicast(sc)) != 0) {
1745: if (ncif != NULL)
1746: FREE(ncif, M_IFADDR);
1747: return (error);
1748: }
1749:
1750: #ifdef INET6
1751: if (sc->sc_naddrs6 < 0 &&
1752: (error = carp_join_multicast6(sc)) != 0) {
1753: if (ncif != NULL)
1754: FREE(ncif, M_IFADDR);
1755: carp_multicast_cleanup(sc);
1756: return (error);
1757: }
1758: #endif
1759:
1760: /* attach carp interface to physical interface */
1761: if (ncif != NULL)
1762: ifp->if_carp = (caddr_t)ncif;
1763: sc->sc_carpdev = ifp;
1764: cif = (struct carp_if *)ifp->if_carp;
1765: TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list) {
1766: if (vr == sc)
1767: myself = 1;
1768: if (vr->sc_vhid < sc->sc_vhid)
1769: after = vr;
1770: }
1771:
1772: if (!myself) {
1773: /* We're trying to keep things in order */
1774: if (after == NULL) {
1775: TAILQ_INSERT_TAIL(&cif->vhif_vrs, sc, sc_list);
1776: } else {
1777: TAILQ_INSERT_AFTER(&cif->vhif_vrs, after,
1778: sc, sc_list);
1779: }
1780: cif->vhif_nvrs++;
1781: }
1782: if (sc->sc_naddrs || sc->sc_naddrs6)
1783: sc->sc_if.if_flags |= IFF_UP;
1784: carp_set_enaddr(sc);
1785: s = splnet();
1786: sc->lh_cookie = hook_establish(ifp->if_linkstatehooks, 1,
1787: carp_carpdev_state, ifp);
1788: carp_carpdev_state(ifp);
1789: splx(s);
1790: } else {
1791: carpdetach(sc);
1792: sc->sc_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
1793: }
1794: return (0);
1795: }
1796:
1797: void
1798: carp_set_enaddr(struct carp_softc *sc)
1799: {
1800: if (sc->sc_vhid != -1 && sc->sc_carpdev) {
1801: /* XXX detach ipv6 link-local address? */
1802: if (sc->sc_if.if_flags & IFF_LINK2)
1803: sc->sc_carplladdr[0] = 1;
1804: else
1805: sc->sc_carplladdr[0] = 0;
1806: sc->sc_carplladdr[1] = 0;
1807: sc->sc_carplladdr[2] = 0x5e;
1808: sc->sc_carplladdr[3] = 0;
1809: sc->sc_carplladdr[4] = 1;
1810: sc->sc_carplladdr[5] = sc->sc_vhid;
1811: } else
1812: bzero(sc->sc_carplladdr, ETHER_ADDR_LEN);
1813:
1814: /*
1815: * Use the carp lladdr if the running one isn't manually set.
1816: * Only compare static parts of the lladdr.
1817: */
1818: if ((bcmp(sc->sc_ac.ac_enaddr + 1, sc->sc_carplladdr + 1,
1819: ETHER_ADDR_LEN - 2) == 0) ||
1820: (!sc->sc_ac.ac_enaddr[0] && !sc->sc_ac.ac_enaddr[1] &&
1821: !sc->sc_ac.ac_enaddr[2] && !sc->sc_ac.ac_enaddr[3] &&
1822: !sc->sc_ac.ac_enaddr[4] && !sc->sc_ac.ac_enaddr[5]))
1823: bcopy(sc->sc_carplladdr, sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN);
1824:
1825: /* Make sure the enaddr has changed before further twiddling. */
1826: if (bcmp(sc->sc_ac.ac_enaddr, sc->sc_curlladdr, ETHER_ADDR_LEN) != 0) {
1827: bcopy(sc->sc_ac.ac_enaddr, LLADDR(sc->sc_if.if_sadl),
1828: ETHER_ADDR_LEN);
1829: bcopy(sc->sc_ac.ac_enaddr, sc->sc_curlladdr, ETHER_ADDR_LEN);
1830: #ifdef INET6
1831: /*
1832: * (re)attach a link-local address which matches
1833: * our new MAC address.
1834: */
1835: in6_ifattach_linklocal(&sc->sc_if, NULL);
1836: #endif
1837: carp_set_state(sc, INIT);
1838: carp_setrun(sc, 0);
1839: }
1840: }
1841:
1842: void
1843: carp_addr_updated(void *v)
1844: {
1845: struct carp_softc *sc = (struct carp_softc *) v;
1846: struct ifaddr *ifa;
1847: int new_naddrs = 0, new_naddrs6 = 0;
1848:
1849: TAILQ_FOREACH(ifa, &sc->sc_if.if_addrlist, ifa_list) {
1850: if (ifa->ifa_addr->sa_family == AF_INET)
1851: new_naddrs++;
1852: else if (ifa->ifa_addr->sa_family == AF_INET6 &&
1853: !IN6_IS_ADDR_LINKLOCAL(&ifatoia6(ifa)->ia_addr.sin6_addr))
1854: new_naddrs6++;
1855: }
1856:
1857: /* Handle a callback after SIOCDIFADDR */
1858: if (new_naddrs < sc->sc_naddrs || new_naddrs6 < sc->sc_naddrs6) {
1859: struct in_addr mc_addr;
1860: struct in_multi *inm;
1861:
1862: sc->sc_naddrs = new_naddrs;
1863: sc->sc_naddrs6 = new_naddrs6;
1864:
1865: /* Re-establish multicast membership removed by in_control */
1866: mc_addr.s_addr = INADDR_CARP_GROUP;
1867: IN_LOOKUP_MULTI(mc_addr, &sc->sc_if, inm);
1868: if (inm == NULL) {
1869: bzero(&sc->sc_imo, sizeof(sc->sc_imo));
1870:
1871: if (sc->sc_carpdev != NULL && sc->sc_naddrs > 0)
1872: carp_join_multicast(sc);
1873: }
1874:
1875: if (sc->sc_naddrs == 0 && sc->sc_naddrs6 == 0) {
1876: sc->sc_if.if_flags &= ~IFF_UP;
1877: carp_set_state(sc, INIT);
1878: } else
1879: carp_hmac_prepare(sc);
1880: }
1881:
1882: carp_setrun(sc, 0);
1883: }
1884:
1885: int
1886: carp_set_addr(struct carp_softc *sc, struct sockaddr_in *sin)
1887: {
1888: struct ifnet *ifp = sc->sc_carpdev;
1889: struct in_ifaddr *ia, *ia_if;
1890: int error = 0;
1891:
1892: if (sin->sin_addr.s_addr == 0) {
1893: if (!(sc->sc_if.if_flags & IFF_UP))
1894: carp_set_state(sc, INIT);
1895: if (sc->sc_naddrs)
1896: sc->sc_if.if_flags |= IFF_UP;
1897: carp_setrun(sc, 0);
1898: return (0);
1899: }
1900:
1901: /* we have to do this by hand to ensure we don't match on ourselves */
1902: ia_if = NULL;
1903: for (ia = TAILQ_FIRST(&in_ifaddr); ia;
1904: ia = TAILQ_NEXT(ia, ia_list)) {
1905:
1906: /* and, yeah, we need a multicast-capable iface too */
1907: if (ia->ia_ifp != &sc->sc_if &&
1908: ia->ia_ifp->if_type != IFT_CARP &&
1909: (ia->ia_ifp->if_flags & IFF_MULTICAST) &&
1910: (sin->sin_addr.s_addr & ia->ia_subnetmask) ==
1911: ia->ia_subnet) {
1912: if (!ia_if)
1913: ia_if = ia;
1914: }
1915: }
1916:
1917: if (ia_if) {
1918: ia = ia_if;
1919: if (ifp) {
1920: if (ifp != ia->ia_ifp)
1921: return (EADDRNOTAVAIL);
1922: } else {
1923: ifp = ia->ia_ifp;
1924: }
1925: }
1926:
1927: if ((error = carp_set_ifp(sc, ifp)))
1928: return (error);
1929:
1930: if (sc->sc_carpdev == NULL)
1931: return (EADDRNOTAVAIL);
1932:
1933: if (sc->sc_naddrs == 0 && (error = carp_join_multicast(sc)) != 0)
1934: return (error);
1935:
1936: sc->sc_naddrs++;
1937: if (sc->sc_carpdev != NULL)
1938: sc->sc_if.if_flags |= IFF_UP;
1939:
1940: carp_set_state(sc, INIT);
1941:
1942: /*
1943: * Hook if_addrhooks so that we get a callback after in_ifinit has run,
1944: * to correct any inappropriate routes that it inserted.
1945: */
1946: if (sc->ah_cookie == NULL)
1947: sc->ah_cookie = hook_establish(sc->sc_if.if_addrhooks, 0,
1948: carp_addr_updated, sc);
1949:
1950: return (0);
1951: }
1952:
1953: int
1954: carp_join_multicast(struct carp_softc *sc)
1955: {
1956: struct ip_moptions *imo = &sc->sc_imo, tmpimo;
1957: struct in_addr addr;
1958:
1959: bzero(&tmpimo, sizeof(tmpimo));
1960: addr.s_addr = INADDR_CARP_GROUP;
1961: if ((tmpimo.imo_membership[0] =
1962: in_addmulti(&addr, &sc->sc_if)) == NULL) {
1963: return (ENOBUFS);
1964: }
1965:
1966: imo->imo_membership[0] = tmpimo.imo_membership[0];
1967: imo->imo_num_memberships = 1;
1968: imo->imo_multicast_ifp = &sc->sc_if;
1969: imo->imo_multicast_ttl = CARP_DFLTTL;
1970: imo->imo_multicast_loop = 0;
1971: return (0);
1972: }
1973:
1974:
1975: #ifdef INET6
1976: int
1977: carp_set_addr6(struct carp_softc *sc, struct sockaddr_in6 *sin6)
1978: {
1979: struct ifnet *ifp = sc->sc_carpdev;
1980: struct in6_ifaddr *ia, *ia_if;
1981: int error = 0;
1982:
1983: if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
1984: if (!(sc->sc_if.if_flags & IFF_UP))
1985: carp_set_state(sc, INIT);
1986: if (sc->sc_naddrs6)
1987: sc->sc_if.if_flags |= IFF_UP;
1988: carp_setrun(sc, 0);
1989: return (0);
1990: }
1991:
1992: /* we have to do this by hand to ensure we don't match on ourselves */
1993: ia_if = NULL;
1994: for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
1995: int i;
1996:
1997: for (i = 0; i < 4; i++) {
1998: if ((sin6->sin6_addr.s6_addr32[i] &
1999: ia->ia_prefixmask.sin6_addr.s6_addr32[i]) !=
2000: (ia->ia_addr.sin6_addr.s6_addr32[i] &
2001: ia->ia_prefixmask.sin6_addr.s6_addr32[i]))
2002: break;
2003: }
2004: /* and, yeah, we need a multicast-capable iface too */
2005: if (ia->ia_ifp != &sc->sc_if &&
2006: ia->ia_ifp->if_type != IFT_CARP &&
2007: (ia->ia_ifp->if_flags & IFF_MULTICAST) &&
2008: (i == 4)) {
2009: if (!ia_if)
2010: ia_if = ia;
2011: }
2012: }
2013:
2014: if (ia_if) {
2015: ia = ia_if;
2016: if (sc->sc_carpdev) {
2017: if (sc->sc_carpdev != ia->ia_ifp)
2018: return (EADDRNOTAVAIL);
2019: } else {
2020: ifp = ia->ia_ifp;
2021: }
2022: }
2023:
2024: if ((error = carp_set_ifp(sc, ifp)))
2025: return (error);
2026:
2027: if (sc->sc_carpdev == NULL)
2028: return (EADDRNOTAVAIL);
2029:
2030: if (sc->sc_naddrs6 == 0 && (error = carp_join_multicast6(sc)) != 0)
2031: return (error);
2032:
2033: if (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
2034: sc->sc_naddrs6++;
2035: if (sc->sc_carpdev != NULL && sc->sc_naddrs6)
2036: sc->sc_if.if_flags |= IFF_UP;
2037: carp_set_state(sc, INIT);
2038: carp_setrun(sc, 0);
2039:
2040: return (0);
2041: }
2042:
2043: int
2044: carp_join_multicast6(struct carp_softc *sc)
2045: {
2046: struct in6_multi_mship *imm, *imm2;
2047: struct ip6_moptions *im6o = &sc->sc_im6o;
2048: struct sockaddr_in6 addr6;
2049: int error;
2050:
2051: /* Join IPv6 CARP multicast group */
2052: bzero(&addr6, sizeof(addr6));
2053: addr6.sin6_family = AF_INET6;
2054: addr6.sin6_len = sizeof(addr6);
2055: addr6.sin6_addr.s6_addr16[0] = htons(0xff02);
2056: addr6.sin6_addr.s6_addr16[1] = htons(sc->sc_if.if_index);
2057: addr6.sin6_addr.s6_addr8[15] = 0x12;
2058: if ((imm = in6_joingroup(&sc->sc_if,
2059: &addr6.sin6_addr, &error)) == NULL) {
2060: return (error);
2061: }
2062: /* join solicited multicast address */
2063: bzero(&addr6.sin6_addr, sizeof(addr6.sin6_addr));
2064: addr6.sin6_addr.s6_addr16[0] = htons(0xff02);
2065: addr6.sin6_addr.s6_addr16[1] = htons(sc->sc_if.if_index);
2066: addr6.sin6_addr.s6_addr32[1] = 0;
2067: addr6.sin6_addr.s6_addr32[2] = htonl(1);
2068: addr6.sin6_addr.s6_addr32[3] = 0;
2069: addr6.sin6_addr.s6_addr8[12] = 0xff;
2070: if ((imm2 = in6_joingroup(&sc->sc_if,
2071: &addr6.sin6_addr, &error)) == NULL) {
2072: in6_leavegroup(imm);
2073: return (error);
2074: }
2075:
2076: /* apply v6 multicast membership */
2077: im6o->im6o_multicast_ifp = &sc->sc_if;
2078: if (imm)
2079: LIST_INSERT_HEAD(&im6o->im6o_memberships, imm,
2080: i6mm_chain);
2081: if (imm2)
2082: LIST_INSERT_HEAD(&im6o->im6o_memberships, imm2,
2083: i6mm_chain);
2084:
2085: return (0);
2086: }
2087:
2088: #endif /* INET6 */
2089:
2090: int
2091: carp_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr)
2092: {
2093: struct proc *p = curproc; /* XXX */
2094: struct carp_softc *sc = ifp->if_softc, *vr;
2095: struct carpreq carpr;
2096: struct ifaddr *ifa = (struct ifaddr *)addr;
2097: struct ifreq *ifr = (struct ifreq *)addr;
2098: struct ifnet *cdev = NULL;
2099: int error = 0;
2100:
2101: switch (cmd) {
2102: case SIOCSIFADDR:
2103: switch (ifa->ifa_addr->sa_family) {
2104: #ifdef INET
2105: case AF_INET:
2106: sc->sc_if.if_flags |= IFF_UP;
2107: bcopy(ifa->ifa_addr, ifa->ifa_dstaddr,
2108: sizeof(struct sockaddr));
2109: error = carp_set_addr(sc, satosin(ifa->ifa_addr));
2110: break;
2111: #endif /* INET */
2112: #ifdef INET6
2113: case AF_INET6:
2114: sc->sc_if.if_flags |= IFF_UP;
2115: error = carp_set_addr6(sc, satosin6(ifa->ifa_addr));
2116: break;
2117: #endif /* INET6 */
2118: default:
2119: error = EAFNOSUPPORT;
2120: break;
2121: }
2122: break;
2123:
2124: case SIOCSIFFLAGS:
2125: if (sc->sc_state != INIT && !(ifr->ifr_flags & IFF_UP)) {
2126: timeout_del(&sc->sc_ad_tmo);
2127: timeout_del(&sc->sc_md_tmo);
2128: timeout_del(&sc->sc_md6_tmo);
2129: if (sc->sc_state == MASTER) {
2130: /* we need the interface up to bow out */
2131: sc->sc_if.if_flags |= IFF_UP;
2132: sc->sc_bow_out = 1;
2133: carp_send_ad(sc);
2134: }
2135: sc->sc_if.if_flags &= ~IFF_UP;
2136: carp_set_state(sc, INIT);
2137: carp_setrun(sc, 0);
2138: } else if (sc->sc_state == INIT && (ifr->ifr_flags & IFF_UP)) {
2139: sc->sc_if.if_flags |= IFF_UP;
2140: carp_setrun(sc, 0);
2141: }
2142: carp_set_enaddr(sc); /* for changes on LINK2 */
2143: if (ifr->ifr_flags & IFF_LINK0)
2144: carp_update_lsmask(sc);
2145: break;
2146:
2147: case SIOCSVH:
2148: if ((error = suser(p, p->p_acflag)) != 0)
2149: break;
2150: if ((error = copyin(ifr->ifr_data, &carpr, sizeof carpr)))
2151: break;
2152: error = 1;
2153: if (carpr.carpr_carpdev[0] != '\0' &&
2154: (cdev = ifunit(carpr.carpr_carpdev)) == NULL)
2155: return (EINVAL);
2156: if ((error = carp_set_ifp(sc, cdev)))
2157: return (error);
2158: if (sc->sc_state != INIT && carpr.carpr_state != sc->sc_state) {
2159: switch (carpr.carpr_state) {
2160: case BACKUP:
2161: timeout_del(&sc->sc_ad_tmo);
2162: carp_set_state(sc, BACKUP);
2163: carp_setrun(sc, 0);
2164: carp_setroute(sc, RTM_DELETE);
2165: break;
2166: case MASTER:
2167: carp_master_down(sc);
2168: break;
2169: default:
2170: break;
2171: }
2172: }
2173: if (carpr.carpr_vhid > 0 && carpr.carpr_vhid != sc->sc_vhid) {
2174: if (carpr.carpr_vhid > 255) {
2175: error = EINVAL;
2176: break;
2177: }
2178: if (sc->sc_carpdev) {
2179: struct carp_if *cif;
2180: cif = (struct carp_if *)sc->sc_carpdev->if_carp;
2181: TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list)
2182: if (vr != sc &&
2183: vr->sc_vhid == carpr.carpr_vhid)
2184: return (EINVAL);
2185: }
2186: if (carpr.carpr_vhid != sc->sc_vhid) {
2187: sc->sc_vhid = carpr.carpr_vhid;
2188: carp_set_enaddr(sc);
2189: carp_set_state(sc, INIT);
2190: }
2191: error--;
2192: }
2193: if (carpr.carpr_advbase > 0 || carpr.carpr_advskew > 0) {
2194: if (carpr.carpr_advskew >= 255) {
2195: error = EINVAL;
2196: break;
2197: }
2198: if (carpr.carpr_advbase > 255) {
2199: error = EINVAL;
2200: break;
2201: }
2202: sc->sc_advbase = carpr.carpr_advbase;
2203: sc->sc_advskew = carpr.carpr_advskew;
2204: error--;
2205: }
2206: bcopy(carpr.carpr_key, sc->sc_key, sizeof(sc->sc_key));
2207: if (error > 0)
2208: error = EINVAL;
2209: else {
2210: error = 0;
2211: carp_setrun(sc, 0);
2212: }
2213: break;
2214:
2215: case SIOCGVH:
2216: bzero(&carpr, sizeof(carpr));
2217: if (sc->sc_carpdev != NULL)
2218: strlcpy(carpr.carpr_carpdev, sc->sc_carpdev->if_xname,
2219: IFNAMSIZ);
2220: carpr.carpr_state = sc->sc_state;
2221: carpr.carpr_vhid = sc->sc_vhid;
2222: carpr.carpr_advbase = sc->sc_advbase;
2223: carpr.carpr_advskew = sc->sc_advskew;
2224: if (suser(p, p->p_acflag) == 0)
2225: bcopy(sc->sc_key, carpr.carpr_key,
2226: sizeof(carpr.carpr_key));
2227: error = copyout(&carpr, ifr->ifr_data, sizeof(carpr));
2228: break;
2229:
2230: case SIOCADDMULTI:
2231: error = carp_ether_addmulti(sc, ifr);
2232: break;
2233:
2234: case SIOCDELMULTI:
2235: error = carp_ether_delmulti(sc, ifr);
2236: break;
2237: case SIOCAIFGROUP:
2238: case SIOCDIFGROUP:
2239: if (sc->sc_suppress)
2240: carp_ifgroup_ioctl(ifp, cmd, addr);
2241: break;
2242: case SIOCSIFGATTR:
2243: carp_ifgattr_ioctl(ifp, cmd, addr);
2244: break;
2245: default:
2246: error = EINVAL;
2247: }
2248:
2249: if (bcmp(sc->sc_ac.ac_enaddr, sc->sc_curlladdr, ETHER_ADDR_LEN) != 0)
2250: carp_set_enaddr(sc);
2251: carp_hmac_prepare(sc);
2252: return (error);
2253: }
2254:
2255: void
2256: carp_ifgroup_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr)
2257: {
2258: struct ifgroupreq *ifgr = (struct ifgroupreq *)addr;
2259: struct ifg_list *ifgl;
2260:
2261: if (!strcmp(ifgr->ifgr_group, IFG_ALL))
2262: return;
2263: TAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next)
2264: if (!strcmp(ifgl->ifgl_group->ifg_group, ifgr->ifgr_group)) {
2265: if (cmd == SIOCAIFGROUP)
2266: ifgl->ifgl_group->ifg_carp_demoted++;
2267: else if (cmd == SIOCDIFGROUP &&
2268: ifgl->ifgl_group->ifg_carp_demoted)
2269: ifgl->ifgl_group->ifg_carp_demoted--;
2270: }
2271: }
2272:
2273: void
2274: carp_ifgattr_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr)
2275: {
2276: struct ifgroupreq *ifgr = (struct ifgroupreq *)addr;
2277: struct carp_softc *sc = ifp->if_softc;
2278:
2279: if (ifgr->ifgr_attrib.ifg_carp_demoted > 0 && (sc->sc_if.if_flags &
2280: (IFF_UP|IFF_RUNNING)) == (IFF_UP|IFF_RUNNING) &&
2281: sc->sc_state == MASTER)
2282: carp_send_ad(sc);
2283: }
2284:
2285: /*
2286: * Start output on carp interface. This function should never be called.
2287: */
2288: void
2289: carp_start(struct ifnet *ifp)
2290: {
2291: #ifdef DEBUG
2292: printf("%s: start called\n", ifp->if_xname);
2293: #endif
2294: }
2295:
2296: int
2297: carp_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa,
2298: struct rtentry *rt)
2299: {
2300: struct carp_softc *sc = ((struct carp_softc *)ifp->if_softc);
2301:
2302: if (sc->sc_carpdev != NULL && sc->sc_state == MASTER)
2303: return (sc->sc_carpdev->if_output(ifp, m, sa, rt));
2304: else {
2305: m_freem(m);
2306: return (ENETUNREACH);
2307: }
2308: }
2309:
2310: void
2311: carp_set_state(struct carp_softc *sc, int state)
2312: {
2313: if (sc->sc_state == state)
2314: return;
2315:
2316: sc->sc_state = state;
2317: carp_update_lsmask(sc);
2318:
2319: switch (state) {
2320: case BACKUP:
2321: sc->sc_if.if_link_state = LINK_STATE_DOWN;
2322: break;
2323: case MASTER:
2324: sc->sc_if.if_link_state = LINK_STATE_UP;
2325: break;
2326: default:
2327: sc->sc_if.if_link_state = LINK_STATE_UNKNOWN;
2328: break;
2329: }
2330: if_link_state_change(&sc->sc_if);
2331: }
2332:
2333: void
2334: carp_group_demote_adj(struct ifnet *ifp, int adj)
2335: {
2336: struct ifg_list *ifgl;
2337: int *dm;
2338: struct carp_softc *nil = NULL;
2339:
2340: TAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next) {
2341: if (!strcmp(ifgl->ifgl_group->ifg_group, IFG_ALL))
2342: continue;
2343: dm = &ifgl->ifgl_group->ifg_carp_demoted;
2344:
2345: if (*dm + adj >= 0)
2346: *dm += adj;
2347: else
2348: *dm = 0;
2349:
2350: if (adj > 0 && *dm == 1)
2351: carp_send_ad_all();
2352: CARP_LOG(nil, ("%s demoted group %s to %d", ifp->if_xname,
2353: ifgl->ifgl_group->ifg_group, *dm));
2354: }
2355: }
2356:
2357: int
2358: carp_group_demote_count(struct carp_softc *sc)
2359: {
2360: struct ifg_list *ifgl;
2361: int count = 0;
2362:
2363: TAILQ_FOREACH(ifgl, &sc->sc_if.if_groups, ifgl_next)
2364: count += ifgl->ifgl_group->ifg_carp_demoted;
2365:
2366: return (count);
2367: }
2368:
2369: void
2370: carp_carpdev_state(void *v)
2371: {
2372: struct carp_if *cif;
2373: struct carp_softc *sc;
2374: struct ifnet *ifp = v;
2375:
2376: if (ifp->if_type == IFT_CARP)
2377: return;
2378:
2379: cif = (struct carp_if *)ifp->if_carp;
2380:
2381: TAILQ_FOREACH(sc, &cif->vhif_vrs, sc_list) {
2382: int suppressed = sc->sc_suppress;
2383:
2384: if (sc->sc_carpdev->if_link_state == LINK_STATE_DOWN ||
2385: !(sc->sc_carpdev->if_flags & IFF_UP)) {
2386: sc->sc_if.if_flags &= ~IFF_RUNNING;
2387: timeout_del(&sc->sc_ad_tmo);
2388: timeout_del(&sc->sc_md_tmo);
2389: timeout_del(&sc->sc_md6_tmo);
2390: carp_set_state(sc, INIT);
2391: sc->sc_suppress = 1;
2392: carp_setrun(sc, 0);
2393: if (!suppressed)
2394: carp_group_demote_adj(&sc->sc_if, 1);
2395: } else {
2396: carp_set_state(sc, INIT);
2397: sc->sc_suppress = 0;
2398: carp_setrun(sc, 0);
2399: if (suppressed)
2400: carp_group_demote_adj(&sc->sc_if, -1);
2401: }
2402: }
2403: }
2404:
2405: int
2406: carp_ether_addmulti(struct carp_softc *sc, struct ifreq *ifr)
2407: {
2408: struct ifnet *ifp;
2409: struct carp_mc_entry *mc;
2410: u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
2411: int error;
2412:
2413: ifp = sc->sc_carpdev;
2414: if (ifp == NULL)
2415: return (EINVAL);
2416:
2417: error = ether_addmulti(ifr, (struct arpcom *)&sc->sc_ac);
2418: if (error != ENETRESET)
2419: return (error);
2420:
2421: /*
2422: * This is new multicast address. We have to tell parent
2423: * about it. Also, remember this multicast address so that
2424: * we can delete them on unconfigure.
2425: */
2426: MALLOC(mc, struct carp_mc_entry *, sizeof(struct carp_mc_entry),
2427: M_DEVBUF, M_NOWAIT);
2428: if (mc == NULL) {
2429: error = ENOMEM;
2430: goto alloc_failed;
2431: }
2432:
2433: /*
2434: * As ether_addmulti() returns ENETRESET, following two
2435: * statement shouldn't fail.
2436: */
2437: (void)ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi);
2438: ETHER_LOOKUP_MULTI(addrlo, addrhi, &sc->sc_ac, mc->mc_enm);
2439: memcpy(&mc->mc_addr, &ifr->ifr_addr, ifr->ifr_addr.sa_len);
2440: LIST_INSERT_HEAD(&sc->carp_mc_listhead, mc, mc_entries);
2441:
2442: error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)ifr);
2443: if (error != 0)
2444: goto ioctl_failed;
2445:
2446: return (error);
2447:
2448: ioctl_failed:
2449: LIST_REMOVE(mc, mc_entries);
2450: FREE(mc, M_DEVBUF);
2451: alloc_failed:
2452: (void)ether_delmulti(ifr, (struct arpcom *)&sc->sc_ac);
2453:
2454: return (error);
2455: }
2456:
2457: int
2458: carp_ether_delmulti(struct carp_softc *sc, struct ifreq *ifr)
2459: {
2460: struct ifnet *ifp;
2461: struct ether_multi *enm;
2462: struct carp_mc_entry *mc;
2463: u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
2464: int error;
2465:
2466: ifp = sc->sc_carpdev;
2467: if (ifp == NULL)
2468: return (EINVAL);
2469:
2470: /*
2471: * Find a key to lookup carp_mc_entry. We have to do this
2472: * before calling ether_delmulti for obvious reason.
2473: */
2474: if ((error = ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi)) != 0)
2475: return (error);
2476: ETHER_LOOKUP_MULTI(addrlo, addrhi, &sc->sc_ac, enm);
2477: if (enm == NULL)
2478: return (EINVAL);
2479:
2480: LIST_FOREACH(mc, &sc->carp_mc_listhead, mc_entries)
2481: if (mc->mc_enm == enm)
2482: break;
2483:
2484: /* We won't delete entries we didn't add */
2485: if (mc == NULL)
2486: return (EINVAL);
2487:
2488: error = ether_delmulti(ifr, (struct arpcom *)&sc->sc_ac);
2489: if (error != ENETRESET)
2490: return (error);
2491:
2492: /* We no longer use this multicast address. Tell parent so. */
2493: error = (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)ifr);
2494: if (error == 0) {
2495: /* And forget about this address. */
2496: LIST_REMOVE(mc, mc_entries);
2497: FREE(mc, M_DEVBUF);
2498: } else
2499: (void)ether_addmulti(ifr, (struct arpcom *)&sc->sc_ac);
2500: return (error);
2501: }
2502:
2503: /*
2504: * Delete any multicast address we have asked to add from parent
2505: * interface. Called when the carp is being unconfigured.
2506: */
2507: void
2508: carp_ether_purgemulti(struct carp_softc *sc)
2509: {
2510: struct ifnet *ifp = sc->sc_carpdev; /* Parent. */
2511: struct carp_mc_entry *mc;
2512: union {
2513: struct ifreq ifreq;
2514: struct {
2515: char ifr_name[IFNAMSIZ];
2516: struct sockaddr_storage ifr_ss;
2517: } ifreq_storage;
2518: } u;
2519: struct ifreq *ifr = &u.ifreq;
2520:
2521: if (ifp == NULL)
2522: return;
2523:
2524: memcpy(ifr->ifr_name, ifp->if_xname, IFNAMSIZ);
2525: while ((mc = LIST_FIRST(&sc->carp_mc_listhead)) != NULL) {
2526: memcpy(&ifr->ifr_addr, &mc->mc_addr, mc->mc_addr.ss_len);
2527: (void)(*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)ifr);
2528: LIST_REMOVE(mc, mc_entries);
2529: FREE(mc, M_DEVBUF);
2530: }
2531: }
CVSweb