Date: Sat, 11 Jul 2009 21:46:20 +0000 (UTC) From: Kip Macy <kmacy@FreeBSD.org> To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r195623 - in user/kmacy/head_ppacket/sys: net netinet Message-ID: <200907112146.n6BLkK8f064060@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: kmacy Date: Sat Jul 11 21:46:20 2009 New Revision: 195623 URL: http://svn.freebsd.org/changeset/base/195623 Log: - provide reference counting for gre_softc - serialize access to gre_softc - take first pass at decoupling ip_gre from if_gre Modified: user/kmacy/head_ppacket/sys/net/if_gre.c user/kmacy/head_ppacket/sys/net/if_gre.h user/kmacy/head_ppacket/sys/netinet/ip_gre.c Modified: user/kmacy/head_ppacket/sys/net/if_gre.c ============================================================================== --- user/kmacy/head_ppacket/sys/net/if_gre.c Sat Jul 11 17:36:59 2009 (r195622) +++ user/kmacy/head_ppacket/sys/net/if_gre.c Sat Jul 11 21:46:20 2009 (r195623) @@ -86,9 +86,44 @@ #endif #include <net/bpf.h> - #include <net/if_gre.h> +struct gre_softc { + struct mtx gre_mtx; + int gre_unit; + /* + * refcount counts total references, not list external + * like rtentry as that has proven to be error-prone + */ + int gre_refcnt; + u_int gre_fibnum; /* use this fib for envelopes */ + struct route route; /* routing entry that determines, where a + encapsulated packet should go */ + const struct encaptab *encap; /* encapsulation cookie */ + + int called; /* infinite recursion preventer */ + + uint32_t key; /* key included in outgoing GRE packets */ + /* zero means none */ + +#define MTX_BUF_SIZE 32 + char sc_mtx_buf[MTX_BUF_SIZE]; + LIST_ENTRY(gre_softc) sc_list; + struct gre_softc_external gre_ext; +}; +#define gre_src gre_ext.g_src +#define gre_dst gre_ext.g_dst +#define gre_proto gre_ext.g_proto +#define gre_wccp_ver gre_ext.g_wccp_ver +LIST_HEAD(gre_softc_head, gre_softc); + +#define GRE_LOCK(sc) mtx_lock(&(sc)->gre_mtx); +#define GRE_UNLOCK(sc) mtx_unlock(&(sc)->gre_mtx); +#define GRE_ADDREF(sc) do { \ + GRE_LOCK(sc); \ + (sc)->gre_refcnt++; \ + GRE_UNLOCK(sc); \ + } while (0) /* * It is not easy to calculate the right value for a GRE MTU. * We leave this task to the admin and use the same default that @@ -188,6 +223,9 @@ gre_clone_create(ifc, unit, params) free(sc, M_GRE); return (ENOSPC); } + snprintf(sc->sc_mtx_buf, MTX_BUF_SIZE, "%s%d_mtx", ifc->ifc_name, unit); + mtx_init(&sc->gre_mtx, sc->sc_mtx_buf, NULL, MTX_DEF); + sc->gre_refcnt = 1; GRE2IFP(sc)->if_softc = sc; if_initname(GRE2IFP(sc), ifc->ifc_name, unit); @@ -199,13 +237,13 @@ gre_clone_create(ifc, unit, params) GRE2IFP(sc)->if_flags = IFF_POINTOPOINT|IFF_MULTICAST; GRE2IFP(sc)->if_output = gre_output; GRE2IFP(sc)->if_ioctl = gre_ioctl; - sc->g_dst.s_addr = sc->g_src.s_addr = INADDR_ANY; - sc->g_proto = IPPROTO_GRE; + sc->gre_dst.s_addr = sc->gre_src.s_addr = INADDR_ANY; + sc->gre_proto = IPPROTO_GRE; GRE2IFP(sc)->if_flags |= IFF_LINK0; sc->encap = NULL; sc->called = 0; sc->gre_fibnum = curthread->td_proc->p_fibnum; - sc->wccp_ver = WCCP_V1; + sc->gre_wccp_ver = WCCP_V1; sc->key = 0; if_attach(GRE2IFP(sc)); bpfattach(GRE2IFP(sc), DLT_NULL, sizeof(u_int32_t)); @@ -215,29 +253,43 @@ gre_clone_create(ifc, unit, params) return (0); } -static void -gre_clone_destroy(ifp) - struct ifnet *ifp; +void +gre_free(struct gre_softc *sc) { - struct gre_softc *sc = ifp->if_softc; + struct ifnet *ifp; - mtx_lock(&gre_mtx); - LIST_REMOVE(sc, sc_list); - mtx_unlock(&gre_mtx); + GRE_LOCK(sc); + (sc)->gre_refcnt--; + if ((sc)->gre_refcnt > 0) { + GRE_UNLOCK((sc)); + return; + } #ifdef INET if (sc->encap != NULL) encap_detach(sc->encap); #endif + ifp = GRE2IFP(sc); bpfdetach(ifp); if_detach(ifp); if_free(ifp); free(sc, M_GRE); } +static void +gre_clone_destroy(struct ifnet *ifp) +{ + struct gre_softc *sc = ifp->if_softc; + + mtx_lock(&gre_mtx); + LIST_REMOVE(sc, sc_list); + mtx_unlock(&gre_mtx); + gre_free(sc); +} + /* * The output routine. Takes a packet and encapsulates it in the protocol - * given by sc->g_proto. See also RFC 1701 and RFC 2004 + * given by sc->gre_proto. See also RFC 1701 and RFC 2004 */ static int gre_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, @@ -256,7 +308,8 @@ gre_output(struct ifnet *ifp, struct mbu struct mobile_h mob_h; u_int32_t af; int extra = 0; - + + GRE_LOCK(sc); /* * gre may cause infinite recursion calls when misconfigured. * We'll prevent this by introducing upper limit. @@ -271,7 +324,7 @@ gre_output(struct ifnet *ifp, struct mbu if (!((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING)) || - sc->g_src.s_addr == INADDR_ANY || sc->g_dst.s_addr == INADDR_ANY) { + sc->gre_src.s_addr == INADDR_ANY || sc->gre_dst.s_addr == INADDR_ANY) { m_freem(m); error = ENETDOWN; goto end; @@ -293,7 +346,7 @@ gre_output(struct ifnet *ifp, struct mbu m->m_flags &= ~(M_BCAST|M_MCAST); - if (sc->g_proto == IPPROTO_MOBILE) { + if (sc->gre_proto == IPPROTO_MOBILE) { if (dst->sa_family == AF_INET) { struct mbuf *m0; int msiz; @@ -313,19 +366,19 @@ gre_output(struct ifnet *ifp, struct mbu memset(&mob_h, 0, MOB_H_SIZ_L); mob_h.proto = (ip->ip_p) << 8; mob_h.odst = ip->ip_dst.s_addr; - ip->ip_dst.s_addr = sc->g_dst.s_addr; + ip->ip_dst.s_addr = sc->gre_dst.s_addr; /* * If the packet comes from our host, we only change * the destination address in the IP header. * Else we also need to save and change the source */ - if (in_hosteq(ip->ip_src, sc->g_src)) { + if (in_hosteq(ip->ip_src, sc->gre_src)) { msiz = MOB_H_SIZ_S; } else { mob_h.proto |= MOB_H_SBIT; mob_h.osrc = ip->ip_src.s_addr; - ip->ip_src.s_addr = sc->g_src.s_addr; + ip->ip_src.s_addr = sc->gre_src.s_addr; msiz = MOB_H_SIZ_L; } mob_h.proto = htons(mob_h.proto); @@ -365,13 +418,13 @@ gre_output(struct ifnet *ifp, struct mbu error = EINVAL; goto end; } - } else if (sc->g_proto == IPPROTO_GRE) { + } else if (sc->gre_proto == IPPROTO_GRE) { switch (dst->sa_family) { case AF_INET: ip = mtod(m, struct ip *); gre_ip_tos = ip->ip_tos; gre_ip_id = ip->ip_id; - if (sc->wccp_ver == WCCP_V2) { + if (sc->gre_wccp_ver == WCCP_V2) { extra = sizeof(uint32_t); etype = WCCP_PROTOCOL_TYPE; } else { @@ -417,7 +470,7 @@ gre_output(struct ifnet *ifp, struct mbu M_SETFIB(m, sc->gre_fibnum); /* The envelope may use a different FIB */ gh = mtod(m, struct greip *); - if (sc->g_proto == IPPROTO_GRE) { + if (sc->gre_proto == IPPROTO_GRE) { uint32_t *options = gh->gi_options; memset((void *)gh, 0, sizeof(struct greip) + extra); @@ -432,10 +485,10 @@ gre_output(struct ifnet *ifp, struct mbu } } - gh->gi_pr = sc->g_proto; - if (sc->g_proto != IPPROTO_MOBILE) { - gh->gi_src = sc->g_src; - gh->gi_dst = sc->g_dst; + gh->gi_pr = sc->gre_proto; + if (sc->gre_proto != IPPROTO_MOBILE) { + gh->gi_src = sc->gre_src; + gh->gi_dst = sc->gre_dst; ((struct ip*)gh)->ip_v = IPPROTO_IPV4; ((struct ip*)gh)->ip_hl = (sizeof(struct ip)) >> 2; ((struct ip*)gh)->ip_ttl = GRE_TTL; @@ -454,6 +507,7 @@ gre_output(struct ifnet *ifp, struct mbu error = ip_output(m, NULL, &sc->route, IP_FORWARDING, (struct ip_moptions *)NULL, (struct inpcb *)NULL); end: + GRE_UNLOCK(sc); sc->called = 0; if (error) ifp->if_oerrors++; @@ -467,7 +521,6 @@ gre_ioctl(struct ifnet *ifp, u_long cmd, struct if_laddrreq *lifr = (struct if_laddrreq *)data; struct in_aliasreq *aifr = (struct in_aliasreq *)data; struct gre_softc *sc = ifp->if_softc; - int s; struct sockaddr_in si; struct sockaddr *sa = NULL; int error, adj; @@ -477,7 +530,7 @@ gre_ioctl(struct ifnet *ifp, u_long cmd, error = 0; adj = 0; - s = splnet(); + GRE_LOCK(sc); switch (cmd) { case SIOCSIFADDR: ifp->if_flags |= IFF_UP; @@ -492,13 +545,13 @@ gre_ioctl(struct ifnet *ifp, u_long cmd, if ((error = priv_check(curthread, PRIV_NET_SETIFFLAGS)) != 0) break; if ((ifr->ifr_flags & IFF_LINK0) != 0) - sc->g_proto = IPPROTO_GRE; + sc->gre_proto = IPPROTO_GRE; else - sc->g_proto = IPPROTO_MOBILE; + sc->gre_proto = IPPROTO_MOBILE; if ((ifr->ifr_flags & IFF_LINK2) != 0) - sc->wccp_ver = WCCP_V2; + sc->gre_wccp_ver = WCCP_V2; else - sc->wccp_ver = WCCP_V1; + sc->gre_wccp_ver = WCCP_V1; goto recompute; case SIOCSIFMTU: /* @@ -573,8 +626,8 @@ gre_ioctl(struct ifnet *ifp, u_long cmd, */ if ((error = priv_check(curthread, PRIV_NET_GRE)) != 0) break; - sc->g_proto = ifr->ifr_flags; - switch (sc->g_proto) { + sc->gre_proto = ifr->ifr_flags; + switch (sc->gre_proto) { case IPPROTO_GRE: ifp->if_flags |= IFF_LINK0; break; @@ -587,7 +640,7 @@ gre_ioctl(struct ifnet *ifp, u_long cmd, } goto recompute; case GREGPROTO: - ifr->ifr_flags = sc->g_proto; + ifr->ifr_flags = sc->gre_proto; break; case GRESADDRS: case GRESADDRD: @@ -600,9 +653,9 @@ gre_ioctl(struct ifnet *ifp, u_long cmd, */ sa = &ifr->ifr_addr; if (cmd == GRESADDRS) - sc->g_src = (satosin(sa))->sin_addr; + sc->gre_src = (satosin(sa))->sin_addr; if (cmd == GRESADDRD) - sc->g_dst = (satosin(sa))->sin_addr; + sc->gre_dst = (satosin(sa))->sin_addr; recompute: #ifdef INET if (sc->encap != NULL) { @@ -610,8 +663,8 @@ gre_ioctl(struct ifnet *ifp, u_long cmd, sc->encap = NULL; } #endif - if ((sc->g_src.s_addr != INADDR_ANY) && - (sc->g_dst.s_addr != INADDR_ANY)) { + if ((sc->gre_src.s_addr != INADDR_ANY) && + (sc->gre_dst.s_addr != INADDR_ANY)) { bzero(&sp, sizeof(sp)); bzero(&sm, sizeof(sm)); bzero(&dp, sizeof(dp)); @@ -620,14 +673,14 @@ gre_ioctl(struct ifnet *ifp, u_long cmd, sizeof(struct sockaddr_in); sp.sin_family = sm.sin_family = dp.sin_family = dm.sin_family = AF_INET; - sp.sin_addr = sc->g_src; - dp.sin_addr = sc->g_dst; + sp.sin_addr = sc->gre_src; + dp.sin_addr = sc->gre_dst; sm.sin_addr.s_addr = dm.sin_addr.s_addr = INADDR_BROADCAST; #ifdef INET - sc->encap = encap_attach(AF_INET, sc->g_proto, + sc->encap = encap_attach(AF_INET, sc->gre_proto, sintosa(&sp), sintosa(&sm), sintosa(&dp), - sintosa(&dm), (sc->g_proto == IPPROTO_GRE) ? + sintosa(&dm), (sc->gre_proto == IPPROTO_GRE) ? &in_gre_protosw : &in_mobile_protosw, sc); if (sc->encap == NULL) printf("%s: unable to attach encap\n", @@ -645,7 +698,7 @@ gre_ioctl(struct ifnet *ifp, u_long cmd, memset(&si, 0, sizeof(si)); si.sin_family = AF_INET; si.sin_len = sizeof(struct sockaddr_in); - si.sin_addr.s_addr = sc->g_src.s_addr; + si.sin_addr.s_addr = sc->gre_src.s_addr; sa = sintosa(&si); ifr->ifr_addr = *sa; break; @@ -653,7 +706,7 @@ gre_ioctl(struct ifnet *ifp, u_long cmd, memset(&si, 0, sizeof(si)); si.sin_family = AF_INET; si.sin_len = sizeof(struct sockaddr_in); - si.sin_addr.s_addr = sc->g_dst.s_addr; + si.sin_addr.s_addr = sc->gre_dst.s_addr; sa = sintosa(&si); ifr->ifr_addr = *sa; break; @@ -674,8 +727,8 @@ gre_ioctl(struct ifnet *ifp, u_long cmd, error = EINVAL; break; } - sc->g_src = aifr->ifra_addr.sin_addr; - sc->g_dst = aifr->ifra_dstaddr.sin_addr; + sc->gre_src = aifr->ifra_addr.sin_addr; + sc->gre_dst = aifr->ifra_dstaddr.sin_addr; goto recompute; case SIOCSLIFPHYADDR: /* @@ -694,8 +747,8 @@ gre_ioctl(struct ifnet *ifp, u_long cmd, error = EINVAL; break; } - sc->g_src = (satosin(&lifr->addr))->sin_addr; - sc->g_dst = + sc->gre_src = (satosin(&lifr->addr))->sin_addr; + sc->gre_dst = (satosin(&lifr->dstaddr))->sin_addr; goto recompute; case SIOCDIFPHYADDR: @@ -705,49 +758,49 @@ gre_ioctl(struct ifnet *ifp, u_long cmd, */ if ((error = priv_check(curthread, PRIV_NET_SETIFPHYS)) != 0) break; - sc->g_src.s_addr = INADDR_ANY; - sc->g_dst.s_addr = INADDR_ANY; + sc->gre_src.s_addr = INADDR_ANY; + sc->gre_dst.s_addr = INADDR_ANY; goto recompute; case SIOCGLIFPHYADDR: - if (sc->g_src.s_addr == INADDR_ANY || - sc->g_dst.s_addr == INADDR_ANY) { + if (sc->gre_src.s_addr == INADDR_ANY || + sc->gre_dst.s_addr == INADDR_ANY) { error = EADDRNOTAVAIL; break; } memset(&si, 0, sizeof(si)); si.sin_family = AF_INET; si.sin_len = sizeof(struct sockaddr_in); - si.sin_addr.s_addr = sc->g_src.s_addr; + si.sin_addr.s_addr = sc->gre_src.s_addr; memcpy(&lifr->addr, &si, sizeof(si)); - si.sin_addr.s_addr = sc->g_dst.s_addr; + si.sin_addr.s_addr = sc->gre_dst.s_addr; memcpy(&lifr->dstaddr, &si, sizeof(si)); break; case SIOCGIFPSRCADDR: #ifdef INET6 case SIOCGIFPSRCADDR_IN6: #endif - if (sc->g_src.s_addr == INADDR_ANY) { + if (sc->gre_src.s_addr == INADDR_ANY) { error = EADDRNOTAVAIL; break; } memset(&si, 0, sizeof(si)); si.sin_family = AF_INET; si.sin_len = sizeof(struct sockaddr_in); - si.sin_addr.s_addr = sc->g_src.s_addr; + si.sin_addr.s_addr = sc->gre_src.s_addr; bcopy(&si, &ifr->ifr_addr, sizeof(ifr->ifr_addr)); break; case SIOCGIFPDSTADDR: #ifdef INET6 case SIOCGIFPDSTADDR_IN6: #endif - if (sc->g_dst.s_addr == INADDR_ANY) { + if (sc->gre_dst.s_addr == INADDR_ANY) { error = EADDRNOTAVAIL; break; } memset(&si, 0, sizeof(si)); si.sin_family = AF_INET; si.sin_len = sizeof(struct sockaddr_in); - si.sin_addr.s_addr = sc->g_dst.s_addr; + si.sin_addr.s_addr = sc->gre_dst.s_addr; bcopy(&si, &ifr->ifr_addr, sizeof(ifr->ifr_addr)); break; case GRESKEY: @@ -779,7 +832,7 @@ gre_ioctl(struct ifnet *ifp, u_long cmd, break; } - splx(s); + GRE_UNLOCK(sc); return (error); } @@ -802,7 +855,7 @@ gre_compute_route(struct gre_softc *sc) ro = &sc->route; memset(ro, 0, sizeof(struct route)); - ((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->g_dst; + ((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->gre_dst; ro->ro_dst.sa_family = AF_INET; ro->ro_dst.sa_len = sizeof(ro->ro_dst); @@ -843,7 +896,7 @@ gre_compute_route(struct gre_softc *sc) * the route and search one to this interface ... */ if ((GRE2IFP(sc)->if_flags & IFF_LINK1) == 0) - ((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->g_dst; + ((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->gre_dst; #ifdef DIAGNOSTIC printf(", choosing %s with gateway %s", if_name(ro->ro_rt->rt_ifp), @@ -883,6 +936,31 @@ gre_in_cksum(u_int16_t *p, u_int len) return (~sum); } +/* + * Find the gre interface associated with our src/dst/proto set. + * + */ +struct gre_softc * +gre_lookup(struct mbuf *m, u_char proto, + int (*func)(struct gre_softc_external *, struct mbuf *, u_char)) +{ + struct gre_softc *sc; + + mtx_lock(&gre_mtx); + for (sc = LIST_FIRST(&gre_softc_list); sc != NULL; + sc = LIST_NEXT(sc, sc_list)) { + if (func(&sc->gre_ext, m, proto) && + ((GRE2IFP(sc)->if_flags & IFF_UP) != 0)) { + GRE_ADDREF(sc); + mtx_unlock(&gre_mtx); + return (sc); + } + } + mtx_unlock(&gre_mtx); + + return (NULL); +} + static int gremodevent(module_t mod, int type, void *data) { Modified: user/kmacy/head_ppacket/sys/net/if_gre.h ============================================================================== --- user/kmacy/head_ppacket/sys/net/if_gre.h Sat Jul 11 17:36:59 2009 (r195622) +++ user/kmacy/head_ppacket/sys/net/if_gre.h Sat Jul 11 21:46:20 2009 (r195623) @@ -54,30 +54,19 @@ typedef enum { WCCP_V2 } wccp_ver_t; -struct gre_softc { - struct ifnet *sc_ifp; - LIST_ENTRY(gre_softc) sc_list; - int gre_unit; - int gre_flags; - u_int gre_fibnum; /* use this fib for envelopes */ +/* + * The binary contract is to have the ifp at the front of the softc + * + */ +#define GRE2IFP(sc) (*(struct ifnet **)(&sc)) +struct gre_softc_external { + struct ifnet *gre_ifp; struct in_addr g_src; /* source address of gre packets */ struct in_addr g_dst; /* destination address of gre packets */ - struct route route; /* routing entry that determines, where a - encapsulated packet should go */ u_char g_proto; /* protocol of encapsulator */ - - const struct encaptab *encap; /* encapsulation cookie */ - - int called; /* infinite recursion preventer */ - - uint32_t key; /* key included in outgoing GRE packets */ - /* zero means none */ - - wccp_ver_t wccp_ver; /* version of the WCCP */ + wccp_ver_t g_wccp_ver; /* version of the WCCP */ }; -#define GRE2IFP(sc) ((sc)->sc_ifp) - - + struct gre_h { u_int16_t flags; /* GRE flags */ u_int16_t ptype; /* protocol type of payload typically @@ -184,11 +173,11 @@ struct mobip_h { #define GRESKEY _IOW('i', 108, struct ifreq) #ifdef _KERNEL -LIST_HEAD(gre_softc_head, gre_softc); -extern struct mtx gre_mtx; -extern struct gre_softc_head gre_softc_list; - +struct gre_softc; u_int16_t gre_in_cksum(u_int16_t *, u_int); +struct gre_softc *gre_lookup(struct mbuf *m, u_char proto, + int (*func)(struct gre_softc_external *, struct mbuf *, u_char)); +void gre_free(struct gre_softc *sc); #endif /* _KERNEL */ #endif Modified: user/kmacy/head_ppacket/sys/netinet/ip_gre.c ============================================================================== --- user/kmacy/head_ppacket/sys/netinet/ip_gre.c Sat Jul 11 17:36:59 2009 (r195622) +++ user/kmacy/head_ppacket/sys/netinet/ip_gre.c Sat Jul 11 21:46:20 2009 (r195623) @@ -91,35 +91,14 @@ __FBSDID("$FreeBSD$"); #include <machine/stdarg.h> -#if 1 -void gre_inet_ntoa(struct in_addr in); /* XXX */ -#endif - -static struct gre_softc *gre_lookup(struct mbuf *, u_int8_t); - -static struct mbuf *gre_input2(struct mbuf *, int, u_char); - -/* - * De-encapsulate a packet and feed it back through ip input (this - * routine is called whenever IP gets a packet with proto type - * IPPROTO_GRE and a local destination address). - * This really is simple - */ -void -gre_input(struct mbuf *m, int off) +static int +gre_input_lookup_func(struct gre_softc_external *sc, struct mbuf *m, u_char proto) { - int proto; - - proto = (mtod(m, struct ip *))->ip_p; - - m = gre_input2(m, off, proto); + struct ip *ip = mtod(m, struct ip *); - /* - * If no matching tunnel that is up is found. We inject - * the mbuf to raw ip socket to see if anyone picks it up. - */ - if (m != NULL) - rip_input(m, off); + return ((sc->g_dst.s_addr == ip->ip_src.s_addr) && + (sc->g_src.s_addr == ip->ip_dst.s_addr) && + (sc->g_proto == proto)); } /* @@ -137,15 +116,15 @@ gre_input2(struct mbuf *m ,int hlen, u_c u_int16_t flags; u_int32_t af; - if ((sc = gre_lookup(m, proto)) == NULL) { + if ((sc = gre_lookup(m, proto, gre_input_lookup_func)) == NULL) { /* No matching tunnel or tunnel is down. */ return (m); } if (m->m_len < sizeof(*gip)) { m = m_pullup(m, sizeof(*gip)); - if (m == NULL) - return (NULL); + if (m == NULL) + goto done; } gip = mtod(m, struct greip *); @@ -164,7 +143,7 @@ gre_input2(struct mbuf *m ,int hlen, u_c hlen += 4; /* We don't support routing fields (variable length) */ if (flags & GRE_RP) - return (m); + goto done; if (flags & GRE_KP) hlen += 4; if (flags & GRE_SP) @@ -172,7 +151,7 @@ gre_input2(struct mbuf *m ,int hlen, u_c switch (ntohs(gip->gi_ptype)) { /* ethertypes */ case WCCP_PROTOCOL_TYPE: - if (sc->wccp_ver == WCCP_V2) + if (((struct gre_softc_external *)sc)->g_wccp_ver == WCCP_V2) hlen += 4; /* FALLTHROUGH */ case ETHERTYPE_IP: /* shouldn't need a schednetisr(), */ @@ -193,17 +172,18 @@ gre_input2(struct mbuf *m ,int hlen, u_c #endif default: /* Others not yet supported. */ - return (m); + goto done; } break; default: /* Others not yet supported. */ - return (m); + goto done; } if (hlen > m->m_pkthdr.len) { m_freem(m); - return (NULL); + m = NULL; + goto done; } /* Unlike NetBSD, in FreeBSD m_adj() adjusts m->m_pkthdr.len as well */ m_adj(m, hlen); @@ -213,11 +193,37 @@ gre_input2(struct mbuf *m ,int hlen, u_c } m->m_pkthdr.rcvif = GRE2IFP(sc); - + gre_free(sc); netisr_queue(isr, m); /* Packet is done, no further processing needed. */ return (NULL); +done: + gre_free(sc); + return (m); +} + +/* + * De-encapsulate a packet and feed it back through ip input (this + * routine is called whenever IP gets a packet with proto type + * IPPROTO_GRE and a local destination address). + * This really is simple + */ +void +gre_input(struct mbuf *m, int off) +{ + int proto; + + proto = (mtod(m, struct ip *))->ip_p; + + m = gre_input2(m, off, proto); + + /* + * If no matching tunnel that is up is found. We inject + * the mbuf to raw ip socket to see if anyone picks it up. + */ + if (m != NULL) + rip_input(m, off); } /* @@ -226,7 +232,6 @@ gre_input2(struct mbuf *m ,int hlen, u_c * encapsulating header was not prepended, but instead inserted * between IP header and payload */ - void gre_mobile_input(struct mbuf *m, int hlen) { @@ -235,7 +240,7 @@ gre_mobile_input(struct mbuf *m, int hle struct gre_softc *sc; int msiz; - if ((sc = gre_lookup(m, IPPROTO_MOBILE)) == NULL) { + if ((sc = gre_lookup(m, IPPROTO_MOBILE, gre_input_lookup_func)) == NULL) { /* No matching tunnel or tunnel is down. */ m_freem(m); return; @@ -244,7 +249,7 @@ gre_mobile_input(struct mbuf *m, int hle if (m->m_len < sizeof(*mip)) { m = m_pullup(m, sizeof(*mip)); if (m == NULL) - return; + goto done; } ip = mtod(m, struct ip *); mip = mtod(m, struct mobip_h *); @@ -261,7 +266,7 @@ gre_mobile_input(struct mbuf *m, int hle if (m->m_len < (ip->ip_hl << 2) + msiz) { m = m_pullup(m, (ip->ip_hl << 2) + msiz); if (m == NULL) - return; + goto done; ip = mtod(m, struct ip *); mip = mtod(m, struct mobip_h *); } @@ -271,7 +276,7 @@ gre_mobile_input(struct mbuf *m, int hle if (gre_in_cksum((u_int16_t *)&mip->mh, msiz) != 0) { m_freem(m); - return; + goto done; } bcopy((caddr_t)(ip) + (ip->ip_hl << 2) + msiz, (caddr_t)(ip) + @@ -297,38 +302,8 @@ gre_mobile_input(struct mbuf *m, int hle } m->m_pkthdr.rcvif = GRE2IFP(sc); - netisr_queue(NETISR_IP, m); -} - -/* - * Find the gre interface associated with our src/dst/proto set. - * - * XXXRW: Need some sort of drain/refcount mechanism so that the softc - * reference remains valid after it's returned from gre_lookup(). Right - * now, I'm thinking it should be reference-counted with a gre_dropref() - * when the caller is done with the softc. This is complicated by how - * to handle destroying the gre softc; probably using a gre_drain() in - * in_gre.c during destroy. - */ -static struct gre_softc * -gre_lookup(struct mbuf *m, u_int8_t proto) -{ - struct ip *ip = mtod(m, struct ip *); - struct gre_softc *sc; - mtx_lock(&gre_mtx); - for (sc = LIST_FIRST(&gre_softc_list); sc != NULL; - sc = LIST_NEXT(sc, sc_list)) { - if ((sc->g_dst.s_addr == ip->ip_src.s_addr) && - (sc->g_src.s_addr == ip->ip_dst.s_addr) && - (sc->g_proto == proto) && - ((GRE2IFP(sc)->if_flags & IFF_UP) != 0)) { - mtx_unlock(&gre_mtx); - return (sc); - } - } - mtx_unlock(&gre_mtx); - - return (NULL); +done: + gre_free(sc); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200907112146.n6BLkK8f064060>