errno_t mbuf_set_service_class(mbuf_t m, mbuf_svc_class_t sc) { if (m == NULL || !(m->m_flags & M_PKTHDR)) return (EINVAL); return (m_set_service_class(m, sc)); }
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); }
/* 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; }