/* * Shared implementation to inject a packet to or from an interface * Return value: * 0: successful * -1: memory allocation failed * 1: other errors */ static int ip_inject_impl(inject_t style, net_inject_t *packet, boolean_t isv6, ip_stack_t *ipst) { ddi_taskq_t *tq = NULL; void (* func)(void *); injection_t *inject; mblk_t *mp; ASSERT(packet != NULL); ASSERT(packet->ni_packet != NULL); ASSERT(packet->ni_packet->b_datap->db_type == M_DATA); switch (style) { case NI_QUEUE_IN: inject = kmem_alloc(sizeof (*inject), KM_NOSLEEP); if (inject == NULL) return (-1); inject->inj_data = *packet; inject->inj_isv6 = isv6; /* * deliver up into the kernel, immitating its reception by a * network interface, add to list and schedule timeout */ func = ip_ni_queue_in_func; tq = eventq_queue_in; break; case NI_QUEUE_OUT: inject = kmem_alloc(sizeof (*inject), KM_NOSLEEP); if (inject == NULL) return (-1); inject->inj_data = *packet; inject->inj_isv6 = isv6; /* * deliver out of the kernel, as if it were being sent via a * raw socket so that IPFilter will see it again, add to list * and schedule timeout */ func = ip_ni_queue_out_func; tq = eventq_queue_out; break; case NI_DIRECT_OUT: { struct sockaddr *sock; mp = packet->ni_packet; sock = (struct sockaddr *)&packet->ni_addr; /* * ipfil_sendpkt was provided by surya to ease the * problems associated with sending out a packet. */ switch (ipfil_sendpkt(sock, mp, packet->ni_physical, netstackid_to_zoneid( ipst->ips_netstack->netstack_stackid))) { case 0 : case EINPROGRESS: return (0); case ECOMM : case ENONET : return (1); default : return (1); } /* NOTREACHED */ } default: freemsg(packet->ni_packet); return (1); } ASSERT(tq != NULL); inject->inj_ptr = ipst; if (ddi_taskq_dispatch(tq, func, (void *)inject, DDI_SLEEP) == DDI_FAILURE) { ip2dbg(("ip_inject: ddi_taskq_dispatch failed\n")); freemsg(packet->ni_packet); return (1); } return (0); }
zoneid_t netstack_get_zoneid(netstack_t *ns) { return (netstackid_to_zoneid(ns->netstack_stackid)); }
/* * Find the interface used for traffic to an address. * For lint reasons, next/next6/sin/sin6 are all declared and assigned * a value at the top. The alternative would end up with two bunches * of assignments, with each bunch setting half to NULL. */ static phy_if_t ip_routeto_impl(struct sockaddr *address, struct sockaddr *nexthop, ip_stack_t *ipst) { struct sockaddr_in6 *next6 = (struct sockaddr_in6 *)nexthop; struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)address; struct sockaddr_in *next = (struct sockaddr_in *)nexthop; struct sockaddr_in *sin = (struct sockaddr_in *)address; ire_t *ire; ire_t *nexthop_ire; phy_if_t phy_if; zoneid_t zoneid; zoneid = netstackid_to_zoneid(ipst->ips_netstack->netstack_stackid); if (address->sa_family == AF_INET6) { ire = ire_route_recursive_v6(&sin6->sin6_addr, 0, NULL, zoneid, NULL, MATCH_IRE_DSTONLY, B_TRUE, 0, ipst, NULL, NULL, NULL); } else { ire = ire_route_recursive_v4(sin->sin_addr.s_addr, 0, NULL, zoneid, NULL, MATCH_IRE_DSTONLY, B_TRUE, 0, ipst, NULL, NULL, NULL); } ASSERT(ire != NULL); /* * For some destinations, we have routes that are dead ends, so * return to indicate that no physical interface can be used to * reach the destination. */ if (ire->ire_flags & (RTF_REJECT|RTF_BLACKHOLE)) { ire_refrele(ire); return (NULL); } nexthop_ire = ire_nexthop(ire); if (nexthop_ire == NULL) { ire_refrele(ire); return (0); } if (nexthop_ire->ire_flags & (RTF_REJECT|RTF_BLACKHOLE)) { ire_refrele(nexthop_ire); ire_refrele(ire); return (0); } ASSERT(nexthop_ire->ire_ill != NULL); if (nexthop != NULL) { if (address->sa_family == AF_INET6) { next6->sin6_addr = nexthop_ire->ire_addr_v6; } else { next->sin_addr.s_addr = nexthop_ire->ire_addr; } } phy_if = (phy_if_t)nexthop_ire->ire_ill->ill_phyint->phyint_ifindex; ire_refrele(ire); ire_refrele(nexthop_ire); return (phy_if); }