//////////////////////////////////////////////////////////////////////////////// // // firewire_demux // // IN: ifnet_t ifp,struct mbuf *m,char *frame_header, // u_long *protocol_family // // Invoked by : // dlil_input_packet() // //////////////////////////////////////////////////////////////////////////////// __private_extern__ int firewire_demux(ifnet_t ifp, mbuf_t m, char *frame_header, protocol_family_t *protocol_family) { register struct firewire_header *eh = (struct firewire_header *)frame_header; IOFWInterface *fwIf = (IOFWInterface*)ifnet_softc(ifp); if(fwIf == NULL) return EINVAL; struct firewire_desc_blk_str *desc_blk = (struct firewire_desc_blk_str *)fwIf->getFamilyCookie(); if (desc_blk == NULL) return EINVAL; u_short fw_type = eh->fw_type; u_int16_t type = DLIL_DESC_ETYPE2; u_long maxd = desc_blk->n_max_used; struct fw_desc *ed = desc_blk->block_ptr; /* * Search through the connected protocols for a match. */ for (u_long i = 0; i < maxd; i++) { if ((ed[i].type == type) && (ed[i].data[0] == fw_type)) { *protocol_family = ed[i].protocol_family; return 0; } } return ENOENT; }
/* ----------------------------------------------------------------------------- pre_output function ----------------------------------------------------------------------------- */ errno_t ppp_ip_preoutput(ifnet_t ifp, protocol_family_t protocol, mbuf_t *packet, const struct sockaddr *dest, void *route, char *frame_type, char *link_layer_dest) { errno_t err; struct ppp_if *wan = (struct ppp_if *)ifnet_softc(ifp); u_int16_t ftype = PPP_IP; LOGMBUF("ppp_ip_preoutput", *packet); lck_mtx_lock(ppp_domain_mutex); #if 0 (*packet)->m_flags &= ~M_HIGHPRI; /* If this packet has the "low delay" bit set in the IP header, set priority bit for the packet. */ ip = mtod(*packet, struct ip *); if (ip->ip_tos & IPTOS_LOWDELAY) (*packet)->m_flags |= M_HIGHPRI; #endif if ((wan->sc_flags & SC_LOOP_LOCAL) && (!memcmp(&((struct sockaddr_in *)(void*)dest)->sin_addr.s_addr, &wan->ip_src.s_addr, sizeof(struct in_addr))) // Wcast-align fix - memcmp for unaligned compare && wan->lo_ifp) { err = ifnet_output(wan->lo_ifp, PF_INET, *packet, 0, (struct sockaddr *)dest); lck_mtx_unlock(ppp_domain_mutex); return (err ? err : EJUSTRETURN); } lck_mtx_unlock(ppp_domain_mutex); memcpy(frame_type, &ftype, sizeof(u_int16_t)); // Wcast-align fix - memcpy for unaligned move return 0; }
/* ----------------------------------------------------------------------------- attach the PPPx interface ifp to the network protocol IP, called when the ppp interface is ready for ppp traffic ----------------------------------------------------------------------------- */ errno_t ppp_ip_attach(ifnet_t ifp, protocol_family_t protocol) { int ret; struct ifnet_attach_proto_param reg; struct ppp_if *wan = (struct ppp_if *)ifnet_softc(ifp); LOGDBG(ifp, ("ppp_ip_attach: name = %s, unit = %d\n", ifnet_name(ifp), ifnet_unit(ifp))); if (wan->ip_attached) return 0; // already attached bzero(®, sizeof(struct ifnet_attach_proto_param)); reg.input = ppp_ip_input; reg.pre_output = ppp_ip_preoutput; reg.ioctl = ppp_ip_ioctl; ret = ifnet_attach_protocol(ifp, PF_INET, ®); LOGRETURN(ret, ret, "ppp_ip_attach: ifnet_attach_protocol error = 0x%x\n"); LOGDBG(ifp, ("ppp_i6_attach: ifnet_attach_protocol family = 0x%x\n", protocol)); ifnet_find_by_name("lo0", &wan->lo_ifp); wan->ip_attached = 1; return 0; }
/* Network Interface functions */ static void utun_start(ifnet_t interface) { mbuf_t data; struct utun_pcb*pcb = ifnet_softc(interface); for (;;) { bool can_accept_packets = true; ifnet_lock_shared(pcb->utun_ifp); can_accept_packets = (pcb->utun_pending_packets < pcb->utun_max_pending_packets); if (!can_accept_packets && pcb->utun_ctlref) { u_int32_t difference = 0; if (ctl_getenqueuereadable(pcb->utun_ctlref, pcb->utun_unit, &difference) == 0) { if (difference > 0) { // If the low-water mark has not yet been reached, we still need to enqueue data // into the buffer can_accept_packets = true; } } } if (!can_accept_packets) { errno_t error = ifnet_disable_output(interface); if (error != 0) { printf("utun_start: ifnet_disable_output returned error %d\n", error); } ifnet_lock_done(pcb->utun_ifp); break; } ifnet_lock_done(pcb->utun_ifp); if (ifnet_dequeue(interface, &data) != 0) break; if (utun_output(interface, data) != 0) break; } }
static errno_t utun_framer( __unused ifnet_t interface, mbuf_t *packet, __unused const struct sockaddr *dest, __unused const char *desk_linkaddr, const char *frame_type, u_int32_t *prepend_len, u_int32_t *postpend_len) { struct utun_pcb *pcb = ifnet_softc(interface); VERIFY(interface == pcb->utun_ifp); u_int32_t header_length = UTUN_HEADER_SIZE(pcb); if (mbuf_prepend(packet, header_length, MBUF_DONTWAIT) != 0) { printf("utun_framer - ifnet_output prepend failed\n"); ifnet_stat_increment_out(interface, 0, 0, 1); // just return, because the buffer was freed in mbuf_prepend return EJUSTRETURN; } if (prepend_len != NULL) *prepend_len = header_length; if (postpend_len != NULL) *postpend_len = 0; // place protocol number at the beginning of the mbuf *(protocol_family_t *)mbuf_data(*packet) = *(protocol_family_t *)(uintptr_t)(size_t)frame_type; return 0; }
/* ----------------------------------------------------------------------------- Compare the source address of the packet with the dst address of the interface ----------------------------------------------------------------------------- */ int ppp_ip_af_src_in(ifnet_t ifp, char *pkt) { struct ppp_if *wan = (struct ppp_if *)ifnet_softc(ifp); struct ip *ip; // Wcast-align fixes - use memcmp for unaligned accesses ip = (struct ip *)(void*)pkt; return (memcmp(&ip->ip_src.s_addr, &wan->ip_dst.s_addr, sizeof(struct in_addr)) == 0 ? 0 : 1); }
static void utun_detached( ifnet_t interface) { struct utun_pcb *pcb = ifnet_softc(interface); FREE(pcb, M_DEVBUF); /* Release reference acquired via ifnet_allocate_extended() */ (void) ifnet_release(interface); }
static void utun_detached( ifnet_t interface) { struct utun_pcb *pcb = ifnet_softc(interface); utun_free(pcb); OSDecrementAtomic(&utun_ifcount); }
//////////////////////////////////////////////////////////////////////////////// // // in_firewire_arp_input // // IN: register struct mbuf *m // // Invoked by : // firewire_arpintr calls it from the context of dlil_input_thread queue // // ARP for Internet protocols on 10 Mb/s Ethernet. // Algorithm is that given in RFC 826. // In addition, a sanity check is performed on the sender // protocol address, to catch impersonators. // We no longer handle negotiations for use of trailer protocol: // Formerly, ARP replied for protocol type ETHERTYPE_TRAIL sent // along with IP replies if we wanted trailers sent to us, // and also sent them in response to IP replies. // This allowed either end to announce the desire to receive trailer packets. // We no longer reply to requests for ETHERTYPE_TRAIL protocol either, // but formerly didn't normally send requests. // //////////////////////////////////////////////////////////////////////////////// static void inet_firewire_arp_input( mbuf_t m) { IP1394_ARP *fwa; struct sockaddr_dl sender_hw; struct sockaddr_in sender_ip; struct sockaddr_in target_ip; ifnet_t ifp = mbuf_pkthdr_rcvif((mbuf_t)m); IOFWInterface *fwIf = (IOFWInterface*)ifnet_softc(ifp); if(fwIf == NULL) return; IOFireWireIP *fwIpObj = (IOFireWireIP*)fwIf->getController(); if(fwIpObj == NULL) return; if (mbuf_len(m) < (int)sizeof(IP1394_ARP) && mbuf_pullup(&m, sizeof(IP1394_ARP)) != 0) return; fwa = (IP1394_ARP*)mbuf_data(m); // Verify this is an firewire/ip arp and address lengths are correct if (fwa->hardwareType != htons(ARP_HDW_TYPE) || fwa->protocolType != htons(FWTYPE_IP) || fwa->hwAddrLen != sizeof(IP1394_HDW_ADDR) || fwa->ipAddrLen != IPV4_ADDR_SIZE) { mbuf_free(m); return; } bzero(&sender_ip, sizeof(sender_ip)); sender_ip.sin_len = sizeof(sender_ip); sender_ip.sin_family = AF_INET; sender_ip.sin_addr.s_addr = fwa->senderIpAddress; target_ip = sender_ip; target_ip.sin_addr.s_addr = fwa->targetIpAddress; bzero(&sender_hw, sizeof(sender_hw)); sender_hw.sdl_len = sizeof(sender_hw); sender_hw.sdl_family = AF_LINK; sender_hw.sdl_type = IFT_IEEE1394; sender_hw.sdl_alen = FIREWIRE_ADDR_LEN; bcopy(&fwa->senderUniqueID, LLADDR(&sender_hw), FIREWIRE_ADDR_LEN); if(fwIpObj->arpCacheHandler(fwa)) inet_arp_handle_input(ifp, ntohs(fwa->opcode), &sender_hw, &sender_ip, &target_ip); mbuf_free((mbuf_t)m); }
static void ipsec_detached( ifnet_t interface) { struct ipsec_pcb *pcb = ifnet_softc(interface); ifnet_release(pcb->ipsec_ifp); ipsec_free(pcb); OSDecrementAtomic(&ipsec_ifcount); }
/* 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; }
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; }
/* ----------------------------------------------------------------------------- detach the PPPx interface ifp from the network protocol IPv6, called when the ppp interface stops ip traffic ----------------------------------------------------------------------------- */ void ppp_ipv6_detach(ifnet_t ifp, protocol_family_t protocol) { int ret; struct ppp_if *wan = (struct ppp_if *)ifnet_softc(ifp); LOGDBG(ifp, ("ppp_ipv6_detach\n")); if (!wan->ipv6_attached) return; // already detached ret = ifnet_detach_protocol(ifp, PF_INET6); if (ret) IOLog("ppp_ipv6_detach: ifnet_detach_protocol error = 0x%x\n", ret); wan->ipv6_attached = 0; }
/* ----------------------------------------------------------------------------- called from dlil when an ioctl is sent to the interface ----------------------------------------------------------------------------- */ errno_t ppp_ip_ioctl(ifnet_t ifp, protocol_family_t protocol, u_long command, void* argument) { struct ppp_if *wan = (struct ppp_if *)ifnet_softc(ifp); struct sockaddr_in addr, dstaddr; int error = 0; switch (command) { case SIOCSIFADDR: case SIOCAIFADDR: LOGDBG(ifp, ("ppp_ip_ioctl: cmd = SIOCSIFADDR/SIOCAIFADDR\n")); error = ifaddr_address(argument, (struct sockaddr *)&addr, sizeof (addr)); if (error != 0) { error = EAFNOSUPPORT; break; } // only an IPv4 address should arrive here if (addr.sin_family != AF_INET) { error = EAFNOSUPPORT; break; } error = ifaddr_dstaddress(argument, (struct sockaddr *)&dstaddr, sizeof (dstaddr)); if (error != 0) { error = EAFNOSUPPORT; break; } // only an IPv4 address should arrive here if (dstaddr.sin_family != AF_INET) { error = EAFNOSUPPORT; break; } wan->ip_src.s_addr = addr.sin_addr.s_addr; wan->ip_dst.s_addr = dstaddr.sin_addr.s_addr; break; default : error = EOPNOTSUPP; } return error; }
/* ----------------------------------------------------------------------------- Check if the packet is a bootp packet for us ----------------------------------------------------------------------------- */ int ppp_ip_bootp_client_in(ifnet_t ifp, char *pkt) { struct ppp_if *wan = (struct ppp_if *)ifnet_softc(ifp); struct ip *ip; struct udphdr udp; // Wcast-align fixes - use memcmp and memcpy for unaligned accesses ip = (struct ip *)(void*)pkt; if (!memcmp(&ip->ip_dst.s_addr, &wan->ip_src.s_addr, sizeof(struct in_addr)) && ip->ip_p == IPPROTO_UDP) { memcpy(&udp, pkt + sizeof(struct ip), sizeof(struct udphdr)); if (udp.uh_sport == htons(IPPORT_BOOTPS) && udp.uh_dport == htons(IPPORT_BOOTPC)) { return 1; } } return 0; }
static errno_t utun_proto_input( ifnet_t interface, protocol_family_t protocol, mbuf_t m, __unused char *frame_header) { // remove protocol family first struct utun_pcb *pcb = ifnet_softc(interface); mbuf_adj(m, UTUN_HEADER_SIZE(pcb)); if (proto_input(protocol, m) != 0) { m_freem(m); } return 0; }
/* Helpers */ int ipsec_interface_isvalid (ifnet_t interface) { struct ipsec_pcb *pcb = NULL; if (interface == NULL) return 0; pcb = ifnet_softc(interface); if (pcb == NULL) return 0; /* When ctl disconnects, ipsec_unit is set to 0 */ if (pcb->ipsec_unit == 0) return 0; return 1; }
void ipsec_set_pkthdr_for_interface(ifnet_t interface, mbuf_t packet, int family) { if (packet != NULL && interface != NULL) { struct ipsec_pcb *pcb = ifnet_softc(interface); if (pcb != NULL) { /* Set traffic class, set flow */ m_set_service_class(packet, pcb->ipsec_output_service_class); packet->m_pkthdr.pkt_flowsrc = FLOWSRC_IFNET; packet->m_pkthdr.pkt_flowid = interface->if_flowhash; if (family == AF_INET) { struct ip *ip = mtod(packet, struct ip *); packet->m_pkthdr.pkt_proto = ip->ip_p; } else if (family == AF_INET) { struct ip6_hdr *ip6 = mtod(packet, struct ip6_hdr *); packet->m_pkthdr.pkt_proto = ip6->ip6_nxt; } packet->m_pkthdr.pkt_flags = (PKTF_FLOW_ID | PKTF_FLOW_ADV | PKTF_FLOW_LOCALSRC); }
//////////////////////////////////////////////////////////////////////////////// // // firewire_del_proto // // IN: ifnet_t ifp, u_long protocol_family // // Invoked by : // dlil_detach_protocol calls this funcion // // Release all descriptor entries owned by this ifp/protocol_family (there may be several). // Setting the type to 0 releases the entry. Eventually we should compact-out // the unused entries. // //////////////////////////////////////////////////////////////////////////////// __private_extern__ int firewire_del_proto(ifnet_t ifp, protocol_family_t protocol_family) { IOFWInterface *fwIf = (IOFWInterface*)ifnet_softc(ifp); if(fwIf == NULL) return EINVAL; struct firewire_desc_blk_str *desc_blk = (struct firewire_desc_blk_str *)fwIf->getFamilyCookie(); if (desc_blk == NULL) return EINVAL; int found = 0; for (u_long current = desc_blk->n_max_used; current > 0; current--) { if (desc_blk->block_ptr[current - 1].protocol_family == protocol_family) { found = 1; desc_blk->block_ptr[current - 1].type = 0; desc_blk->n_used--; } } if (desc_blk->n_used == 0) { FREE(fwIf->getFamilyCookie(), M_IFADDR); fwIf->setFamilyCookie(NULL); } else { /* Decrement n_max_used */ for (; desc_blk->n_max_used > 0 && desc_blk->block_ptr[desc_blk->n_max_used - 1].type == 0; desc_blk->n_max_used--) ; } return found; }
//////////////////////////////////////////////////////////////////////////////// // // firewire_add_proto // // IN: ifnet_t ifp, u_long protocol_family, struct ddesc_head_str *desc_head // // Invoked by : // dlil_attach_protocol calls this funcion // // //////////////////////////////////////////////////////////////////////////////// __private_extern__ int firewire_add_proto_internal(ifnet_t ifp, u_long protocol_family, const struct ifnet_demux_desc *demux) { IOFWInterface *fwIf = (IOFWInterface*)ifnet_softc(ifp); if(fwIf == NULL) return EINVAL; struct firewire_desc_blk_str *desc_blk = (struct firewire_desc_blk_str *)fwIf->getFamilyCookie(); struct fw_desc *ed; u_long i; switch (demux->type) { case DLIL_DESC_ETYPE2: if (demux->datalen != 2) return EINVAL; break; default: return EOPNOTSUPP; } // Check for case where all of the descriptor blocks are in use if (desc_blk == NULL || desc_blk->n_used == desc_blk->n_count) { struct firewire_desc_blk_str *tmp; u_long new_count = FIREWIRE_DESC_BLK_SIZE; u_long new_size; u_long old_size = 0; i = 0; if (desc_blk) { new_count += desc_blk->n_count; old_size = desc_blk->n_count * sizeof(struct fw_desc) + FIREWIRE_DESC_HEADER_SIZE; i = desc_blk->n_used; } new_size = new_count * sizeof(struct fw_desc) + FIREWIRE_DESC_HEADER_SIZE; tmp = (struct firewire_desc_blk_str*)_MALLOC(new_size, M_IFADDR, MBUF_WAITOK); if (tmp == 0) return ENOMEM; bzero(tmp + old_size, new_size - old_size); if (desc_blk) { bcopy(desc_blk, tmp, old_size); FREE(desc_blk, M_IFADDR); } desc_blk = tmp; fwIf->setFamilyCookie(desc_blk); desc_blk->n_count = new_count; } else { // Find a free entry for (i = 0; i < desc_blk->n_count; i++) { if (desc_blk->block_ptr[i].type == 0) break; } } // Bump n_max_used if appropriate if (i + 1 > desc_blk->n_max_used) { desc_blk->n_max_used = i + 1; } ed = &desc_blk->block_ptr[i]; ed->protocol_family = protocol_family; ed->data[0] = 0; ed->data[1] = 0; switch (demux->type) { case DLIL_DESC_ETYPE2: /* 2 byte ethernet raw protocol type is at native_type */ /* prtocol must be in network byte order */ ed->type = DLIL_DESC_ETYPE2; ed->data[0] = *(u_int16_t*)demux->data; break; } desc_blk->n_used++; return 0; }
/* 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; }
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; }