void gre_mobile_input(struct mbuf *m, int hlen) { struct ip *ip; struct mobip_h *mip; struct gre_softc *sc; int msiz; if ((sc = gre_lookup(m, IPPROTO_MOBILE)) == NULL) { /* No matching tunnel or tunnel is down. */ m_freem(m); return; } if (m->m_len < sizeof(*mip)) { m = m_pullup(m, sizeof(*mip)); if (m == NULL) return; } ip = mtod(m, struct ip *); mip = mtod(m, struct mobip_h *); GRE2IFP(sc)->if_ipackets++; GRE2IFP(sc)->if_ibytes += m->m_pkthdr.len; if (ntohs(mip->mh.proto) & MOB_H_SBIT) { msiz = MOB_H_SIZ_L; mip->mi.ip_src.s_addr = mip->mh.osrc; } else msiz = MOB_H_SIZ_S; if (m->m_len < (ip->ip_hl << 2) + msiz) { m = m_pullup(m, (ip->ip_hl << 2) + msiz); if (m == NULL) return; ip = mtod(m, struct ip *); mip = mtod(m, struct mobip_h *); }
int gre_mobile_input(struct mbuf **mp, int *offp, int proto) { static const uint32_t af = AF_INET; struct mbuf *m = *mp; struct ip *ip = mtod(m, struct ip *); struct mobip_h *mip = mtod(m, struct mobip_h *); struct gre_softc *sc; u_char osrc = 0; int msiz, hlen; hlen = *offp; if ((sc = gre_lookup(m, IPPROTO_MOBILE)) == NULL) { /* No matching tunnel or tunnel is down. */ m_freem(m); return(IPPROTO_DONE); } sc->sc_if.if_ipackets++; sc->sc_if.if_ibytes += m->m_pkthdr.len; if(ntohs(mip->mh.proto) & MOB_H_SBIT) { osrc = 1; msiz = MOB_H_SIZ_L; mip->mi.ip_src.s_addr = mip->mh.osrc; } else { msiz = MOB_H_SIZ_S; } mip->mi.ip_dst.s_addr = mip->mh.odst; mip->mi.ip_p = (ntohs(mip->mh.proto) >> 8); if (gre_in_cksum((u_short*)&mip->mh,msiz) != 0) { m_freem(m); return(IPPROTO_DONE); } bcopy((caddr_t)(ip) + (ip->ip_hl << 2) + msiz, (caddr_t)(ip) + (ip->ip_hl << 2), m->m_len - msiz - (ip->ip_hl << 2)); m->m_len -= msiz; m->m_pkthdr.len -= msiz; /* * On FreeBSD, rip_input() supplies us with ip->ip_len * already converted into host byteorder and also decreases * it by the lengh of IP header, however, ip_input() expects * that this field is in the original format (network byteorder * and full size of IP packet), so that adjust accordingly. */ ip->ip_len = htons(ip->ip_len + sizeof(struct ip) - msiz); ip->ip_sum = 0; ip->ip_sum = in_cksum(m, (ip->ip_hl << 2)); if (sc->sc_if.if_bpf) bpf_ptap(sc->sc_if.if_bpf, m, &af, sizeof(af)); m->m_pkthdr.rcvif = &sc->sc_if; netisr_queue(NETISR_IP, m); return(IPPROTO_DONE); }
static int gre_input2(struct mbuf *m ,int hlen, u_char proto) { static const uint32_t af = AF_INET; struct greip *gip = mtod(m, struct greip *); int isr; struct gre_softc *sc; u_short flags; if ((sc = gre_lookup(m, proto)) == NULL) { /* No matching tunnel or tunnel is down. */ return (0); } sc->sc_if.if_ipackets++; sc->sc_if.if_ibytes += m->m_pkthdr.len; switch (proto) { case IPPROTO_GRE: hlen += sizeof (struct gre_h); /* process GRE flags as packet can be of variable len */ flags = ntohs(gip->gi_flags); /* Checksum & Offset are present */ if ((flags & GRE_CP) | (flags & GRE_RP)) hlen += 4; /* We don't support routing fields (variable length) */ if (flags & GRE_RP) return(0); if (flags & GRE_KP) hlen += 4; if (flags & GRE_SP) hlen +=4; switch (ntohs(gip->gi_ptype)) { /* ethertypes */ case ETHERTYPE_IP: case WCCP_PROTOCOL_TYPE: isr = NETISR_IP; break; #ifdef NETATALK case ETHERTYPE_ATALK: isr = NETISR_ATALK1; break; #endif case ETHERTYPE_IPV6: /* FALLTHROUGH */ default: /* others not yet supported */ return(0); } break; default: /* others not yet supported */ return(0); } m->m_data += hlen; m->m_len -= hlen; m->m_pkthdr.len -= hlen; if (sc->sc_if.if_bpf) bpf_ptap(sc->sc_if.if_bpf, m, &af, sizeof(af)); m->m_pkthdr.rcvif = &sc->sc_if; netisr_queue(isr, m); return(1); /* packet is done, no further processing needed */ }
/* * Decapsulate. Does the real work and is called from gre_input() * (above). Returns an mbuf back if packet is not yet processed, * and NULL if it needs no further processing. proto is the protocol * number of the "calling" foo_input() routine. */ static struct mbuf * gre_input2(struct mbuf *m ,int hlen, u_char proto) { struct greip *gip; int isr; struct gre_softc *sc; u_int16_t flags; u_int32_t af; if ((sc = gre_lookup(m, proto)) == 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); } gip = mtod(m, struct greip *); GRE2IFP(sc)->if_ipackets++; GRE2IFP(sc)->if_ibytes += m->m_pkthdr.len; switch (proto) { case IPPROTO_GRE: hlen += sizeof(struct gre_h); /* process GRE flags as packet can be of variable len */ flags = ntohs(gip->gi_flags); /* Checksum & Offset are present */ if ((flags & GRE_CP) | (flags & GRE_RP)) hlen += 4; /* We don't support routing fields (variable length) */ if (flags & GRE_RP) return (m); if (flags & GRE_KP) hlen += 4; if (flags & GRE_SP) hlen += 4; switch (ntohs(gip->gi_ptype)) { /* ethertypes */ case WCCP_PROTOCOL_TYPE: if (sc->wccp_ver == WCCP_V2) hlen += 4; /* FALLTHROUGH */ case ETHERTYPE_IP: /* shouldn't need a schednetisr(), */ isr = NETISR_IP;/* as we are in ip_input */ af = AF_INET; break; #ifdef INET6 case ETHERTYPE_IPV6: isr = NETISR_IPV6; af = AF_INET6; break; #endif #ifdef NETATALK case ETHERTYPE_ATALK: isr = NETISR_ATALK1; af = AF_APPLETALK; break; #endif default: /* Others not yet supported. */ return (m); } break; default: /* Others not yet supported. */ return (m); } if (hlen > m->m_pkthdr.len) { m_freem(m); return (NULL); } /* Unlike NetBSD, in FreeBSD m_adj() adjusts m->m_pkthdr.len as well */ m_adj(m, hlen); if (bpf_peers_present(GRE2IFP(sc)->if_bpf)) { bpf_mtap2(GRE2IFP(sc)->if_bpf, &af, sizeof(af), m); } if ((GRE2IFP(sc)->if_flags & IFF_MONITOR) != 0) { m_freem(m); return(NULL); } m->m_pkthdr.rcvif = GRE2IFP(sc); netisr_queue(isr, m); /* Packet is done, no further processing needed. */ return (NULL); }
static int gre_input2(struct mbuf *m ,int hlen, u_char proto) { struct greip *gip = mtod(m, struct greip *); int s; struct ifqueue *ifq; struct gre_softc *sc; u_short flags; if ((sc = gre_lookup(m, proto)) == NULL) { /* No matching tunnel or tunnel is down. */ return (0); } sc->sc_if.if_ipackets++; sc->sc_if.if_ibytes += m->m_pkthdr.len; switch (proto) { case IPPROTO_GRE: hlen += sizeof (struct gre_h); /* process GRE flags as packet can be of variable len */ flags = ntohs(gip->gi_flags); /* Checksum & Offset are present */ if ((flags & GRE_CP) | (flags & GRE_RP)) hlen += 4; /* We don't support routing fields (variable length) */ if (flags & GRE_RP) return(0); if (flags & GRE_KP) hlen += 4; if (flags & GRE_SP) hlen +=4; switch (ntohs(gip->gi_ptype)) { /* ethertypes */ case ETHERTYPE_IP: /* shouldn't need a schednetisr(), as */ case WCCP_PROTOCOL_TYPE: /* we are in ip_input */ ifq = &ipintrq; break; #ifdef NS case ETHERTYPE_NS: ifq = &nsintrq; schednetisr(NETISR_NS); break; #endif #ifdef NETATALK case ETHERTYPE_ATALK: ifq = &atintrq1; schednetisr(NETISR_ATALK); break; #endif case ETHERTYPE_IPV6: /* FALLTHROUGH */ default: /* others not yet supported */ return(0); } break; default: /* others not yet supported */ return(0); } m->m_data += hlen; m->m_len -= hlen; m->m_pkthdr.len -= hlen; if (sc->sc_if.if_bpf) { struct mbuf m0; u_int32_t af = AF_INET; m0.m_next = m; m0.m_len = 4; m0.m_data = (char *)⁡ BPF_MTAP(&(sc->sc_if), &m0); } m->m_pkthdr.rcvif = &sc->sc_if; s = splnet(); /* possible */ if (_IF_QFULL(ifq)) { _IF_DROP(ifq); m_freem(m); } else { IF_ENQUEUE(ifq,m); } splx(s); return(1); /* packet is done, no further processing needed */ }
/* * Decapsulate. Does the real work and is called from in_gre_input() * (above) or ipv4_infilter(), Returns an mbuf back if packet is not * yet processed, and NULL if it needs no further processing. * proto is the protocol number of the "calling" foo_input() routine. */ mbuf_t in_gre_input(mbuf_t m, int hlen) { struct greip *gip; struct gre_softc *sc; u_int16_t flags; //static u_int32_t af; //u_int8_t proto; //proto = ((struct ip *)mbuf_data(m))->ip_p; if ((sc = gre_lookup(m, IPPROTO_GRE)) == NULL) { /* No matching tunnel or tunnel is down. */ return m; } /* from here on, we increased the sc->sc_refcnt, so do remember to decrease it before return */ if (mbuf_len(m) < sizeof(struct greip)) { mbuf_pullup(&m, sizeof(struct greip)); if (m == NULL) goto done; } gip = mbuf_data(m); //switch (proto) { // case IPPROTO_GRE: hlen += sizeof(struct gre_h); /* process GRE flags as packet can be of variable len */ flags = ntohs(gip->gi_flags); /* Checksum & Offset are present */ if ((flags & GRE_CP) | (flags & GRE_RP)) hlen += 4; /* We don't support routing fields (variable length) */ if (flags & GRE_RP) goto done; if (flags & GRE_KP) hlen += 4; if (flags & GRE_SP) hlen += 4; switch (ntohs(gip->gi_ptype)) { /* ethertypes */ case WCCP_PROTOCOL_TYPE: if (sc->wccp_ver == WCCP_V2) hlen += 4; /* FALLTHROUGH */ case ETHERTYPE_IP: //af = AF_INET; break; case ETHERTYPE_IPV6: //af = AF_INET6; break; //case ETHERTYPE_AT: // af = AF_APPLETALK; // break; default: /* Others not yet supported. */ goto done; } // break; // default: /* Others not yet supported. */ // goto done; //} if (hlen > mbuf_pkthdr_len(m)) { /* not a valid GRE packet */ mbuf_freem(m); m = NULL; goto done; } /* Unlike NetBSD, in FreeBSD(as well as Darwin) m_adj() adjusts mbuf_pkthdr_len(m) as well */ mbuf_adj(m, hlen); mbuf_pkthdr_setrcvif(m, sc->sc_ifp); mbuf_pkthdr_setheader(m, NULL); //mbuf_pkthdr_setheader(m, &af); /* it's ugly... */ struct ifnet_stat_increment_param incs; bzero(&incs, sizeof(incs)); incs.packets_in = 1; incs.bytes_in = mbuf_pkthdr_len(m); ifnet_input(sc->sc_ifp, m, &incs); m = NULL; /* ifnet_input() has freed the mbuf */ done: /* since we got sc->sc_refcnt add by one, we decrease it when done */ gre_sc_release(sc); return m; }
/* * input routine for IPPRPOTO_MOBILE * This is a little bit diffrent from the other modes, as the * encapsulating header was not prepended, but instead inserted * between IP header and payload */ mbuf_t in_mobile_input(mbuf_t m, int hlen) { #ifdef DEBUG printf("%s: got packet\n", __FUNCTION__); #endif struct ip *ip; struct mobip_h *mip; struct gre_softc *sc; int msiz; if ((sc = gre_lookup(m, IPPROTO_MOBILE)) == NULL) { /* No matching tunnel or tunnel is down. */ return m; } /* from here on, we increased the sc->sc_refcnt, so do remember to decrease it before return */ if (mbuf_len(m) < sizeof(*mip)) { mbuf_pullup(&m, sizeof(*mip)); if (m == NULL) goto done; } ip = mbuf_data(m); mip = mbuf_data(m); if (ntohs(mip->mh.proto) & MOB_H_SBIT) { msiz = MOB_H_SIZ_L; mip->mi.ip_src.s_addr = mip->mh.osrc; } else msiz = MOB_H_SIZ_S; if (mbuf_len(m) < (ip->ip_hl << 2) + msiz) { mbuf_pullup(&m, (ip->ip_hl << 2) + msiz); if (m == NULL) goto done; ip = mbuf_data(m); mip = mbuf_data(m); } mip->mi.ip_dst.s_addr = mip->mh.odst; mip->mi.ip_p = (ntohs(mip->mh.proto) >> 8); if (gre_in_cksum((u_int16_t *)&mip->mh, msiz) != 0) { mbuf_freem(m); m = NULL; goto done; } bcopy((caddr_t)(ip) + (ip->ip_hl << 2) + msiz, (caddr_t)(ip) + (ip->ip_hl << 2), mbuf_len(m) - msiz - (ip->ip_hl << 2)); mbuf_setdata(m, mbuf_data(m), mbuf_len(m) - msiz); mbuf_pkthdr_adjustlen(m, - msiz); /* * On FreeBSD, rip_input() supplies us with ip->ip_len * already converted into host byteorder and also decreases * it by the lengh of IP header, however, ip_input() expects * that this field is in the original format (network byteorder * and full size of IP packet), so that adjust accordingly. */ ip->ip_len = htons(ip->ip_len + sizeof(struct ip) - msiz); ip->ip_sum = 0; ip->ip_sum = in_cksum(m, (ip->ip_hl << 2)); mbuf_pkthdr_setrcvif(m, sc->sc_ifp); mbuf_pkthdr_setheader(m, NULL); struct ifnet_stat_increment_param incs; bzero(&incs, sizeof(incs)); incs.packets_in = 1; incs.bytes_in = mbuf_pkthdr_len(m); ifnet_input(sc->sc_ifp, m, &incs); m = NULL; /* ifnet_input() has freed the mbuf */ done: /* since we got sc->sc_refcnt add by one, we decrease it when done */ gre_sc_release(sc); return m; }