/* * Ethernet output routine. * Encapsulate a packet of type family for the local net. * Use trailer local net encapsulation if enough data in first * packet leaves a multiple of 512 bytes of data in remainder. */ int ether_frameout( struct ifnet *ifp, struct mbuf **m, const struct sockaddr *ndest, const char *edst, const char *ether_type) { struct ether_header *eh; int hlen; /* link layer header length */ hlen = ETHER_HDR_LEN; /* * If a simplex interface, and the packet is being sent to our * Ethernet address or a broadcast address, loopback a copy. * XXX To make a simplex device behave exactly like a duplex * device, we should copy in the case of sending to our own * ethernet address (thus letting the original actually appear * on the wire). However, we don't do that here for security * reasons and compatibility with the original behavior. */ if ((ifp->if_flags & IFF_SIMPLEX) && ((*m)->m_flags & M_LOOP)) { if (lo_ifp) { if ((*m)->m_flags & M_BCAST) { struct mbuf *n = m_copy(*m, 0, (int)M_COPYALL); if (n != NULL) dlil_output(lo_ifp, ndest->sa_family, n, NULL, ndest, 0); } else { if (_ether_cmp(edst, ifnet_lladdr(ifp)) == 0) { dlil_output(lo_ifp, ndest->sa_family, *m, NULL, ndest, 0); return EJUSTRETURN; } } } } /* * Add local net header. If no space in first mbuf, * allocate another. */ M_PREPEND(*m, sizeof (struct ether_header), M_DONTWAIT); if (*m == 0) { return (EJUSTRETURN); } eh = mtod(*m, struct ether_header *); (void)memcpy(&eh->ether_type, ether_type, sizeof(eh->ether_type)); (void)memcpy(eh->ether_dhost, edst, ETHER_ADDR_LEN); ifnet_lladdr_copy_bytes(ifp, eh->ether_shost, ETHER_ADDR_LEN); return 0; }
/** * Internal worker for vboxNetFltOsInitInstance and vboxNetFltOsMaybeRediscovered. * * @returns VBox status code. * @param pThis The instance. * @param fRediscovery If set we're doing a rediscovery attempt, so, don't * flood the release log. */ static int vboxNetFltDarwinAttachToInterface(PVBOXNETFLTINS pThis, bool fRediscovery) { LogFlow(("vboxNetFltDarwinAttachToInterface: pThis=%p (%s)\n", pThis, pThis->szName)); /* * Locate the interface first. * * The pIfNet member is updated before iflt_attach is called and used * to deal with the hypothetical case where someone rips out the * interface immediately after our iflt_attach call. */ ifnet_t pIfNet = NULL; errno_t err = ifnet_find_by_name(pThis->szName, &pIfNet); if (err) { Assert(err == ENXIO); if (!fRediscovery) LogRel(("VBoxFltDrv: failed to find ifnet '%s' (err=%d)\n", pThis->szName, err)); else Log(("VBoxFltDrv: failed to find ifnet '%s' (err=%d)\n", pThis->szName, err)); return VERR_INTNET_FLT_IF_NOT_FOUND; } RTSpinlockAcquire(pThis->hSpinlock); ASMAtomicUoWritePtr(&pThis->u.s.pIfNet, pIfNet); RTSpinlockReleaseNoInts(pThis->hSpinlock); /* * Get the mac address while we still have a valid ifnet reference. */ err = ifnet_lladdr_copy_bytes(pIfNet, &pThis->u.s.MacAddr, sizeof(pThis->u.s.MacAddr)); if (!err) { /* * Try attach the filter. */ struct iff_filter RegRec; RegRec.iff_cookie = pThis; RegRec.iff_name = "VBoxNetFlt"; RegRec.iff_protocol = 0; RegRec.iff_input = vboxNetFltDarwinIffInput; RegRec.iff_output = vboxNetFltDarwinIffOutput; RegRec.iff_event = vboxNetFltDarwinIffEvent; RegRec.iff_ioctl = vboxNetFltDarwinIffIoCtl; RegRec.iff_detached = vboxNetFltDarwinIffDetached; interface_filter_t pIfFilter = NULL; err = iflt_attach(pIfNet, &RegRec, &pIfFilter); Assert(err || pIfFilter); RTSpinlockAcquire(pThis->hSpinlock); pIfNet = ASMAtomicUoReadPtrT(&pThis->u.s.pIfNet, ifnet_t); if (pIfNet && !err) { ASMAtomicUoWriteBool(&pThis->fDisconnectedFromHost, false); ASMAtomicUoWritePtr(&pThis->u.s.pIfFilter, pIfFilter); pIfNet = NULL; /* don't dereference it */ } RTSpinlockReleaseNoInts(pThis->hSpinlock); /* Report capabilities. */ if ( !pIfNet && vboxNetFltTryRetainBusyNotDisconnected(pThis)) { Assert(pThis->pSwitchPort); pThis->pSwitchPort->pfnReportMacAddress(pThis->pSwitchPort, &pThis->u.s.MacAddr); pThis->pSwitchPort->pfnReportPromiscuousMode(pThis->pSwitchPort, vboxNetFltDarwinIsPromiscuous(pThis)); pThis->pSwitchPort->pfnReportGsoCapabilities(pThis->pSwitchPort, 0, INTNETTRUNKDIR_WIRE | INTNETTRUNKDIR_HOST); pThis->pSwitchPort->pfnReportNoPreemptDsts(pThis->pSwitchPort, 0 /* none */); vboxNetFltRelease(pThis, true /*fBusy*/); } } /* Release the interface on failure. */ if (pIfNet) ifnet_release(pIfNet); int rc = RTErrConvertFromErrno(err); if (RT_SUCCESS(rc)) LogRel(("VBoxFltDrv: attached to '%s' / %.*Rhxs\n", pThis->szName, sizeof(pThis->u.s.MacAddr), &pThis->u.s.MacAddr)); else LogRel(("VBoxFltDrv: failed to attach to ifnet '%s' (err=%d)\n", pThis->szName, err)); return rc; }
errno_t firewire_inet_arp( ifnet_t ifp, u_short arpop, const struct sockaddr_dl* sender_hw, const struct sockaddr* sender_proto, const struct sockaddr_dl* target_hw, const struct sockaddr* target_proto) { mbuf_t m; errno_t result; register struct firewire_header *fwh; register IP1394_ARP *fwa; const struct sockaddr_in* sender_ip = (const struct sockaddr_in*)sender_proto; const struct sockaddr_in* target_ip = (const struct sockaddr_in*)target_proto; char *datap; IOFWInterface *fwIf = (IOFWInterface*)ifnet_softc(ifp); if(fwIf == NULL) return EINVAL; IOFireWireIP *fwIpObj = (IOFireWireIP*)fwIf->getController(); if(fwIpObj == NULL) return EINVAL; LCB *lcb = fwIpObj->getLcb(); if (target_ip == NULL) return EINVAL; if ((sender_ip && sender_ip->sin_family != AF_INET) || (target_ip && target_ip->sin_family != AF_INET)) return EAFNOSUPPORT; result = mbuf_gethdr(MBUF_DONTWAIT, MBUF_TYPE_DATA, &m); if (result != 0) return result; mbuf_setlen(m, sizeof(*fwa)); mbuf_pkthdr_setlen(m, sizeof(*fwa)); /* Move the data pointer in the mbuf to the end, aligned to 4 bytes */ datap = (char*)mbuf_datastart(m); datap += mbuf_trailingspace(m); datap -= (((u_long)datap) & 0x3); mbuf_setdata(m, datap, sizeof(*fwa)); fwa = (IP1394_ARP*)mbuf_data(m); bzero((caddr_t)fwa, sizeof(*fwa)); /* Prepend the ethernet header, we will send the raw frame */ result = mbuf_prepend(&m, sizeof(*fwh), MBUF_DONTWAIT); if(result != 0) return result; fwh = (struct firewire_header*)mbuf_data(m); fwh->fw_type = htons(FWTYPE_ARP); /* Fill out the arp packet */ fwa->hardwareType = htons(ARP_HDW_TYPE); fwa->protocolType = htons(FWTYPE_IP); fwa->hwAddrLen = sizeof(IP1394_HDW_ADDR); fwa->ipAddrLen = IPV4_ADDR_SIZE; fwa->opcode = htons(arpop); fwa->senderMaxRec = lcb->ownHardwareAddress.maxRec; fwa->sspd = lcb->ownHardwareAddress.spd; fwa->senderUnicastFifoHi = htons(lcb->ownHardwareAddress.unicastFifoHi); fwa->senderUnicastFifoLo = htonl(lcb->ownHardwareAddress.unicastFifoLo); /* Sender Hardware */ if (sender_hw != NULL) bcopy(CONST_LLADDR(sender_hw), &fwa->senderUniqueID, sizeof(fwa->senderUniqueID)); else ifnet_lladdr_copy_bytes(ifp, &fwa->senderUniqueID, FIREWIRE_ADDR_LEN); ifnet_lladdr_copy_bytes(ifp, fwh->fw_shost, sizeof(fwh->fw_shost)); /* Sender IP */ if (sender_ip != NULL) fwa->senderIpAddress = sender_ip->sin_addr.s_addr; else { ifaddr_t *addresses; struct sockaddr sa; if (ifnet_get_address_list_family(ifp, &addresses, AF_INET) == 0) { ifaddr_address( addresses[0], &sa, 16 ); fwa->senderIpAddress = ((UInt32)(sa.sa_data[5] & 0xFF)) << 24; fwa->senderIpAddress |= ((UInt32)(sa.sa_data[4] & 0xFF)) << 16; fwa->senderIpAddress |= ((UInt32)(sa.sa_data[3] & 0xFF)) << 8; fwa->senderIpAddress |= ((UInt32)(sa.sa_data[2] & 0xFF)); ifnet_free_address_list(addresses); } else { mbuf_free(m); return ENXIO; } } /* Target Hardware */ if (target_hw == 0) bcopy(fwbroadcastaddr, fwh->fw_dhost, sizeof(fwh->fw_dhost)); else bcopy(CONST_LLADDR(target_hw), fwh->fw_dhost, sizeof(fwh->fw_dhost)); /* Target IP */ fwa->targetIpAddress = target_ip->sin_addr.s_addr; ifnet_output_raw(ifp, PF_INET, m); return 0; }
/* * Parallel to llc_rtrequest. */ static void arp_rtrequest( int req, struct rtentry *rt, __unused struct sockaddr *sa) { struct sockaddr *gate = rt->rt_gateway; struct llinfo_arp *la = rt->rt_llinfo; static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK, 0, 0, 0, 0, 0, {0}}; struct timeval timenow; if (!arpinit_done) { panic("%s: ARP has not been initialized", __func__); /* NOTREACHED */ } lck_mtx_assert(rnh_lock, LCK_MTX_ASSERT_OWNED); RT_LOCK_ASSERT_HELD(rt); if (rt->rt_flags & RTF_GATEWAY) return; getmicrotime(&timenow); switch (req) { case RTM_ADD: /* * XXX: If this is a manually added route to interface * such as older version of routed or gated might provide, * restore cloning bit. */ if ((rt->rt_flags & RTF_HOST) == 0 && SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff) rt->rt_flags |= RTF_CLONING; if (rt->rt_flags & RTF_CLONING) { /* * Case 1: This route should come from a route to iface. */ if (rt_setgate(rt, rt_key(rt), (struct sockaddr *)&null_sdl) == 0) { gate = rt->rt_gateway; SDL(gate)->sdl_type = rt->rt_ifp->if_type; SDL(gate)->sdl_index = rt->rt_ifp->if_index; /* * In case we're called before 1.0 sec. * has elapsed. */ rt->rt_expire = MAX(timenow.tv_sec, 1); } break; } /* Announce a new entry if requested. */ if (rt->rt_flags & RTF_ANNOUNCE) { RT_UNLOCK(rt); dlil_send_arp(rt->rt_ifp, ARPOP_REQUEST, SDL(gate), rt_key(rt), NULL, rt_key(rt)); RT_LOCK(rt); } /*FALLTHROUGH*/ case RTM_RESOLVE: if (gate->sa_family != AF_LINK || gate->sa_len < sizeof(null_sdl)) { if (log_arp_warnings) log(LOG_DEBUG, "arp_rtrequest: bad gateway value\n"); break; } SDL(gate)->sdl_type = rt->rt_ifp->if_type; SDL(gate)->sdl_index = rt->rt_ifp->if_index; if (la != 0) break; /* This happens on a route change */ /* * Case 2: This route may come from cloning, or a manual route * add with a LL address. */ rt->rt_llinfo = la = arp_llinfo_alloc(); if (la == NULL) { if (log_arp_warnings) log(LOG_DEBUG, "%s: malloc failed\n", __func__); break; } rt->rt_llinfo_free = arp_llinfo_free; arp_inuse++, arp_allocated++; Bzero(la, sizeof(*la)); la->la_rt = rt; rt->rt_flags |= RTF_LLINFO; LIST_INSERT_HEAD(&llinfo_arp, la, la_le); /* * This keeps the multicast addresses from showing up * in `arp -a' listings as unresolved. It's not actually * functional. Then the same for broadcast. */ if (IN_MULTICAST(ntohl(SIN(rt_key(rt))->sin_addr.s_addr))) { RT_UNLOCK(rt); dlil_resolve_multi(rt->rt_ifp, rt_key(rt), gate, sizeof(struct sockaddr_dl)); RT_LOCK(rt); rt->rt_expire = 0; } else if (in_broadcast(SIN(rt_key(rt))->sin_addr, rt->rt_ifp)) { struct sockaddr_dl *gate_ll = SDL(gate); size_t broadcast_len; ifnet_llbroadcast_copy_bytes(rt->rt_ifp, LLADDR(gate_ll), sizeof(gate_ll->sdl_data), &broadcast_len); gate_ll->sdl_alen = broadcast_len; gate_ll->sdl_family = AF_LINK; gate_ll->sdl_len = sizeof(struct sockaddr_dl); /* In case we're called before 1.0 sec. has elapsed */ rt->rt_expire = MAX(timenow.tv_sec, 1); } if (SIN(rt_key(rt))->sin_addr.s_addr == (IA_SIN(rt->rt_ifa))->sin_addr.s_addr) { /* * This test used to be * if (loif.if_flags & IFF_UP) * It allowed local traffic to be forced * through the hardware by configuring the loopback down. * However, it causes problems during network configuration * for boards that can't receive packets they send. * It is now necessary to clear "useloopback" and remove * the route to force traffic out to the hardware. */ rt->rt_expire = 0; ifnet_lladdr_copy_bytes(rt->rt_ifp, LLADDR(SDL(gate)), SDL(gate)->sdl_alen = 6); if (useloopback) { #if IFNET_ROUTE_REFCNT /* Adjust route ref count for the interfaces */ if (rt->rt_if_ref_fn != NULL && rt->rt_ifp != lo_ifp) { rt->rt_if_ref_fn(lo_ifp, 1); rt->rt_if_ref_fn(rt->rt_ifp, -1); } #endif /* IFNET_ROUTE_REFCNT */ rt->rt_ifp = lo_ifp; } } break; case RTM_DELETE: if (la == 0) break; arp_inuse--; /* * Unchain it but defer the actual freeing until the route * itself is to be freed. rt->rt_llinfo still points to * llinfo_arp, and likewise, la->la_rt still points to this * route entry, except that RTF_LLINFO is now cleared. */ LIST_REMOVE(la, la_le); la->la_le.le_next = NULL; la->la_le.le_prev = NULL; rt->rt_flags &= ~RTF_LLINFO; if (la->la_hold != NULL) m_freem(la->la_hold); la->la_hold = NULL; } }