ip6.c revision 0ec92a15793cedb674b4f9dffc0b3dd9058fc529
/* Temporary; for CR 6451644 work-around */ * These rules should be judiciously applied * if there is a need to identify something as IPv6 versus IPv4 * IPv6 funcions will end with _v6 in the ip module. * IPv6 funcions will end with _ipv6 in the transport modules. * Some macros end with _V6; e.g. ILL_FRAG_HASH_V6 * Some macros start with V6_; e.g. V6_OR_V4_INADDR_ANY * And then there are ..V4_PART_OF_V6. * The intent is that macros in the ip module end with _V6. * IPv6 global variables will start with ipv6_ * IPv6 structures will start with ipv6 * IPv6 defined constants should start with IPV6_ * (but then there are NDP_DEFAULT_VERS_PRI_AND_FLOW, etc) * ip6opt_ls is used to enable IPv6 (via /etc/system on TX systems). * We need to do this because we didn't obtain the IP6OPT_LS (0x0a) * from IANA. This mechanism will remain in effect until an official {
0xffffffffU,
0xffffffffU,
0xffffffffU,
0xffffffffU };
{
0xff020000U, 0,
0x00000001U,
0xff000000U };
{
0x000002ffU, 0,
0x01000000U,
0x000000ffU };
/* Leave room for ip_newroute to tack on the src and target addresses */ * A template for an IPv6 AR_ENTRY_QUERY sizeof (
areq_t),
/* name len (filled by ill_arp_alloc) */ sizeof (
areq_t),
/* target addr offset */ 1000,
/* (re)xmit_interval in milliseconds */ 4 /* max # of requests to buffer */ /* anything else filled in by the code */ * Handle IPv6 ICMP packets sent to us. Consume the mblk passed in. * The message has already been checksummed and if needed, * a copy has been made to be sent any interested ICMP client (conn) * Note that this is different than icmp_inbound() which does the fanout * to conn's as well as local processing of the ICMP packets. * All error messages are passed to the matching transport stream. * The packet is only processed in the context of the specified zone: typically * only this zone will reply to an echo request. This means that the caller must * call icmp_inbound_v6() for each relevant zone. ip1dbg((
"icmp_inbound_v6: pullupmsg failed\n"));
* On a labeled system, we have to check whether the zone itself is * permitted to receive raw traffic. ip1dbg((
"icmp_inbound_v6: zone %d can't receive raw",
/* Initiate IPPF processing here */ * If the ifindex changes due to SIOCSLIFINDEX * packet may return to IP on the wrong ill. * We must have exclusive use of the mblk to convert it to * Turn the echo into an echo reply. * Remove any extension headers (do not reverse a source route) * and clear the flow id (keep traffic class for now). * Reverse the source and destination addresses. * If the return address is a multicast, zero out the source * (ip_wput_v6 will set an address). * Prepare for checksum by putting icmp length in the icmp * checksum field. The checksum is calculated in ip_wput_v6. * ICMP echo replies should go out on the same interface * the request came on as probes used by in.mpathd for * detecting NIC failures are ECHO packets. We turn-off load * spreading by allocating a ip6i and setting ip6i_attach_if * to B_TRUE which is handled both by ip_wput_v6 and * ip_newroute_v6. If we don't turnoff load spreading, * the packets might get dropped if there are no * in.mpathd would wrongly detect a failure or mis-detect * a NIC failure as a link failure. As load spreading can * happen only if ill_group is not NULL, we do only for * that case and this does not affect the normal case. * We force this only on echo packets that came from on-link * hosts. We restrict this to link-local addresses which * is used by in.mpathd for probing. In the IPv6 case, * default routes typically have an ire_ipif pointer and * might work. As a default route out of this interface * may not be present, enforcing this packet to go out in * this case may not work. * If we are sending replies to ourselves, don't * set ATTACH_IF as we may not be able to find * the IRE_LOCAL on this ill i.e setting ATTACH_IF * causes ip_wput_v6 to look for an IRE_LOCAL on * "ill" which it may not find and will try to * create an IRE_CACHE for our local address. Once * we do this, we will try to forward all packets * meant to our LOCAL address. * This packet should go out the same way as it * came in i.e in clear. To make sure that global * policy will not be applied to this in ip_wput, * we attach a IPSEC_IN mp and clear ipsec_in_secure. /* This is not a secure packet */ /* XXX may wish to pass first_mp up to ndp_input someday. */ /* XXX may wish to pass first_mp up to ndp_input someday. */ * As there is no upper client to deliver, we don't * need the first_mp any more. * The next three icmp messages will be handled by MLD. * Pass all valid MLD packets up to any process(es) * listening on a raw ICMP socket. MLD messages are * freed by mld_input function. * Process received IPv6 ICMP Packet too big. * After updating any IRE it does the fanout to any matching transport streams. * Assumes the IPv6 plus ICMPv6 headers have been pulled up but nothing else. * We must have exclusive use of the mblk to update the MTU * If there's an M_CTL present, we know that allocated first_mp * earlier in this function, so we know first_mp has refcnt of one. * For link local destinations matching simply on IRE type is not * sufficient. Same link local addresses for different ILL's is ip1dbg((
"Received mtu less than IPv6 " * If an mtu less than IPv6 min mtu is received, * we must include a fragment header in ip1dbg((
"Received mtu from router: %d\n",
mtu));
/* Record the new max frag size for the ULP. */ * If we need a fragment header in every packet * (above case or multirouting), make sure the * ULP takes it into account when computing the * for non-link local destinations we match only on the IRE type ip1dbg((
"Received mtu less than IPv6" * If an mtu less than IPv6 min mtu is * received, we must include a fragment * header in subsequent packets. ip1dbg((
"Received mtu from router: %d\n",
mtu));
/* Record the new max frag size for the ULP. */ * If we need a fragment header in * every packet (above case or * multirouting), make sure the ULP * takes it into account when computing /* create message and drop it on this connections read queue */ * Fanout received ICMPv6 error packets to the transports. * Assumes the IPv6 plus ICMPv6 headers have been pulled up but nothing else. uint16_t *
up;
/* Pointer to ports in ULP header */ * Need to pullup everything in order to use * ip_hdr_length_nexthdr_v6() ip1dbg((
"icmp_inbound_error_fanout_v6: " /* Set message type, must be done after pullups */ * Deliver indication of ICMP6_PACKET_TOO_BIG to interested * Note I don't like walking every connection to deliver * this information to a set of listeners. A separate * list could be kept to keep the cost of this down. /* Try to pass the ICMP message to clients who need it */ * Verify we have at least ICMP_MIN_TP_HDR_LEN bytes of * UDP header to get the port information. * Attempt to find a client stream based on port. * Note that we do a reverse lookup since the header is * in the form we sent it out. * The rip6h header is only used for the IPCL_UDP_MATCH_V6 * and we only set the src and dst addresses and nexthdr. * Verify we have at least ICMP_MIN_TP_HDR_LEN bytes of * the TCP header to get the port information. * Attempt to find a client stream based on port. * Note that we do a reverse lookup since the header is * in the form we sent it out. * The rip6h header is only used for the IP_TCP_*MATCH_V6 and * we only set the src and dst addresses and nexthdr. * Verify we have at least ICMP_MIN_TP_HDR_LEN bytes of * the SCTP header to get the port information. * We need a IPSEC_IN in the front to fanout to AH/ESP. * We will re-use the IPSEC_IN if it is already present as * AH/ESP will not affect any fields in the IPSEC_IN for * ICMP errors. If there is no IPSEC_IN, allocate a new * one and attach it in the front. * ip_fanout_proto_again converts the ICMP errors * that come back from AH/ESP to M_DATA so that * if it is non-AH/ESP and we do a pullupmsg in * this function, it would work. Convert it back * to M_CTL before we send up as this is a ICMP * error. This could have been generated locally or * by some router. Validate the inner IPSEC * NOTE : ill_index is used by ip_fanout_proto_again * IPSEC_IN is not present. We attach a ipsec_in * message and send up to IPSEC for validating * and removing the IPSEC headers. Clear * ipsec_in_secure so that when we return * from IPSEC, we don't mistakenly think that this * is a secure packet came from the network. * NOTE : ill_index is used by ip_fanout_proto_again /* This is not a secure packet */ * For tunnels that have used IPsec protection, * we need to adjust the MTU to take into account * Self-encapsulated case. As in the ipv4 case, * we need to strip the 2nd IP header. Since mp * is already pulled-up, we can simply bcopy * the 3rd header + data over the 2nd header. * Make sure we don't do recursion more than once. * We are about to modify the packet. Make a copy if * someone else has a reference to it. * Need to set db_type back to M_DATA before * refeeding mp into this function. * Copy the 3rd header + remaining data on top * Subtract length of the 2nd header. * Now recurse, and see what I _really_ should be * The rip6h header is only used for the lookup and we * only set the src and dst addresses and nexthdr. ip1dbg((
"icmp_inbound_error_fanout_v6: drop pkt\n"));
* Process received IPv6 ICMP Redirect messages. /* Verify if it is a valid redirect */ /* ipif will be refreleased afterwards */ * Verify that the IP source address of the redirect is * the same as the current first-hop router for the specified * ICMP destination address. * Also, Make sure we had a route for the dest in question and * that route was pointing to the old gateway (the source of the * the redirect was not from ourselves * old gateway is still directly reachable * Should we use the old ULP info to create the new gateway? From * a user's perspective, we should inherit the info so that it * is a "smooth" transition. If we do not do that, then new * connections going thru the new gateway will have no route metrics, * which is counter-intuitive to user. From a network point of * view, this may or may not make sense even though the new gateway * is still directly connected to us so the route metrics should not * But if the old ire_uinfo is not initialized, we do another * recursive lookup on the dest using the new gateway. There may * be a route to that. If so, use it to initialize the redirect * Only do the following if the redirection is really to * Check to see if link layer address has changed and * process the nce_state accordingly. ip1dbg((
"icmp_redirect_v6: NCE create failed %d\n",
/* icmp_redirect_ok_v6() must have already verified this */ * Create a Route Association. This will allow us to remember * a router told us to use the particular gateway. NULL,
/* Fast Path header */ * Just create an on link entry, i.e. interface route. dst,
/* gateway == dst */ NULL,
/* Fast Path header */ /* Release reference from earlier ipif_get_next_ipif() */ /* tell routing sockets that we received a redirect */ * Delete any existing IRE_HOST type ires for this destination. * This together with the added IRE has the effect of * modifying an existing redirect. ip0dbg((
"ip_queue_to_ill_v6: no ill\n"));
* Assigns an appropriate source address to the packet. * If origdst is one of our IP addresses that use it as the source. * If the queue is an ill queue then select a source from that ill. * Otherwise pick a source based on a route lookup back to the origsrc. * src is the return parameter. Returns a pointer to src or NULL if failure. /* Destined to one of our addresses */ /* What is the route back to the original source? */ * Does not matter whether we use ire_stq or ire_ipif here. * Just pick an ill for ICMP replies. * Unusual case - can't find a usable source address to reach the * original source. Use what in the route to the source. * Build and ship an IPv6 ICMP message using the packet data in mp, * and the ICMP header pointed to by "stuff". (May be called as * Note: assumes that icmp_pkt_err_ok_v6 has been called to * verify that an icmp error packet can be sent. * If q is an ill write side queue (which is the case when packets * arrive from ip_rput) then ip_wput code will ensure that packets to * link-local destinations are sent out that ill. * If v6src_ptr is set use it as a source. Otherwise select a reasonable * source address (see above function). * 1) a IPSEC_OUT, then this is caused by outbound * datagram originating on this host. IPSEC processing * may or may not have been done. Refer to comments above * icmp_inbound_error_fanout for details. * 2) a IPSEC_IN if we are generating a icmp_message * for an incoming datagram destined for us i.e called * from ip_fanout_send_icmp. * Convert the IPSEC_IN to IPSEC_OUT. * Clear out ipsec_out_proc_begin, so we do a fresh * This is in clear. The icmp message we are building * here should go out in clear. /* This is not a secure packet */ * For trusted extensions using a shared IP address we can * Convert the IPSEC_IN to IPSEC_OUT. * Set ipsec_out_icmp_loopback so we can let the ICMP messages this * node generates be accepted in peace by all on-host destinations. * If we do NOT assume that all on-host destinations trust * self-generated ICMP messages, then rework here, ip.c, and spd.c. * (Look for ipsec_out_icmp_loopback). * Prepare for checksum by putting icmp length in the icmp * checksum field. The checksum is calculated in ip_wput_v6. /* Send to V6 writeside put routine */ * Update the output mib when ICMPv6 packets are sent. * Check if it is ok to send an ICMPv6 error packet in * response to the IP packet in mp. * Free the message and return null if no * ICMP error packet should be sent. /* Check if source address uniquely identifies the host */ /* Explicitly do not generate errors in response to redirects */ * Check that the destination is not multicast and that the packet * was not sent on link layer broadcast or multicast. (Exception * is Packet too big message as per the draft - when mcast_ok is set.) * Only send ICMP error packets every so often. * but for now this will suffice. * Generate an ICMPv6 redirect message. * Include target link layer address option if it exits. * Always include redirect header. * We are called from ip_rput where we could * not have attached an IPSEC_IN. /* max_redir_hdr_data_len and nd_opt_rh_len must be multiple of 8 */ /* Make sure mp is 8 byte aligned */ /* ipif_v6src_addr contains the link-local source address */ * The receiver of the redirect will verify whether it * had a route through us (srcp that we will use in * the redirect) or not. As we load spread even link-locals, * we don't know which source address the receiver of * redirect has in its route for communicating with us. * Thus we randomly choose a source here and finally we * should get to the right one and it will eventually * accept the redirect from us. We can't call * ip_lookup_scope_v6 because we don't have the right * link-local address here. Thus we randomly choose one. /* Redirects sent by router, and router is global zone */ /* Generate an ICMP time exceeded message. (May be called as writer.) */ * Generate an ICMP unreachable message. * Generate an ICMP pkt too big message. * Generate an ICMP parameter problem message. (May be called as writer.) * 'offset' is the offset from the beginning of the packet in error. * This code will need to take into account the possibility of binding * to a link local address on a multi-homed host, in which case the * outgoing interface (from the conn) will need to be used when getting * an ire for the dst. Going through proper outgoing interface and * choosing the source address corresponding to the outgoing interface * is necessary when the destination address is a link-local address and * IPV6_BOUND_IF or IPV6_PKTINFO or scope_id has been set. * This can happen when active connection is setup; thus ipp pointer * is passed here from tcp_connect_*() routines, in non-TCP cases NULL * pointer is passed as ipp pointer. if (
len < (
sizeof (*
tbr) +
1)) {
"ip_bind_v6: bogus msg, len %ld",
len);
/* Back up and extract the protocol identifier. */ /* Reset the message type in preparation for shipping it back. */ * Check for a zero length address. This is from a protocol that * wants to register to receive all packets of its type. * TCP, SCTP, AH, and ESP have single protocol fanouts. * Do not allow others to bind to these. * The udp module never sends down a zero-length address, * and allowing this on a labeled system will break MLP /* Allow ipsec plumbing */ /* Extract the address pointer from the message. */ ip1dbg((
"ip_bind_v6: no address\n"));
ip1dbg((
"ip_bind_v6: unaligned address\n"));
ip1dbg((
"ip_bind_v6: bad address length %d\n",
/* Verification of local address only */ * Verify that both the source and destination addresses * Note that we allow connect to broadcast and multicast * addresses when ire_requested is set. Thus the ULP * has to check for IRE_BROADCAST and multicast. /* For raw socket, the local port is not set. */ /* Always verify destination reachability. */ * Verify that the source address is valid. * Note that we allow connect to broadcast and multicast * addresses when ire_requested is set. Thus the ULP * has to check for IRE_BROADCAST and multicast. * Client that passed ipa6_conn_x_t to us specifies whether to * verify destination reachability. /* Bind to IPv4 address */ * Bind to local and remote address. Local might be * unspecified in which case it will be extracted from /* Connect to IPv4 address */ /* Is the source unspecified or mapped? */ "dst is mapped, but not the src\n"));
* XXX Fix needed. Need to pass ipsec_policy_set /* Always verify destination reachability. */ "src is mapped, but not the dst\n"));
/* Update qinfo if v4/v6 changed */ * Pass the IPSEC headers size in ire_ipsec_overhead. * We can't do this in ip_bind_insert_ire because the policy * may not have been inherited at that point in time and hence * conn_out_enforce_policy may not be set. * Here address is verified to be a valid local address. * If the IRE_DB_REQ_TYPE mp is present, a multicast * address is also considered a valid local address. * In the case of a multicast address, however, the * upper protocol is expected to reset the src address * to 0 if it sees an ire with IN6_IS_ADDR_MULTICAST returned so that * no packets are emitted with multicast address as * The addresses valid for bind are: * (2) - IP address of an UP interface * (3) - IP address of a DOWN interface * (4) - a multicast address. In this case * the conn will only receive packets destined to * the specified multicast address. Note: the * application still has to issue an * IPV6_JOIN_GROUP socket option. * In all the above cases, the bound address must be valid in the current zone. * When the address is loopback or multicast, there might be many matching IREs * so bind has to look up based on the zone. * If it was previously connected, conn_fully_bound would have * If an address other than in6addr_any is requested, * we verify that it is a valid address for bind * Note: Following code is in if-else-if form for * readability compared to a condition check. * (2) Bind to address of local UP interface * (4) bind to multicast address. * Fake out the IRE returned to upper * layer to be a broadcast IRE in * ip_bind_insert_ire_v6(). * Pass other information that matches * the ipif (e.g. the source address). * conn_multicast_ill is only used for * Not a valid address for bind * Just to keep it consistent with the processing in /* Red Alert! Attempting to be a bogon! */ * Allow setting new policies. For example, disconnects come * down as ipa_t bind. As we would have set conn_policy_cached * to B_TRUE before, we should set it to B_FALSE, so that policy * can change after the disconnect. /* If not fanout_insert this was just an address verification */ * The addresses have been verified. Time to insert in * the correct fanout list. * We need to make sure that the conn_recv is set to a non-null * value before we insert the conn_t into the classifier table. * This is to avoid a race with an incoming packet which does * As of now assume that nothing else accompanies /* Pass sticky_ipp for scope_id and pktinfo */ * Verify that both the source and destination addresses * are valid. If verify_dst, then destination address must also be reachable, * i.e. have a route. Protocols like TCP want this. Tunnels do not. * It takes ip6_pkt_t * as one of the arguments to determine correct * source address when IPV6_PKTINFO or scope_id is set along with a link-local * destination address. Note that parameter ipp is only useful for TCP connect * when scope_id is set or IPV6_PKTINFO option is set with an ifindex. For all * non-TCP cases, it is NULL and for all other tcp cases it is not useful. * NOTE: The protocol is beyond the wptr because that's how * the undocumented transport<-->IP T_BIND_REQ behavior works. * If we never got a disconnect before, clear it now. * Use an "emulated" IRE_BROADCAST to tell the transport it * Pass other information that matches * the ipif (e.g. the source address). * conn_multicast_ill is only used for IPv6 packets /* Look for default like ip_wput_v6 */ * We also prevent ire's with src address INADDR_ANY to * be used, which are created temporarily for * sending out packets from endpoints that have * When verifying destination reachability, we always * When not verifying destination reachability but we * found an IRE, i.e. the destination is reachable, * then the other tests still apply and we complain. * We now know that routing will allow us to reach the destination. * Check whether Trusted Solaris policy allows communication with this * host, and pretend that the destination is unreachable if not. * This is never a problem for TCP, since that transport is known to * compute the label properly as part of the tcp_rput_other T_BIND_ACK * handling. If the remote is unreachable, it will be detected at that * point, so there's no reason to check it here. * Note that for sendto (and other datagram-oriented friends), this * check is done as part of the data path label computation instead. * The check here is just to make non-TCP connect() report the right pr_addr_dbg(
"ip_bind_connected: no label for dst %s\n",
* If the app does a connect(), it means that it will most likely * send more than 1 packet to the destination. It makes sense * to clear the temporary flag. * See if we should notify ULP about MDT; we do this whether or not * ire_requested is TRUE, in order to handle active connects; MDT * eligibility tests for passive connects are handled separately * through tcp_adapt_ire(). We do this before the source address * selection, because dst_ire may change after a call to * ipif_select_source_v6(). This is a best-effort check, as the * packet for this connection may not actually go through * dst_ire->ire_stq, and the exact IRE can only be known after * calling ip_newroute_v6(). This is why we further check on the * IRE during Multidata packet transmission in tcp_multisend(). * Pick a source address so that a proper inbound load * spreading would happen. Use dst_ill specified by the * app. when socket option or scopeid is set. * Scope id or IPV6_PKTINFO ip1dbg((
"ip_bind_connected_v6:" * For IPV6_BOUND_IF socket option, * conn_outgoing_ill should be set ip1dbg((
"ip_bind_connected_v6:" "no ill for bound_if\n"));
/* No need to hold ill here */ /* No need to hold ill here */ "no usable source address for " * We do ire_route_lookup_v6() here (and not an interface lookup) * as we assert that v6src should only come from an * UP interface for hard binding. /* src_ire must be a local|loopback */ * If the source address is a loopback address, the * destination had best be local or multicast. * The transports that can't handle multicast will reject ip1dbg((
"ip_bind_connected_v6: bad connected loopback\n"));
* Allow setting new policies. For example, disconnects come * down as ipa_t bind. As we would have set conn_policy_cached * to B_TRUE before, we should set it to B_FALSE, so that policy * can change after the disconnect. * The addresses have been verified. Initialize the conn * before calling the policy as they expect the conns * Note that sire will not be NULL if this is an off-link * connection and there is not cache for that dest yet. * XXX Because of an existing bug, if there are multiple * default routes, the IRE returned now may not be the actual * default route used (default routes are chosen in a * round robin fashion). So if the metrics for different * default routes are different, we may return the wrong * metrics. This will not be a problem if the existing * Cache IPsec policy in this conn. If we have per-socket policy, * we'll cache that. If we don't, we'll inherit global policy. * We can't insert until the conn reflects the policy. Note that * conn_policy_cached is set by ipsec_conn_cache_policy() even for * connections where we don't have a policy. This is to prevent * global policy lookups in the inbound path. * If we insert before we set conn_policy_cached, * CONN_INBOUND_POLICY_PRESENT_V6() check can still evaluate true * because global policy cound be non-empty. We normally call * ipsec_check_policy() for conn_policy_cached connections only if * conn_in_enforce_policy is set. But in this case, * conn_policy_cached can get set anytime since we made the * CONN_INBOUND_POLICY_PRESENT_V6() check and ipsec_check_policy() * is called, which will make the above assumption false. Thus, we * need to insert after we set conn_policy_cached. /* If not fanout_insert this was just an address verification */ * The addresses have been verified. Time to insert in * the correct fanout list. * We need to make sure that the conn_recv is set to a non-null * value before we insert the conn_t into the classifier table. * This is to avoid a race with an incoming packet which does * Our initial checks for MDT have passed; the IRE is not * be supporting MDT. Pass the IRE, IPC and ILL into * ip_mdinfo_return(), which performs further checks * against them and upon success, returns the MDT info * mblk which we will attach to the bind acknowledgment. * As of now assume that nothing else accompanies * Insert the ire in b_cont. Returns false if it fails (due to lack of space). * Makes the IRE be IRE_BROADCAST if dst is a multicast address. * mp1 initialized above to IRE_DB_REQ_TYPE * appended mblk. Its <upper protocol>'s * job to make sure there is room. * No IRE was found. Remove IRE mblk. * Add an ip6i_t header to the front of the mblk. * Inline if possible else allocate a separate mblk containing only the ip6i_t. * Returns NULL if allocation fails (and frees original message). * Used in outgoing path when going through ip_newroute_*v6(). * Used in incoming path to pass ifindex to transports. * Handle protocols with which IP is less intimate. There * can be more than one stream bound to a particular * protocol. When this is the case, normally each one gets a copy * of any incoming packets. * However, if the packet was tunneled and not multicast we only send to it * Packets will be distributed to streams in all zones. This is really only * useful for ICMPv6 as only applications in the global zone can create raw * sockets for other protocols. * If the packet was tunneled and not multicast we only send to it * We don't allow multilevel ports for raw IP, so no need to * No one bound to this port. Is * there a client that wants all * XXX: Fix the multiple protocol listeners case. We should not * be walking the conn->next list here. * Only send message to one tunnel driver by immediately * Just copy the data part alone. The mctl part is * needed just for verifying policy and it is never * No more intested clients or memory * For link-local always add ifindex so that transport can set * sin6_scope_id. Avoid it for ICMP error fanout. * Don't enforce here if we're a tunnel - let "tun" do /* Follow the next pointer before releasing the conn. */ /* Last one. Send it upstream. */ /* Initiate IPPF processing */ * For link-local always add ifindex so that transport can set * sin6_scope_id. Avoid it for ICMP error fanout. * Tunneled packet. We enforce policy in the tunnel * Send the WHOLE packet up (incl. IPSEC_IN) without * Don't enforce here if we're a tunnel - let "tun" do * Send an ICMP error after patching up the packet appropriately. Returns * non-zero if the appropriate MIB should be bumped; zero otherwise. * If this is an ICMP error being reported - which goes * up as M_CTLs, we need to convert them to M_DATA till * we finish checking with global policy because * ipsec_check_global_policy() assumes M_DATA as clear * We are generating an icmp error for some inbound packet. * Called from all ip_fanout_(udp, tcp, proto) functions. * Before we generate an error, check with global policy * to see whether this is allowed to enter the system. As * there is no "conn", we are checking with global policy. panic(
"ip_fanout_send_icmp_v6: wrong type");
* The caller puts <fport, lport> in the ports parameter. * No hard-bound match. Send Reset. /* Initiate IPPf processing, if needed. */ * For fused tcp loopback, assign the eager's * squeue to be that of the active connect's. * db_cksumstuff is unused in the incoming * path; Thus store the ifindex here. It will * be cleared in tcp_conn_create_v6(). * Discard first_mp early since we're dealing with a * fully-connected conn_t and tcp doesn't do policy in * this case. Also, if someone is bound to IPPROTO_TCP * over raw IP, they don't expect to see a M_CTL. /* Initiate IPPF processing */ * ip_add_info_v6 might return a new mp. * For link-local always add ifindex so that TCP can bind to that * interface. Avoid it for ICMP error fanout. * Fanout for UDP packets. * The caller puts <fport, lport> in the ports parameter. * ire_type must be IRE_BROADCAST for multicast and broadcast packets. * If SO_REUSEADDR is set all multicast and broadcast packets * will be delivered to all streams bound to the same port. * Multicast packets will be distributed to streams in all zones. /* Extract ports in net byte order */ * No need to handle exclusive-stack zones since ALL_ZONES * only applies to the shared stack. * If no shared MLP is found, tsol_mlp_findzone returns * ALL_ZONES. In that case, we assume it's SLP, and * search for the zone based on the packet label. * That will also return ALL_ZONES on failure, but * we never allow conn_zoneid to be set to ALL_ZONES. /* Attempt to find a client stream based on destination port. */ * Not multicast. Send to the one (first) client we find. /* Initiate IPPF processing */ * For link-local always add ifindex so that * transport can set sin6_scope_id. Avoid it for * Just copy the data part alone. The mctl part is * needed just for verifying policy and it is never * No more interested clients or memory * For link-local always add ifindex so that transport * can set sin6_scope_id. Avoid it for ICMP error /* mp1 could have changed */ /* Follow the next pointer before releasing the conn. */ /* Last one. Send it upstream. */ /* Initiate IPPF processing */ * For link-local always add ifindex so that transport can set * sin6_scope_id. Avoid it for ICMP error fanout. * No one bound to this port. Is * there a client that wants all * This routine is used by the upper layer protocols and the IP tunnel * - Set extension header pointers to appropriate locations * - Determine IPv6 header length and return it * - Return a pointer to the last nexthdr value * The caller must initialize ipp_fields. * NOTE: If multiple extension headers of the same type are present, * ip_find_hdr_v6() will set the respective extension header pointers * to the first one that it encounters in the IPv6 header. It also * skips fragment headers. This routine deals with malformed packets * of various sorts in which case the returned length is up to the /* Is there enough left for len + nexthdr? */ /* return only 1st hbh */ * ipp_dstopts is set to the destination header after a * Assume it is a post-rthdr destination header * and adjust when we find an rthdr. /* return only 1st rthdr */ * Make any destination header we've seen be a * pre-rthdr destination header. ip1dbg((
"ip_hdr_complete_v6: no source IRE\n"));
* Try to determine where and what are the IPv6 header length and * pointer to nexthdr value for the upper layer protocol (or an * Parameters returns a pointer to the nexthdr value; * Must handle malformed packets of various sorts. * Function returns failure for malformed cases. /* Is there enough left for len + nexthdr? */ /* Assumes the headers are identical for hbh and dst */ /* No next header means we're finished */ * If any know extension headers are still to be processed, * the packet's malformed (or at least all the IP header(s) are * not in the same mblk - and that should never happen. * If we get here, we know that all of the IP headers were in * the same mblk, even if the ULP header is in the next mblk. * Return the length of the IPv6 related headers (including extension headers) * Returns a length even if the packet is malformed. * Select an ill for the packet by considering load spreading across * a different ill in the group if dst_ill is part of some group. * We schedule irrespective of whether the source address is * INADDR_UNSPECIED or not. * For groups with names ip_sioctl_groupname ensures that all * ills are of same type. For groups without names, ifgrp_insert * ip_newroute_v6 is called by ip_rput_data_v6 or ip_wput_v6 whenever we need * to send out a packet to a destination address for which we do not have * specific routing information. * Handle non-multicast packets. If ill is non-NULL the match is done * When a specific ill is specified (using IPV6_PKTINFO, * IPV6_MULTICAST_IF, or IPV6_BOUND_IF) we will only match * on routing entries (ftable and ctable) that have a matching * ire->ire_ipif->ipif_ill. Thus this can only be used * for destinations that are on-link for the specific ill * and that can appear on multiple links. Thus it is useful * for multicast destinations, link-local destinations, and * at some point perhaps for site-local destinations (if the * node sits at a site boundary). * We create the cache entries in the regular ctable since * it can not "confuse" things for other destinations. * When ill is part of a ill group, we subject the packets * to load spreading even if the ill is specified by the * means described above. We disable only for IPV6_BOUND_PIF * and for the cases where IP6I_ATTACH_IF is set i.e NS/NA/ * Echo replies to link-local destinations have IP6I_ATTACH_IF * NOTE : These are the scopes of some of the variables that point at IRE, * which needs to be followed while making any future modifications * - ire and sire are the entries looked up initially by * - ipif_ire is used to hold the interface ire associated with * the new cache ire. But it's scope is limited, so we always REFRELE * it before branching out to error paths. * - save_ire is initialized before ire_create, so that ire returned * by ire_create will not over-write the ire. We REFRELE save_ire * before breaking out of the switch. * Thus on failures, we have to REFRELE only ire and sire, if they * v6srcp may be used in the future. Currently unused. * If this end point is bound to IPIF_NOFAILOVER, set bnf_ill and * bind_to_nofailover B_TRUE. We can't use conn to determine as it * This information can appear either in an ip6i_t or an IPSEC_OUT /* Failure case frees things for us. */ * Check if we need an ire that will not be * looked up by anybody else i.e. HIDDEN. ip1dbg((
"ip_newroute_v6: dst with loopback addr\n"));
ip1dbg((
"ip_newroute_v6: src with loopback addr\n"));
* If this IRE is created for forwarding or it is not for * TCP traffic, mark it as temporary. * Is it sufficient just to check the next header?? * Get what we can from ire_ftable_lookup_v6 which will follow an IRE * chain until it gets the most specific information available. * For example, we know that there is no IRE_CACHE for this dest, * but there may be an IRE_OFFSUBNET which specifies a gateway. * ire_ftable_lookup_v6 will look up the gateway, etc. * ire_add_then_send -> ip_newroute_v6 in the CGTP case passes * in a NULL ill, but the packet could be a neighbor * attach_ill is set only for communicating with * on-link hosts. So, don't look for DEFAULT. * ip_wput_v6 passes the right ill in this case and ip3dbg((
"ip_newroute_v6: ire_ftable_lookup_v6() " "returned ire %p, sire %p\n", (
void *)
ire, (
void *)
sire));
* In the forwarding case, we can use a route from any zone * since we won't change the source address. We can easily * assert that the source address is already set when there's no * ip6_info header - otherwise we'd have to call pullupmsg(). * We enter a loop that will be run only once in most cases. * The loop is re-entered in the case where the destination * can be reached through multiple RTF_MULTIRT-flagged routes. * The intention is to compute multiple routes to a single * destination in a single ip_newroute_v6 call. * The information is contained in sire->ire_flags. ip3dbg((
"ip_newroute_v6: starting new resolution " "with first_mp %p, tag %d\n",
* We check if there are trailing unresolved routes for * the destination contained in sire. ip3dbg((
"ip_newroute_v6: multirt_is_resolvable %d, " * No more multirt routes to resolve; give up * (all routes resolved or no more resolvable * We simply use first_sire as a flag that * indicates if a resolvable multirt route has * already been found during the preceding * loops. If it is not the case, we may have * to send an ICMP error to report that the * destination is unreachable. We do not * IRE_REFHOLD first_sire. * either ire == NULL (the destination cannot be * resolved) or ire == sire (the gateway cannot be * resolved). At this point, there are no more routes * to resolve for the destination, thus we exit. "ire %p, sire %p, first_sire %p\n",
* At least one multirt route has been found * in the same ip_newroute() call; there is no * need to report an ICMP error. * first_sire was not IRE_REFHOLDed. * Verify that the returned IRE does not have either the * RTF_REJECT or RTF_BLACKHOLE flags set and that the IRE is * either an IRE_CACHE, IRE_IF_NORESOLVER or IRE_IF_RESOLVER. * Increment the ire_ob_pkt_count field for ire if it is an * INTERFACE (IF_RESOLVER or IF_NORESOLVER) IRE type, and * increment the same for the parent IRE, sire, if it is some * sort of prefix IRE (which includes DEFAULT, PREFIX, and HOST) * We have a route to reach the destination. * 1) If the interface is part of ill group, try to get a new * ill taking load spreading into account. * 2) After selecting the ill, get a source address that might * create good inbound load spreading and that matches the * right scope. ipif_select_source_v6 does this for us. * If the application specified the ill (ifindex), we still * load spread. Only if the packets needs to go out specifically * on a given ill e.g. bind to IPIF_NOFAILOVER address, * IPV6_BOUND_PIF we don't try to use a different ill for load * If the interface belongs to an interface group, * make sure the next possible interface in the group * is used. This encourages load spreading among * peers in an interface group. However, in the case * of multirouting, load spreading is not used, as we * actually want to replicate outgoing packets through * Note: While we pick a dst_ill we are really only * interested in the ill for load spreading. * The source ipif is determined by source address /* For uniformity do a refhold */ * If we are here trying to create an IRE_CACHE * for an offlink destination and have the * IRE_CACHE for the next hop and the latter is * using virtual IP source address selection i.e * it's ire->ire_ipif is pointing to a virtual * network interface (vni) then * ip_newroute_get_dst_ll() will return the vni * interface as the dst_ill. Since the vni is * virtual i.e not associated with any physical * interface, it cannot be the dst_ill, hence * in such a case call ip_newroute_get_dst_ll() * with the stq_ill instead of the ire_ipif ILL. * The function returns a refheld ill. * If "ill" is not part of any group, we should * have found a route matching "ill" as we * called ire_ftable_lookup_v6 with * Rather than asserting when there is a * mismatch, we just drop the packet. ip0dbg((
"ip_newroute_v6: BOUND_IF failed : " /* For uniformity do refhold */ * We should have found a route matching ill as we * called ire_ftable_lookup_v6 with MATCH_IRE_ILL. * Rather than asserting, while there is a mismatch, * we just drop the packet. ip0dbg((
"ip_newroute_v6: Packet dropped as " "IP6I_ATTACH_IF ill is %s, " "ire->ire_ipif->ipif_ill is %s\n",
* Pick a source address which matches the scope of the * For RTF_SETSRC routes, the source address is imposed by the * The ire cache entry we're adding is for the * gateway itself. The source address in this case * is relative to the gateway's address. * Check that the ipif matching the requested * source address still exists. printf(
"ip_newroute_v6: interface name %s\n",
ip2dbg((
"\tire type %s (%d)\n",
* At this point in ip_newroute_v6(), ire is either the * IRE_CACHE of the next-hop gateway for an off-subnet * destination or an IRE_INTERFACE type that should be used * to resolve an on-subnet destination or an on-subnet * In the IRE_CACHE case, we have the following : * 1) src_ipif - used for getting a source address. * means packets using this IRE_CACHE will go out on dst_ill. * 3) The IRE sire will point to the prefix that is the longest * matching route for the destination. These prefix types * include IRE_DEFAULT, IRE_PREFIX, IRE_HOST. * The newly created IRE_CACHE entry for the off-subnet * destination is tied to both the prefix route and the * interface route used to resolve the next-hop gateway * via the ire_phandle and ire_ihandle fields, respectively. * In the IRE_INTERFACE case, we have the following : * 1) src_ipif - used for getting a source address. * means packets using the IRE_CACHE that we will build * here will go out on dst_ill. * 3) sire may or may not be NULL. But, the IRE_CACHE that is * to be created will only be tied to the IRE_INTERFACE that * was derived from the ire_ihandle field. * If sire is non-NULL, it means the destination is off-link * and we will first create the IRE_CACHE for the gateway. * Next time through ip_newroute_v6, we will create the * IRE_CACHE for the final destination as described above. * We need 3 ire's to create a new cache ire for an * off-link destination from the cache ire of the * 1. The prefix ire 'sire' * 2. The cache ire of the gateway 'ire' * 3. The interface ire 'ipif_ire' * We have (1) and (2). We lookup (3) below. * If there is no interface route to the gateway, * it is a race condition, where we found the cache * but the inteface route has been deleted. "ire_ihandle_lookup_offlink_v6 failed\n"));
* Assume DL_UNITDATA_REQ is same for all physical * interfaces in the ifgrp. If it isn't, this code will * have to be seriously rewhacked to allow the * fastpath probing (such that I cache the link * header in the IRE_CACHE) to work over ifgrps. * We have what we need to build an IRE_CACHE. * Note: the new ire inherits RTF_SETSRC * and RTF_MULTIRT to propagate these flags from prefix * Check cached gateway IRE for any security * attributes; if found, associate the gateway * credentials group to the destination IRE. &
v6gw,
/* gateway address */ NULL,
/* Fast Path header */ /* reference now held by IRE */ * Prevent sire and ipif_ire from getting deleted. The * newly created ire is tied to both of them via the * phandle and ihandle respectively. /* Has it been removed already ? */ /* Has it been removed already ? */ /* Assert that sire is not deleted yet. */ /* Assert that ipif_ire is not deleted yet. */ * Search for the next unresolved * We have what we need to build an IRE_CACHE. * Create a new dlureq_mp with the IPv6 gateway * address in destination address in the DLPI hdr * if the physical length is exactly 16 bytes. * handle the Gated case, where we create * a NORESOLVER route for loopback. * TSol note: We are creating the ire cache for the * destination 'dst'. If 'dst' is offlink, going * through the first hop 'gw', the security attributes * of 'dst' must be set to point to the gateway * credentials of gateway 'gw'. If 'dst' is onlink, it * is possible that 'dst' is a potential gateway that is * referenced by some route that has some security * attributes. Thus in the former case, we need to do a * gcgrp_lookup of 'gw' while in the latter case we * need to do gcgrp_lookup of 'dst' itself. * Note: the new ire inherits sire flags RTF_SETSRC * and RTF_MULTIRT to propagate those rules from prefix &
v6gw,
/* gateway address */ NULL,
/* Fast Path header */ /* reference now held by IRE */ /* Prevent save_ire from getting deleted */ /* Has it been removed already ? */ * In case of MULTIRT, a copy of the current packet * to send is made to further re-enter the * loop and attempt another route resolution /* Assert that it is not deleted yet. */ * If we found a (no)resolver, we ignore any * trailing top priority IRE_CACHE in * further loops. This ensures that we do not * omit any (no)resolver despite the priority * IRE_CACHE, if any, will be processed * by another thread entering ip_newroute(), * (on resolver response, for example). * We use this to force multiple parallel * resolution as soon as a packet needs to be * sent. The result is, after one packet * emission all reachable routes are generally * Otherwise, complete resolution of MULTIRT * routes would require several emissions as * Search for the next unresolved multirt /* Don't need sire anymore */ * We can't build an IRE_CACHE yet, but at least we * found a resolver that can help. * To be at this point in the code with a non-zero gw * means that dst is reachable through a gateway that * we have never resolved. By changing dst to the gw * addr we resolve the gateway first. When * ire_add_then_send() tries to put the IP dg to dst, * it will reenter ip_newroute() at which time we will * find the IRE_CACHE for the gw and create another * IRE_CACHE above (for dst itself). * Ask the external resolver to do its thing. * Make an mblk chain in the following form: * ARQ_REQ_MBLK-->IRE_MBLK-->packet ip1dbg((
"ip_newroute_v6:ILLF_XRESOLV\n"));
&
v6gw,
/* gateway address */ NULL,
/* Fast Path header */ * processing a copy of the packet to * send for further resolution loops * Now create or find an nce for this interface. * The hw addr will need to to be set from * the reply to the AR_ENTRY_QUERY that * we're about to send. This will be done in * New cache entry created. * Break, then ask the external * Resolution in progress; * packet has been queued by * Check if another multirt * route must be resolved. * If we found a resolver, we * ignore any trailing top * further loops. The reason is * the same as for noresolver. * unresolved multirt route. * Transient error; packet will be * Now set up the AR_ENTRY_QUERY and send it. * link the chain, then send up to the resolver. "putnext to resolver\n"));
* Check if another multirt route * If we find a resolver, we ignore any * trailing top priority IRE_CACHE in * further loops. The reason is the * same as for noresolver. * Search for the next unresolved * Non-external resolver case. * TSol note: Please see the note above the * IRE_IF_NORESOLVER case. &
v6gw,
/* gateway address */ NULL,
/* Fast Path header */ /* reference now held by IRE */ /* Prevent save_ire from getting deleted */ /* Has it been removed already ? */ * We have a resolved cache entry, /* Assert that it is not deleted yet. */ * Check if another multirt route * If we find a resolver, we ignore any * trailing top priority IRE_CACHE in * further loops. The reason is the * same as for noresolver. * Search for the next unresolved * mp was consumed - presumably queued. * No need for ire, presumably resolution is * in progress, and ire will be added when the * Check if another multirt route * If we find a resolver, we ignore any * trailing top priority IRE_CACHE in * further loops. The reason is the * same as for noresolver. * Search for the next unresolved /* Some transient error */ ip1dbg((
"ip_newroute_v6: dropped\n"));
/* Did this packet originate externally? */ ip1dbg((
"ip_newroute_v6: no route\n"));
* We need to set sire to NULL to avoid double freeing if we * ever goto err_ret from below. /* Skip ip6i_t header if present */ /* Make sure the IPv6 header is present */ ip1dbg((
"ip_newroute_v6: pullupmsg failed\n"));
/* Did this packet originate externally? */ * At this point we will have ire only if RTF_BLACKHOLE * or RTF_REJECT flags are set on the IRE. It will not * generate ICMP6_DST_UNREACH_NOROUTE if RTF_BLACKHOLE is set. * ip_newroute_ipif_v6 is called by ip_wput_v6 and ip_wput_ipsec_out_v6 whenever * we need to send out a packet to a destination address for which we do not * have specific routing information. It is only used for multicast packets. * If unspec_src we allow creating an IRE with source address zero. * ire_send_v6() will delete it after the packet is sent. * This loop is run only once in most cases. * We loop to resolve further routes only when the destination * can be reached through multiple RTF_MULTIRT-flagged ires. printf(
"ip_newroute_ipif_v6: if %s, v6 %d\n",
* If the interface is a pt-pt interface we look for an * IRE_IF_RESOLVER or IRE_IF_NORESOLVER that matches both the * local_address and the pt-pt destination address. * Otherwise we just match the local address. * If this end point is bound to IPIF_NOFAILOVER, set bnf_ill * and bind_to_nofailover B_TRUE. We can't use conn to determine * This information can appear either in an ip6i_t or an /* Failure case frees things for us. */ * Check if we need an ire that will not be * looked up by anybody else i.e. HIDDEN. * We check if an IRE_OFFSUBNET for the addr that goes through * ipif exists. We need it to determine if the RTF_SETSRC and/or * RTF_MULTIRT flags must be honored. ip2dbg((
"ip_newroute_ipif_v6: " "ipif_lookup_multi_ire_v6(" "ipif %p, dst %08x) = fire %p\n",
* If the application specified the ill (ifindex), we still * load spread. Only if the packets needs to go out specifically * on a given ill e.g. binding to IPIF_NOFAILOVER address or * IPV6_BOUND_PIF, or there is a parent ire entry that specified * multirouting, then we don't try to use a different ill for * If the interface belongs to an interface group, * make sure the next possible interface in the group * is used. This encourages load spreading among peers * Note: While we pick a dst_ill we are really only * interested in the ill for load spreading. The source * ipif is determined by source address selection below. /* For uniformity do a refhold */ /* refheld by ip_newroute_get_dst_ill_v6 */ "no dst ill for dst %s\n",
* ip_wput_v6 passes the right ipif for IPIF_NOFAILOVER * and IPV6_BOUND_PIF case. /* attach_ill is already refheld */ * Pick a source address which matches the scope of the * For RTF_SETSRC routes, the source address is imposed by the * Check that the ipif matching the requested source printf(
" through interface %s\n",
printf(
"ip_newroute_ipif_v6: " ip1dbg((
"ip_newroute_ipif_v6: interface type %s (%d),",
ip2dbg((
"ip_newroute_ipif: ire %p, ipif %p\n",
* an IRE_OFFSUBET was looked up * this ire has RTF_MULTIRT flag, * will be re-entered to resolve * additional routes on other * interfaces. For that purpose, * a copy of the packet is /* We have what we need to build an IRE_CACHE. */ * Create a new dlureq_mp with the * IPv6 gateway address in destination address in the * DLPI hdr if the physical length is exactly 16 bytes. * handle the Gated case, where we create * a NORESOLVER route for loopback. * The newly created ire will inherit the flags of the NULL,
/* gateway address */ NULL,
/* Fast Path header */ /* Prevent save_ire from getting deleted */ /* Has it been removed already ? */ /* Assert that it is not deleted yet. */ * The resolution loop is re-entered if we * actually are in a multirouting case. * ipif_lookup_group_v6() calls * ire_lookup_multi_v6() that uses * ire_ftable_lookup_v6() to find * an IRE_INTERFACE for the group. * ire_lookup_multi_v6() then invokes * ire_multirt_lookup_v6() to find * the next resolvable ire. * As a result, we obtain a new * interface, derived from the "multirt dst %08x, ipif %p\n",
* We obtain a partial IRE_CACHE which we will pass * along with the resolver query. When the response * comes back it will be there ready for us to add. * the newly created ire will inherit the flags of the NULL,
/* gateway address */ NULL,
/* Fast Path header */ /* Resolve and add ire to the ctable */ /* Prevent save_ire from getting deleted */ /* Has it been removed already ? */ * We have a resolved cache entry, /* Assert that it is not deleted yet. */ * The resolution loop is re-entered if we * actually are in a multirouting case. * ipif_lookup_group_v6() calls * ire_lookup_multi_v6() that * uses ire_ftable_lookup_v6() * to find an IRE_INTERFACE for * the group. In the multirt * case, ire_lookup_multi_v6() * ire_multirt_lookup_v6() to * find the next resolvable ire. * As a result, we obtain a new * interface, derived from the * mp was consumed - presumably queued. * No need for ire, presumably resolution is * in progress, and ire will be added when the * The resolution loop is re-entered if we * actually are in a multirouting case. * ipif_lookup_group_v6() calls * ire_lookup_multi_v6() that * uses ire_ftable_lookup_v6() * to find an IRE_INTERFACE for * the group. In the multirt * case, ire_lookup_multi_v6() * ire_multirt_lookup_v6() to * find the next resolvable ire. * As a result, we obtain a new * interface, derived from the /* Some transient error */ /* Multicast - no point in trying to generate ICMP error */ ip1dbg((
"ip_newroute_ipif_v6: dropped\n"));
* Parse and process any hop-by-hop or destination options. * Assumes that q is an ill read queue so that ICMP errors for link-local * destinations are sent out the correct interface. * Returns -1 if there was an error and mp has been consumed. * Returns 0 if no special action is needed. * Returns 1 if the packet contained a router alert option for this node * XXX Note: In future as more hbh or dest options are defined, * it may be better to have different routines for hbh and dest * options as opt_type fields other than IP6OPT_PAD1 and IP6OPT_PADN * may have same value in different namespaces. Or is it same namespace ?? * Current code checks for each opt_type (other than pads) if it is in * the expected nexthdr (hbh or dest) * Note:We don't verify that (N-2) pad octets * are zero as required by spec. Adhere to * "be liberal in what you accept..." part of * implementation philosophy (RFC791,RFC1122) /* Check total length and alignment */ * Minimal support for the home address option * (which is required by all IPv6 nodes). * Implement by just swapping the home address * XXX Note: this has IPsec implications since * AH needs to take this into account. * Also, when IPsec is used we need to ensure * that this is only processed once * in the received packet (to avoid swapping * NOTE:This option processing is considered * to be unsafe and prone to a denial of * The current processing is not safe even with * IPsec secured IP packets. Since the home * address option processing requirement still * is in the IETF draft and in the process of * being redefined for its usage, it has been * decided to turn off the option by default. * If this section of code needs to be executed, * ndd variable ip6_ignore_home_address_opt * should be set to 0 at the user's own risk. * We did this dest. opt the first time * around (i.e. before AH processing). * If we've done AH... stop now. /* Check total length and alignment */ /* Swap ip6_src and the home address */ /* XXX Note: only 8 byte alignment option */ /* Determine which zone should send error */ ip1dbg((
"ip_process_options_v6: %s " ip1dbg((
"ip_process_options_v6: %s " "opt 0x%x; packet dropped\n",
/* Determine which zone should send error */ * Process a routing header that is not yet empty. * Only handles type 0 routing headers. /* XXX Check for source routed out same interface? */ /* Sent by forwarding path, and router is global zone */ /* rthdr->ip6r0_len is twice the number of addresses in the header */ /* An odd length is impossible */ /* Sent by forwarding path, and router is global zone */ /* segleft exceeds number of addresses in routing header */ /* Sent by forwarding path, and router is global zone */ /* Don't allow any mapped addresses - ip_wput_v6 can't handle them */ /* Sent by forwarding path, and router is global zone */ /* IPsec kstats: bean counter? */ * Read side put procedure for IPv6 module. * Things are opening or closing - only accept DLPI * ack messages. If the stream is closing and ip_wsrv * has completed, ip_close is out of the qwait, but has * not yet completed qprocsoff. Don't proceed any further * because the ill has been cleaned up and things hanging * off the ill have been freed. * This is a work-around for CR 6451644, a bug in Nemo. It * should be removed when that problem is fixed. ucp[-
5] == 0 &&
ucp[-
6] ==
0x81)
* If it's a group address, then fabricate a * DL_UNITDATA_IND message. /* Go handle anything other than data elsewhere. */ /* Save the DLPI header. */ panic(
"ip_rput_v6: got an M_BREAK");
* if db_ref > 1 then copymsg and free original. Packet may be * changed and do not want other entity who has a reference to this * message to trip over the changes. This is a blind change because * trying to catch all places that might change packet is too * difficult (since it may be a module above this one). * It may be a bit too expensive to do this mapped address * check here, but in the interest of robustness, it seems * like the correct place. * TODO: Avoid this check for e.g. connected TCP sockets ip1dbg((
"ip_rput_v6: pkt with mapped src addr\n"));
ip1dbg((
"ip_rput_v6: pkt with loopback src"));
ip1dbg((
"ip_rput_v6: pkt with loopback dst"));
* Walk through the IPv6 packet in mp and see if there's an AH header * in it. See if the AH header needs to get done before other headers in * the packet. (Worker function for ipsec_early_ah_v6().) * For now just pullup everything. In general, the less pullups, * the better, but there's so much squirrelling through anyway, * it's just easier this way. * We can't just use the argument nexthdr in the place * of nexthdrp becaue we don't dereference nexthdrp * till we confirm whether it is a valid address. /* Is there enough left for len + nexthdr? */ /* Assumes the headers are identical for hbh and dst */ * Return DONT_PROCESS because of potential Mobile IPv6 * cruft for destination options. * If there's more hops left on the routing header, * return now with DON'T PROCESS. /* Wait for reassembly */ /* No next header means we're finished */ panic(
"ipsec_needs_processing_v6");
* Path for AH if options are present. If this is the first time we are * sending a datagram to AH, allocate a IPSEC_IN message and prepend it. * Otherwise, just fanout. Return value answers the boolean question: * "Did I consume the mblk you sent me?" * Sometimes AH needs to be done before other IPv6 headers for security * reasons. This function (and its ipsec_needs_processing_v6() above) * indicates if that is so, and fans out to the appropriate IPsec protocol * for the datagram passed in. /* Default means send it to AH! */ ip1dbg((
"ipsec_early_ah_v6: IPSEC_IN " "allocation failure.\n"));
* Store the ill_index so that when we come back * from IPSEC we ride on the same queue. * Cache hardware acceleration info. "caching data attr.\n"));
/* we're done with IPsec processing, send it up */ * Validate the IPv6 mblk for alignment. /* check for alignment and full IPv6 header */ ip1dbg((
"ip_rput_v6: pullupmsg failed\n"));
* Check for bogus (too short packet) and packet which * was padded by the link layer. ip1dbg((
"ip_rput_data_v6: packet too short %d %d\n",
ip1dbg((
"ip_rput_data_v6: adjmsg failed\n"));
* ip_rput_data_v6 -- received IPv6 packets in M_DATA messages show up here. * ip_rput_v6 has already verified alignment, the min length, the version, * The ill passed in (the arg named inill) is the ill that the packet * actually arrived on. We need to remember this when saving the * input interface index into potential IPV6_PKTINFO data in * This routine doesn't free dl_mp; that's the caller's responsibility on * return. (Note that the callers are complex enough that there's no tail * recursion here anyway.) * It's an IPsec accelerated packet. * Keep a pointer to the data attributes around until * we allocate the ipsecinfo structure. (
"ip_rput_data_v6: inbound HW accelerated IPsec pkt\n"));
* Since it is accelerated, it came directly from /* Clear checksum flags in case we need to forward */ /* Process hop by hop header options */ * Packet has been consumed and any * needed ICMP messages sent. * Attach any necessary label information to this packet. ip0dbg((
"tsol_get_pkt_label v6 failed\n"));
* On incoming v6 multicast packets we will bypass the ire table, * and assume that the read queue corresponds to the targetted * The effect of this is the same as the IPv4 original code, but is * much cleaner I think. See ip_rput for how that was done. * XXX TODO Give to mrouted to for multicast forwarding. * If a packet was received on an interface that is a 6to4 tunnel, * incoming IPv6 packets, with a 6to4 addressed IPv6 destination, must * be checked to have a 6to4 prefix (2002:V4ADDR::/48) that is equal to * the 6to4 prefix of the address configured on the receiving interface. * Otherwise, the packet was delivered to this interface in error and * the packet must be dropped. "addressed packet which is not for us: " * Find an ire that matches destination. For link-local addresses * we have to match the ill. * TBD for site local addresses. * No matching IRE found. Mark this packet as having /* Sent by forwarding path, and router is global zone */ * Per RFC 3513 section 2.5.2, we must not forward packets with * an unspecified source address. /* we have a matching IRE */ * To be quicker, we may wish not to chase pointers * (ire->ire_ipif->ipif_ill...) and instead store the * forwarding policy in the ire. An unfortunate side- * effect of this would be requiring an ire flush whenever * the ILLF_ROUTER flag changes. For now, chase pointers * once and store in the boolean no_forward. * This appears twice to keep it out of the non-forwarding, * yes-it's-for-us-on-the-right-interface case. * This ire has a send-to queue - forward the packet. * ipIfStatsHCInForwDatagrams should only be increment if there * will be an attempt to forward the packet, which is why we * increment after the above condition has been checked. ip1dbg((
"ip_rput_data_v6: hop limit expired.\n"));
/* Sent by forwarding path, and router is global zone */ * Per RFC 3513 section 2.5.2, we must not forward packets with * an unspecified source address. /* Size may have changed */ * Handle labeled packet resizing. /* Sent by forwarding path, and router is global zone */ * Check to see if we're forwarding the packet to a * different link from which it came. If so, check the * source and destination addresses since routers must not * forward any packets with link-local source or * destination addresses to other links. Otherwise (if * we're forwarding onto the same link), conditionally send /* TBD add site-local check at site boundary? */ * Don't send a redirect when forwarding a source * We won't send redirects to a router * that doesn't have a link local * address, but will forward. * The source is directly connected. /* Hoplimit verified above */ * Need to put on correct queue for reassembly to find it. * No need to use put() since reassembly has its own locks. * Note: multicast packets and packets destined to addresses * assigned to loopback (ire_rfq is NULL) will be reassembled on * the arriving ill. Unlike the IPv4 case, enabling strict * destination multihoming will prevent accepting packets * addressed to an IRE_LOCAL on lo0. /* Don't use the ire after this point, we'll NULL it out to be sure. */ * Looks like this packet is for us one way or another. * This is where we'll process destination headers etc. /* TCP needs all of the TCP header */ * Extract the offset field from the TCP header. ip1dbg((
"ip_rput_data_v6: short " * There must be TCP options. * Make sure we can grab them. * TCP checksum calculation. First sum up the * - Destination IPv6 address /* SCTP needs all of the SCTP header */ /* Verify that at least the ports are present */ * Before going through the regular checksum * calculation, make sure the received checksum * is non-zero. RFC 2460 says, a 0x0000 checksum * in a UDP packet (within IPv6 packet) is invalid * and should be replaced by 0xffff. This makes * sense as regular checksum calculation will * pass for both the cases i.e. 0x0000 and 0xffff. * Removing one of the case makes error detection /* 0x0000 checksum is invalid */ ip1dbg((
"ip_rput_data_v6: Invalid UDP " "checksum value 0x0000\n"));
* UDP checksum calculation. First sum up the * - Destination IPv6 address /* IPv6 ICMP checksum failed */ ip1dbg((
"ip_rput_data_v6: ICMPv6 checksum " /* Check variable for testing applications */ * Assume that there is always at least one conn for * ICMPv6 (in.ndpd) i.e. don't optimize the case * where there is no conn. * In the multicast case, applications may have * joined the group from different zones, so we * need to deliver the packet to each of them. * Loop through the multicast memberships * structures (ilm) on the receive ill and send * a copy of the packet up each matching one. * Handle protocols with which IPv6 is less intimate. ip0dbg((
"default hada drop\n"));
* Enable sending ICMP for "Unknown" nexthdr * case. i.e. where we did not FALLTHRU from * IPPROTO_ICMPV6 processing case above. * If we did FALLTHRU, then the packet has already been * processed for IPPF, don't process it again in * ip_fanout_proto_v6; set IP6_NO_IPPOLICY in the /* Check if AH is present. */ ip0dbg((
"dst early hada drop\n"));
* Reinitialize pointers, as ipsec_early_ah_v6() does * complete pullups. We don't have to do more pullups * Note: XXX This code does not seem to make * distinction between Destination Options Header * happen if we are at the end of source route. * This may become significant in future. * (No real significant Destination Options are * Packet has been consumed and any needed /* No action needed continue */ * Unnexpected return value * (Router alert is a Hop-by-Hop option) panic(
"ip_rput_data_v6: router " "alert hbh opt indication in dest opt");
* Invoke the CGTP (multirouting) filtering module to * process the incoming packet. Packets identified as * duplicates must be discarded. Filtering is active * only if the the ip_cgtp_filter ndd variable is * Only applies to the shared stack since the * filter_ops do not carry an ip_stack_t or zoneid. /* Reassembly is still pending */ /* The first mblk are the headers before the frag hdr */ * Illegal header sequence. * (Hop-by-hop headers are processed above * and required to immediately follow IPv6 header) /* Check if AH is present. */ ip0dbg((
"routing hada drop\n"));
* Reinitialize pointers, as ipsec_early_ah_v6() does * complete pullups. We don't have to do more pullups /* Not end of source route */ * Fast path for AH/ESP. If this is the first time * we are sending a datagram to AH/ESP, allocate * a IPSEC_IN message and prepend it. Otherwise, ip1dbg((
"ip_rput_data_v6: IPSEC_IN " "allocation failure.\n"));
* Store the ill_index so that when we come back * from IPSEC we ride on the same queue. * Cache hardware acceleration info. "caching data attr.\n"));
/* select inbound SA and have IPsec process the pkt */ /* we're done with IPsec processing, send it up */ /* All processing is done. Count as "delivered". */ ip1dbg((
"ip_rput_data_v6: packet too short %d %lu %d\n",
/* Initiate IPPF processing */ ip1dbg((
"ip_rput_data_v6: malformed accelerated packet\n"));
/* IPsec kstats: bump counter here */ * When it returns a completed message the first mblk will only contain * the headers prior to the fragment header. * prev_nexthdr_offset is an offset indication of where the nexthdr field is * of the preceding header. This is needed to patch the previous header's * nexthdr field when reassembly completes. * We utilize hardware computed checksum info only for UDP since * IP fragmentation is a normal occurence for the protocol. In * addition, checksum offload support for IP fragments carrying * UDP payload is commonly implemented across network adapters. /* Record checksum information from the packet */ /* fragmented payload offset from beginning of mblk */ * Partial checksum has been calculated by hardware * and attached to the packet; in addition, any * prepended extraneous data is even byte aligned. * If any such data exists, we adjust the checksum; * this would also handle any postpended data. /* One's complement subtract extraneous checksum */ /* Clear hardware checksumming flag */ * Note: Fragment offset in header is in 8-octet units. * Clearing least significant 3 bits not only extracts * it but also gets it in units of octets. * Is the more frags flag on and the payload length not a multiple * Would fragment cause reassembled packet to have a payload length * greater than IP_MAXPACKET - the max payload size? * This packet just has one fragment. Reassembly not * Drop the fragmented as early as possible, if * we don't have resource(s) to re-assemble. /* Record the ECN field info. */ * If this is not the first fragment, dump the unfragmentable * Fragmentation reassembly. Each ILL has a hash table for * queueing packets undergoing reassembly for all IPIFs * associated with the ILL. The hash is based on the packet * IP ident field. The ILL frag hash table was allocated * as a timer block at the time the ILL was created. Whenever * there is anything on the reassembly queue, the timer will * If the reassembly list for this ILL will get too big /* Try to find an existing fragment queue for this packet. */ * It has to match on ident, source address, and * If we have received too many * duplicate fragments for this packet * If we pruned the list, do we want to store this new * fragment?. We apply an optimization here based on the * fact that most fragments will be received in order. * So if the offset of this incoming fragment is zero, * it is the first fragment of a new packet. We will * keep it. Otherwise drop the fragment, as we have * probably pruned the packet already (since the * packet cannot be found). /* New guy. Allocate a frag message. */ * Too many fragmented packets in this hash bucket. /* Initialize the fragment header. */ /* Record reassembly start time. */ /* Record ipf generation and account for frag header */ /* Store checksum value in fragment header */ * We handle reassembly two ways. In the easy case, * where all the fragments show up in order, we do * minimal bookkeeping, and just clip new pieces on * the end. If we ever see a hole, then we go off * to ip_reassemble which has to mark the pieces and * keep track of the number of holes, etc. Obviously, * the point of having both mechanisms is so we can * handle the easy case as efficiently as possible. /* Easy case, in-order reassembly so far. */ /* Update the byte count */ * Keep track of next expected offset in /* Hard case, hole at the beginning. */ * ipf_end == 0 means that we have given up /* Forget checksum offload from now on */ * ipf_hole_cnt is set by ip_reassemble. * ipf_count is updated by ip_reassemble. * No need to check for return value here * as we don't expect reassembly to complete or * fail for the first fragment itself. /* Update per ipfb and ill byte counts */ /* If the frag timer wasn't already going, start it. */ * If the packet's flag has changed (it could be coming up * from an interface different than the previous, therefore * possibly different checksum capability), then forget about * any stored checksum states. Otherwise add the value to * the existing one stored in the fragment header. /* Forget checksum offload from now on */ * We have a new piece of a datagram which is already being * reassembled. Update the ECN info if all IP fragments * are ECN capable. If there is one which is not, clear * all the info. If there is at least one which has CE * code point, IP needs to report that up to transport. /* The new fragment fits at the end */ /* Update the byte count */ /* Update per ipfb and ill byte counts */ /* Save current byte count */ /* Count of bytes added and subtracted (freeb()ed) */ /* Update per ipfb and ill byte counts */ /* Reassembly failed. Free up all resources */ /* We will reach here iff 'ret' is IP_REASS_COMPLETE */ * We have completed reassembly. Unhook the frag header from * Grab the unfragmentable header length next header value out * Before we free the frag header, record the ECN info * to report back to the transport. * Store the nextheader field in the header preceding the fragment /* We need to supply these to caller */ /* Ditch the frag header. */ * Make sure the packet is good by doing some sanity * check. If bad we can silentely drop the packet. ip1dbg((
"ip_rput_frag_v6: bad packet\n"));
* Remove the fragment header from the initial header by * splitting the mblk into the non-fragmentable header and * everthing after the fragment extension header. This has the * side effect of putting all the headers that need destination * processing into the b_cont block-- on return this fact is * used in order to avoid having to look at the extensions * Note that this code assumes that the unfragmentable portion * of the header is in the first mblk and increments * the read pointer past it. If this assumption is broken ip1dbg((
"ip_rput_frag_v6: dupb failed\n"));
/* Restore original IP length in header. */ /* Record the ECN info. */ /* Reassembly is successful; return checksum information if needed */ * Walk through the options to see if there is a routing header. * If present get the destination which is the last address of * If the caller doesn't care whether the packet * is a fragment or not, we can stop here since * we have our destination. * This function is called by redirect code in ip_rput_data_v6 to * know whether this packet is source routed through this node i.e * whether this node (router) is part of the journey. This * function is called under two cases : * case 1 : Routing header was processed by this node and * ip_process_rthdr replaced ip6_dst with the next hop * and we are forwarding the packet to the next hop. * case 2 : Routing header was not processed by this node and we * are just forwarding the packet. * For case (1) we don't want to send redirects. For case(2) we * want to send redirects. ip2dbg((
"ip_source_routed_v6\n"));
/* if a routing hdr is preceeded by HOPOPT or DSTOPT */ * Check if we have already processed * packets or we are just a forwarding * router which only pulled up msgs up * to IPV6HDR and one HBH ext header ip2dbg((
"ip_source_routed_v6: Extension" " headers not processed\n"));
* If for some reason, we haven't pulled up * the routing hdr data mblk, then we must * not have processed it at all. So for sure * we are not part of the source routed journey. ip2dbg((
"ip_source_routed_v6: Routing" " header not processed\n"));
* Either we are an intermediate router or the * last hop before destination and we have * already processed the routing header. * If segment_left is greater than or equal to zero, * then we must be the (numaddr - segleft) entry * of the routing header. Although ip6r0_segleft * is a unit8_t variable, we still check for zero * or greater value, if in case the data type * is changed someday in future. ip1dbg((
"ip_source_routed_v6: No ire found\n"));
ip2dbg((
"ip_source_routed_v6: Not source routed here\n"));
* ip_wput_v6 -- Packets sent down from transport modules show up here. * Assumes that the following set of headers appear in the first * ip6i_t (if present) CAN also appear as a separate mblk. * The routine can handle an ICMPv6 header that is not in the first mblk. * The order to determine the outgoing interface is as follows: * 1. IPV6_BOUND_PIF is set, use that ill (conn_outgoing_pill) * 2. If conn_nofailover_ill is set then use that ill. * 3. If an ip6i_t with IP6I_IFINDEX set then use that ill. * 4. If q is an ill queue and (link local or multicast destination) then * 5. If IPV6_BOUND_IF has been set use that ill. * 6. For multicast: if IPV6_MULTICAST_IF has been set use it. Otherwise * look for the best IRE match for the unspecified group to determine * 7. For unicast: Just do an IRE lookup for the best match. * arg2 is always a queue_t *. * When that queue is an ill_t (i.e. q_next != NULL), then arg must be * When that queue is not an ill_t, then arg must be a conn_t pointer. /* Otherwise contains insert offset for checksum */ * Highest bit in version field is Reachability Confirmation bit * used by NUD in ip_xmit_v6(). * M_CTL comes from 6 places * 1) TCP sends down IPSEC_OUT(M_CTL) for detached connections * both V4 and V6 datagrams. * 2) AH/ESP sends down M_CTL after doing their job with both * 3) NDP callbacks when nce is resolved and IPSEC_OUT has been * 4) Notifications from an external resolver (for XRESOLV ifs) * 5) AH/ESP send down IPSEC_CTL(M_CTL) to be relayed to hardware for * IPsec hardware acceleration support. * We need to handle (1)'s IPv6 case and (3) here. For the * IPv4 case in (1), and (2), IPSEC processing has already * started. The code in ip_wput() already knows how to handle * continuing IPSEC processing (for IPv4 and IPv6). All other * M_CTLs (including case (4)) are passed on to ip_wput_nondata() /* Multidata transmit? */ * We should never get here, since all Multidata messages * originating from tcp should have been directed over to * tcp_multisend() in the first place. * Validate this M_CTL message. The only three types of * M_CTL messages we expect to see in this code path are * ipsec_out_t or ipsec_in_t structures (allocated as * ipsec_info_t unions), or ipsec_ctl_t structures. * The ipsec_out_type and ipsec_in_type overlap in the two * data structures, and they are either set to IPSEC_OUT * or IPSEC_IN depending on which data structure it is. * ipsec_ctl_t is an IPSEC_CTL. * All other M_CTL messages are sent to ip_wput_nondata() /* NDP callbacks have q_next non-NULL. That's case #3. */ * For a freshly-generated TCP dgram that needs IPV6 * processing, don't call ip_wput immediately. We can * tell this by the ipsec_out_proc_begin. In-progress * IPSEC_OUT messages have proc_begin set to TRUE, * and we want to send all IPSEC_IN messages to * ip_wput() for IPsec processing or finishing. * We don't know if this ill will be used for IPv6 * until the ILLF_IPV6 flag is set via SIOCSLIFNAME. * ipif_set_values() sets the ill_isv6 flag to true if * ILLF_IPV6 is set. If the ill_isv6 flag isn't true, ip1dbg((
"ip_wput_v6: Received an IPv6 packet before " /* For uniformity do a refhold */ /* is queue flow controlled? */ * 1) TCP sends down M_CTL for detached connections. * 2) AH/ESP sends down M_CTL. * We don't flow control either of the above. Only * UDP and others are flow controlled for which we * If there is a policy, try to attach an ipsec_out in * the front. At the end, first_mp either points to a * M_DATA message or IPSEC_OUT message linked to a * M_DATA message. We have to do it now as we might * lose the "conn" if we go through ip_newroute. /* XXX Any better way to get the protocol fast ? */ /* check for alignment and full IPv6 header */ ip0dbg((
"ip_wput_v6: bad alignment or length\n"));
* Once neighbor discovery has completed, ndp_process() will provide * locally generated packets for which processing can be reattempted. * In these cases, connp is NULL and the original zone is part of a * When coming from icmp_input_v6, the zoneid might not match * for the loopback case, because inside icmp_input_v6 the * queue_t is a conn queue from the sending side. * This is an ip6i_t header followed by an ip6_hdr. * Check which fields are set. * When the packet comes from a transport we should have * all needed headers in the first mblk. However, when * going through ip_newroute*_v6 the ip6i might be in * a separate mblk when we return here. In that case * we pullup everything to ensure that extension and transport * headers "stay" in the first mblk. ip1dbg((
"ip_wput_v6: pullupmsg failed\n"));
* Advance rptr past the ip6i_t to get ready for * transmitting the packet. However, if the packet gets * passed to ip_newroute*_v6 then rptr is moved back so * that the ip6i_t header can be inspected when the * packet comes back here after passing through * IP6I_ATTACH_IF is set in this function when we had a * conn and it was either bound to the IPFF_NOFAILOVER address * or IPV6_BOUND_PIF was set. These options override other * options that set the ifindex. We come here with * IP6I_ATTACH_IF set when we can't find the ire and * ip_newroute_v6 is feeding the packet for second time. ip1dbg((
"ip_wput_v6: bad ifindex %d\n",
* Preserve the index so that when we return * from IPSEC processing, we know where to * This is a multipathing probe packet that has * been delayed in ND resolution. Drop the * packet for the reasons mentioned in * Use IPCL_ZONEID to honor SO_ALLZONES. ip1dbg((
"ip_wput_v6: bad source " /* No need to verify again when using ip_newroute */ * Make sure they match since ip_newroute*_v6 etc might * (unknown to them) inspect ip6i_nexthop when * they think they access ip6_dst. * Store ip6i_t info that we need after we come back /* 1. IPV6_BOUND_PIF takes precedence over all the ifindex settings. */ * Check if we need an ire that will not be * looked up by anybody else i.e. HIDDEN. /* 2. If ipc_nofailover_ill is set then use that ill. */ * Assumes that ipc_nofailover_ill is used only for * multipathing probe packets. These packets are better * dropped, if they are delayed in ND resolution, for * the reasons described in nce_queue_mp(). * IP6I_DROP_IFDELAYED will be set later on in this * function for this packet. * Check if we need an ire that will not be * looked up by anybody else i.e. HIDDEN. * Redo 1. If we did not find an IRE_CACHE the first time, we should * have an ip6i_t with IP6I_ATTACH_IF if IPV6_BOUND_PIF or * bind to the IPIF_NOFAILOVER address was used on this endpoint. * Check if we need an ire that will not be * looked up by anybody else i.e. HIDDEN. /* 3. If an ip6i_t with IP6I_IFINDEX set then use that ill. */ * 4. If q is an ill queue and (link local or multicast destination) /* 5. If IPV6_BOUND_IF has been set use that ill. */ * 6. For unicast: Just do an IRE lookup for the best match. * If we get here for a link-local address it is rather random * what interface we pick on a multihomed host. * *If* there is an IRE_CACHE (and the link-local address * isn't duplicated on multi links) this will find the IRE_CACHE. * Otherwise it will use one of the matching IRE_INTERFACE routes * for the link-local prefix. Hence, applications * *should* be encouraged to specify an outgoing interface when sending * to a link local address. * We cache IRE_CACHEs to avoid lookups. We don't do * this for the tcp global queue and listen end point * as it does not really have a real destination to * IRE_MARK_CONDEMNED is marked in ire_delete. We don't * grab a lock here to check for CONDEMNED as it is okay * to send a packet or two with the IRE_CACHE that is going /* Release the old ire */ * We can continue to use the ire but since it * was not cached, we should drop the extra /* Handle IRE_LOCAL's that might appear here */ * Check if the ire has the RTF_MULTIRT flag, inherited * from an IRE_OFFSUBNET ire entry in ip_newroute(). * Force hop limit of multirouted packets if required. * The hop limit of such packets is bounded by the * ip_multirt_ttl ndd variable. * NDP packets must have a hop limit of 255; don't * change the hop limit in that case. ip2dbg((
"ip_wput_v6: forcing multirt " "hop limit to %d (was %d) ",
* We look at this point if there are pending * unresolved routes. ire_multirt_need_resolve_v6() * checks in O(n) that all IRE_OFFSUBNET ire * entries for the packet's destination and * flagged RTF_MULTIRT are currently resolved. * If some remain unresolved, we do a copy * of the current message. It will be used * to initiate additional route resolutions. ip2dbg((
"ip_wput_v6: ire %p, " "multirt_need_resolve %d, first_mp %p\n",
* Try to resolve another multiroute if * ire_multirt_need_resolve_v6() deemed it necessary. * copy_mp will be consumed (sent or freed) by * No full IRE for this destination. Send it to * ip_newroute_v6 to see if anything else matches. * Mark this packet as having originated on this * Update rptr if there was an ip6i_t header. * Add ip6i_t header to carry unspec_src * until the packet comes back in ip_wput_v6. * ndp_resolver called from ip_newroute_v6 * expects pulled up message. ip1dbg((
"ip_wput_v6: pullupmsg" * Handle multicast packets with or without an conn. * Assumes that the transports set ip6_hops taking * IPV6_MULTICAST_HOPS (and the other ways to set the hoplimit) ip2dbg((
"ip_wput_v6: multicast\n"));
* 1. IPV6_BOUND_PIF takes precedence over all the ifindex settings * 2. If conn_nofailover_ill is set then use that ill. * Hold the conn_lock till we refhold the ill of interest that is * while holding any locks, postpone the refrele until after the ip1dbg((
"ip_output_v6: multicast" " conn_outgoing_pill no ipif\n"));
* Check if we need an ire that will not be * looked up by anybody else i.e. HIDDEN. ip1dbg((
"ip_output_v6: multicast" " conn_nofailover_ill no ipif\n"));
* Check if we need an ire that will not be * looked up by anybody else i.e. HIDDEN. * Redo 1. If we did not find an IRE_CACHE the first time, * we should have an ip6i_t with IP6I_ATTACH_IF if * IPV6_BOUND_PIF or bind to the IPIF_NOFAILOVER address was * Check if we need an ire that will not be * looked up by anybody else i.e. HIDDEN. /* 3. If an ip6i_t with IP6I_IFINDEX set then use that ill. */ * 4. If q is an ill queue and (link local or multicast * destination) then use that ill. * We don't need the ipif initialization here. * This useless assert below is just to prevent lint from * reporting a null body if statement. * 5. If IPV6_BOUND_IF has been set use that ill. * 6. For multicast: if IPV6_MULTICAST_IF has been set use it. * Otherwise look for the best IRE match for the unspecified * group to determine the ill. * conn_multicast_ill is used for only IPv6 packets. * conn_multicast_ipif is used for only IPv4 packets. * Thus a PF_INET6 socket send both IPv4 and IPv6 * multicast packets using different IP*_MULTICAST_IF ip1dbg((
"ip_output_v6: multicast" " conn_outgoing_ill no ipif\n"));
ip1dbg((
"ip_output_v6: multicast" " conn_multicast_ill no ipif\n"));
ip1dbg((
"ip_output_v6: multicast no ipif\n"));
* We have a ref to this ipif, so we can safely ip1dbg((
"ip_output_v6: multicast no ipif\n"));
* Save binding until IPV6_MULTICAST_IF * For multicast loopback interfaces replace the multicast address * with a unicast address for the ire lookup. * As we may lose the conn by the time we reach ip_wput_ire_v6 * we copy conn_multicast_loop and conn_dontroute on to an * ipsec_out. In case if this datagram goes out secure, * we need the ill_index also. Copy that also into the /* This is not a secure packet */ * When a specific ill is specified (using IPV6_PKTINFO, * IPV6_MULTICAST_IF, or IPV6_BOUND_IF) we will only match * on routing entries (ftable and ctable) that have a matching * ire->ire_ipif->ipif_ill. Thus this can only be used * for destinations that are on-link for the specific ill * and that can appear on multiple links. Thus it is useful * for multicast destinations, link-local destinations, and * at some point perhaps for site-local destinations (if the * node sits at a site boundary). * We create the cache entries in the regular ctable since * it can not "confuse" things for other destinations. * NOTE : conn_ire_cache is not used for caching ire_ctable_lookups. * It is used only when ire_cache_lookup is used above. * Check if the ire has the RTF_MULTIRT flag, inherited * from an IRE_OFFSUBNET ire entry in ip_newroute(). * Force hop limit of multirouted packets if required. * The hop limit of such packets is bounded by the * ip_multirt_ttl ndd variable. * NDP packets must have a hop limit of 255; don't * change the hop limit in that case. ip2dbg((
"ip_wput_v6: forcing multirt " "hop limit to %d (was %d) ",
* We look at this point if there are pending * unresolved routes. ire_multirt_need_resolve_v6() * checks in O(n) that all IRE_OFFSUBNET ire * entries for the packet's destination and * flagged RTF_MULTIRT are currently resolved. * If some remain unresolved, we make a copy * of the current message. It will be used * to initiate additional route resolutions. ip2dbg((
"ip_wput_v6[send_from_ill]: ire %p, " "multirt_need_resolve %d, first_mp %p\n",
ip1dbg((
"ip_wput_v6: send on %s, ire = %p, ill index = %d\n",
* Try to resolve another multiroute if * ire_multirt_need_resolve_v6() deemed it necessary. * copy_mp will be consumed (sent or freed) by * ip_newroute_[ipif_]v6(). ip1dbg((
"ip_wput_v6: No ipif for " /* Update rptr if there was an ip6i_t header. */ * Add ip6i_t header to carry unspec_src * or attach_if until the packet comes back in * ndp_resolver called from ip_newroute_v6 * expects a pulled up message. ip1dbg((
"ip_wput_v6: pullupmsg" /* This is a multipathing probe packet */ * XXX implement a IPv4 and IPv6 packet counter per conn and * switch when ratio exceeds e.g. 10:1 /* change conn_send for the tcp_v4_connections */ /* The 'q' is the default SCTP queue */ * If this is a conn_t queue, then we pass in the conn. This includes the * Otherwise, this is a message for an ill_t queue, * in which case we use the global zoneid since those are all part of * NULL send-to queue - packet is to be delivered locally. * Remove reachability confirmation bit from version field * before passing the packet on to any firewall hooks or * looping back the packet. * M_DATA mblk, so init mblk (chain) for /* check for full IPv6+ICMPv6 header */ ip1dbg((
"ip_wput_v6: ICMP hdr pullupmsg" /* Update output mib stats */ /* Check variable for testing applications */ * Assume that there is always at least one conn for * ICMPv6 (in.ndpd) i.e. don't optimize the case * where there is no conn. * In the multicast case, applications may have * joined the group from different zones, so we * need to deliver the packet to each of them. * Loop through the multicast memberships * structures (ilm) on the receive ill and send * a copy of the packet up each matching one. * However, we don't do this for multicasts sent * on the loopback interface (PHYI_LOOPBACK flag * set) as they must stay in the sender's zone. * Handle protocols with which IPv6 is less intimate. * Enable sending ICMP for "Unknown" nexthdr * case. i.e. where we did not FALLTHRU from * IPPROTO_ICMPV6 processing case above. * Note: There can be more than one stream bound * to a particular protocol. When this is the case, * each one gets a copy of any incoming packets. * Checksumming is controlled by cksum_request: * Otherwise => checksum_request contains insert offset for checksum * Assumes that the following set of headers appear in the first * The routine can handle an ICMPv6 header that is not in the first mblk. * NOTE : This function does not ire_refrele the ire passed in as the * argument unlike ip_wput_ire where the REFRELE is done. * Refer to ip_wput_ire for more on this. * Grab the zone id now because the M_CTL can be discarded by * ip_wput_ire_parse_ipsec_out() below. * For the multicast case, ipsec_out carries conn_dontroute and * conn_multicast_loop as conn may not be available here. We * need this for multicast loopback and forwarding which is done * If conn_dontroute is not set or conn_multicast_loop * datagrams from ip_wput_multicast, conn_dontroute is * set to B_TRUE and conn_multicast_loop is set to * B_FALSE so that we neither do forwarding nor * If the sender didn't supply the hop limit and there is a default * unicast hop limit associated with the output interface, we use * that if the packet is unicast. Interface specific unicast hop * limits as set via the SIOCSLIFLNKINFO ioctl. * When a zone sends a packet to another zone, we try to deliver * the packet under the same conditions as if the destination * was a real node on the network. To do so, we look for a * matching route in the forwarding table. * RTF_REJECT and RTF_BLACKHOLE are handled just like * Note that IRE_LOCAL are special, since they are used * when the zoneid doesn't match in some cases. This means that * we need to handle ipha_src differently since ire_src_addr * belongs to the receiving zone instead of the sending zone. * When ip_restrict_interzone_loopback is set, then * ire_cache_lookup_v6() ensures that IRE_LOCAL are only used * for loopback between zones when the logical "Ethernet" would * Select the source address using ipif_select_source_v6. printf(
"ip_wput_ire_v6: interface name %s\n",
"Loopback multicast\n"));
* every local zone, except * Local multicast or just loopback on loopback ip1dbg((
"ip_wput_ire_v6: local multicast only\n"));
* non-NULL send-to queue - packet is to be sent /* Driver is flow-controlling? */ * Queue packet if we have an conn to give back * pressure. We can't queue packets intended for * hardware acceleration since we've tossed that * state already. If the packet is being fed back * from ire_send_v6, we don't know the position in * the queue to enqueue the packet and we discard * caller == IP_WSRV implies we are * the service thread, and the * queue is already noenabled. * The check for canput and * the putbq is not atomic. * So we need to check again. * Look for reachability confirmations from the transport. * The packet header is processed once for all, even * in the multirouting case. We disable hardware * checksum if the packet is multirouted, as it will be * replicated via several interfaces, and not all of * them may have this capability. /* Skip the transport checksum */ * Do user-configured raw checksum. * Compute checksum and insert at offset "cksum_request" /* check for enough headers for checksum */ ip1dbg((
"ip_wput_v6: ICMP hdr pullupmsg" * icmp has placed length and routing * header adjustment in *insp. * Check for full IPv6 header + enough TCP header * to get at the checksum field. ip1dbg((
"ip_wput_v6: TCP hdr pullupmsg" * Note: The TCP module has stored the length value * into the tcp checksum field, so we don't * need to explicitly sum it in here. /* Fold the initial sum */ * check for full IPv6 header + enough UDP header * to get at the UDP checksum field ip1dbg((
"ip_wput_v6: UDP hdr pullupmsg" * Note: The UDP module has stored the length value * into the udp checksum field, so we don't * need to explicitly sum it in here. /* Fold the initial sum */ /* check for full IPv6+ICMPv6 header */ ip1dbg((
"ip_wput_v6: ICMP hdr pullupmsg" * icmp has placed length and routing * header adjustment in icmp6_cksum. /* Update output mib stats */ ip1dbg((
"ip_wput_v6: SCTP hdr pullupmsg" * We force the insertion of a fragment header using the * IPH_FRAG_HDR flag in two cases: * - after reception of an ICMPv6 "packet too big" message * with a MTU < 1280 (cf. RFC 2460 section 5) * - for multirouted IPv6 packets, so that the receiver can * discard duplicates according to their fragment identifier * Two flags modifed from the API can modify this behavior. * The first is IPV6_USE_MIN_MTU. With this API the user * can specify how to manage PMTUD for unicast and multicast. * IPV6_DONTFRAG disallows fragmentation. ip0dbg((
"Packet length mismatch: %d, %ld\n",
/* Do IPSEC processing first */ ip2dbg((
"Fragmenting Size = %d, mtu = %d\n",
/* Initiate IPPF processing */ /* Do IPSEC processing first */ * IPsec headers will push the packet over the * MTU limit. Issue an ICMPv6 Packet Too Big * message for this packet if the upper-layer * that issued this packet will be able to * react to the icmp_pkt2big_v6() that we'll * XXX multicast: add ip_mforward_v6() here. * XXX The only purpose of this statement is to avoid lint * errors. See the above "XXX multicast". When that gets * fixed, remove this whole #ifdef lint section. ip3dbg((
"multicast forward is %s.\n",
* Outbound IPv6 fragmentation routine using MDT. * Move read ptr past unfragmentable portion, we don't want this part * of the data in our fragments. /* Calculate how many packets we will send out */ /* Allocate a message block which will hold all the IP Headers. */ * Create the header buffer, Multidata and destination address * and SAP attribute that should be associated with it. * Add a payload buffer to the Multidata; this operation must not * fail, or otherwise our logic in this routine is broken. There * is no memory allocation done by the routine, so any returned * failure simply tells us that we've done something wrong. * A failure tells us that either we're adding the same payload * buffer more than once, or we're trying to add more buffers than * allowed. None of the above cases should happen, and we panic * because either there's horrible heap corruption, and/or * len is the total length of the fragmentable data in this * datagram. For each fragment sent, we will decrement len * by the amount of fragmentable data sent in that fragment * until len reaches zero. * Record offset and size of header and data of the next packet * in the multidata message. * Attach the next payload message block to the * Any failure other than ENOMEM indicates that we * have passed in invalid pdesc info or parameters * to mmd_addpdesc, which must not happen. * EINVAL is a result of failure on boundary checks * against the pdesc info contents. It should not * happen, and we panic because either there's * horrible heap corruption, and/or programming "pdesc logic error detected for " "mmd %p pinfo %p (%d)\n",
/* Free unattached payload message blocks as well */ /* Advance fragment offset. */ /* Advance to location for next header in the buffer. */ /* Did we reach the next payload message block? */ * Attach the next message block with payload * data to the multidata message. /* Update IP statistics */ * The ipv6 header len is accounted for in unfragmentable_len so * when calculating the fragmentation overhead just add the frag "error for mmd %p pbuf %p (%d)", (
void *)
mmd, (
void *)
mp,
* IPv6 fragmentation. Essentially the same as IPv4 fragmentation. * We have not optimized this in terms of number of mblks * allocated. For instance, for each fragment sent we always allocate a * mblk to hold the IPv6 header and fragment header. * Assumes that all the extension headers are contained in the first mblk. * The fragment header is inserted after an hop-by-hop options header * and after [an optional destinations header followed by] a routing header. * NOTE : This function does not ire_refrele the ire passed in as * Determine the length of the unfragmentable portion of this * datagram. This consists of the IPv6 header, a potential * hop-by-hop options header, a potential pre-routing-header * destination options header, and a potential routing header. /* Check if we can use MDT to send out the frags. */ * Allocate an mblk with enough room for the link-layer * header, the unfragmentable part of the datagram, and the * fragment header. This (or a copy) will be used as the * first mblk for each fragment we send. * len is the total length of the fragmentable data in this * datagram. For each fragment sent, we will decrement len * by the amount of fragmentable data sent in that fragment * until len reaches zero. * Move read ptr past unfragmentable portion, we don't want this part * of the data in our fragments. ip1dbg((
"ip_wput_frag_v6: copyb failed\n"));
* Note: Optimization alert. * In IPv6 (and IPv4) protocol header, Fragment Offset * ("offset") is 13 bits wide and in 8-octet units. * In IPv6 protocol header (unlike IPv4) in a 16 bit field, * it occupies the most significant 13 bits. * (least significant 13 bits in IPv4). * We do not do any shifts here. Not shifting is same effect * as taking offset value in octet units, dividing by 8 and * then shifting 3 bits left to line it up in place in proper /* mp has already been freed by ip_carve_mp() */ ip1dbg((
"ip_carve_mp: failed\n"));
/* Get the priority marking, if any */ reachable = 0;
/* No need to redo state machine in loop */ * Determine if the ill and multicast aspects of that packets * conn_incoming_ill is set by IPV6_BOUND_IF which limits * unicast and multicast reception to conn_incoming_ill. * conn_wantpacket_v6 is called both for unicast and * 1) The unicast copy of the packet can come anywhere in * the ill group if it is part of the group. Thus, we * need to check to see whether the ill group matches * if in_ill is part of a group. * 2) ip_rput does not suppress duplicate multicast packets. * If there are two interfaces in a ill group and we have * 2 applications (conns) joined a multicast group G on * both the interfaces, ilm_lookup_ill filter in ip_rput * will give us two packets because we join G on both the * interfaces rather than nominating just one interface * for receiving multicast like broadcast above. So, * we have to call ilg_lookup_ill to filter out duplicate * copies, if ill is part of a group, to supress duplicates. * No IPMP, and the packet did not arrive on conn_incoming_ill * OR, IPMP in use and the packet arrived on an IPMP group * different from the conn_incoming_ill's IPMP group. * Unicast case: we match the conn only if it's in the specified * Loopback case: the sending endpoint has IP_MULTICAST_LOOP * disabled, therefore we don't dispatch the multicast packet to * Multicast packet on the loopback interface: we only match * conns who joined the group in the specified zone. * Transmit a packet and update any NUD state based on the flags * XXX need to "recover" any ip6i_t when doing putq! * NOTE : This function does not ire_refrele the ire passed in as the ip0dbg((
"ip_xmit_v6: ire_to_ill failed\n"));
* If a packet is to be sent out an interface that is a 6to4 * tunnel, outgoing IPv6 packets, with a 6to4 addressed IPv6 * destination, must be checked to have a 6to4 prefix * (2002:V4ADDR::/48) that is NOT equal to the 6to4 prefix of * address configured on the sending interface. Otherwise, * the packet was delivered to this interface in error and the * packet must be dropped. "send 6to4 addressed IPv6 " "destination (%s) out the wrong " /* Flow-control check has been done in ip_wput_ire_v6 */ * In most cases, the emission loop below is entered only * once. Only in the case where the ire holds the * RTF_MULTIRT flag, do we loop to process all RTF_MULTIRT * flagged ires in the bucket, and send the packet * through all crossed RTF_MULTIRT routes. * Multirouting case. The bucket where ire is stored * probably holds other RTF_MULTIRT flagged ires * to the destination. In this call to ip_xmit_v6, * we attempt to send the packet through all * those ires. Thus, we first ensure that ire is the * first RTF_MULTIRT ire in the bucket, * before walking the ire list. /* Make sure we do not omit any multiroute ire. */ /* ire will be released by the caller */ * This tcp connection was marked as MDT-capable, but * it has been turned off due changes in the interface. * Now that the interface support is back, turn it on * by notifying tcp. We don't directly modify tcp_mdt, * since we leave all the details to the tcp code that ip0dbg((
"ip_xmit_v6: can't re-enable MDT for " "connp %p (ENOMEM)\n", (
void *)
connp));
* We are in a multiple send case, need to get * the next ire and make a duplicate of the * packet. ire1 holds here the next ire to * process in the bucket. If multirouting is * expected, any non-RTF_MULTIRT ire that has * the right destination address is ignored. /* Last multiroute ire; don't loop anymore. */ /* Initiate IPPF processing */ * Check for fastpath, we need to hold nce_lock to * prevent fastpath update from chaining nce_fp_mp. * make sure there is room for the fastpath /* Get the priority marking, if any */ * fastpath - pre-pend datalink * Get the DL_UNITDATA_REQ. ip1dbg((
"ip_xmit_v6: No resolution " "block ire = %p\n", (
void *)
ire));
* Prepend the DL_UNITDATA_REQ. /* Get the priority marking, if any */ * Proceed with the next RTF_MULTIRT * ire, also set up the send-to queue * Update ire and MIB counters; for save_ire, this has * been done by the caller. * Send it down. XXX Do we want to flow control AH/ESP * packets that carry TCP payloads? We don't flow * control TCP packets, but we should also not * flow-control TCP packets that have been protected. * We don't have an easy way to find out if an AH/ESP * packet was originally TCP or not currently. * Safety Pup says: make sure this is * going to the right interface! /* IPsec kstats: bump lose counter */ * Proceed with the next RTF_MULTIRT * ire, also set up the send-to queue * Check for upper layer advice * It should be o.k. to check the state without * a lock here, at most we lose an advice. * Proceed with the next RTF_MULTIRT * ire, also set up the send-to queue " ill_reachable_time = %d \n",
delta,
* ND_REACHABLE is identical to * ND_STALE in this specific case. If * reachable time has expired for this * neighbor (delta is greater than * reachable time), conceptually, the * neighbor cache is no longer in * REACHABLE state, but already in * STALE state. So the correct * transition here is to ND_DELAY. /* Timers have already started */ * ndp timer has detected that this nce * is unreachable and initiated deleting * this nce and all its associated IREs. * This is a race where we found the * ire before it was deleted and have * just sent out a packet using this * Proceed with the next RTF_MULTIRT ire, * Also set up the send-to queue accordingly. * In the multirouting case, release the last ire used for * emission. save_ire will be released by the caller. * Queue packet if we have an conn to give back pressure. * We can't queue packets intended for hardware acceleration * since we've tossed that state already. If the packet is * being fed back from ire_send_v6, we don't know the * position in the queue to enqueue the packet and we discard * caller == IP_WSRV implies we are * the service thread, and the * queue is already noenabled. * The check for canput and * the putbq is not atomic. * So we need to check again. * pr_addr_dbg function provides the needed buffer space to call * inet_ntop() function's 3rd argument. This function should be * used by any kernel routine which wants to save INET6_ADDRSTRLEN * stack buffer space in it's own stack frame. This function uses * a buffer from it's own stack and prints the information. * Example: pr_addr_dbg("func: no route for %s\n ", AF_INET, addr) * Note: This function can call inet_ntop() once. ip0dbg((
"pr_addr_dbg: Wrong arguments\n"));
* This does not compare debug level and just prints * out. Thus it is the responsibility of the caller * to check the appropriate debug-level before calling * Return the length in bytes of the IPv6 headers (base header, ip6i_t * if needed and extension headers) that will be needed based on the * ip6_pkt_t structure passed by the caller. * The returned length does not include the length of the upper level * En-route destination options * Only do them if there's a routing header as well * All-purpose routine to build a header chain of an IPv6 header * followed by any required extension headers and a proto header, * preceeded (where necessary) by an ip6i_t private header. * The fields of the IPv6 header that are derived from the ip6_pkt_t * will be filled in appropriately. * Thus the caller must fill in the rest of the IPv6 header, such as * traffic class/flowid, source address (if not set here), hoplimit (if not * set here) and destination address. * The extension headers and ip6i_t header will all be fully filled in. * If sending private ip6i_t header down (checksum info, nexthop, * or ifindex), adjust ip header pointer and set ip6i_t header pointer, * then fill it in. (The checksum info will be filled in by icmp). * Enable per-packet source address verification if * IPV6_PKTINFO specified the source address. * ip6_src is set in the transport's _wput function. * We need to set this flag so that IP doesn't * rewrite the IPv6 header's hoplimit with the * tell IP this is an ip6i_t private header /* Initialize IPv6 header */ * Here's where we have to start stringing together * any extension headers in the right order: * Hop-by-hop, destination, routing, and final destination opts. * En-route destination options * Only do them if there's a routing header as well * Do ultimate destination options * Now set the last header pointer to the proto passed in * Return a pointer to the routing header extension header * in the IPv6 header(s) chain passed in. * If none found, return NULL * Assumes that all extension headers are in same mblk as the v6 header * The routing header will precede all extension headers * other than the hop-by-hop and destination options * extension headers, so if we see anything other than those, * we're done and didn't find it. * We could see a destination options header alone but no * routing header, in which case we'll return NULL as soon as * we see anything after that. * Hop-by-hop and destination option headers are identical, * so we can use either one we want as a template. /* Is there enough left for len + nexthdr? */ /* Assumes the headers are identical for hbh and dst */ * Called for source-routed packets originating on this node. * Manipulates the original routing header by moving every entry up * one slot, placing the first entry in the v6 header's v6_dst field, * and placing the ultimate destination in the routing header's last * Returns the checksum diference between the ultimate destination * (last hop in the routing header when the packet is sent) and * the first hop (ip6_dst when the packet is sent) * Perform any processing needed for source routing. * We know that all extension headers will be in the same mblk * If no segments left in header, or the header length field is zero, * don't move hop addresses around; * Checksum difference is zero. * Here's where the fun begins - we have to * move all addresses up one spot, take the * first hop and make it our first ip6_dst, * and place the ultimate destination in the * newly-opened last slot. * From the checksummed ultimate destination subtract the checksummed * current ip6_dst (the first hop address). Return that number. * (In the v4 case, the second part of this is done in each routine * that calls ip_massage_options(). We do it all in this one place * Propagate a multicast group membership operation (join/leave) (*fn) on * all interfaces crossed by the related multirt routes. * The call is considered successful if the operation succeeds * on at least one interface. * The function is called if the destination address in the packet to send /* No resolver exists for the gateway; skip this ire. */ * A resolver exists: we can get the interface on which we have * to apply the operation. ip2dbg((
"ip_multirt_apply_membership_v6: " "called %s, multirt group 0x%08x via itf 0x%08x, " "error %d [success %u]\n",
* Consider the call as successful if we succeeded on at least * one interface. Otherwise, return the last encountered error. * The following two functions set and get the value for the * IPV6_SRC_PREFERENCES socket option. * We only support preferences that are covered by * Look for conflicting preferences or default preferences. If * both bits of a related pair are clear, the application wants the * system's default value for that pair. Both bits in a pair can't * Verify the source address and ifindex. Privileged users can use * any source address. For ancillary data the source address is * We just want to know if the interface exists, we * don't really care about the ill pointer itself. error = 0;
/* Ensure we don't use it below */ * Get the size of the IP options (including the IP headers size) * without including the AH header's size. If till_ah is B_FALSE, * and if AH header is present, dest options beyond AH header will * also be included in the returned size. /* Assume IP has already stripped it */ * If we don't have a AH header to traverse, * return now. This happens normally for * outbound datagrams where we have not inserted * We don't include the AH header's size * to be symmetrical with other cases where * we either don't have a AH header (outbound) * or peek into the AH header yet (inbound and * The destination options header * is not part of the first mblk.