/* * bpf_mtap into the ipfw interface. * eh == NULL when mbuf is a packet, then use the fake_eh * the ip_len need to be twisted before and after bpf copy. */ void ipfw_log(struct mbuf *m, struct ether_header *eh, uint16_t id) { struct ifnet *the_if = NULL; if (fw_verbose) { #ifndef WITHOUT_BPF LOGIF_RLOCK(); the_if = log_if_table[id]; if (the_if == NULL || the_if->if_bpf == NULL) { LOGIF_RUNLOCK(); return; } if (eh != NULL) { bpf_gettoken(); bpf_mtap_hdr(the_if->if_bpf, (caddr_t)eh, ETHER_HDR_LEN, m, 0); bpf_reltoken(); } else { struct ip *ip; ip = mtod(m, struct ip *); /* twist the ip_len for the bpf copy */ ip->ip_len =htons(ip->ip_len); bpf_gettoken(); bpf_mtap_hdr(the_if->if_bpf, (caddr_t)fake_eh, ETHER_HDR_LEN, m, 0); bpf_reltoken(); ip->ip_len =ntohs(ip->ip_len); } LOGIF_RUNLOCK(); #endif /* !WITHOUT_BPF */ } }
/* * The output routine. Takes a packet and encapsulates it in the protocol * given by sc->g_proto. See also RFC 1701 and RFC 2004 */ static int gre_output_serialized(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct rtentry *rt) { int error = 0; struct gre_softc *sc = ifp->if_softc; struct greip *gh; struct ip *ip; u_short etype = 0; struct mobile_h mob_h; struct route *ro; struct sockaddr_in *ro_dst; ASSERT_NETISR_NCPUS(mycpuid); /* * gre may cause infinite recursion calls when misconfigured. * We'll prevent this by introducing upper limit. */ if (++(sc->called) > max_gre_nesting) { kprintf("%s: gre_output: recursively called too many " "times(%d)\n", if_name(&sc->sc_if), sc->called); m_freem(m); error = EIO; /* is there better errno? */ goto end; } if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == 0 || sc->g_src.s_addr == INADDR_ANY || sc->g_dst.s_addr == INADDR_ANY) { m_freem(m); error = ENETDOWN; goto end; } ro = &sc->route_pcpu[mycpuid]; ro_dst = (struct sockaddr_in *)&ro->ro_dst; if (ro->ro_rt != NULL && ((ro->ro_rt->rt_flags & RTF_UP) == 0 || ro_dst->sin_addr.s_addr != sc->g_dst.s_addr)) { RTFREE(ro->ro_rt); ro->ro_rt = NULL; } if (ro->ro_rt == NULL) { error = gre_compute_route(sc, ro); if (error) { m_freem(m); goto end; } } gh = NULL; ip = NULL; if (ifp->if_bpf) { bpf_gettoken(); if (ifp->if_bpf) { uint32_t af = dst->sa_family; bpf_ptap(ifp->if_bpf, m, &af, sizeof(af)); } bpf_reltoken(); } m->m_flags &= ~(M_BCAST|M_MCAST); if (sc->g_proto == IPPROTO_MOBILE) { if (dst->sa_family == AF_INET) { struct mbuf *m0; int msiz; ip = mtod(m, struct ip *); /* * RFC2004 specifies that fragmented datagrams shouldn't * be encapsulated. */ if (ip->ip_off & (IP_MF | IP_OFFMASK)) { m_freem(m); error = EINVAL; /* is there better errno? */ goto end; } 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; /* * 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)) { 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; msiz = MOB_H_SIZ_L; } mob_h.proto = htons(mob_h.proto); mob_h.hcrc = gre_in_cksum((u_short *)&mob_h, msiz); if ((m->m_data - msiz) < m->m_pktdat) { /* need new mbuf */ MGETHDR(m0, M_NOWAIT, MT_HEADER); if (m0 == NULL) { m_freem(m); error = ENOBUFS; goto end; } m0->m_next = m; m->m_data += sizeof(struct ip); m->m_len -= sizeof(struct ip); m0->m_pkthdr.len = m->m_pkthdr.len + msiz; m0->m_len = msiz + sizeof(struct ip); m0->m_data += max_linkhdr; memcpy(mtod(m0, caddr_t), (caddr_t)ip, sizeof(struct ip)); m = m0; } else { /* we have some space left in the old one */ m->m_data -= msiz; m->m_len += msiz; m->m_pkthdr.len += msiz; bcopy(ip, mtod(m, caddr_t), sizeof(struct ip)); } ip = mtod(m, struct ip *); memcpy((caddr_t)(ip + 1), &mob_h, (unsigned)msiz); ip->ip_len = ntohs(ip->ip_len) + msiz; } else { /* AF_INET */ m_freem(m); error = EINVAL; goto end; } } else if (sc->g_proto == IPPROTO_GRE) {