agentKernelIntfce.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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 1999-2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Routines in this program implement OS-specific portions of
* a Mobile-IP agent (RFC 2002).
*
*/
#ifndef _REENTRANT
#error "Error! Reentrant must be defined!"
#endif
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <fcntl.h>
#include <netdb.h>
#include <errno.h>
#include <assert.h>
#include <synch.h>
#include <syslog.h>
#include <stropts.h>
#include <netinet/if_ether.h>
#include "agent.h"
#include "mip.h"
#include "agentKernelIntfce.h"
#include "conflib.h"
/* Check for bad os version, and compile anyway xxx WORK -- remove this */
#ifndef IFF_NORTEXCH
#define IFF_NORTEXCH 0
#define IFF_MIPRUNNING 1
#define RTF_PRIVATE 2
#endif
/*
* Routing socket message len for creating route for
* reverse tunnel
*/
#define MIP_RTUN_RTM_MSGLEN sizeof (struct rt_msghdr) + \
sizeof (struct sockaddr_in) + \
sizeof (struct sockaddr_in) + \
sizeof (struct sockaddr_in) + \
sizeof (struct sockaddr_dl) + \
sizeof (struct sockaddr_in) + \
sizeof (struct sockaddr_dl)
/*
* Routing socket message len for normal route
* created to send reg reply to MN
*/
#define MIP_RTM_MSGLEN sizeof (struct rt_msghdr) + \
sizeof (struct sockaddr_in) + \
sizeof (struct sockaddr_in) + \
sizeof (struct sockaddr_in)
/* Common to all mobility agents */
extern struct hash_table haMobileNodeHash;
extern struct hash_table maAdvConfigHash;
extern struct hash_table mipTunlHash;
extern int logVerbosity;
struct dynamicIfacetype *dynamicIfaceHead;
static int ioctl_sockid;
static int rtsock;
static rwlock_t gbl_tunnelLock;
static int first_tun_to_check = 0;
char *err2str(int);
#define DEVICEDIR "/dev/"
#ifndef ETH_ALEN
#define ETH_ALEN sizeof (struct ether_addr)
#endif
/* Definitions needed for refresh_mn_arp() module */
#define ABS(x) ((x) < 0 ? -(x) : (x))
#define BITSPERBYTE 8
#define DEVICEDIR "/dev/"
#define BCAST_HW_ADDR "ff:ff:ff:ff:ff:ff"
#define MAX_ERR 2048
/* Tunnel related definitions */
#define MAX_TUNNEL_SUPPORTED 256
#define DEV_NAME_NOT_FOUND ENXIO
#define INVALID_IP_ADDR ENXIO
/* Table for mapping tunnelno with mobile-node address */
/*
* WORK -- this will be removed once the tunneling interface returns us
* a unique tunnel id.
*/
static struct {
#define MAXWAIT 15
/* Maximum address buffer length */
#define MAXDLADDR 1024
/* Handy macro. */
#define OFFADDR(s, n) (unsigned char *)((char *)(s) + (int)(n))
/* Internal Prototypes */
static int plumb_one_tun(int tnum);
static int unplumb_one_tun(int muxfd);
int *flagsp);
static int arpgetHWaddr(ipaddr_t, unsigned char *);
/* External Prototypes */
int muxfd);
/*
* Function: InitTunnelModule
*
* Arguments: none
*
* Description: Initialize our globals. Currently, initalize the global
* tunnel lock.
*
* Returns: int (zero on success)
*/
static int
{
int result;
return (result);
} /* InitTunnelModule */
/*
* Function: newtunnel
*
* Arguments: ipaddr_t addr
* ipaddr_t tsrc_addr
* int *tunnels_scanned
*
* Description: This function returns the available tunnel number in the
* range 0 through MAX_TUNNEL_SUPPORTED. If none are available
* it returns NO_FREE_TUNNEL. tunnels_scanned is used by the caller
* to figure out if all the tunnel numbers are scanned before
* concluding that there's no free tunnel left.
*
* Returns: int (tunnel number, or -1 on error)
*/
static int
{
int i;
int tun_num;
/* WARNING: check this xxx WORK */
(void) rw_wrlock(&gbl_tunnelLock);
*tunnels_scanned = 0;
for (i = 0; i < MAX_TUNNEL_SUPPORTED; i++) {
/* start scanning tunnel numbers where we were left last time */
/* is this an available tunnel? */
break;
}
}
/*
* Send back the number of tunnels scanned, so that caller can
* give up after scanning MAX_TUNNEL_SUPPORTED many tunnels.
* Also save where we were left, so that next time we start scanning
* from that point on.
*/
if (found) {
*tunnels_scanned = i + 1;
} else {
/*
* First_tun_to_check stays same. We did a one full round of
* scanning tunnel numbers and couldn't find any available.
* Next time we come here to find another available, we'll
* start from the same tunnel number.
*/
}
(void) rw_unlock(&gbl_tunnelLock);
if (found) {
return (tun_num);
} else {
return (-1);
}
} /* newtunnel */
/*
* Function: freetunnel
*
* Arguments: int tnum
*
* Description: This function will free the current tunnel resource. This
* function will disappear with the new kernel tunnel interface.
*
* Returns: void
*/
static void
freetunnel(int tnum)
{
(void) rw_wrlock(&gbl_tunnelLock);
(void) rw_unlock(&gbl_tunnelLock);
} /* freetunnel */
/*
* Gets the tunnel number corresponding to given
* mobile node address .
* If the corresponding tunnel number exist then it return s the tunnel no.
* else return s -(TUNNEL_NOT_FOUND)
*/
/*
* Function: gettunnelno
*
* Arguments: ipaddr_t mnaddr
* ipaddr_t tsrc_addr
*
* Description: Returns the tunnel number corresponding to a given mobile
* node address. If the corresponding tunnel number exists, then
* it returns the tunnel number. Otherwise it returns (-1)
* When called from HA mnaddr=mnaddr.
* when called from FA mnaddr=haaddr
* Tunnel source end-point addr=tsrc_addr
*
* Returns: int (Tunnel Number, -1 on failure)
*/
int
{
int i;
(void) rw_rdlock(&gbl_tunnelLock);
for (i = 0; i < MAX_TUNNEL_SUPPORTED; i++) {
break;
}
}
(void) rw_unlock(&gbl_tunnelLock);
return (i);
} else {
return (-1);
}
} /* gettunnelno */
#if 0
/*
* Function: printtunnels
*
* Arguments: none
*
* Description: This function prints out all the tunnels. It is used for
* debugging.
*
* Returns: void
*/
void
{
int i;
char mnaddr[INET_ADDRSTRLEN];
(void) rw_rdlock(&gbl_tunnelLock);
for (i = 0; i < MAX_TUNNEL_SUPPORTED; i++) {
if (mnaddr_tunl[i].mnaddr != 0) {
mipverbose(("Tunnel %d is for %s with refcnt %d\n",
mnaddr_tunl[i].refcnt));
}
}
(void) rw_unlock(&gbl_tunnelLock);
} /* printtunnels */
#endif
/* Convert a negative error value into a human readable error message */
/*
* Function: err2str
*
* Arguments: int errval
*
* Description: This function tries to return an error message based on
* an error code, or errno. It first checks for special errors,
* then checks the strerror string.
* WARNING: If the error is not found, then it returns a
* pointer to a static string. This function is NOT thread safe.
*
* Returns: char * (error string)
*/
char *
{
static char tmp[30];
switch (err) {
case INVALID_PPA:
return ("Invalid PPA");
case INVALID_STRING:
return ("Invalid input string");
case DLOKACK_SHORT_RESPONSE:
return ("Short DLOKACK response");
case DLOKACK_NOT_M_PCPROTO:
return ("DLOKACK is not M_PCPROTO");
case ERR_MORECTL:
return ("MORECTL");
case ERR_MOREDATA:
return ("MOREDATA");
case ERR_MORECTLDATA:
return ("MORECTL or MOREDATA");
case SHORT_CONTROL_PORTION:
return ("Control portion is short");
case DL_PRIMITIVE_ERROR:
return ("DL primitive error");
case INVALID_ADDR:
return ("Invalid Address");
case MN_ENTRY_ABSENT:
return ("Missing Mobile node entry");
case NO_MAPPING:
return ("Bad ARP mapping for mobile node");
default:
{
/* Check for errno error */
char *reason;
return (reason);
} else {
err);
return (tmp);
}
}
} /* switch */
} /* err2str */
/*
* Function: ifname2devppa
*
* Arguments: char *ifname, char *devname, int *ppa
*
* Description: Parse the interface name(e.g. "le0" or "hme1") and place the
* devname and the ppa(e.g. 0 or 1 for the examples above) in ppa.
* It expects that the caller will pass adequate buffer in
* 'devname' such that it can hold the full devicename.
*
* Returns: void
*/
void
{
char *p;
int i, j, val;
val = 0;
if (*p >= '0' && *p <= '9')
else
devname[j++] = *p;
}
devname[j] = '\0';
} /* ifname2devppa */
/*
* Function: mkpt2pt
*
* Arguments: char *ifname, ipaddr_t srcaddr, ipaddr_t dstaddr
*
* Description: Configure the point-to-point interface named ifname with the
* given address. The source address being 'srcaddr' and
* destination address being 'dstaddr'
*
* Returns: int
*/
static int
{
struct sockaddr_in *sin;
/* set the interface address */
return (-1);
}
return (-1);
}
return (0);
} /* mkpt2pt */
/*
* Function: InitNet
*
* Arguments: none
*
* Description: Network-related initialization, e.g. loading tunneling module
* etc. Information about each mobility supporting interface is
* available in maAdvConfigHash
*
* Returns: int (zero on success)
*/
int
InitNet()
{
/*
* Enable forwarding, disable ICMP redirects in kernel, e.g. FA
* should not redirect visiting mobile nodes to another router).
*/
(void) system(
(void) system(
mipverbose(("IP forwarding on, ICMP redirects off.\n"));
/* Initialize the tunnel management module */
if (InitTunnelModule() < 0) {
return (-1);
}
/* Make a socket for the various SIOCxxxx ioctl commands */
"Error: could not create socket for SIOCxxxx commands.");
return (-1);
}
/* Open a routing socket for passing route commands */
"Error: could not create socket for Route commands.");
return (-1);
}
return (0);
} /* InitNet */
/*
* Function: encapadd
*
* Arguments: ipaddr_t target, ipaddr_t tsrc, uint32_t tdst, uint8_t tflags
*
* Description: Enables encapsulation of pkts meant for target addr to the
* tunnel's destination addr (tdst) with the source address
* being that of the specified agent (tsrc). To configure an
* IP-in-IP tunnel, first get an unused tunnel number and
* then plumb it. Next, invoke any ipsec policies to ensure outbound
* tunnel packets to, and incomming tunnel packets from the agent-peer are
* protected (or we, or they will discard)! We do NOT set the peer-flag
* here as it's unnecessary, and should have been done anyway when we got
* the registration request (peer status isn't, after all, just about
* having a security association). Next set up a point-to-point
* interface between the target addr (target) - this is
* usually the mobile node address and address of the specified
* agent (tsrc) - this is usually the home agent address;
* the routine also sets up the tunnel with the source address
* of the tunnel being the specified agent address (tsrc)
* and the destination address of the tunnel being the
* address (tdst) - this usually is the foreign agent address.
* Next a number of interface specific flags are set and
* the tunnel is enabled. The tunnel specific entry data is
* next added to the hash table, keying on target address.
*
* If a tunnel entry already exists for the target addr
* increase the entry reference count.
*
* For now, tflags only identify if we're to protect a reverse tunnel,
* but in the future it can be used to identify when a tunnel other than
* an IP in IP tunnel should be set up.
*
* Returns: int
*/
int
{
int tunnels_scanned; /* no. of tunnels scanned in a */
/* single newtunnel() call. */
int total_tunnels_scanned; /* total no. of tunnels scanned */
/* in this encapadd() call. */
/*
* We don't need a MipTunlEntryLookup here to match
* with destination endpoint address as we know that
* the target(mnaddr) is unique per HA
*/
0)) != NULL) {
return (0);
}
muxfd = -1;
while ((total_tunnels_scanned < MAX_TUNNEL_SUPPORTED) &&
(muxfd == -1)) {
return (-1);
}
}
if (muxfd == -1) {
return (-1);
}
/*
* Before we can call settaddr, we need to see if we should pass down
* any IPSEC SAs so treqs can be set.
*/
/* for encapadd, we're an HA using "ipSecTunnel apply ..." */
/* pass down what we've parsed */
/* Symetric tunnels: should we set the reverse bit? */
if (tflags & REG_REVERSE_TUNNEL)
mae->maIPsecFlags |=
}
/* unlock */
}
(void) unplumb_one_tun(muxfd);
return (-1);
}
IFF_PRIVATE) == -1) {
(void) unplumb_one_tun(muxfd);
return (-1);
}
(void) unplumb_one_tun(muxfd);
return (-1);
}
return (0);
} /* encapadd */
/*
* Function: encaprem
*
* Arguments: ipaddr_t target
*
* Description: Terminates encapulation service for target addr.
* First find the tunnel entry in the hash table.
* If this is the last reference count to the tunnel entry
* then unplumb the tunnel and break the tunnel association
* between the foreign agent and home agent for
* encapsulation of packets destined for the target address.
* Next free the tunnel and the tunnel entry from hash table.
*
* Returns: int -1 on failure, the tunnel reference count on success.
*/
int
{
/*
* NOTE: We do not need to call MipTunlEntryLookup here
* because we assume MN home address(target) is unique per HA.
*/
return (-1);
}
"encaprem: unplumb of tunnel %d failed", tnum);
return (-1);
}
}
/* if refcnt is 0, this encapsulation point just went away */
/* WORK:Todo: This should call delHashTableEntry */
HashEntry *p, *q;
while (p) {
break;
q = p;
p = p->next;
}
else
free(p);
} else {
/* Release the lock held in findHashTableEntryUint */
}
} /* encaprem */
/*
* Function: decapadd
*
* Arguments: ipaddr_t ipipsrc, ipaddr_t ipipdst
*
* Description: Enable decapsulation service for target addr. To configure
* an IP-in-IP tunnel, first get an unused tunnel number and
* then plumb it. Next set up a point-to-point interface
* between the ipipdst addr - this is usually the foreign agent
* address and a dummy address ("0.0.0.0"); the routine
* also sets up the tunnel with the source address
* of the tunnel being ipipdst - usually foreign agent address
* and the destination address of the tunnel being the address
* ipipsrc - this usually is the home agent address. Next a
* number of interface specific flags are set and the tunnel is
* enabled. The tunnel specific entry data is next added to
* the hash table, keying on ipipsrc address.
*
* If a tunnel entry already exists for the ipipsrc addr
* increase the entry reference count.
* This function is called at the foreign agent end of tunnel.
*
* Returns: int (zero on success)
*/
int
{
int tunnels_scanned; /* no. of tunnels scanned in a */
/* single newtunnel() call. */
int total_tunnels_scanned; /* total no. of tunnels scanned */
/* in this decapadd() call. */
return (0);
}
muxfd = -1;
while ((total_tunnels_scanned < MAX_TUNNEL_SUPPORTED) &&
(muxfd == -1)) {
&tunnels_scanned)) < 0) {
return (-1);
}
}
if (muxfd == -1) {
return (-1);
}
/*
* Before tunnel is plumbed, and the interface is created, see if we
* have an IPsecPolicy. If so, point at it for settaddr().
*/
/*
* for decapadd, we're an FA using "IPsecTunnel permit ..."
* Note that we set the IPSEC_REVERSE_TUNNEL_PERMIT flag when
* processing for a reverse-tunnel request.
* Note that we don't check to see if the IPSEC_TUNNEL_PERMIT
* flag is set because we always want to make sure the tunnel's
* protected correctly.
*/
/* pass down what we've parsed */
/* set the invoked bit in case we have to restore */
}
/* unlock */
}
/*
* Tunnels in Solaris are bi-directional, with the obvious caveat that
* the dst address must be set. For security reasons, we only do this
* if the MN is requesting a reverse tunnel. If so, ipipsrc should be
* the MN's home agent address. ipsr contains our ipsec values.
* From FA end the parameters are : tsrc=COA, tdst=HAA, dstaddr=0.0.0.0
* srcaddr=COA
*/
(void) unplumb_one_tun(muxfd);
return (-1);
}
(void) unplumb_one_tun(muxfd);
return (-1);
}
/* Entry will be locked after CreateTunlEntry */
(void) unplumb_one_tun(muxfd);
return (-1);
}
return (0);
} /* decapadd */
/*
* Function: decaprem
*
* Arguments: ipaddr_t target : Tunnel outer destination IP address at FA
* ipaddr_t tsrc : Tunnel outer source IP address at FA
*
* Description: Terminates decapulation service for target address.
* First find the tunnel entry in the hash table.
* If this is the last reference count to the tunnel entry
* then unplumb the tunnel and break the tunnel association
* between the foreign agent and home agent for
* decapsulation of packets. Next free the tunnel and the
* tunnel entry from hash table.
*
* Returns: int (zero on success)
*/
int
{
return (-1);
}
"decaprem: unplumb of tunnel %d failed", tnum);
return (-1);
}
}
HashEntry *p, *q;
while (p) {
break;
q = p;
p = p->next;
}
else
free(p);
} else {
/*
* Release the lock. Other mobile node(s) may be
* using this tunnel.
*/
}
}
/*
* Function: MipTunlEntryLookup
* Arguments: entry - Pointer to MipTunl entry
* p1- First parameter to match (Tunnel src-endpoint IPaddr)
* p2- Second Parameter to match (unused)
* p3- Second Parameter to match (unused)
* Description:
* This function is used to lookup a tunnel entry which is hashed
* by the tunnel destination endpoint address and matched with
* it's source end point address. This matching is necessary
* to support multihomed foreign agent with more than one COAs
*/
/* ARGSUSED */
{
return (_B_TRUE);
return (_B_FALSE);
}
/*
* Function: arpadd
*
* Arguments: ipaddr_t host, unsigned char *eaddr, char *flag
*
* Description: Adds an arp entry with ip address set to host and hardware
* address set to eaddr with approriate flags specified by flag
* argument, e.g. arpadd(inet_addr("129.146.122.121"),
* "08:20:AB:FE:33:11", "pub") creates a proxy ARP entry for
* 129.146.122.121.
*
* Returns: int
*/
int
{
struct sockaddr_in *sin;
/* LINTED E_BAD_PTR_CAST_ALIGN */
#if 0
#endif
return ((-1) * errno);
}
return (0);
} /* arpadd */
/*
* Function: arpdel
*
* Arguments: ipaddr_t host
*
* Description: Deletes an arp entry for ip address set to host
*
* Returns: int (zero on success)
*/
int
{
struct sockaddr_in *sin;
/* LINTED E_BAD_PTR_CAST_ALIGN */
return ((-1) * errno);
}
return (0);
} /* arpdel */
/*
* Function: arpgetHWaddr
*
* Arguments: ipaddr_t mnaddr, unsigned char *mnetheraddr
*
* Description: Get the hardware address corresponding to mnaddr from
* the arp table.
*
* Returns: int (zero on success)
*/
static int
{
struct sockaddr_in *sin;
/* LINTED E_BAD_PTR_CAST_ALIGN */
return (-1 * (errno));
else {
return (0);
}
} /* arpgetHWaddr */
/*
* Function: arprefresh
*
* Arguments: HaMobileNodeEntry *hentry, ipaddr_t mnaddr
*
* Description: Sends gratuitous arp for the mnaddr using the hardware address
* found for mnaddr in its own ARP cache (making sure that the
* hardware address is not HA's own). The home agent calls
* arprefresh when a mobile node returns home and successfully
* deregisters itself.
*
* Returns: int (zero on success)
*/
int
{
int ret;
0x00, 0x00, 0x00};
mipverbose(("Arp refresh called for %d.%d.%d.%d\n",
/* Get the matching maIfaceAddr from mnAdvConfigTable */
}
return (ret);
return (-1 * NO_MAPPING);
else
} /* arprefresh */
/*
* Function: routemodify
*
* Arguments: ipaddr_t dst, ipaddr_t gw,
* ipaddr_t insrc, int in_if, int out_if,
* unsigned int cmd
*
* Description: Add or Delete route depending on 'cmd' argument.
* 'cmd' argument can be either ADDRT or DELRT.
* process and reply functions, only dst,gw args
* are required. Thus that is defined as simple route.
* NOTE: simple route is not used by mipagent registration
* reply process as it uses IP_XMIT_IF socket option
* instead of simple route. Simple route can not distinguish
* between two different mobile nodes with same private
* addresses. But the code still contains simple route
* section, in case it's needed in future for any purpose.
* After the visitor is accepted at FA, the
* forward route created from FA to MN to relay the
* packet from tunnel from home agent is defined
* as 'ftun_route'. This route must have in_if and out_if
* index arguments. For reverse tunnel route, this
* function expects a valid in_if and a valid out_if
* value and a non-zero source address(insrc). For ftun_route
* insrc must be zero.
*
* To set up forward route to reach MN:
* dst= MN's home addr, gw= COA, in_if=tun's if_index
* out_if = FA's interface index on which MN is attached.
* insrc = 0.0.0.0
*
* To set up reverse tunnel route:
* dst = 0.0.0.0 gw = 0.0.0.0 in_if = FA's interface index on
* which MN is attached, out_if = tunnel's interface index.
* insrc = MN's homeaddr
*
* Returns: int (zero on success)
*/
int
{
struct sockaddr_in *dstaddr;
struct sockaddr_in *gwaddr;
struct sockaddr_in *insrcaddr;
struct sockaddr_dl *rta_ifp;
struct sockaddr_dl *rta_srcifp;
char *cp;
static int rtmseq;
int rlen;
/* Simple route case dst<->gw: not used by mipagent */
/* Forward route to MN from tunnel */
/* Reverse tunnel route: insrc != 0 */
} else {
/* Invalid Call */
return (-1 * EINVAL);
}
return (-1 * (errno));
}
else
/* DST */
/* LINTED E_BAD_PTR_CAST_ALIGN */
if (!rtun_route)
else
/* GATEWAY */
cp += sizeof (struct sockaddr_in);
/* LINTED E_BAD_PTR_CAST_ALIGN */
/* NETMASK */
cp += sizeof (struct sockaddr_in);
/* LINTED E_BAD_PTR_CAST_ALIGN */
if (!rtun_route) {
} else {
}
/* Check if ftun_route or rtun_route is set, else it's simple_route */
if (ftun_route) {
/*
* We need to set both RTA_IFP and RTA_SRCIFP
* in order to support Lucent PPP interfaces to
* mobile nodes. Since there may not be an interface
* route for the dynamically plumbed PPP interfaces
* which are used in 3Gwireless technology to connect
* to the mobile node from the PDSN (Packet Data Service
* Network, IS-835, TIA document), thus the foreign agent
* (PDSN) end of PPP interface may have non-unique address
* (for example, all these special PPP interfaces may have
* same address, COA in the PDSN end). So it is not
* possible to derive interface index from the supplied
* gateway address. Hence the caller of this function
* must provide both outgoing and incoming interface
* index when creating the forward tunnel.
*/
/* IFP */
cp += sizeof (struct sockaddr_in);
/* LINTED E_BAD_PTR_CAST_ALIGN */
/* SRCIFP */
cp += sizeof (struct sockaddr_dl);
/* LINTED E_BAD_PTR_CAST_ALIGN */
} else if (rtun_route) {
/* it's a reverse tunnel route */
/* IFP */
cp += sizeof (struct sockaddr_in);
/* LINTED E_BAD_PTR_CAST_ALIGN */
/* SRC */
cp += sizeof (struct sockaddr_dl);
/* LINTED E_BAD_PTR_CAST_ALIGN */
/* SRCIFP */
cp += sizeof (struct sockaddr_in);
/* LINTED E_BAD_PTR_CAST_ALIGN */
}
/* Send the routing message */
if (rlen > 0) {
mipverbose(("Added route\n"));
else
mipverbose(("Deleted route\n"));
}
/* Free rt_msg now */
if (rlen < 0)
return ((-1) * (errno));
return (0);
} /* routemodify */
/* Routines for refresh_mn_arp() */
/* -------- Start of dlcommon routines */
/*
* Common (shared) DLPI test routines.
* Mostly pretty boring boilerplate sorta stuff.
* These can be split into individual library routines later
* but it's just convenient to keep them in a single file
* while they're being developed.
*
* Not supported:
* Connection Oriented stuff
* QOS stuff
*/
/*
* Function: dlinforeq
*
* Arguments: fd
*
* Description:
*
* Returns: int
*/
static int
{
return (-1 * errno);
}
return (0);
} /* dlinforeq */
/*
* Function: dlinfoack
*
* Arguments: fd, bufp
*
* Description:
*
* Returns: int
*/
static int
{
union DL_primitives *dlp;
int flags;
int ret;
/* LINTED E_BAD_PTR_CAST_ALIGN */
return (ret);
}
return (-1 * DLOKACK_SHORT_RESPONSE);
}
return (-1 * DLOKACK_NOT_M_PCPROTO);
}
return (-1 * DLOKACK_SHORT_RESPONSE);
}
return (0);
} /* dlinfoack */
/*
* Function: dlattachreq
*
* Arguments: fd, ppa
*
* Description:
*
* Returns: int
*/
int
{
return (-1 * errno);
return (0);
} /* dlattachreq */
/*
* Function: dlbindreq
*
* Arguments: fd, sap, max_conind, service_mode, conn_mgmt, xidtest
*
* Description:
*
* Returns: int
*/
int
{
return (-1 * errno);
return (0);
} /* dlbindreq */
/*
* Function: dlunitdatareq
*
* Arguments: int fd, unsigned char *addrp, int addrlen, ulong_t minpri
* ulong_t maxpri, unsigned char *datap, int datalen)
*
* Description:
*
* Returns: int
*/
static int
{
union DL_primitives *dlp;
addrlen);
return (-1 * errno);
return (0);
} /* dlunitdatareq */
/*
* Function: dlokack
*
* Arguments: int fd, char *bufp
*
* Description:
*
* Returns: int
*/
int
{
union DL_primitives *dlp;
int flags;
int ret;
/* LINTED E_BAD_PTR_CAST_ALIGN */
return (ret);
return (-1 * DLOKACK_SHORT_RESPONSE);
return (-1 * DLOKACK_NOT_M_PCPROTO);
return (-1 * DLOKACK_SHORT_RESPONSE);
return (0);
} /* dlokack */
/*
* Function: dlbindack
*
* Arguments: int fd, char *bufp
*
* Description:
*
* Returns: int
*/
int
{
union DL_primitives *dlp;
int flags;
int ret;
/* LINTED E_BAD_PTR_CAST_ALIGN */
return (ret);
return (-1 * DLOKACK_NOT_M_PCPROTO);
return (-1 * DLOKACK_SHORT_RESPONSE);
return (0);
} /* dlbindack */
/*
* Function: strgetmsg
*
* Arguments: int fd, struct strbuf *ctlp, struct strbuf *datap, int *flagsp,
* char *caller
*
* Description:
*
* Returns: int
*/
static int
{
int rc;
/*
* Set flags argument and issue getmsg().
*/
*flagsp = 0;
return (-1 * errno);
}
/*
*/
return (-1 * ERR_MORECTLDATA);
return (-1 * ERR_MORECTL);
return (-1 * ERR_MOREDATA);
/*
* Check for at least sizeof (long) control data portion.
*/
return (-1 * SHORT_CONTROL_PORTION);
return (0);
} /* strgetmsg */
/*
* Function: expecting
*
* Arguments: int prim, union DL_primitives *dlp
*
* Description:
*
* Returns: int (zero on success)
*/
static int
{
return (-1 * DL_PRIMITIVE_ERROR);
return (0);
} /* expecting */
/*
* Function: MAaddrtostring
*
* Arguments: unsigned char *addr, ulong_t length, unsigned char *s
*
* Description: return hardware address as string.
*
* Returns: void
*/
static void
{
int i;
for (i = 0; i < length; i++) {
s = s + strlen((char *)s);
}
if (length)
*(--s) = '\0';
} /* MAaddrtostring */
#if 0
/*
* Function: stringtoaddr
*
* Arguments: char *sp, char *addr
*
* Description: This function converts the string to an address.
*
* Returns: int (length of address)
*/
int
{
int n = 0;
char *p;
unsigned int val;
p = sp;
while (p = strtok(p, ":")) {
return (-1 * INVALID_STRING);
if (val > 0xff)
return (-1 * INVALID_STRING);
n++;
p = NULL;
}
return (n);
} /* stringtoaddr */
#endif
/* -------- End of dlcommon routines */
/*
* The parms are as follows:
* ppa Int for the instance of the device (e.g. 3, for "le3").
* phys Byte String for the dst MAC address of this packet.
* This is just the bcast address("ff:ff:ff:ff:ff:ff")
* physlen Length (int) of the mac address (not the string). E.g:
* 6 for enet.
* ipaddr long for the ip address of the host we are advertising
* our mac address for.
* ether_addr Ether address we want to set for the ipaddress we are
* impersonating
* NOTE: The mac addr of this system is not passed in, it is obtained
* directly from the dlpi info ack structure.
* Steps executed :-
* -----------------
* Open datalink provider.
* Attach to PPA.
* Bind to sap
* Send arp request as DL_UNITDATA_REQ msg
*
*/
{
int saplen;
int sapval = ETHERTYPE_ARP;
int localsap = ETHERTYPE_ARP;
int fd;
int addrlen;
union DL_primitives *dlp;
int i, ret;
/* initialize buf[] */
for (i = 0; i < MAXDLBUF; i++)
buf[i] = (unsigned char) i & 0xff;
/* Open the device. */
return (-1 * errno);
/* Attach. */
return (ret);
}
return (ret);
}
/* Bind. */
return (ret);
}
return (ret);
}
/* Get info */
return (ret);
}
return (ret);
}
/*
* Verify sap and phys address lengths.
*/
/* LINTED E_BAD_PTR_CAST_ALIGN */
/*
* Convert destination address string to address.
*/
for (i = 0; i < saplen; ++i) {
}
/*
* printdlprim(dlp);
*/
return (-1 * INVALID_ADDR);
}
/*
* Construct destination address.
*/
/* obtain our MAC address */
/*
* (void) memcpy((char *)my_etheraddr,
* (char *)OFFADDR(dlp,
* dlp->info_ack.dl_addr_offset + saplen),
* physlen);
*/
} else { /* order is phys+sap */
/* Obtain our MAC address */
/*
* (void) memcpy((char *)my_etheraddr,
* (char *)OFFADDR(dlp, dlp->info_ack.dl_addr_offset), physlen);
*/
}
/* create arp request */
/* Transmit it. */
if ((ret =
size)) < 0) {
return (ret);
}
return (0);
} /* send_gratuitous_arp() */
/*
* SYNOPSIS:
* garp interface ipaddr ether_addr
*
* RETURN VALUE :
* Returns 0 on success else -(error code)
* "interface" is the interface to send the grarp out on.
* "interface" is expressed in ifname convention(e.g. "le0", "bf2"),
* and it will be converted by ifname2device_ppa() into the dlpi convention
* "ipaddr" is the ipaddr of the system we're "impersonating"
* ether_addr is the ethernet address to which we want to be impersonated.
* Sends a gratuitous arp to hw addr ff:ff:ff:ff:ff:ff.
*
* The arp packet fields are filled in as follows:
* (To be in conformance gratuitous arp described in RFC2002)
* In the gratuitous arp packet for Mobile - IP :
* Ethernet header :
* Source address : Its own hardware address
* Destination address : ff:ff:ff:ff:ff:ff(Broadcast address)
*
* Arp Packet :
* Format of hardware address : ARPHRD_ETHER 1
* Format of protocol address : 0x0800
* Length of hardware address : ETH_ALEN 6
* Length of protocol address : 4
* ARP opcode : ARPOP_REQUEST 1
* Sender hardware address : Ethernet address to which to be updated.
* Destination harware address : XXXX Don't Care
* Sender IP address : IP Address(Cache entry to be updated)
* Target IP address : Sender IP Address.
* For an ARP Request Packet :
*
* Note : For ARP Reply packet target IP address should be set same
* as source IP address
*
* Modified from gabriels's arp module which was
* blatantly stolen from dlunitdatareq.c by Neal Nuckolls. Just added
* stuff to compose an arp packet.
*/
int
{
int ppa;
/* Validate arguments. */
if (ppa < 0)
return (-1 * INVALID_PPA);
mnaddr, mnetheraddr));
} /* garp */
/*
* Function: OScleanup
*
* Arguments: none
*
* Description: Close filedescriptors for shutdown.
* Also cleans up the dynamic interface and static
* interface list entries.
*
* Returns: void
*/
void
{
(void) close(ioctl_sockid);
/* Cleanup static existing interface table */
if (dynamicIfaceHead != NULL) {
struct dynamicIfacetype *dp;
struct dynamicIfacetype *savep;
}
}
if (StaticIntfaceHead != NULL) {
struct staticIface *sp;
struct staticIface *save_sp;
}
}
ioctl_sockid = -1;
} /* OScleanup */
/*
* Function: plumb_one_tun
*
* Arguments: int tnum
*
* Description: Plumb the tunnel interface by opening the
* associated devices and pushing the required modules eg.
* 'tunl' module and others and then create persistent links.
*
* Returns: -1 on error and mux_fd is returned upon success.
* mux_fd will be used by unplumb_one_tun to destroy
* the tunnel.
*/
static int
plumb_one_tun(int tnum)
{
return (-1);
}
return (-1);
}
return (-1);
}
return (-1);
}
/* Get the existing flags for this stream */
return (-1);
}
return (-1);
}
return (-1);
}
/*
* Tell IP the muxids of the LINKed interface
* streams so that they can be closed down at a later
* time by an unplumb operation.
*/
return (-1);
}
return (mux_fd);
} /* plumb_one_tun */
/*
* Function: unplumb_one_tun
*
* Arguments: int mux_fd
*
* Description: Unplumb the tunnel interface. Destroy all streams
* associated with this tunnel and close it.
*
* Returns: int
*/
static int
unplumb_one_tun(int mux_fd)
{
int retval;
return (retval);
}
/*
* Function: setifflags
*
* Arguments: int tnum, int value
*
* Description: Set the interface specific flags indicated in
* the argument 'value' for the given tunnel interface whose
* tunnel number is the argument 'tnum'.
*
* Returns: int
*/
static int
{
return (-1);
}
if (value < 0) {
} else
return (-1);
}
return (0);
}
/*
* Function: settaddr
*
* Arguments: int tnum, ipaddr_t ifaddr1, ipaddr_t ifaddr2,
* ipaddr_t saddr, ipaddr_t daddr, struct ipsec_req_t *ipsr
*
* Description: First forms a point-to-point interface between
* ifaddr1 and ifaddr2 addresses. Next the source address of
* the tunnel is set to address 'saddr'. This is the source
* address of an outer encapsulating IP header and it must be
* the address of an interface that has already been configured.
* The destination address of the tunnel is set to 'daddr'.
*
* Returns: static int
*/
static int
{
struct sockaddr_in *sin;
return (-1);
}
sizeof (treq.ifta_lifr_name));
return (-1);
}
return (-1);
}
sizeof (treq.ifta_lifr_name));
/* non-null means there's tunnel protection to be added! */
/* finally set the ipsec protection bits! */
/* set the flag so the kernel sets up the security! */
}
return (-1);
}
return (0);
} /* settaddr */
/*
* Function: getEthernetAddr
*
* Arguments: char *ename, unsigned char *eaddr
*
* Description: Get the hardware address for specified interface name.
*
* Returns: int
*/
int
{
int saplen;
int localsap = ETHERTYPE_ARP;
int fd;
union DL_primitives *dlp;
int i, ret;
int physlen = ETHERADDRL;
int ppa;
char *lasts;
/*
* If this is a virtual interface, remove the ':' character (and
* everything following that character. We do not really care
* about it since the MAC address is the same as the physical
* interface.
*/
return (-1);
}
/* initialize buf[] */
for (i = 0; i < MAXDLBUF; i++)
buf[i] = (unsigned char) i & 0xff;
/* Open the device. */
return (-1 * errno);
/* Attach. */
return (ret);
}
return (ret);
}
/* Bind. */
return (ret);
}
return (ret);
}
/* Get info */
return (ret);
}
/* WORK -- check this error message, and send to mohanp@eng */
(void) sleep(1);
return (ret);
}
/* Verify sap and phys address lengths */
/* LINTED E_BAD_PTR_CAST_ALIGN */
/* Construct destination address. */
/* obtain our MAC address */
physlen);
} else { /* order is phys+sap */
/* Obtain our MAC address */
physlen);
}
return (0);
} /* getEthernetAddr */
/*
* Function: getIfaceInfo
*
* Arguments: char *ifaceName, ipaddr_t *addr, ipaddr_t *mask, uint64_t *flags
* uint32_t *ifindex
*
* Description: Gets the interface information given the name.
*
* Returns: int
*/
int
{
struct sockaddr_in *sin;
int ioc_sockid;
if (ioc_sockid < 0) {
"Could not open socket for ioctls in getIfaceInfo()");
return (-1);
}
(void) close(ioc_sockid);
return (-1);
}
(void) close(ioc_sockid);
return (-1);
}
(void) close(ioc_sockid);
return (-1);
}
(void) close(ioc_sockid);
return (-1);
}
(void) close(ioc_sockid);
return (0);
} /* getIfaceInfo */
/*
* Function: arpIfadd
*
* Arguments: vaddr - visitor MN's IP address
* inIfindex - inbound interface index
* slla - MN's source link layer addr
*
* Description: Add an ARP entry given the interface index. Invokes
* SIOCSXARP with sdl_data array filled with interface
* name (without null terminator) followed by address.
* This code assumes it is being invoked on Ethernet.
*
* Returns: 0 - sucesss; errno - failure
*/
int
{
char *etheraddr;
int val;
char addrstr1[INET_ADDRSTRLEN];
struct ether_addr ether;
return ((-1) * errno);
}
/*
* Mark this entry permanent to prevent ARP from blowing this
* away.
*/
mipverbose(("Adding temporary ARP entry for visitor %s,"
" hardware address %s on interface %s [index %d]\n",
if (val < 0)
return ((-1) * errno);
else
return (val);
}
/*
* Function: arpIfdel
*
* Arguments: vaddr - visitor MN's IP address
* slla - MN's source link layer addr (used here for mipverbose)
* inIfindex - inbound interface index
*
* Description: Delete an ARP entry based on the interface index. Invokes
* SIOCDXARP with sdl_data array filled with interface
* name. This code assumes it is being invoked on Ethernet.
*
* Returns: 0 - sucesss; errno - failure
*/
int
{
int val;
char *etheraddr;
char addrstr1[INET_ADDRSTRLEN];
struct ether_addr ether;
return ((-1) * errno);
}
mipverbose(("Deleting temporary ARP entry for visitor %s,"
" hardware address %s on interface %s [index %d]\n",
/*
* Delete an ARP entry in the ARP cache
*/
if (val < 0)
return ((-1) * errno);
else
return (0);
}
/*
* Function: CreateListOfExistingIntfce
* This function stores a list of existing interfaces into a
* static interface entry table when the mipagent is started.
* The existing interface list does not include any IPv6,
* loopback and logical interfaces.
* Return value : 0 on success, -1 on failure
*/
int
CreateListOfExistingIntfce(void) {
int numifs;
int bufsize;
int iocsock;
int n;
char *buf;
if (iocsock < 0) {
return (-1);
}
lifn.lifn_flags = 0;
return (-1);
}
"Can't create existing interface list: Out of memory: %m");
return (-1);
}
lifc.lifc_flags = 0;
"Can't get existing system interface configuration: %m");
return (-1);
}
continue;
"Can't get flag information for %s: %m",
continue;
}
continue;
/* Create or add interface list */
ifce_ptr = (struct staticIface *)
malloc(sizeof (struct staticIface));
"malloc: Can't create existing interface list: %m");
return (-1);
}
if (StaticIntfaceHead == NULL)
}
}
return (0);
}
/*
* This function returns true or false based on matching entries
* from StaticIfaceEntry list
*/
existingStaticInterface(const char *ifname) {
struct staticIface *Sptr;
mipverbose(("existingStaticInterface:"
"Found a static existing entry\n"));
return (_B_TRUE);
}
}
return (_B_FALSE);
}