diff --git a/sys/modules/Makefile b/sys/modules/Makefile index 61f9066..7b3aea9 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -103,6 +103,7 @@ SUBDIR= ${_3dfx} \ ${_ida} \ ${_ie} \ if_bridge \ + if_carp \ if_disc \ if_edsc \ if_ef \ diff --git a/sys/modules/if_carp/Makefile b/sys/modules/if_carp/Makefile new file mode 100644 index 0000000..a280b3d --- /dev/null +++ b/sys/modules/if_carp/Makefile @@ -0,0 +1,19 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../netinet + +KMOD= if_carp +SRCS= ip_carp.c +SRCS+= opt_carp.h opt_bpf.h opt_inet.h opt_inet6.h vnode_if.h + +.if !defined(KERNBUILDDIR) +opt_inet.h: + @echo "#define INET 1" > ${.TARGET} + +.if ${MK_INET6_SUPPORT} != "no" +opt_inet6.h: + @echo "#define INET6 1" > ${.TARGET} +.endif +.endif + +.include diff --git a/sys/net/if.c b/sys/net/if.c index 4d4b676..8c51af6 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -87,9 +87,6 @@ #include #include #endif -#ifdef DEV_CARP -#include -#endif #include @@ -114,6 +111,7 @@ SYSCTL_INT(_net_link, OID_AUTO, log_link_state_change, CTLFLAG_RW, void (*bstp_linkstate_p)(struct ifnet *ifp, int state); void (*ng_ether_link_state_p)(struct ifnet *ifp, int state); void (*lagg_linkstate_p)(struct ifnet *ifp, int state); +void (*carp_linkstate_p)(struct ifnet *ifp); struct mbuf *(*tbr_dequeue_ptr)(struct ifaltq *, int) = NULL; @@ -1582,10 +1580,9 @@ if_unroute(struct ifnet *ifp, int flag, int fam) pfctlinput(PRC_IFDOWN, ifa->ifa_addr); ifp->if_qflush(ifp); -#ifdef DEV_CARP if (ifp->if_carp) - carp_carpdev_state(ifp->if_carp); -#endif + (*carp_linkstate_p)(ifp); + rt_ifmsg(ifp); } @@ -1606,10 +1603,8 @@ if_route(struct ifnet *ifp, int flag, int fam) TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family)) pfctlinput(PRC_IFUP, ifa->ifa_addr); -#ifdef DEV_CARP if (ifp->if_carp) - carp_carpdev_state(ifp->if_carp); -#endif + (*carp_linkstate_p)(ifp); rt_ifmsg(ifp); #ifdef INET6 in6_if_up(ifp); @@ -1660,10 +1655,8 @@ do_link_state_change(void *arg, int pending) if ((ifp->if_type == IFT_ETHER || ifp->if_type == IFT_L2VLAN) && IFP2AC(ifp)->ac_netgraph != NULL) (*ng_ether_link_state_p)(ifp, link_state); -#ifdef DEV_CARP if (ifp->if_carp) - carp_carpdev_state(ifp->if_carp); -#endif + (*carp_linkstate_p)(ifp); if (ifp->if_bridge) { KASSERT(bstp_linkstate_p != NULL,("if_bridge bstp not loaded!")); (*bstp_linkstate_p)(ifp, link_state); diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c index ef8cf5b..2c6edb5 100644 --- a/sys/net/if_bridge.c +++ b/sys/net/if_bridge.c @@ -122,9 +122,6 @@ __FBSDID("$FreeBSD$"); #include #include #endif -#ifdef DEV_CARP -#include -#endif #include #include /* for struct arpcom */ #include @@ -2127,6 +2124,8 @@ drop: m_freem(m); } +int (*carp_forus_p)(struct carp_if *, u_char *); + /* * bridge_input: * @@ -2235,17 +2234,12 @@ bridge_input(struct ifnet *ifp, struct mbuf *m) return (m); } -#ifdef DEV_CARP -# define OR_CARP_CHECK_WE_ARE_DST(iface) \ +#define OR_CARP_CHECK_WE_ARE_DST(iface) \ || ((iface)->if_carp \ - && carp_forus((iface)->if_carp, eh->ether_dhost)) -# define OR_CARP_CHECK_WE_ARE_SRC(iface) \ + && (*carp_forus_p)((iface)->if_carp, eh->ether_dhost)) +#define OR_CARP_CHECK_WE_ARE_SRC(iface) \ || ((iface)->if_carp \ - && carp_forus((iface)->if_carp, eh->ether_shost)) -#else -# define OR_CARP_CHECK_WE_ARE_DST(iface) -# define OR_CARP_CHECK_WE_ARE_SRC(iface) -#endif + && (*carp_forus_p)((iface)->if_carp, eh->ether_shost)) #ifdef INET6 # define OR_PFIL_HOOKED_INET6 \ diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index 38bf7d4..ca62352 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -81,10 +81,6 @@ #include #endif -#ifdef DEV_CARP -#include -#endif - #ifdef IPX #include #include @@ -121,6 +117,9 @@ void (*ng_ether_attach_p)(struct ifnet *ifp); void (*ng_ether_detach_p)(struct ifnet *ifp); void (*vlan_input_p)(struct ifnet *, struct mbuf *); +int (*carp_forus_p)(struct ifnet *, u_char *); +int (*carp_output_p)(struct ifnet *, struct mbuf *, struct sockaddr *, + struct rtentry *); /* if_bridge(4) support */ struct mbuf *(*bridge_input_p)(struct ifnet *, struct mbuf *); @@ -396,11 +395,9 @@ ether_output(struct ifnet *ifp, struct mbuf *m, return (error); } -#ifdef DEV_CARP if (ifp->if_carp && - (error = carp_output(ifp, m, dst, NULL))) + (error = (*carp_output_p)(ifp, m, dst, NULL))) goto bad; -#endif /* Handle ng_ether(4) processing, if any */ if (IFP2AC(ifp)->ac_netgraph != NULL) { @@ -702,7 +699,6 @@ ether_input(struct ifnet *ifp, struct mbuf *m) return; } -#ifdef DEV_CARP /* * Clear M_PROMISC on frame so that carp(4) will see it when the * mbuf flows up to Layer 3. @@ -713,11 +709,9 @@ ether_input(struct ifnet *ifp, struct mbuf *m) * TODO: Maintain a hash table of ethernet addresses other than * ether_dhost which may be active on this ifp. */ - if (ifp->if_carp && carp_forus(ifp->if_carp, eh->ether_dhost)) { + if (ifp->if_carp && (*carp_forus_p)(ifp, eh->ether_dhost)) m->m_flags &= ~M_PROMISC; - } else -#endif - { + else { /* * If the frame received was not for our MAC address, set the * M_PROMISC flag on the mbuf chain. The frame may need to diff --git a/sys/netinet/if_ether.c b/sys/netinet/if_ether.c index 38e420e..fee8196 100644 --- a/sys/netinet/if_ether.c +++ b/sys/netinet/if_ether.c @@ -73,10 +73,6 @@ __FBSDID("$FreeBSD$"); #include #include -#ifdef DEV_CARP -#include -#endif - #include #define SIN(s) ((struct sockaddr_in *)s) @@ -116,6 +112,8 @@ static void arpintr(struct mbuf *); static void arptimer(void *); #ifdef INET static void in_arpinput(struct mbuf *); +int (*carp_iamatch_p)(struct ifnet *, struct in_ifaddr *, struct in_addr *, + u_int8_t **); #endif #ifndef VIMAGE_GLOBALS @@ -471,9 +469,7 @@ in_arpinput(struct mbuf *m) struct mbuf *m0; int req_len; int bridged = 0, is_bridge = 0; -#ifdef DEV_CARP int carp_match = 0; -#endif struct sockaddr_in sin; sin.sin_len = sizeof(struct sockaddr_in); sin.sin_family = AF_INET; @@ -510,14 +506,12 @@ in_arpinput(struct mbuf *m) ia->ia_ifp == ifp) && itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) goto match; -#ifdef DEV_CARP if (ifp->if_carp != NULL && - carp_iamatch(ifp->if_carp, ia, &isaddr, &enaddr) && + (*carp_iamatch_p)(ifp, ia, &isaddr, &enaddr) && itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) { carp_match = 1; goto match; } -#endif } LIST_FOREACH(ia, INADDR_HASH(isaddr.s_addr), ia_hash) if (((bridged && ia->ia_ifp->if_bridge != NULL) || @@ -599,11 +593,7 @@ match: IF_AFDATA_UNLOCK(ifp); if (la != NULL) { /* the following is not an error when doing bridging */ - if (!bridged && la->lle_tbl->llt_ifp != ifp -#ifdef DEV_CARP - && (ifp->if_type != IFT_CARP || !carp_match) -#endif - ) { + if (!bridged && la->lle_tbl->llt_ifp != ifp && !carp_match) { if (log_arp_wrong_iface) log(LOG_ERR, "arp: %s is on %s " "but got reply from %*D on %s\n", diff --git a/sys/netinet/in.c b/sys/netinet/in.c index bb3973c..de39b3f 100644 --- a/sys/netinet/in.c +++ b/sys/netinet/in.c @@ -794,13 +794,9 @@ in_ifinit(struct ifnet *ifp, struct in_ifaddr *ia, struct sockaddr_in *sin, ia->ia_net = i & ia->ia_netmask; ia->ia_subnet = i & ia->ia_subnetmask; in_socktrim(&ia->ia_sockmask); -#ifdef DEV_CARP - /* - * XXX: carp(4) does not have interface route - */ + /* XXX: a special case for carp(4) */ if (ifp->if_type == IFT_CARP) return (0); -#endif /* * Add route for the network. */ @@ -930,13 +926,12 @@ in_scrubprefix(struct in_ifaddr *target) * the route itself to it. Make sure that routing daemons * get a heads-up. * - * XXX: a special case for carp(4) interface + * XXX: a special case for carp(4) interface - this should be more + * generally specified as an interface that doesn't support + * such action. */ - if ((ia->ia_flags & IFA_ROUTE) == 0 -#ifdef DEV_CARP - && (ia->ia_ifp->if_type != IFT_CARP) -#endif - ) { + if ((ia->ia_flags & IFA_ROUTE) == 0 && + (ia->ia_ifp->if_type != IFT_CARP)) { rtinit(&(target->ia_ifa), (int)RTM_DELETE, rtinitflags(target)); target->ia_flags &= ~IFA_ROUTE; diff --git a/sys/netinet/in_proto.c b/sys/netinet/in_proto.c index c25f6eb..fdcfa4e 100644 --- a/sys/netinet/in_proto.c +++ b/sys/netinet/in_proto.c @@ -38,7 +38,6 @@ __FBSDID("$FreeBSD$"); #include "opt_inet6.h" #include "opt_route.h" #include "opt_pf.h" -#include "opt_carp.h" #include "opt_sctp.h" #include "opt_mpath.h" @@ -94,10 +93,6 @@ static struct pr_usrreqs nousrreqs; #include #endif -#ifdef DEV_CARP -#include -#endif - extern struct domain inetdomain; /* Spacer for loadable protocols. */ @@ -319,18 +314,6 @@ struct protosw inetsw[] = { .pr_usrreqs = &rip_usrreqs }, #endif /* DEV_PFSYNC */ -#ifdef DEV_CARP -{ - .pr_type = SOCK_RAW, - .pr_domain = &inetdomain, - .pr_protocol = IPPROTO_CARP, - .pr_flags = PR_ATOMIC|PR_ADDR, - .pr_input = carp_input, - .pr_output = (pr_output_t*)rip_output, - .pr_ctloutput = rip_ctloutput, - .pr_usrreqs = &rip_usrreqs -}, -#endif /* DEV_CARP */ /* Spacer n-times for loadable protocols. */ IPPROTOSPACER, IPPROTOSPACER, @@ -340,6 +323,7 @@ IPPROTOSPACER, IPPROTOSPACER, IPPROTOSPACER, IPPROTOSPACER, +IPPROTOSPACER, /* raw wildcard */ { .pr_type = SOCK_RAW, @@ -352,13 +336,16 @@ IPPROTOSPACER, }, }; +#define INETSW_SZ (sizeof(inetsw) / sizeof(inetsw[0])) +#define LAST_INETSW (&inetsw[INETSW_SZ]) + extern int in_inithead(void **, int); struct domain inetdomain = { .dom_family = AF_INET, .dom_name = "internet", .dom_protosw = inetsw, - .dom_protoswNPROTOSW = &inetsw[sizeof(inetsw)/sizeof(inetsw[0])], + .dom_protoswNPROTOSW = LAST_INETSW, #ifdef RADIX_MPATH .dom_rtattach = rn4_mpath_inithead, #else @@ -370,6 +357,45 @@ struct domain inetdomain = { .dom_ifdetach = in_domifdetach }; +/* XXX: these protos should be in a header file */ +int in_proto_register(struct protosw *); +int in_proto_unregister(short proto); + +int +in_proto_register(struct protosw *pr) { + struct protosw *prp = inetsw, *pr_targ = NULL; + + for (;prp <= LAST_INETSW;prp++) { + /* Q: Is it really reasonable to disallow more than one protocol + * handler for a given protocol? */ + if (prp->pr_protocol == pr->pr_protocol) + return EINVAL; + if (pr_targ == NULL && prp->pr_protocol == PROTO_SPACER) + pr_targ = prp; + } + + if (pr_targ == NULL) + return ENOSPC; + + memcpy(prp, pr, sizeof(*prp)); + return 0; +} + +int +in_proto_unregister(short proto) { + struct protosw *prp = inetsw; + + for (;prp <= LAST_INETSW;prp++) + if (prp->pr_protocol == proto) { + prp->pr_domain = &inetdomain; + prp->pr_usrreqs = &nousrreqs; + prp->pr_protocol = PROTO_SPACER; + return 0; + } + + return EEXIST; +} + DOMAIN_SET(inet); SYSCTL_NODE(_net, PF_INET, inet, CTLFLAG_RW, 0, @@ -395,6 +421,3 @@ SYSCTL_NODE(_net_inet, IPPROTO_RAW, raw, CTLFLAG_RW, 0, "RAW"); #ifdef DEV_PFSYNC SYSCTL_NODE(_net_inet, IPPROTO_PFSYNC, pfsync, CTLFLAG_RW, 0, "PFSYNC"); #endif -#ifdef DEV_CARP -SYSCTL_NODE(_net_inet, IPPROTO_CARP, carp, CTLFLAG_RW, 0, "CARP"); -#endif diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c index 33b5059..3295ff1 100644 --- a/sys/netinet/ip_carp.c +++ b/sys/netinet/ip_carp.c @@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -75,6 +76,9 @@ __FBSDID("$FreeBSD$"); #include #include #include + +extern int in_proto_register(struct protosw *); +extern int in_proto_unregister(short); #endif #ifdef INET6 @@ -84,6 +88,10 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include + +extern int in6_proto_register(struct ip6protosw *); +extern int in6_proto_unregister(short); #endif #include @@ -136,8 +144,27 @@ struct carp_softc { }; #define SC2IFP(sc) ((sc)->sc_ifp) +/* These are external networking stack hooks for CARP */ +/* net/if.c */ +extern void (*carp_linkstate_p)(struct ifnet *); +/* net/if_bridge.c net/if_ethersubr.c */ +extern struct ifnet *(*carp_forus_p)(struct ifnet *, u_char *); +/* net/if_ethersubr.c */ +extern int (*carp_output_p)(struct ifnet *, struct mbuf *, + struct sockaddr *, struct rtentry *); +/* netinet/if_ether.c */ +extern int (*carp_iamatch_p)(struct ifnet *, struct in_ifaddr *, + struct in_addr *, u_int8_t **); +#ifdef INET6 +extern struct ifaddr *(*carp_iamatch6_p)(struct ifnet *, struct in6_addr *); +extern caddr_t (*carp_macmatch6_p)(struct ifnet *, struct mbuf *, + const struct in6_addr *); +#endif + int carp_suppress_preempt = 0; int carp_opts[CARPCTL_MAXID] = { 0, 1, 0, 1, 0, 0 }; /* XXX for now */ + +SYSCTL_NODE(_net_inet, IPPROTO_CARP, carp, CTLFLAG_RW, 0, "CARP"); SYSCTL_INT(_net_inet_carp, CARPCTL_ALLOW, allow, CTLFLAG_RW, &carp_opts[CARPCTL_ALLOW], 0, "Accept incoming CARP packets"); SYSCTL_INT(_net_inet_carp, CARPCTL_PREEMPT, preempt, CTLFLAG_RW, @@ -1134,10 +1161,10 @@ carp_addrcount(struct carp_if *cif, struct in_ifaddr *ia, int type) } int -carp_iamatch(void *v, struct in_ifaddr *ia, +carp_iamatch(struct ifnet *ifp, struct in_ifaddr *ia, struct in_addr *isaddr, u_int8_t **enaddr) { - struct carp_if *cif = v; + struct carp_if *cif = ifp->if_carp; struct carp_softc *vh; int index, count = 0; struct ifaddr *ifa; @@ -1206,9 +1233,9 @@ carp_iamatch(void *v, struct in_ifaddr *ia, #ifdef INET6 struct ifaddr * -carp_iamatch6(void *v, struct in6_addr *taddr) +carp_iamatch6(struct ifnet *ifp, struct in6_addr *taddr) { - struct carp_if *cif = v; + struct carp_if *cif = ifp->if_carp; struct carp_softc *vh; struct ifaddr *ifa; @@ -1230,11 +1257,11 @@ carp_iamatch6(void *v, struct in6_addr *taddr) return (NULL); } -void * -carp_macmatch6(void *v, struct mbuf *m, const struct in6_addr *taddr) +caddr_t +carp_macmatch6(struct ifnet *ifp, struct mbuf *m, const struct in6_addr *taddr) { struct m_tag *mtag; - struct carp_if *cif = v; + struct carp_if *cif = ifp->if_carp; struct carp_softc *sc; struct ifaddr *ifa; @@ -1269,9 +1296,9 @@ carp_macmatch6(void *v, struct mbuf *m, const struct in6_addr *taddr) #endif struct ifnet * -carp_forus(void *v, void *dhost) +carp_forus(struct ifnet *ifp, u_char *dhost) { - struct carp_if *cif = v; + struct carp_if *cif = ifp->if_carp; struct carp_softc *vh; u_int8_t *ena = dhost; @@ -2167,9 +2194,9 @@ carp_set_state(struct carp_softc *sc, int state) } void -carp_carpdev_state(void *v) +carp_carpdev_state(struct ifnet *ifp) { - struct carp_if *cif = v; + struct carp_if *cif = ifp->if_carp; CARP_LOCK(cif); carp_carpdev_state_locked(cif); @@ -2221,6 +2248,35 @@ carp_sc_state_locked(struct carp_softc *sc) return; } +#ifdef INET +extern struct domain inetdomain; +static struct protosw carp_pr = { + .pr_type = SOCK_RAW, + .pr_domain = &inetdomain, + .pr_protocol = IPPROTO_CARP, + .pr_flags = PR_ATOMIC|PR_ADDR, + .pr_input = carp_input, + /* XXX: fix this type mismatch! */ + .pr_output = (pr_output_t *)rip_output, + .pr_ctloutput = rip_ctloutput, + .pr_usrreqs = &rip_usrreqs +}; +#endif + +#ifdef INET6 +extern struct domain inet6domain; +static struct ip6protosw carp_pr6 = { + .pr_type = SOCK_RAW, + .pr_domain = &inet6domain, + .pr_protocol = IPPROTO_CARP, + .pr_flags = PR_ATOMIC|PR_ADDR, + .pr_input = carp6_input, + .pr_output = rip6_output, + .pr_ctloutput = rip6_ctloutput, + .pr_usrreqs = &rip6_usrreqs +}; +#endif + static int carp_modevent(module_t mod, int type, void *data) { @@ -2233,9 +2289,29 @@ carp_modevent(module_t mod, int type, void *data) mtx_init(&carp_mtx, "carp_mtx", NULL, MTX_DEF); LIST_INIT(&carpif_list); if_clone_attach(&carp_cloner); + carp_linkstate_p = carp_carpdev_state; + carp_forus_p = carp_forus; + carp_output_p = carp_output; + carp_iamatch_p = carp_iamatch; +#ifdef INET6 + carp_iamatch6_p = carp_iamatch6; + carp_macmatch6_p = carp_macmatch6; + in6_proto_register(&carp_pr6); +#endif + in_proto_register(&carp_pr); break; case MOD_UNLOAD: + in_proto_unregister(IPPROTO_CARP); +#ifdef INET6 + in6_proto_unregister(IPPROTO_CARP); + carp_iamatch6_p = NULL; + carp_macmatch6_p = NULL; +#endif + carp_linkstate_p = NULL; + carp_forus_p = NULL; + carp_output_p = NULL; + carp_iamatch_p = NULL; EVENTHANDLER_DEREGISTER(ifnet_departure_event, if_detach_event_tag); if_clone_detach(&carp_cloner); mtx_destroy(&carp_mtx); diff --git a/sys/netinet/ip_carp.h b/sys/netinet/ip_carp.h index 47bb494..1e06806 100644 --- a/sys/netinet/ip_carp.h +++ b/sys/netinet/ip_carp.h @@ -157,15 +157,15 @@ struct carpreq { } #ifdef _KERNEL -void carp_carpdev_state(void *); +void carp_carpdev_state(struct ifnet *); void carp_input (struct mbuf *, int); int carp6_input (struct mbuf **, int *, int); int carp_output (struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *); -int carp_iamatch (void *, struct in_ifaddr *, struct in_addr *, +int carp_iamatch (struct ifnet *, struct in_ifaddr *, struct in_addr *, u_int8_t **); -struct ifaddr *carp_iamatch6(void *, struct in6_addr *); -void *carp_macmatch6(void *, struct mbuf *, const struct in6_addr *); -struct ifnet *carp_forus (void *, void *); +struct ifaddr *carp_iamatch6(struct ifnet *, struct in6_addr *); +caddr_t carp_macmatch6(struct ifnet *, struct mbuf *, const struct in6_addr *); +struct ifnet *carp_forus (struct ifnet *, u_char *); #endif #endif /* _IP_CARP_H */ diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index a294d0a..8356ab5 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -76,9 +76,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#ifdef DEV_CARP -#include -#endif #ifdef IPSEC #include #endif /* IPSEC */ @@ -574,9 +571,7 @@ passin: */ checkif = V_ip_checkinterface && (V_ipforwarding == 0) && ifp != NULL && ((ifp->if_flags & IFF_LOOPBACK) == 0) && -#ifdef DEV_CARP !ifp->if_carp && -#endif (dchg == 0); /* diff --git a/sys/netinet6/in6_proto.c b/sys/netinet6/in6_proto.c index 8908d67..e55c2ba 100644 --- a/sys/netinet6/in6_proto.c +++ b/sys/netinet6/in6_proto.c @@ -68,7 +68,6 @@ __FBSDID("$FreeBSD$"); #include "opt_ipsec.h" #include "opt_ipstealth.h" #include "opt_route.h" -#include "opt_carp.h" #include "opt_sctp.h" #include "opt_mpath.h" @@ -112,10 +111,6 @@ __FBSDID("$FreeBSD$"); #include #include -#ifdef DEV_CARP -#include -#endif - #ifdef SCTP #include #include @@ -142,6 +137,13 @@ static struct pr_usrreqs nousrreqs; #define PR_LISTEN 0 #define PR_ABRTACPTDIS 0 +#define IPPROTO6SPACER \ +{ \ + .pr_domain = &inet6domain, \ + .pr_protocol = PROTO6_SPACER, \ + .pr_usrreqs = &nousrreqs, \ +} + struct ip6protosw inet6sw[] = { { .pr_type = 0, @@ -323,18 +325,12 @@ struct ip6protosw inet6sw[] = { .pr_ctloutput = rip6_ctloutput, .pr_usrreqs = &rip6_usrreqs }, -#ifdef DEV_CARP -{ - .pr_type = SOCK_RAW, - .pr_domain = &inet6domain, - .pr_protocol = IPPROTO_CARP, - .pr_flags = PR_ATOMIC|PR_ADDR, - .pr_input = carp6_input, - .pr_output = rip6_output, - .pr_ctloutput = rip6_ctloutput, - .pr_usrreqs = &rip6_usrreqs -}, -#endif /* DEV_CARP */ +IPPROTO6SPACER, +IPPROTO6SPACER, +IPPROTO6SPACER, +IPPROTO6SPACER, +IPPROTO6SPACER, +IPPROTO6SPACER, /* raw wildcard */ { .pr_type = SOCK_RAW, @@ -349,12 +345,14 @@ struct ip6protosw inet6sw[] = { extern int in6_inithead(void **, int); +#define INET6SW_SZ (sizeof(inet6sw) / sizeof(inet6sw[0])) +#define LAST_INET6SW (&inet6sw[INET6SW_SZ]) + struct domain inet6domain = { .dom_family = AF_INET6, .dom_name = "internet6", .dom_protosw = (struct protosw *)inet6sw, - .dom_protoswNPROTOSW = (struct protosw *) - &inet6sw[sizeof(inet6sw)/sizeof(inet6sw[0])], + .dom_protoswNPROTOSW = (struct protosw *)LAST_INET6SW, #ifdef RADIX_MPATH .dom_rtattach = rn6_mpath_inithead, #else @@ -366,6 +364,43 @@ struct domain inet6domain = { .dom_ifdetach = in6_domifdetach }; +/* XXX: these should go in a header file */ +int in6_proto_register(struct ip6protosw *); +int in6_proto_unregister(short); + +int +in6_proto_register(struct ip6protosw *pr) { + struct ip6protosw *prp = inet6sw, *pr_targ = NULL; + + for (;prp <= LAST_INET6SW;prp++) { + if (prp->pr_protocol == pr->pr_protocol) + return EINVAL; + if (pr_targ == NULL && prp->pr_protocol == PROTO_SPACER) + pr_targ = prp; + } + + if (pr_targ == NULL) + return ENOSPC; + + memcpy(prp, pr, sizeof(*prp)); + return 0; +} + +int +in6_proto_unregister(short proto) { + struct ip6protosw *prp; + + for (prp = inet6sw;prp <= LAST_INET6SW;prp++) + if (prp->pr_protocol == proto) { + prp->pr_domain = &inet6domain; + prp->pr_usrreqs = &nousrreqs; + prp->pr_protocol = PROTO_SPACER; + return 0; + } + + return EEXIST; +} + DOMAIN_SET(inet6); /* diff --git a/sys/netinet6/ip6protosw.h b/sys/netinet6/ip6protosw.h index 2a7cea4..dd6d0d4 100644 --- a/sys/netinet6/ip6protosw.h +++ b/sys/netinet6/ip6protosw.h @@ -141,6 +141,14 @@ struct ip6protosw { #ifdef _KERNEL extern struct ip6protosw inet6sw[]; + +/* + * from sys/protosw.h: + * This number should be defined again within each protocol family to avoid + * confusion. + */ +#define PROTO6_SPACER 32767 /* spacer for loadable protocols */ + #endif #endif /* !_NETINET6_IP6PROTOSW_H_ */ diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c index c83a245..dea5032 100644 --- a/sys/netinet6/nd6_nbr.c +++ b/sys/netinet6/nd6_nbr.c @@ -76,10 +76,6 @@ __FBSDID("$FreeBSD$"); #include #include -#ifdef DEV_CARP -#include -#endif - #define SDL(s) ((struct sockaddr_dl *)s) struct dadq; @@ -91,6 +87,10 @@ static void nd6_dad_ns_output(struct dadq *, struct ifaddr *); static void nd6_dad_ns_input(struct ifaddr *); static void nd6_dad_na_input(struct ifaddr *); +struct ifaddr *(*carp_iamatch6_p)(struct ifnet *, struct in6_addr *); +caddr_t (*carp_macmatch6_p)(struct ifnet *, struct mbuf *, + const struct in6_addr *); + #ifdef VIMAGE_GLOBALS int dad_ignore_ns; int dad_maxtry; @@ -225,14 +225,12 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len) * (3) "tentative" address on which DAD is being performed. */ /* (1) and (3) check. */ -#ifdef DEV_CARP - if (ifp->if_carp) - ifa = carp_iamatch6(ifp->if_carp, &taddr6); - if (ifa == NULL) + if (ifp->if_carp) { + ifa = (*carp_iamatch6_p)(ifp, &taddr6); + if (ifa == NULL) + ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6); + } else ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6); -#else - ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6); -#endif /* (2) check. */ if (ifa == NULL) { @@ -1024,14 +1022,12 @@ nd6_na_output(struct ifnet *ifp, const struct in6_addr *daddr6_0, * my address) use lladdr configured for the interface. */ if (sdl0 == NULL) { -#ifdef DEV_CARP - if (ifp->if_carp) - mac = carp_macmatch6(ifp->if_carp, m, taddr6); - if (mac == NULL) + if (ifp->if_carp) { + mac = (*carp_macmatch6_p)(ifp, m, taddr6); + if (mac == NULL) + mac = nd6_ifptomac(ifp); + } else mac = nd6_ifptomac(ifp); -#else - mac = nd6_ifptomac(ifp); -#endif } else if (sdl0->sa_family == AF_LINK) { struct sockaddr_dl *sdl; sdl = (struct sockaddr_dl *)sdl0;