ip_netinfo.c revision 67c1caee8f1e9738d11e0824aa6f3645fbc57690
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <inet/ipclassifier.h>
#include <inet/ipp_common.h>
#include <inet/ip_ftable.h>
/*
* IPv4 netinfo entry point declarations.
*/
netstack_t *);
static int ip_getpmtuenabled(netstack_t *);
net_ifaddr_t [], void *, netstack_t *);
static int ip_ispartialchecksum(mblk_t *);
static int ip_isvalidchecksum(mblk_t *);
netstack_t *);
net_ifaddr_t [], void *, netstack_t *);
static int ipv6_isvalidchecksum(mblk_t *);
/* Netinfo private functions */
static int ip_getifname_impl(phy_if_t, char *,
ip_stack_t *);
ip_stack_t *ipst);
ip_stack_t *ipst);
ip_stack_t *);
void *);
ip_stack_t *);
static void ip_ni_queue_in_func(void *);
static void ip_ni_queue_out_func(void *);
static net_info_t ipv4info = {
};
static net_info_t ipv6info = {
};
/*
* The taskq eventq_queue_in is used to process the upside inject messages.
* The taskq eventq_queue_out is used to process the downside inject messages.
* The taskq eventq_queue_nic is used to process the nic event messages.
*/
/*
* Initialize queues for inject.
*/
void
{
if (eventq_queue_out == NULL) {
if (eventq_queue_out == NULL)
"ddi_taskq_create failed for IP_INJECT_QUEUE_OUT");
}
if (eventq_queue_in == NULL) {
if (eventq_queue_in == NULL)
"ddi_taskq_create failed for IP_INJECT_QUEUE_IN");
}
if (eventq_queue_nic == NULL) {
if (eventq_queue_nic == NULL)
"ddi_taskq_create failed for IP_NIC_EVENT_QUEUE");
}
}
/*
* Destroy inject queues
*/
void
{
if (eventq_queue_nic != NULL) {
}
if (eventq_queue_in != NULL) {
}
if (eventq_queue_out != NULL) {
}
}
/*
* Register IPv4 and IPv6 netinfo functions and initialize queues for inject.
*/
void
{
}
/*
* Unregister IPv4 and IPv6 functions and inject queues
*/
void
{
}
}
}
/*
* Initialize IPv4 hooks family the event
*/
void
{
!= 0) {
"net_register_family failed for ipv4");
}
"net_register_event failed for ipv4/physical_in");
}
"net_register_event failed for ipv4/physical_out");
}
"net_register_event failed for ipv4/forwarding");
}
"net_register_event failed for ipv4/loopback_in");
}
"net_register_event failed for ipv4/loopback_out");
}
"net_register_event failed for ipv4/nic_events");
}
}
void
{
&ipst->ips_ip4_forwarding_event) == 0)
}
&ipst->ips_ip4_physical_in_event) == 0)
}
&ipst->ips_ip4_physical_out_event) == 0)
}
&ipst->ips_ip4_loopback_in_event) == 0)
}
&ipst->ips_ip4_loopback_out_event) == 0)
}
&ipst->ips_ip4_nic_events) == 0)
}
&ipst->ips_ipv4root);
}
/*
* Initialize IPv6 hooks family and event
*/
void
{
!= 0) {
"net_register_family failed for ipv6");
}
"net_register_event failed for ipv6/physical_in");
}
"net_register_event failed for ipv6/physical_out");
}
"net_register_event failed for ipv6/forwarding");
}
"net_register_event failed for ipv6/loopback_in");
}
"net_register_event failed for ipv6/loopback_out");
}
"net_register_event failed for ipv6/nic_events");
}
}
void
{
&ipst->ips_ip6_forwarding_event) == 0)
}
&ipst->ips_ip6_physical_in_event) == 0)
}
&ipst->ips_ip6_physical_out_event) == 0)
}
&ipst->ips_ip6_loopback_in_event) == 0)
}
&ipst->ips_ip6_loopback_out_event) == 0)
}
&ipst->ips_ip6_nic_events) == 0)
}
&ipst->ips_ipv6root);
}
/*
* Determine the name of an IPv4 interface
*/
static int
netstack_t *ns)
{
ns->netstack_ip));
}
/*
* Determine the name of an IPv6 interface
*/
static int
netstack_t *ns)
{
ns->netstack_ip));
}
/*
* Shared implementation to determine the name of a given network interface
*/
/* ARGSUSED */
static int
{
char *name;
} else {
/* Fallback to group names only if hook_emulation is set */
if (ipst->ips_ipmp_hook_emulation) {
}
return (1);
}
return (0);
} else {
return (1);
}
}
/*
* Determine the MTU of an IPv4 network interface
*/
static int
{
}
/*
* Determine the MTU of an IPv6 network interface
*/
static int
{
}
/*
* Shared implementation to determine the MTU of a network interface
*
* Note: this does not handle a non-zero ifdata when ipmp_hook_emulation is set.
* But IP Filter only uses a zero ifdata.
*/
/* ARGSUSED */
static int
{
int mtu;
return (0);
if (mtu == 0) {
/*
* Fallback to group names only if hook_emulation
* is set
*/
if (ipst->ips_ipmp_hook_emulation) {
}
return (0);
}
}
return (mtu);
}
/*
* Determine if path MTU discovery is enabled for IP
*/
static int
{
}
/*
* Get next interface from the current list of IPv4 physical network interfaces
*
* Note: this does not handle the case when ipmp_hook_emulation is set.
* But IP Filter does not use this function.
*/
static phy_if_t
{
}
/*
* Get next interface from the current list of IPv6 physical network interfaces
*/
static phy_if_t
{
}
/*
* Determine if a network interface name exists for IPv4
*/
static phy_if_t
{
}
/*
* Determine if a network interface name exists for IPv6
*/
static phy_if_t
{
}
/*
* Implement looking up an ill_t based on the name supplied and matching
* it up with either IPv4 or IPv6. ill_get_ifindex_by_name() is not used
* because it does not match on the address family in addition to the name.
*/
static phy_if_t
{
/* Fallback to group names only if hook_emulation is set */
}
return (0);
return (phy);
}
/*
* Get next interface from the current list of IPv4 logical network interfaces
*/
static lif_if_t
{
ns->netstack_ip));
}
/*
* Get next interface from the current list of IPv6 logical network interfaces
*/
static lif_if_t
{
ns->netstack_ip));
}
/*
* Shared implementation to get next interface from the current list of
* logical network interfaces
*
* Note: this does not handle the case when ipmp_hook_emulation is set.
* But IP Filter does not use this function.
*/
static lif_if_t
{
return (0);
if (ifdata != 0) {
} else {
oldidx = 0;
}
return (0);
}
/*
* It's safe to iterate the ill_ipif list when holding an ill_lock.
* And it's also safe to access ipif_id without ipif refhold.
* See ipif_get_id().
*/
if (!IPIF_CAN_LOOKUP(ipif))
continue;
if (nextok) {
break;
}
}
return (0);
return (MAP_IPIF_ID(newidx));
}
/*
* Inject an IPv4 packet to or from an interface
*/
static int
{
}
/*
* Inject an IPv6 packet to or from an interface
*/
static int
{
}
/*
* Shared implementation to inject a packet to or from an interface
* Return value:
* 0: successful
* -1: memory allocation failed
* 1: other errors
*/
static int
{
struct sockaddr_in6 *sin6;
void (* func)(void *);
switch (style) {
case NI_QUEUE_IN:
return (-1);
/*
* deliver up into the kernel, immitating its reception by a
* network interface, add to list and schedule timeout
*/
break;
case NI_QUEUE_OUT:
return (-1);
/*
* deliver out of the kernel, as if it were being sent via a
* raw socket so that IPFilter will see it again, add to list
* and schedule timeout
*/
break;
case NI_DIRECT_OUT:
/*
* Note:
* For IPv4, the code path below will be greatly simplified
* with the delivery of surya - it will become a single
* function call to X. A follow on project is aimed to
* provide similar functionality for IPv6.
*/
if (!isv6) {
/*
* ipfil_sendpkt was provided by surya to ease the
* problems associated with sending out a packet.
* Currently this function only supports IPv4.
*/
case 0 :
case EINPROGRESS:
return (0);
case ECOMM :
case ENONET :
return (1);
default :
return (1);
}
/* NOTREACHED */
}
ipst);
ip2dbg(("ip_inject: ire_cache_lookup failed\n"));
return (1);
}
/* Send to loopback destination. */
ip2dbg(("ip_inject: bad nexthop\n"));
return (1);
}
return (0);
}
return (0);
} else {
/* prepend L2 header for IPv6 packets. */
/*
* Lock IREs, see 6420438
*/
ip2dbg(("ip_inject: llhdr failed\n"));
return (1);
}
}
break;
default:
return (1);
}
if (tq) {
DDI_SLEEP) == DDI_FAILURE) {
ip2dbg(("ip_inject: ddi_taskq_dispatch failed\n"));
return (1);
}
} else {
}
return (0);
}
/*
* Find the interface used for traffic to a given IPv4 address
*/
static phy_if_t
{
return (0);
}
/*
* Find the interface used for traffic to a given IPv6 address
*/
static phy_if_t
{
return (0);
}
/*
* Find the interface used for traffic to an address
*/
static phy_if_t
{
ipst);
} else {
ipst);
}
return (0);
return (0);
}
return (phy_if);
}
/*
* Determine if checksumming is being used for the given packet.
*
* Return value:
* NET_HCK_NONE: full checksum recalculation is required
* NET_HCK_L3_FULL: full layer 3 checksum
* NET_HCK_L4_FULL: full layer 4 checksum
* NET_HCK_L4_PART: partial layer 4 checksum
*/
static int
{
int ret = 0;
ret |= (int)NET_HCK_L4_FULL;
ret |= (int)NET_HCK_L3_FULL;
}
ret |= (int)NET_HCK_L4_PART;
ret |= (int)NET_HCK_L3_FULL;
}
return (ret);
}
/*
* Return true or false, indicating whether the network and transport
* headers are correct. Use the capabilities flags and flags set in the
* dblk_t to determine whether or not the checksum is valid.
*
* Return:
* 0: the checksum was incorrect
* 1: the original checksum was correct
*/
static int
{
unsigned char *wptr;
int hlen;
int ret;
if (dohwcksum &&
return (1);
/*
* Check that the mblk being passed in has enough data in it
* before blindly checking ip_cksum.
*/
return (0);
return (0);
} else {
}
ret = 1;
else
ret = 0;
return (ret);
}
/*
* Unsupported with IPv6
*/
/*ARGSUSED*/
static int
{
return (-1);
}
/*
* Determine the network addresses for an IPv4 interface
*/
static int
{
}
/*
* Determine the network addresses for an IPv6 interface
*/
static int
{
}
/*
* Shared implementation to determine the network addresses for an interface
*
* Note: this does not handle a non-zero ifdata when ipmp_hook_emulation is set.
* But IP Filter only uses a zero ifdata.
*/
/* ARGSUSED */
static int
{
struct sockaddr_in6 *sin6;
struct sockaddr_in *sin;
int i;
return (1);
ip2dbg(("ip_getlifaddr_impl failed type %d\n",
type[i]));
return (1);
}
}
} else {
return (1);
ip2dbg(("ip_getlifaddr_impl failed type %d\n",
type[i]));
return (1);
}
}
}
return (0);
}
/*
* ip_getlifaddr private function
*/
static int
{
void *src_addr;
int mem_size;
switch (type) {
case NA_ADDRESS:
break;
case NA_PEER:
break;
case NA_BROADCAST:
break;
case NA_NETMASK:
break;
default:
return (-1);
/*NOTREACHED*/
}
} else {
switch (type) {
case NA_ADDRESS:
break;
case NA_PEER:
break;
case NA_BROADCAST:
break;
case NA_NETMASK:
break;
default:
return (-1);
/*NOTREACHED*/
}
}
return (1);
}
/*
* Deliver packet up into the kernel, immitating its reception by a
* network interface.
*/
static void
ip_ni_queue_in_func(void *inject)
{
}
/*
* Deliver out of the kernel, as if it were being sent via a
* raw socket so that IPFilter will see it again.
*/
static void
ip_ni_queue_out_func(void *inject)
{
}
/*
* Shared implementation for inject via ip_output and ip_input
*/
static void
{
/* Fallback to group names only if hook_emulation is set */
}
return;
}
if (out == 0) {
} else {
}
return;
}
/*
* Even though ipcl_conn_create requests that it be passed
* a different value for "TCP", in this case there may not
* be a TCP connection backing the packet and more than
* likely, non-TCP packets will go here too.
*/
IP_WPUT);
} else {
IP_WPUT);
}
}
}
/*
* taskq function for nic events.
*/
void
ip_ne_queue_func(void *arg)
{
}
/*
* Temporary function to support IPMP emulation for IP Filter.
* Lookup an ill based on the ifindex assigned to the group.
* Skips unusable ones i.e. where any of these flags are set:
* (PHYI_FAILED|PHYI_STANDBY|PHYI_OFFLINE|PHYI_INACTIVE)
*/
ill_t *
{
if (ILL_CAN_LOOKUP(ill)) {
return (ill);
}
}
}
return (NULL);
}
/*
* Temporary function to support IPMP emulation for IP Filter.
* Lookup an ill based on the group name.
* Skips unusable ones i.e. where any of these flags are set:
* (PHYI_FAILED|PHYI_STANDBY|PHYI_OFFLINE|PHYI_INACTIVE)
*/
ill_t *
{
if (ILL_CAN_LOOKUP(ill)) {
return (ill);
}
}
}
return (NULL);
}