bool SocketCookie::SendDeferredData() { while (deferredDataHead) { if(deferredDataHead->direction) { if(sock_inject_data_in(socket, deferredDataHead->GetSockAddress(), deferredDataHead->data, deferredDataHead->control, deferredDataHead->flags)) { mbuf_freem(deferredDataHead->data); mbuf_freem(deferredDataHead->control); } } else { sock_inject_data_out(socket, deferredDataHead->GetSockAddress(), deferredDataHead->data, deferredDataHead->control, deferredDataHead->flags); } DeferredData *old = deferredDataHead; deferredDataHead = deferredDataHead->next; delete old; } deferredDataLast = NULL; return true; }
/* Network Interface functions */ static errno_t utun_output( ifnet_t interface, mbuf_t data) { struct utun_pcb *pcb = ifnet_softc(interface); errno_t result; if (m_pktlen(data) >= 4) { bpf_tap_out(pcb->utun_ifp, DLT_NULL, data, 0, 0); } if (pcb->utun_flags & UTUN_FLAGS_NO_OUTPUT) { /* flush data */ mbuf_freem(data); return 0; } // otherwise, fall thru to ctl_enqueumbuf if (pcb->utun_ctlref) { int length; // only pass packets to utun-crypto if crypto is enabled and 'suspend data traffic' is not. if ((pcb->utun_flags & (UTUN_FLAGS_CRYPTO | UTUN_FLAGS_CRYPTO_STOP_DATA_TRAFFIC)) == UTUN_FLAGS_CRYPTO) { if (utun_pkt_crypto_output(pcb, &data) == 0) { return 0; } } /* * The ABI requires the protocol in network byte order */ if (m_pktlen(data) >= 4) *(u_int32_t *)mbuf_data(data) = htonl(*(u_int32_t *)mbuf_data(data)); length = mbuf_pkthdr_len(data); result = ctl_enqueuembuf(pcb->utun_ctlref, pcb->utun_unit, data, CTL_DATA_EOR); if (result != 0) { mbuf_freem(data); printf("utun_output - ctl_enqueuembuf failed: %d\n", result); ifnet_stat_increment_out(interface, 0, 0, 1); } else { if (!pcb->utun_ext_ifdata_stats) ifnet_stat_increment_out(interface, 1, length, 0); } } else mbuf_freem(data); return 0; }
/* ----------------------------------------------------------------------------- Called by socket layer to send a packet ----------------------------------------------------------------------------- */ int l2tp_send(struct socket *so, int flags, mbuf_t m, struct sockaddr *to, mbuf_t control, struct proc *p) { if (control) mbuf_freem(control); if (mbuf_len(m) == 0) { mbuf_freem(m); return 0; } return l2tp_rfc_output(so->so_pcb, m, to); }
static errno_t utun_output(ifnet_t interface, mbuf_t data) { struct utun_pcb *pcb = ifnet_softc(interface); errno_t result; VERIFY(interface == pcb->utun_ifp); if (m_pktlen(data) >= (int32_t)UTUN_HEADER_SIZE(pcb)) { bpf_tap_out(pcb->utun_ifp, DLT_NULL, data, 0, 0); } if (pcb->utun_flags & UTUN_FLAGS_NO_OUTPUT) { /* flush data */ mbuf_freem(data); return 0; } // otherwise, fall thru to ctl_enqueumbuf if (pcb->utun_ctlref) { int length; /* * The ABI requires the protocol in network byte order */ if (m_pktlen(data) >= (int32_t)UTUN_HEADER_SIZE(pcb)) { *(u_int32_t *)mbuf_data(data) = htonl(*(u_int32_t *)mbuf_data(data)); } length = mbuf_pkthdr_len(data); result = ctl_enqueuembuf(pcb->utun_ctlref, pcb->utun_unit, data, CTL_DATA_EOR); if (result != 0) { mbuf_freem(data); printf("utun_output - ctl_enqueuembuf failed: %d\n", result); ifnet_stat_increment_out(interface, 0, 0, 1); } else { if (!pcb->utun_ext_ifdata_stats) ifnet_stat_increment_out(interface, 1, length, 0); } } else mbuf_freem(data); return 0; }
/* ----------------------------------------------------------------------------- called from l2tp_rfc when data are present ----------------------------------------------------------------------------- */ int l2tp_input(void *data, mbuf_t m, struct sockaddr *from, int more) { struct socket *so = (struct socket *)data; int err; lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED); if (so->so_tpcb) { // we are hooked to ppp return l2tp_wan_input(ALIGNED_CAST(struct ppp_link *)so->so_tpcb, m); // Wcast-align fix - we malloc so->so_tpcb } if (m) { if (from == 0) { // no from address, just free the buffer mbuf_freem(m); return 1; } if (sbappendaddr(&so->so_rcv, from, (struct mbuf *)m, 0, &err) == 0) { //IOLog("l2tp_input no space, so = %p\n", so); return 1; } } if (!more) sorwakeup(so); return 0; }
bool SocketCookie::ClearDeferredData() { while (deferredDataHead) { mbuf_freem(deferredDataHead->data); mbuf_freem(deferredDataHead->control); DeferredData *old = deferredDataHead; deferredDataHead = deferredDataHead->next; delete old; } deferredDataLast = NULL; return true; }
errno_t utun_pkt_input (struct utun_pcb *pcb, mbuf_t m) { errno_t result; protocol_family_t protocol = 0; mbuf_pkthdr_setrcvif(m, pcb->utun_ifp); if (m_pktlen(m) >= 4) { protocol = *(u_int32_t *)mbuf_data(m); bpf_tap_in(pcb->utun_ifp, DLT_NULL, m, 0, 0); } if (pcb->utun_flags & UTUN_FLAGS_NO_INPUT) { /* flush data */ mbuf_freem(m); return 0; } // quick exit for keepalive packets if (protocol == AF_UTUN && pcb->utun_flags & UTUN_FLAGS_CRYPTO) { if (utun_pkt_crypto_output(pcb, &m) == 0) { return 0; } printf("%s: utun_pkt_crypto_output failed, flags %x\n", __FUNCTION__, pcb->utun_flags); return EINVAL; } if (!pcb->utun_ext_ifdata_stats) { struct ifnet_stat_increment_param incs; bzero(&incs, sizeof(incs)); incs.packets_in = 1; incs.bytes_in = mbuf_pkthdr_len(m); result = ifnet_input(pcb->utun_ifp, m, &incs); } else { result = ifnet_input(pcb->utun_ifp, m, NULL); } if (result != 0) { ifnet_stat_increment_in(pcb->utun_ifp, 0, 0, 1); printf("%s - ifnet_input failed: %d\n", __FUNCTION__, result); mbuf_freem(m); } return 0; }
/* ----------------------------------------------------------------------------- called from dlil when a packet from the interface is to be dispatched to the specific network protocol attached by dl_tag. the network protocol has been determined earlier by the demux function. the packet is in the mbuf chain m without the frame header, which is provided separately. (not used) ----------------------------------------------------------------------------- */ errno_t ppp_ipv6_input(ifnet_t ifp, protocol_family_t protocol, mbuf_t packet, char* header) { LOGMBUF("ppp_ipv6_input", packet); if (proto_input(PF_INET6, packet)) mbuf_freem(packet); return 0; }
/* * Call portmap to lookup a port number for a particular rpc program * Returns non-zero error on failure. */ int krpc_portmap( struct sockaddr_in *sin, /* server address */ u_int prog, u_int vers, u_int proto, /* host order */ u_int16_t *portp) /* network order */ { struct sdata { u_int32_t prog; /* call program */ u_int32_t vers; /* call version */ u_int32_t proto; /* call protocol */ u_int32_t port; /* call port (unused) */ } *sdata; struct rdata { u_int16_t pad; u_int16_t port; } *rdata; mbuf_t m; int error; /* The portmapper port is fixed. */ if (prog == PMAPPROG) { *portp = htons(PMAPPORT); return 0; } error = mbuf_gethdr(MBUF_WAITOK, MBUF_TYPE_DATA, &m); if (error) return error; mbuf_setlen(m, sizeof(*sdata)); mbuf_pkthdr_setlen(m, sizeof(*sdata)); sdata = mbuf_data(m); /* Do the RPC to get it. */ sdata->prog = htonl(prog); sdata->vers = htonl(vers); sdata->proto = htonl(proto); sdata->port = 0; sin->sin_port = htons(PMAPPORT); error = krpc_call(sin, SOCK_DGRAM, PMAPPROG, PMAPVERS, PMAPPROC_GETPORT, &m, NULL); if (error) return error; rdata = mbuf_data(m); if (mbuf_len(m) >= sizeof(*rdata)) { *portp = rdata->port; } if (mbuf_len(m) < sizeof(*rdata) || !rdata->port) error = EPROGUNAVAIL; mbuf_freem(m); return (error); }
static errno_t ipsec_ctl_send(__unused kern_ctl_ref kctlref, __unused u_int32_t unit, __unused void *unitinfo, mbuf_t m, __unused int flags) { /* Receive messages from the control socket. Currently unused. */ mbuf_freem(m); return 0; }
static errno_t utun_pkt_input (struct utun_pcb *pcb, mbuf_t m) { errno_t result; protocol_family_t protocol = 0; mbuf_pkthdr_setrcvif(m, pcb->utun_ifp); if (m_pktlen(m) >= (int32_t)UTUN_HEADER_SIZE(pcb)) { protocol = *(u_int32_t *)mbuf_data(m); bpf_tap_in(pcb->utun_ifp, DLT_NULL, m, 0, 0); } if (pcb->utun_flags & UTUN_FLAGS_NO_INPUT) { /* flush data */ mbuf_freem(m); return 0; } if (!pcb->utun_ext_ifdata_stats) { struct ifnet_stat_increment_param incs; bzero(&incs, sizeof(incs)); incs.packets_in = 1; incs.bytes_in = mbuf_pkthdr_len(m); result = ifnet_input(pcb->utun_ifp, m, &incs); } else { result = ifnet_input(pcb->utun_ifp, m, NULL); } if (result != 0) { ifnet_stat_increment_in(pcb->utun_ifp, 0, 0, 1); printf("%s - ifnet_input failed: %d\n", __FUNCTION__, result); mbuf_freem(m); } return 0; }
void net_habitue_device_SC101::handleResolvePacket(sockaddr_in *addr, mbuf_t m, size_t len, outstanding *out, void *ctx) { clock_get_uptime(&_lastReply); if (mbuf_len(m) < out->len && mbuf_pullup(&m, out->len) != 0) { KINFO("pullup failed"); return; } KDEBUG("resolve succeeded!"); psan_resolve_response_t *res = (psan_resolve_response_t *)mbuf_data(m); sockaddr_in part; bzero(&part, sizeof(part)); part.sin_len = sizeof(part); part.sin_family = AF_INET; part.sin_port = htons(PSAN_PORT); part.sin_addr = res->ip4; OSData *partData = OSData::withBytes(&part, sizeof(part)); if (partData) { setProperty(gSC101DevicePartitionAddressKey, partData); partData->release(); } OSData *rootData = OSData::withBytes(addr, sizeof(*addr)); if (rootData) { setProperty(gSC101DeviceRootAddressKey, rootData); rootData->release(); } IODelete(out, outstanding, 1); mbuf_freem(m); if (!getProperty(gSC101DeviceSizeKey)) disk(); }
//////////////////////////////////////////////////////////////////////////////// // // inet_firewire_input // // IN: struct mbuf *m, char *frame_header, ifnet_t ifp, // IN: u_long dl_tag, int sync_ok // // Invoked by : // It will be called from the context of dlil_input_thread queue from // dlil_input_packet // // Process a received firewire ARP/IP packet, the packet is in the mbuf // chain m // //////////////////////////////////////////////////////////////////////////////// static errno_t inet_firewire_input( __unused ifnet_t ifp, __unused protocol_family_t protocol_family, mbuf_t m, char *frame_header) { struct firewire_header *eh = (struct firewire_header *)frame_header; u_short fw_type; ifnet_touch_lastchange(ifp); fw_type = ntohs(eh->fw_type); switch (fw_type) { case FWTYPE_IP: { mbuf_pullup(&m, sizeof(struct ip)); if (m == NULL) return EJUSTRETURN; errno_t ret = proto_input(PF_INET, m); if( ret ) mbuf_freem(m); return ret; } case FWTYPE_ARP: firewire_arpintr(m); break; default: return ENOENT; } return 0; }
void net_habitue_device_SC101::handleAsyncIOPacket(sockaddr_in *addr, mbuf_t m, size_t len, outstanding *out, void *ctx) { clock_get_uptime(&_lastReply); outstanding_io *io = (outstanding_io *)ctx; bool isWrite = (io->buffer->getDirection() == kIODirectionOut); UInt32 ioLen = (io->nblks * SECTOR_SIZE); IOStorageCompletion completion = io->completion; IOReturn status = kIOReturnError; IOByteCount wrote = ioLen; if (isWrite) { //KDEBUG("%p write %d %d", io, io->block, io->nblks); status = kIOReturnSuccess; } else { //KDEBUG("%p read %d %d", io, io->block, io->nblks); if (mbuf_buffer(io->buffer, 0, m, sizeof(psan_get_response_t), ioLen)) status = kIOReturnSuccess; else KINFO("mbuf_buffer failed"); } if (status != kIOReturnSuccess) KINFO("%p FAILED", io); completeIO(io); io->addr->release(); IODelete(io, outstanding_io, 1); mbuf_freem(m); IOStorage::complete(completion, status, wrote); }
/* * 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; }
/** * Internal worker that create a darwin mbuf for a (scatter/)gather list. * * @returns Pointer to the mbuf. * @param pThis The instance. * @param pSG The (scatter/)gather list. */ static mbuf_t vboxNetFltDarwinMBufFromSG(PVBOXNETFLTINS pThis, PINTNETSG pSG) { /// @todo future? mbuf_how_t How = preemption enabled ? MBUF_DONTWAIT : MBUF_WAITOK; mbuf_how_t How = MBUF_WAITOK; /* * We need some way of getting back to our instance data when * the mbuf is freed, so use pvUserData for this. * -- this is not relevant anylonger! -- */ Assert(!pSG->pvUserData || pSG->pvUserData == pThis); Assert(!pSG->pvUserData2); pSG->pvUserData = pThis; /* * Allocate a packet and copy over the data. * * Using mbuf_attachcluster() here would've been nice but there are two * issues with it: (1) it's 10.5.x only, and (2) the documentation indicates * that it's not supposed to be used for really external buffers. The 2nd * point might be argued against considering that the only m_clattach user * is mallocs memory for the ext mbuf and not doing what's stated in the docs. * However, it's hard to tell if these m_clattach buffers actually makes it * to the NICs or not, and even if they did, the NIC would need the physical * addresses for the pages they contain and might end up copying the data * to a new mbuf anyway. * * So, in the end it's better to just do it the simple way that will work * 100%, even if it involves some extra work (alloc + copy) we really wished * to avoid. * * Note. We can't make use of the physical addresses on darwin because the * way the mbuf / cluster stuff works (see mbuf_data_to_physical and * mcl_to_paddr). */ mbuf_t pPkt = NULL; errno_t err = mbuf_allocpacket(How, pSG->cbTotal, NULL, &pPkt); if (!err) { /* Skip zero sized memory buffers (paranoia). */ mbuf_t pCur = pPkt; while (pCur && !mbuf_maxlen(pCur)) pCur = mbuf_next(pCur); Assert(pCur); /* Set the required packet header attributes. */ mbuf_pkthdr_setlen(pPkt, pSG->cbTotal); mbuf_pkthdr_setheader(pPkt, mbuf_data(pCur)); /* Special case the single buffer copy. */ if ( mbuf_next(pCur) && mbuf_maxlen(pCur) >= pSG->cbTotal) { mbuf_setlen(pCur, pSG->cbTotal); IntNetSgRead(pSG, mbuf_data(pCur)); } else { /* Multi buffer copying. */ size_t cbLeft = pSG->cbTotal; size_t offSrc = 0; while (cbLeft > 0 && pCur) { size_t cb = mbuf_maxlen(pCur); if (cb > cbLeft) cb = cbLeft; mbuf_setlen(pCur, cb); IntNetSgReadEx(pSG, offSrc, cb, mbuf_data(pCur)); /* advance */ offSrc += cb; cbLeft -= cb; pCur = mbuf_next(pCur); } Assert(cbLeft == 0); } if (!err) { /* * Tag the packet and return successfully. */ PVBOXNETFLTTAG pTagData; err = mbuf_tag_allocate(pPkt, g_idTag, 0 /* type */, sizeof(VBOXNETFLTTAG) /* tag len */, How, (void **)&pTagData); if (!err) { Assert(pSG->aSegs[0].cb >= sizeof(pTagData->EthHdr)); memcpy(&pTagData->EthHdr, pSG->aSegs[0].pv, sizeof(pTagData->EthHdr)); return pPkt; } /* bailout: */ AssertMsg(err == ENOMEM || err == EWOULDBLOCK, ("err=%d\n", err)); } mbuf_freem(pPkt); } else AssertMsg(err == ENOMEM || err == EWOULDBLOCK, ("err=%d\n", err)); pSG->pvUserData = NULL; return NULL; }
/* * 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; }
/* Network Interface functions */ static errno_t ipsec_output(ifnet_t interface, mbuf_t data) { struct ipsec_pcb *pcb = ifnet_softc(interface); struct ipsec_output_state ipsec_state; struct route ro; struct route_in6 ro6; int length; struct ip *ip; struct ip6_hdr *ip6; struct ip_out_args ipoa; struct ip6_out_args ip6oa; int error = 0; u_int ip_version = 0; uint32_t af; int flags = 0; struct flowadv *adv = NULL; // Make sure this packet isn't looping through the interface if (necp_get_last_interface_index_from_packet(data) == interface->if_index) { error = -1; goto ipsec_output_err; } // Mark the interface so NECP can evaluate tunnel policy necp_mark_packet_from_interface(data, interface); ip = mtod(data, struct ip *); ip_version = ip->ip_v; switch (ip_version) { case 4: /* Tap */ af = AF_INET; bpf_tap_out(pcb->ipsec_ifp, DLT_NULL, data, &af, sizeof(af)); /* Apply encryption */ bzero(&ipsec_state, sizeof(ipsec_state)); ipsec_state.m = data; ipsec_state.dst = (struct sockaddr *)&ip->ip_dst; bzero(&ipsec_state.ro, sizeof(ipsec_state.ro)); error = ipsec4_interface_output(&ipsec_state, interface); data = ipsec_state.m; if (error || data == NULL) { printf("ipsec_output: ipsec4_output error %d.\n", error); goto ipsec_output_err; } /* Set traffic class, set flow */ m_set_service_class(data, pcb->ipsec_output_service_class); data->m_pkthdr.pkt_flowsrc = FLOWSRC_IFNET; data->m_pkthdr.pkt_flowid = interface->if_flowhash; data->m_pkthdr.pkt_proto = ip->ip_p; data->m_pkthdr.pkt_flags = (PKTF_FLOW_ID | PKTF_FLOW_ADV | PKTF_FLOW_LOCALSRC); /* Flip endian-ness for ip_output */ ip = mtod(data, struct ip *); NTOHS(ip->ip_len); NTOHS(ip->ip_off); /* Increment statistics */ length = mbuf_pkthdr_len(data); ifnet_stat_increment_out(interface, 1, length, 0); /* Send to ip_output */ bzero(&ro, sizeof(ro)); flags = IP_OUTARGS | /* Passing out args to specify interface */ IP_NOIPSEC; /* To ensure the packet doesn't go through ipsec twice */ bzero(&ipoa, sizeof(ipoa)); ipoa.ipoa_flowadv.code = 0; ipoa.ipoa_flags = IPOAF_SELECT_SRCIF | IPOAF_BOUND_SRCADDR; if (ipsec_state.outgoing_if) { ipoa.ipoa_boundif = ipsec_state.outgoing_if; ipoa.ipoa_flags |= IPOAF_BOUND_IF; } adv = &ipoa.ipoa_flowadv; (void) ip_output(data, NULL, &ro, flags, NULL, &ipoa); data = NULL; if (adv->code == FADV_FLOW_CONTROLLED || adv->code == FADV_SUSPENDED) { error = ENOBUFS; ifnet_disable_output(interface); } goto done; case 6: af = AF_INET6; bpf_tap_out(pcb->ipsec_ifp, DLT_NULL, data, &af, sizeof(af)); data = ipsec6_splithdr(data); ip6 = mtod(data, struct ip6_hdr *); bzero(&ipsec_state, sizeof(ipsec_state)); ipsec_state.m = data; ipsec_state.dst = (struct sockaddr *)&ip6->ip6_dst; bzero(&ipsec_state.ro, sizeof(ipsec_state.ro)); error = ipsec6_interface_output(&ipsec_state, interface, &ip6->ip6_nxt, ipsec_state.m); if (error == 0 && ipsec_state.tunneled == 4) /* tunneled in IPv4 - packet is gone */ goto done; data = ipsec_state.m; if (error || data == NULL) { printf("ipsec_output: ipsec6_output error %d.\n", error); goto ipsec_output_err; } /* Set traffic class, set flow */ m_set_service_class(data, pcb->ipsec_output_service_class); data->m_pkthdr.pkt_flowsrc = FLOWSRC_IFNET; data->m_pkthdr.pkt_flowid = interface->if_flowhash; data->m_pkthdr.pkt_proto = ip6->ip6_nxt; data->m_pkthdr.pkt_flags = (PKTF_FLOW_ID | PKTF_FLOW_ADV | PKTF_FLOW_LOCALSRC); /* Increment statistics */ length = mbuf_pkthdr_len(data); ifnet_stat_increment_out(interface, 1, length, 0); /* Send to ip6_output */ bzero(&ro6, sizeof(ro6)); flags = IPV6_OUTARGS; bzero(&ip6oa, sizeof(ip6oa)); ip6oa.ip6oa_flowadv.code = 0; ip6oa.ip6oa_flags = IPOAF_SELECT_SRCIF | IPOAF_BOUND_SRCADDR; if (ipsec_state.outgoing_if) { ip6oa.ip6oa_boundif = ipsec_state.outgoing_if; ip6oa.ip6oa_flags |= IPOAF_BOUND_IF; } adv = &ip6oa.ip6oa_flowadv; (void) ip6_output(data, NULL, &ro6, flags, NULL, NULL, &ip6oa); data = NULL; if (adv->code == FADV_FLOW_CONTROLLED || adv->code == FADV_SUSPENDED) { error = ENOBUFS; ifnet_disable_output(interface); } goto done; default: printf("ipsec_output: Received unknown packet version %d.\n", ip_version); error = -1; goto ipsec_output_err; } done: return error; ipsec_output_err: if (data) mbuf_freem(data); goto done; }
// Temporarily stuff a vlan tag back into a packet so that tag shows up to bpf. // We do it by creating a temp header mbuf with the enet/vlan header in it and // then point its next field to the proper place (after the dest+src addresses) in the original // mbuf. void IOEthernetInterface::_fixupVlanPacket(mbuf_t mt, u_int16_t vlan_tag, int inputPacket) { mbuf_t newmb; mbuf_t chain; size_t remainingBytes; size_t copyBytes = 0; //initialize to prevent annoying, incorrect warning that it's used uninitialized char * destptr; if( mbuf_gethdr(MBUF_DONTWAIT, MT_DATA, &newmb) ) return; //init enough of the mbuf to keep bpf happy mbuf_setlen(newmb, ETHER_ADDR_LEN*2 + VLAN_HEADER_LEN); mbuf_pkthdr_setlen(newmb, mbuf_pkthdr_len( mt ) + VLAN_HEADER_LEN); mbuf_pkthdr_setrcvif(newmb, mbuf_pkthdr_rcvif( mt ) ); //now walk the incoming mbuf to copy out its dst & src address and //locate the type/len field in the packet. chain = mt; remainingBytes = ETHER_ADDR_LEN*2; destptr = (char *)mbuf_data( newmb ); while(chain && remainingBytes) { copyBytes = remainingBytes > mbuf_len( chain ) ? mbuf_len( chain ): remainingBytes; remainingBytes -= copyBytes; bcopy( mbuf_data( chain ), destptr, copyBytes); destptr += copyBytes; if (mbuf_len( chain ) == copyBytes) //we've completely drained this mbuf { chain = mbuf_next( chain ); //advance to next copyBytes = 0; //if we break out of loop now, make sure the offset is correct } } // chain points to the mbuf that contains the packet data with type/len field // and copyBytes indicates the offset it's at. if(chain==0 || remainingBytes) { mbuf_freem( newmb ); return; //if we can't munge the packet, just return } //patch mbuf so its data points after the dst+src address mbuf_setdata(chain, (char *)mbuf_data( chain ) + copyBytes, mbuf_len( chain ) - copyBytes ); //finish setting up our head mbuf *(short *)(destptr) = htons(ETHERTYPE_VLAN); //vlan magic number *(short *)(destptr + 2) = htons( vlan_tag ); // and the tag's value mbuf_setnext( newmb, chain ); //stick it infront of the rest of the packet // feed the tap if(inputPacket) super::feedPacketInputTap( newmb ); else super::feedPacketOutputTap( newmb ); //release the fake header mbuf_setnext( newmb, NULL ); mbuf_freem( newmb ); //and repair our old mbuf mbuf_setdata( chain, (char *)mbuf_data( chain ) - copyBytes, mbuf_len( chain ) + copyBytes ); }
int osi_NetReceive(osi_socket so, struct sockaddr_in *addr, struct iovec *dvec, int nvecs, int *alength) { #ifdef AFS_DARWIN80_ENV socket_t asocket = (socket_t)so; struct msghdr msg; struct sockaddr_storage ss; int rlen; mbuf_t m; #else struct socket *asocket = (struct socket *)so; struct uio u; #endif int i; struct iovec iov[RX_MAXIOVECS]; struct sockaddr *sa = NULL; int code; size_t resid; int haveGlock = ISAFS_GLOCK(); /*AFS_STATCNT(osi_NetReceive); */ if (nvecs > RX_MAXIOVECS) osi_Panic("osi_NetReceive: %d: Too many iovecs.\n", nvecs); for (i = 0; i < nvecs; i++) iov[i] = dvec[i]; if ((afs_termState == AFSOP_STOP_RXK_LISTENER) || (afs_termState == AFSOP_STOP_COMPLETE)) return -1; if (haveGlock) AFS_GUNLOCK(); #if defined(KERNEL_FUNNEL) thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); #endif #ifdef AFS_DARWIN80_ENV resid = *alength; memset(&msg, 0, sizeof(struct msghdr)); msg.msg_name = &ss; msg.msg_namelen = sizeof(struct sockaddr_storage); sa =(struct sockaddr *) &ss; code = sock_receivembuf(asocket, &msg, &m, 0, alength); if (!code) { size_t offset=0,sz; resid = *alength; for (i=0;i<nvecs && resid;i++) { sz=MIN(resid, iov[i].iov_len); code = mbuf_copydata(m, offset, sz, iov[i].iov_base); if (code) break; resid-=sz; offset+=sz; } } mbuf_freem(m); #else u.uio_iov = &iov[0]; u.uio_iovcnt = nvecs; u.uio_offset = 0; u.uio_resid = *alength; u.uio_segflg = UIO_SYSSPACE; u.uio_rw = UIO_READ; u.uio_procp = NULL; code = soreceive(asocket, &sa, &u, NULL, NULL, NULL); resid = u.uio_resid; #endif #if defined(KERNEL_FUNNEL) thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); #endif if (haveGlock) AFS_GLOCK(); if (code) return code; *alength -= resid; if (sa) { if (sa->sa_family == AF_INET) { if (addr) *addr = *(struct sockaddr_in *)sa; } else printf("Unknown socket family %d in NetReceive\n", sa->sa_family); #ifndef AFS_DARWIN80_ENV FREE(sa, M_SONAME); #endif } return code; }
NTSTATUS SMBRawTransaction( SMBHANDLE inConnection, const void *lpInBuffer, size_t nInBufferSize, void *lpOutBuffer, size_t nOutBufferSize, size_t *lpBytesRead) { NTSTATUS status; int err; void * hContext; struct smb_header header; mbuf_t words = NULL; mbuf_t bytes = NULL; mbuf_t response = NULL; size_t len; const void * ptr; bzero(&header, sizeof(header)); status = SMBServerContext(inConnection, &hContext); if (!NT_SUCCESS(status)) { return status; } if ((size_t)nInBufferSize < sizeof(struct smb_header) || (size_t)nOutBufferSize < sizeof(struct smb_header)) { err = STATUS_BUFFER_TOO_SMALL; goto errout; } /* Split the request buffer into the header, the parameter words and the * data bytes. */ ptr = lpInBuffer; ADVANCE(ptr, sizeof(uint32_t)); header.command = *(uint8_t *)ptr; if ((size_t)nInBufferSize < (sizeof(struct smb_header) + sizeof(uint8_t))) { err = STATUS_BUFFER_TOO_SMALL; goto errout; } ptr = lpInBuffer; ADVANCE(ptr, sizeof(struct smb_header)); len = (*(uint8_t *)ptr) * sizeof(uint16_t); ADVANCE(ptr, sizeof(uint8_t)); /* skip word_count field */ if (mbuf_attachcluster(MBUF_WAITOK, MBUF_TYPE_DATA, &words, (void *)ptr, NULL, len, NULL)) { err = STATUS_NO_MEMORY; goto errout; } mbuf_setlen(words, len); ADVANCE(ptr, len); /* skip parameter words */ if ((uintptr_t)ptr > ((uintptr_t)lpInBuffer + nInBufferSize) || (uintptr_t)ptr < (uintptr_t)mbuf_data(words)) { err = STATUS_MARSHALL_OVERFLOW; goto errout; } len = OSReadLittleInt16(ptr, 0); ADVANCE(ptr, sizeof(uint16_t)); /* skip byte_count field */ if (mbuf_attachcluster(MBUF_WAITOK, MBUF_TYPE_DATA, &bytes, (void *)ptr, NULL, len, NULL)) { err = STATUS_NO_MEMORY; goto errout; } mbuf_setlen(bytes, len); ADVANCE(ptr, len); if ((uintptr_t)ptr > ((uintptr_t)lpInBuffer + nInBufferSize) || (uintptr_t)ptr < (uintptr_t)mbuf_data(bytes)) { err = STATUS_MARSHALL_OVERFLOW; goto errout; } /* Set up the response buffer so that we leave room to place the * SMB header at the front. */ len = (size_t)(nOutBufferSize - sizeof(struct smb_header)); if (mbuf_attachcluster(MBUF_WAITOK, MBUF_TYPE_DATA, &response, ((uint8_t *)lpOutBuffer + sizeof(struct smb_header)), NULL, len, NULL)) { err = STATUS_NO_MEMORY; goto errout; } err = smb_ioc_request(hContext, &header, words, bytes, response); if (err) { err = STATUS_IO_DEVICE_ERROR; goto errout; } /* Stash the new SMB header at the front of the output buffer so the * caller gets the server status code, etc. */ memcpy(lpOutBuffer, lpInBuffer, sizeof(header)); OSWriteLittleInt32(lpOutBuffer, 0, *(const uint32_t *)(void *)SMB_SIGNATURE); OSWriteLittleInt32(lpOutBuffer, offsetof(struct smb_header, status), header.status); OSWriteLittleInt16(lpOutBuffer, offsetof(struct smb_header, flags), header.flags); OSWriteLittleInt32(lpOutBuffer, offsetof(struct smb_header, flags2), header.flags2); *lpBytesRead = mbuf_len(response) + sizeof(struct smb_header); /* We return success, even though the server may have failed the call. The * caller is responsible for parsing the reply packet and looking at the * status field in the header. */ err = STATUS_SUCCESS; errout: if (words) mbuf_freem(words); if (bytes) mbuf_freem(bytes); if (response) mbuf_freem(response); return err; }
/** * Internal worker for vboxNetFltDarwinIffInput and vboxNetFltDarwinIffOutput, * * @returns 0 or EJUSTRETURN. * @param pThis The instance. * @param pMBuf The mbuf. * @param pvFrame The start of the frame, optional. * @param fSrc Where the packet (allegedly) comes from, one INTNETTRUNKDIR_* value. * @param eProtocol The protocol. */ static errno_t vboxNetFltDarwinIffInputOutputWorker(PVBOXNETFLTINS pThis, mbuf_t pMBuf, void *pvFrame, uint32_t fSrc, protocol_family_t eProtocol) { /* * Drop it immediately? */ Log2(("vboxNetFltDarwinIffInputOutputWorker: pThis=%p pMBuf=%p pvFrame=%p fSrc=%#x cbPkt=%x\n", pThis, pMBuf, pvFrame, fSrc, pMBuf ? mbuf_pkthdr_len(pMBuf) : -1)); if (!pMBuf) return 0; #if 0 /* debugging lost icmp packets */ if (mbuf_pkthdr_len(pMBuf) > 0x300) { uint8_t *pb = (uint8_t *)(pvFrame ? pvFrame : mbuf_data(pMBuf)); Log3(("D=%.6Rhxs S=%.6Rhxs T=%04x IFF\n", pb, pb + 6, RT_BE2H_U16(*(uint16_t *)(pb + 12)))); } #endif if (vboxNetFltDarwinMBufIsOur(pThis, pMBuf, pvFrame)) return 0; /* * Active? Retain the instance and increment the busy counter. */ if (!vboxNetFltTryRetainBusyActive(pThis)) return 0; /* * Finalize out-bound packets since the stack puts off finalizing * TCP/IP checksums as long as possible. * ASSUMES this only applies to outbound IP packets. */ if ( (fSrc & INTNETTRUNKDIR_HOST) && eProtocol == PF_INET) { Assert(!pvFrame); mbuf_outbound_finalize(pMBuf, eProtocol, sizeof(RTNETETHERHDR)); } /* * Create a (scatter/)gather list for the mbuf and feed it to the internal network. */ bool fDropIt = false; unsigned cSegs = vboxNetFltDarwinMBufCalcSGSegs(pThis, pMBuf, pvFrame); if (cSegs < VBOXNETFLT_DARWIN_MAX_SEGS) { PINTNETSG pSG = (PINTNETSG)alloca(RT_OFFSETOF(INTNETSG, aSegs[cSegs])); vboxNetFltDarwinMBufToSG(pThis, pMBuf, pvFrame, pSG, cSegs, fSrc); fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, NULL /* pvIf */, pSG, fSrc); if (fDropIt) { /* * Check if this interface is in promiscuous mode. We should not drop * any packets before they get to the driver as it passes them to tap * callbacks in order for BPF to work properly. */ if (vboxNetFltDarwinIsPromiscuous(pThis)) fDropIt = false; else mbuf_freem(pMBuf); } } vboxNetFltRelease(pThis, true /* fBusy */); return fDropIt ? EJUSTRETURN : 0; }
IOReturn REACConnection::sendSamples(UInt32 bufSize, UInt8 *sampleBuffer) { REACMasterDataStream *masterDataStream = OSDynamicCast(REACMasterDataStream, dataStream); const UInt32 ourSamplesSize = REAC_SAMPLES_PER_PACKET*REAC_RESOLUTION* (NULL != masterDataStream ? inChannels : deviceInfo->out_channels); // TODO This is not complete const UInt32 slaveSamplesSize = (NULL != masterDataStream && masterDataStream->isConnectedToSlave()) ? ourSamplesSize : 0; const UInt32 sentSamplesSize = ourSamplesSize+slaveSamplesSize; const UInt32 sampleOffset = sizeof(EthernetHeader)+sizeof(REACPacketHeader); const UInt32 endingOffset = sampleOffset+sentSamplesSize; const UInt32 packetLen = endingOffset+sizeof(REACConstants::ENDING); REACPacketHeader rph; mbuf_t mbuf = NULL; IOReturn result = kIOReturnError; IOReturn processPacketRet; /// Do some argument checks if (!(REAC_SLAVE == mode || REAC_MASTER == mode)) { result = kIOReturnInvalid; goto Done; } if (ourSamplesSize != bufSize && NULL != sampleBuffer) { // bufSize is ignored when sampleBuffer is NULL result = kIOReturnBadArgument; goto Done; } /// Prepare ethernet header EthernetHeader header; memcpy(header.shost, interfaceAddr, sizeof(header.shost)); // Don't initialize header.dhost; that's the responsibility of dataStream->processPacket memcpy(&header.type, REACConstants::PROTOCOL, sizeof(REACConstants::PROTOCOL)); /// Do REAC data stream processing processPacketRet = dataStream->processPacket(&rph, sizeof(header.dhost), header.dhost); if (kIOReturnAborted == processPacketRet) { // The REACDataStream indicates to us that it doesn't want us to send a packet. goto Done; } else if (kIOReturnSuccess != processPacketRet) { IOLog("REACConnection::sendSamples() - Error: Failed to process packet data stream.\n"); goto Done; } /// Allocate mbuf if (0 != mbuf_allocpacket(MBUF_DONTWAIT, packetLen, NULL, &mbuf) || kIOReturnSuccess != MbufUtils::setChainLength(mbuf, packetLen)) { IOLog("REACConnection::sendSamples() - Error: Failed to allocate packet mbuf.\n"); goto Done; } /// Copy ethernet header if (kIOReturnSuccess != MbufUtils::copyFromBufferToMbuf(mbuf, 0, sizeof(EthernetHeader), &header)) { IOLog("REACConnection::sendSamples() - Error: Failed to copy REAC header to packet mbuf.\n"); goto Done; } /// Copy REAC header if (kIOReturnSuccess != MbufUtils::copyFromBufferToMbuf(mbuf, sizeof(EthernetHeader), sizeof(REACPacketHeader), &rph)) { IOLog("REACConnection::sendSamples() - Error: Failed to copy REAC header to packet mbuf.\n"); goto Done; } /// Copy sample data if (NULL != sampleBuffer) { if (kIOReturnSuccess != MbufUtils::copyAudioFromBufferToMbuf(mbuf, sampleOffset, bufSize, sampleBuffer)) { IOLog("REACConnection::sendSamples() - Error: Failed to copy sample data to packet mbuf.\n"); goto Done; } } else { if (kIOReturnSuccess != MbufUtils::zeroMbuf(mbuf, sampleOffset, ourSamplesSize)) { IOLog("REACConnection::sendSamples() - Error: Failed to zero sample data in mbuf.\n"); goto Done; } } if (NULL != masterDataStream && masterDataStream->isConnectedToSlave()) { // TODO This is very incorrect: It doesn't send the slave data, and even if it would, the order of the // data would be jumbled, because it has to send the whole first sample first and so on. if (kIOReturnSuccess != MbufUtils::zeroMbuf(mbuf, sampleOffset+ourSamplesSize, slaveSamplesSize)) { IOLog("REACConnection::sendSamples() - Error: Failed to zero slave sample data in mbuf.\n"); goto Done; } } /// Copy packet ending if (kIOReturnSuccess != MbufUtils::copyFromBufferToMbuf(mbuf, endingOffset, sizeof(REACConstants::ENDING), (void *)REACConstants::ENDING)) { IOLog("REACConnection::sendSamples() - Error: Failed to copy ending to packet mbuf.\n"); goto Done; } /// Send packet if (0 != ifnet_output_raw(interface, 0, mbuf)) { mbuf = NULL; // ifnet_output_raw always frees the mbuf IOLog("REACConnection::sendSamples() - Error: Failed to send packet.\n"); goto Done; } mbuf = NULL; // ifnet_output_raw always frees the mbuf result = kIOReturnSuccess; Done: if (NULL != mbuf) { mbuf_freem(mbuf); mbuf = NULL; } return result; }
/* * Do a remote procedure call (RPC) and wait for its reply. * If from_p is non-null, then we are doing broadcast, and * the address from whence the response came is saved there. */ int krpc_call( struct sockaddr_in *sa, u_int sotype, u_int prog, u_int vers, u_int func, mbuf_t *data, /* input/output */ struct sockaddr_in *from_p) /* output */ { socket_t so; struct sockaddr_in *sin; mbuf_t m, nam, mhead; struct rpc_call *call; struct rpc_reply *reply; int error, timo, secs; size_t len; static u_int32_t xid = ~0xFF; u_int16_t tport; size_t maxpacket = 1<<16; /* * Validate address family. * Sorry, this is INET specific... */ if (sa->sin_family != AF_INET) return (EAFNOSUPPORT); /* Free at end if not null. */ nam = mhead = NULL; /* * Create socket and set its recieve timeout. */ if ((error = sock_socket(AF_INET, sotype, 0, 0, 0, &so))) goto out1; { struct timeval tv; tv.tv_sec = 1; tv.tv_usec = 0; if ((error = sock_setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)))) goto out; } /* * Enable broadcast if necessary. */ if (from_p && (sotype == SOCK_DGRAM)) { int on = 1; if ((error = sock_setsockopt(so, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)))) goto out; } /* * Bind the local endpoint to a reserved port, * because some NFS servers refuse requests from * non-reserved (non-privileged) ports. */ if ((error = mbuf_get(MBUF_WAITOK, MBUF_TYPE_SONAME, &m))) goto out; sin = mbuf_data(m); bzero(sin, sizeof(*sin)); mbuf_setlen(m, sizeof(*sin)); sin->sin_len = sizeof(*sin); sin->sin_family = AF_INET; sin->sin_addr.s_addr = INADDR_ANY; tport = IPPORT_RESERVED; do { tport--; sin->sin_port = htons(tport); error = sock_bind(so, (struct sockaddr*)sin); } while (error == EADDRINUSE && tport > IPPORT_RESERVED / 2); mbuf_freem(m); m = NULL; if (error) { printf("bind failed\n"); goto out; } /* * Setup socket address for the server. */ if ((error = mbuf_get(MBUF_WAITOK, MBUF_TYPE_SONAME, &nam))) goto out; sin = mbuf_data(nam); mbuf_setlen(nam, sa->sin_len); bcopy((caddr_t)sa, (caddr_t)sin, sa->sin_len); if (sotype == SOCK_STREAM) { struct timeval tv; tv.tv_sec = 60; tv.tv_usec = 0; error = sock_connect(so, mbuf_data(nam), MSG_DONTWAIT); if (error && (error != EINPROGRESS)) goto out; error = sock_connectwait(so, &tv); if (error) { if (error == EINPROGRESS) error = ETIMEDOUT; printf("krpc_call: error waiting for TCP socket connect: %d\n", error); goto out; } } /* * Prepend RPC message header. */ m = *data; *data = NULL; #if DIAGNOSTIC if ((mbuf_flags(m) & MBUF_PKTHDR) == 0) panic("krpc_call: send data w/o pkthdr"); if (mbuf_pkthdr_len(m) < mbuf_len(m)) panic("krpc_call: pkthdr.len not set"); #endif len = sizeof(*call); if (sotype == SOCK_STREAM) len += 4; /* account for RPC record marker */ mhead = m; if ((error = mbuf_prepend(&mhead, len, MBUF_WAITOK))) goto out; if ((error = mbuf_pkthdr_setrcvif(mhead, NULL))) goto out; /* * Fill in the RPC header */ if (sotype == SOCK_STREAM) { /* first, fill in RPC record marker */ u_int32_t *recmark = mbuf_data(mhead); *recmark = htonl(0x80000000 | (mbuf_pkthdr_len(mhead) - 4)); call = (struct rpc_call *)(recmark + 1); } else { call = mbuf_data(mhead); } bzero((caddr_t)call, sizeof(*call)); xid++; call->rp_xid = htonl(xid); /* call->rp_direction = 0; */ call->rp_rpcvers = htonl(2); call->rp_prog = htonl(prog); call->rp_vers = htonl(vers); call->rp_proc = htonl(func); /* call->rp_auth = 0; */ /* call->rp_verf = 0; */ /* * Send it, repeatedly, until a reply is received, * but delay each re-send by an increasing amount. * If the delay hits the maximum, start complaining. */ timo = 0; for (;;) { struct msghdr msg; /* Send RPC request (or re-send). */ if ((error = mbuf_copym(mhead, 0, MBUF_COPYALL, MBUF_WAITOK, &m))) goto out; bzero(&msg, sizeof(msg)); if (sotype == SOCK_STREAM) { msg.msg_name = NULL; msg.msg_namelen = 0; } else { msg.msg_name = mbuf_data(nam); msg.msg_namelen = mbuf_len(nam); } error = sock_sendmbuf(so, &msg, m, 0, 0); if (error) { printf("krpc_call: sosend: %d\n", error); goto out; } m = NULL; /* Determine new timeout. */ if (timo < MAX_RESEND_DELAY) timo++; else printf("RPC timeout for server " IP_FORMAT "\n", IP_LIST(&(sin->sin_addr.s_addr))); /* * Wait for up to timo seconds for a reply. * The socket receive timeout was set to 1 second. */ secs = timo; while (secs > 0) { size_t readlen; if (m) { mbuf_freem(m); m = NULL; } if (sotype == SOCK_STREAM) { int maxretries = 60; struct iovec aio; aio.iov_base = &len; aio.iov_len = sizeof(u_int32_t); bzero(&msg, sizeof(msg)); msg.msg_iov = &aio; msg.msg_iovlen = 1; do { error = sock_receive(so, &msg, MSG_WAITALL, &readlen); if ((error == EWOULDBLOCK) && (--maxretries <= 0)) error = ETIMEDOUT; } while (error == EWOULDBLOCK); if (!error && readlen < aio.iov_len) { /* only log a message if we got a partial word */ if (readlen != 0) printf("short receive (%ld/%ld) from server " IP_FORMAT "\n", readlen, sizeof(u_int32_t), IP_LIST(&(sin->sin_addr.s_addr))); error = EPIPE; } if (error) goto out; len = ntohl(len) & ~0x80000000; /* * This is SERIOUS! We are out of sync with the sender * and forcing a disconnect/reconnect is all I can do. */ if (len > maxpacket) { printf("impossible packet length (%ld) from server " IP_FORMAT "\n", len, IP_LIST(&(sin->sin_addr.s_addr))); error = EFBIG; goto out; } do { readlen = len; error = sock_receivembuf(so, NULL, &m, MSG_WAITALL, &readlen); } while (error == EWOULDBLOCK); if (!error && (len > readlen)) { printf("short receive (%ld/%ld) from server " IP_FORMAT "\n", readlen, len, IP_LIST(&(sin->sin_addr.s_addr))); error = EPIPE; } } else { len = maxpacket; readlen = len; bzero(&msg, sizeof(msg)); msg.msg_name = from_p; msg.msg_namelen = (from_p == NULL) ? 0 : sizeof(*from_p); error = sock_receivembuf(so, &msg, &m, 0, &readlen); } if (error == EWOULDBLOCK) { secs--; continue; } if (error) goto out; len = readlen; /* Does the reply contain at least a header? */ if (len < MIN_REPLY_HDR) continue; if (mbuf_len(m) < MIN_REPLY_HDR) continue; reply = mbuf_data(m); /* Is it the right reply? */ if (reply->rp_direction != htonl(RPC_REPLY)) continue; if (reply->rp_xid != htonl(xid)) continue; /* Was RPC accepted? (authorization OK) */ if (reply->rp_astatus != 0) { error = ntohl(reply->rp_u.rpu_errno); printf("rpc denied, error=%d\n", error); /* convert rpc error to errno */ switch (error) { case RPC_MISMATCH: error = ERPCMISMATCH; break; case RPC_AUTHERR: error = EAUTH; break; } goto out; } if (mbuf_len(m) < REPLY_SIZE) { error = RPC_SYSTEM_ERR; } else { error = ntohl(reply->rp_u.rpu_ok.rp_rstatus); } /* Did the call succeed? */ if (error != 0) { printf("rpc status=%d\n", error); /* convert rpc error to errno */ switch (error) { case RPC_PROGUNAVAIL: error = EPROGUNAVAIL; break; case RPC_PROGMISMATCH: error = EPROGMISMATCH; break; case RPC_PROCUNAVAIL: error = EPROCUNAVAIL; break; case RPC_GARBAGE: error = EINVAL; break; case RPC_SYSTEM_ERR: error = EIO; break; } goto out; } goto gotreply; /* break two levels */ } /* while secs */ } /* forever send/receive */ error = ETIMEDOUT; goto out; gotreply: /* * Pull as much as we can into first mbuf, to make * result buffer contiguous. Note that if the entire * result won't fit into one mbuf, you're out of luck. * XXX - Should not rely on making the entire reply * contiguous (fix callers instead). -gwr */ #if DIAGNOSTIC if ((mbuf_flags(m) & MBUF_PKTHDR) == 0) panic("krpc_call: received pkt w/o header?"); #endif len = mbuf_pkthdr_len(m); if (sotype == SOCK_STREAM) len -= 4; /* the RPC record marker was read separately */ if (mbuf_len(m) < len) { if ((error = mbuf_pullup(&m, len))) goto out; reply = mbuf_data(m); } /* * Strip RPC header */ len = sizeof(*reply); if (reply->rp_u.rpu_ok.rp_auth.rp_atype != 0) { len += ntohl(reply->rp_u.rpu_ok.rp_auth.rp_alen); len = (len + 3) & ~3; /* XXX? */ } mbuf_adj(m, len); /* result */ *data = m; out: sock_close(so); out1: if (nam) mbuf_freem(nam); if (mhead) mbuf_freem(mhead); return error; }
IOReturn REACConnection::sendSplitAnnouncementPacket() { const UInt32 fillerSize = 288; const UInt32 fillerOffset = sizeof(EthernetHeader)+sizeof(REACPacketHeader); const UInt32 endingOffset = fillerOffset+fillerSize; const UInt32 packetLen = endingOffset+sizeof(REACConstants::ENDING); REACSplitDataStream *splitDataStream; REACPacketHeader rph; mbuf_t mbuf = NULL; int result = kIOReturnError; /// Do some argument checks if (!REAC_SPLIT == mode) { result = kIOReturnInvalid; goto Done; } /// Prepare REAC packet header splitDataStream = OSDynamicCast(REACSplitDataStream, dataStream); if (NULL == splitDataStream) { IOLog("REACConnection::sendSplitAnnouncementPacket(): Internal error!\n"); result = kIOReturnInternalError; goto Done; } rph.setCounter(splitAnnouncementCounter++); if (!splitDataStream->prepareSplitAnnounce(&rph)) { goto Done; } /// Allocate mbuf if (0 != mbuf_allocpacket(MBUF_DONTWAIT, packetLen, NULL, &mbuf) || kIOReturnSuccess != MbufUtils::setChainLength(mbuf, packetLen)) { IOLog("REACConnection::sendSplitAnnouncementPacket() - Error: Failed to allocate packet mbuf.\n"); goto Done; } /// Copy ethernet header EthernetHeader header; memcpy(header.shost, interfaceAddr, sizeof(header.shost)); memcpy(header.dhost, deviceInfo->addr, sizeof(header.dhost)); memcpy(&header.type, REACConstants::PROTOCOL, sizeof(REACConstants::PROTOCOL)); if (kIOReturnSuccess != MbufUtils::copyFromBufferToMbuf(mbuf, 0, sizeof(EthernetHeader), &header)) { IOLog("REACConnection::sendSplitAnnouncementPacket() - Error: Failed to copy REAC header to packet mbuf.\n"); goto Done; } /// Copy REAC header if (kIOReturnSuccess != MbufUtils::copyFromBufferToMbuf(mbuf, sizeof(EthernetHeader), sizeof(REACPacketHeader), &rph)) { IOLog("REACConnection::sendSplitAnnouncementPacket() - Error: Failed to copy REAC header to packet mbuf.\n"); goto Done; } /// Copy filler if (kIOReturnSuccess != MbufUtils::zeroMbuf(mbuf, fillerOffset, fillerSize)) { IOLog("REACConnection::sendSplitAnnouncementPacket() - Error: Failed to zero filler data in mbuf.\n"); goto Done; } /// Copy packet ending if (kIOReturnSuccess != MbufUtils::copyFromBufferToMbuf(mbuf, endingOffset, sizeof(REACConstants::ENDING), (void *)REACConstants::ENDING)) { IOLog("REACConnection::sendSplitAnnouncementPacket() - Error: Failed to copy ending to packet mbuf.\n"); goto Done; } /// Send packet if (0 != ifnet_output_raw(interface, 0, mbuf)) { mbuf = NULL; // ifnet_output_raw always frees the mbuf IOLog("REACConnection::sendSplitAnnouncementPacket() - Error: Failed to send packet.\n"); goto Done; } mbuf = NULL; // ifnet_output_raw always frees the mbuf result = kIOReturnSuccess; Done: if (NULL != mbuf) { mbuf_freem(mbuf); mbuf = NULL; } return result; }
void rx_upcall(socket_t so, void *arg, __unused int waitflag) { mbuf_t m; int error = 0; int i, flags = 0; struct msghdr msg; struct sockaddr_storage ss; struct sockaddr *sa = NULL; struct sockaddr_in from; struct rx_packet *p; afs_int32 rlen; afs_int32 tlen; afs_int32 savelen; /* was using rlen but had aliasing problems */ size_t nbytes, resid, noffset; p = rxi_AllocPacket(RX_PACKET_CLASS_RECEIVE); rx_computelen(p, tlen); rx_SetDataSize(p, tlen); /* this is the size of the user data area */ tlen += RX_HEADER_SIZE; /* now this is the size of the entire packet */ rlen = rx_maxJumboRecvSize; /* this is what I am advertising. Only check * it once in order to avoid races. */ tlen = rlen - tlen; if (tlen > 0) { tlen = rxi_AllocDataBuf(p, tlen, RX_PACKET_CLASS_RECV_CBUF); if (tlen > 0) { tlen = rlen - tlen; } else tlen = rlen; } else tlen = rlen; /* add some padding to the last iovec, it's just to make sure that the * read doesn't return more data than we expect, and is done to get around * our problems caused by the lack of a length field in the rx header. */ savelen = p->wirevec[p->niovecs - 1].iov_len; p->wirevec[p->niovecs - 1].iov_len = savelen + RX_EXTRABUFFERSIZE; resid = nbytes = tlen + sizeof(afs_int32); memset(&msg, 0, sizeof(struct msghdr)); msg.msg_name = &ss; msg.msg_namelen = sizeof(struct sockaddr_storage); sa =(struct sockaddr *) &ss; do { m = NULL; error = sock_receivembuf(so, &msg, &m, MSG_DONTWAIT, &nbytes); if (!error) { size_t sz, offset = 0; noffset = 0; resid = nbytes; for (i=0;i<p->niovecs && resid;i++) { sz=MIN(resid, p->wirevec[i].iov_len); error = mbuf_copydata(m, offset, sz, p->wirevec[i].iov_base); if (error) break; resid-=sz; offset+=sz; noffset += sz; } } } while (0); mbuf_freem(m); /* restore the vec to its correct state */ p->wirevec[p->niovecs - 1].iov_len = savelen; if (error == EWOULDBLOCK && noffset > 0) error = 0; if (!error) { int host, port; nbytes -= resid; if (sa->sa_family == AF_INET) from = *(struct sockaddr_in *)sa; p->length = nbytes - RX_HEADER_SIZE;; if ((nbytes > tlen) || (p->length & 0x8000)) { /* Bogus packet */ if (nbytes <= 0) { if (rx_stats_active) { MUTEX_ENTER(&rx_stats_mutex); rx_atomic_inc(&rx_stats.bogusPacketOnRead); rx_stats.bogusHost = from.sin_addr.s_addr; MUTEX_EXIT(&rx_stats_mutex); } dpf(("B: bogus packet from [%x,%d] nb=%d", from.sin_addr.s_addr, from.sin_port, nbytes)); } return; } else { /* Extract packet header. */ rxi_DecodePacketHeader(p); host = from.sin_addr.s_addr; port = from.sin_port; if (p->header.type > 0 && p->header.type < RX_N_PACKET_TYPES) { if (rx_stats_active) { rx_atomic_inc(&rx_stats.packetsRead[p->header.type - 1]); } } #ifdef RX_TRIMDATABUFS /* Free any empty packet buffers at the end of this packet */ rxi_TrimDataBufs(p, 1); #endif /* receive pcket */ p = rxi_ReceivePacket(p, so, host, port, 0, 0); } } /* free packet? */ if (p) rxi_FreePacket(p); return; }
static inline bool analyseSegments( mbuf_t packet, /* input packet mbuf */ const UInt32 mbufsInCache, /* number of entries in segsPerMBuf[] */ const UInt32 segsPerMBuf[], /* segments required per mbuf */ SInt32 numSegs, /* total number of segments */ const UInt32 maxSegs) /* max controller segments per mbuf */ { mbuf_t newPacket; // output mbuf chain. mbuf_t out; // current output mbuf link. SInt32 outSize; // size of current output mbuf link. SInt32 outSegs; // segments for current output mbuf link. SInt32 doneSegs; // segments for output mbuf chain. SInt32 outLen; // remaining length of input buffer. mbuf_t in = packet; // save the original input packet pointer. UInt32 inIndex = 0; const uint32_t c_mlen = mbuf_get_mlen(); // Allocate a mbuf (non header mbuf) to begin the output mbuf chain. if(mbuf_get(MBUF_DONTWAIT, MT_DATA, &newPacket)) { ERROR_LOG("analyseSegments: MGET() 1 error\n"); return false; } /* Initialise outgoing packet controls */ out = newPacket; outSize = c_mlen; doneSegs = outSegs = outLen = 0; // numSegs stores the delta between the total and the max. For each // input mbuf consumed, we decrement numSegs. // numSegs -= maxSegs; // Loop through the input packet mbuf 'in' and construct a new mbuf chain // large enough to make (numSegs + doneSegs + outSegs) less than or // equal to zero. // do { uintptr_t vmo; outLen += mbuf_len(in); while (outLen > outSize) { // Oh dear the current outgoing length is too big. if (outSize != MCLBYTES) { // Current mbuf is not yet a cluster so promote, then // check for error. if(mbuf_mclget(MBUF_DONTWAIT, MT_DATA, &out) || !(mbuf_flags(out) & MBUF_EXT) ) { ERROR_LOG("analyseSegments: MCLGET() error\n"); goto bombAnalysis; } outSize = MCLBYTES; continue; } vmo = (uintptr_t)mbuf_data(out); mbuf_setlen(out, MCLBYTES); /* Fill in target copy size */ doneSegs += (round_page(vmo + MCLBYTES) - trunc_page(vmo)) / PAGE_SIZE; // If the number of segments of the output chain, plus // the segment for the mbuf we are about to allocate is greater // than maxSegs, then abort. // if (doneSegs + 1 > (int) maxSegs) { ERROR_LOG("analyseSegments: maxSegs limit 1 reached! %ld %ld\n", doneSegs, maxSegs); goto bombAnalysis; } mbuf_t tempmbuf; if(mbuf_get(MBUF_DONTWAIT, MT_DATA, &tempmbuf)) { ERROR_LOG("analyseSegments: MGET() error\n"); goto bombAnalysis; } mbuf_setnext(out, tempmbuf); out = tempmbuf; outSize = c_mlen; outLen -= MCLBYTES; } // Compute number of segment in current outgoing mbuf. vmo = (uintptr_t)mbuf_data(out); outSegs = ((SInt32)round_page(vmo + outLen) - (SInt32)trunc_page(vmo)) / (SInt32)PAGE_SIZE; if (doneSegs + outSegs > (int) maxSegs) { ERROR_LOG("analyseSegments: maxSegs limit 2 reached! %ld %ld %ld\n", doneSegs, outSegs, maxSegs); goto bombAnalysis; } // Get the number of segments in the current inbuf if (inIndex < mbufsInCache) numSegs -= segsPerMBuf[inIndex]; // Yeah, in cache else { // Hmm, we have to recompute from scratch. Copy code from genPhys. int thisLen = 0, mbufLen; vmo = (uintptr_t)mbuf_data(in); for (mbufLen = (SInt32)mbuf_len(in); mbufLen; mbufLen -= thisLen) { thisLen = MIN((SInt32)next_page(vmo), (SInt32)(vmo + mbufLen)) - (SInt32)vmo; vmo += thisLen; numSegs--; } } // Walk the incoming buffer on one. in = mbuf_next(in); inIndex++; // continue looping until the total number of segments has dropped // to an acceptable level, or if we ran out of mbuf links. } while (in && ((numSegs + doneSegs + outSegs) > 0)); if ( (int) (numSegs + doneSegs + outSegs) <= 0) { // success mbuf_setlen(out, outLen); // Set last mbuf with the remaining length. // The amount to copy is determine by the segment length in each // mbuf linked to newPacket. The sum can be smaller than // packet->pkthdr.len; // coalesceSegments(packet, newPacket); // The initial header mbuf is preserved, its length set to zero, and // linked to the new packet chain. // coalesceSegments() has already freed the mbufs that it coalesced into the newPacket chain. // It also hooked the remaining chain pointed to by "in" to the end of the newPacket chain. // All that remains is to set packet's len to 0 (to "free" the contents that coalesceSegments copied out) // and make it the head of the new chain. mbuf_setlen(packet , 0 ); mbuf_setnext(packet, newPacket); return true; } bombAnalysis: mbuf_freem(newPacket); return false; }