agent.c revision 5c0b7edee9bd9fad49038456b16972ff28fa4187
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 1987 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* file: agent.c
*
* This file contains the routines used to parse and process the
* Mobile-IP registration request and reply, as well as the routines
* used to manage the visitor and binding entries.
*
* This file contains the main mipagent routine.
*/
#include <stdio.h>
#include <dlfcn.h>
#include <signal.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <syslog.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/sysmacros.h>
#include <md5.h>
#include <locale.h>
#include <errno.h>
#include <fcntl.h>
#include <stropts.h>
#include "mip.h"
#include "agent.h"
#ifdef RADIUS_ENABLED
#include "radlib.h"
#endif /* RADIUS_ENABLED */
#include "auth.h"
#include "pool.h"
#include "setup.h"
#include "hash.h"
#include "agentKernelIntfce.h"
#include "conflib.h"
#include "mipagentstat_door.h"
/* Controls verbosity of debug messages when compiled w/ "-D MIP_DEBUG" */
int logVerbosity = 0;
/*
* We no longer use regLifetime global
*/
int advLifetime = DEFAULT_MAX_ADV_TIME;
int performanceInterval = 0;
/* our NAI */
/* challenges */
/* Required? */
/* Required? */
/* these are the IPsec install and remove policy commands */
char *ipsec_policy_action[] = {
};
/* these expand the same index of policy to what it means to humans */
char *ipsec_policy_string[] = {
"registration request apply policy",
"registration reply apply policy",
"tunnel apply policy",
"reverse tunnel apply policy",
"registration request permit policy",
"registration reply permit policy",
"tunnel permit policy",
"reverse tunnel permit policy",
};
#define BUCKET 0 /* Bucket in hashtable to start enumeration at */
#define PERF_MSG_SIZE 256
#ifdef RADIUS_ENABLED
/* Radius Variables */
int radiusEnabled = 0;
#define RADIUS_LOOKUP_TIME 60
#define RADIUS_DEBUG
char radiusSharedLibrary[MAX_FN_LEN];
int (*radInitializeApi)();
#endif /* RADIUS_ENABLED */
/*
* Default Values...
*/
uint32_t defaultPool = 0;
uint32_t defaultNodeSPI = 0;
/* ----------------- Common to all mobility agents ------------------- */
/*
* This table stores configuration information about agent
* advertisements. There's one entry for each mobility
* supporting interface.
*/
/*
* This table stores all of the Security Violations
*/
/*
* This table stores all of the Security Assocations
*/
/*
* This table has one entry for each known Mobility Agent
*/
/*
* This table has one entry for each active tunnel number
*/
/*
* Counters common to all Mobility Agents
*/
char maNai[MAX_NAI_LENGTH];
/*
* This table has one entry for each pool defined in the config file
*/
/* ------------------ Specific to foreign agents -------------------- */
/*
* This table stores information about visitors for which this
* mobility agent is a foreign agent. Some of the entries may
* correspond to unfulfilled registration requests.
*/
/*
* Counters maintained by Foreign Agents
*/
/*
* We need to keep track of the last two Challenge Values that
* we have advertised in order to check for replays.
*/
/* ------------------ Specific to home agents -------------------- */
/*
* This table has one entry for each mobile node for which a mobility
* agent offers Home Agent services.
*/
/*
* Counters maintained by Home Agents
*/
/* Security related stuff */
#ifdef FIREWALL_SUPPORT
#endif /* FIREWALL_SUPPORT */
/* ----------------------------------------------------------------- */
extern int Initialize(char *configFile);
extern void printBuffer(unsigned char *, int);
extern char *hwAddrWrite(unsigned char *, char *);
extern char *sprintTime(char *, int);
extern char *sprintRelativeTime(char *, int);
extern char *err2str(int);
extern int restoreAgentState(void);
extern void Finalize(int);
extern int startPeriodicTaskThread(void);
extern int startSNMPTaskThread(void);
extern int startDispatcherTaskThread(void);
extern int startStatServer();
static int startPerfTestServer(void);
extern uint32_t getRandomValue();
extern void ifname2devppa(char *, char *, int *);
extern int dlattachreq(int, int);
extern int dlokack(int, char *);
extern int dlbindack(int, char *);
static int mip_strioctl(int, int, void *, int, int);
int installIPsecPolicy(char *);
#ifdef FIREWALL_SUPPORT
/*
* Function: isInsideProtectedDomain
*
* Arguments: addr - peer's address.
*
* Description: Check each interval to see if the given addr is inside
* the protected domain
*
* Returns: boolean - _B_TRUE if the address is inside the protected domain.
*
*/
{
int i;
if (domainInfo.addrIntervalCnt == 0)
return (_B_TRUE);
for (i = 0; i < domainInfo.addrIntervalCnt; i++) {
return (_B_TRUE);
}
return (_B_FALSE);
}
#endif /* FIREWALL_SUPPORT */
/*
* Function: mkRegExtList
*
* Arguments: messageHdr - Message Control Block
* headerLength - length of the Mobile-IP heaeder
*
* Description: Examines the packet in the message header starting at the
* packet + the size of the header, which is provided as an
* argument. This function will place all the Mobile IP
* extensions encountered in the message header's extType[]
* and their start points in the extIdx[] field. The maximum
* size of these two arrays is stored in the message header's
* extCnt field. At termination, the extCnt field contains the
* number of extensions found in the message.
*
* Returns: int - 0 if successful.
*
*/
static int
{
unsigned char *currentPos;
/*
* Support for different extension header formats
*/
/*
* Protection against packets that have no extensions.
*/
if (bufLength == 0) {
return (0);
}
mipverbose(("Found extensions:"));
(extSeen < MAX_EXPECTED_EXTENSIONS)) {
/*
* The latest Mobile IP Extensions have a
* different extension header, compliant with, or close to,
* the MIER specification. The following checks the
* actual extension type in order to determine how to
* parse the extension header.
*/
case REG_GEN_AUTH_EXT_TYPE:
/*
* The following handles the generalized Authentication
* extension as well as the generalized keying
* extensions.
*/
(void) memcpy(&longLength,
sizeof (uint16_t));
sizeof (mierLongExt);
break;
/*
* The Vendor Specific Extension has a
* drastically different header, and not supporting
* the header would cause us to drop any packets
* with such headers. Critical Vendor Specific
* Extensions are now supported.
*/
sizeof (uint16_t));
sizeof (uint32_t));
(void) memcpy(&longLength,
sizeof (uint16_t));
#ifdef KEY_DISTRIBUTION
sizeof (vendorSpecExt);
#else /* KEY_DISTRIBUTION */
#endif /* KEY_DISTRIBUTION */
break;
/*
* The Vendor Specific Extension has a
* drastically different header, and not supporting
* the header would cause us to drop any packets
* with such headers. Normal Vendor Specific Extensions
* are now supported.
*/
sizeof (uint8_t));
break;
default:
/*
* The following code supports the traditional
* extensions.
*/
sizeof (uint8_t));
break;
}
/*
* protect against bogus packets.
*/
return (-1);
}
extSeen++;
}
(extSeen >= MAX_EXPECTED_EXTENSIONS)) {
return (-1);
return (-1);
} else {
return (0);
}
}
/*
* Function: IsPacketFromMnValid
*
* Arguments: messageHdr - Message Control Block
*
* Description: This function is called by the Foreign Agent when a
* registration request is received from a Mobile Node
* and will step through each extension that was stored
* in the message header's extType to ensure that the
* packet contains the required extensions and that the
* message follows the protocol rules.
*
* The rules are:
* 1. If the challenge is being advertised, it MUST be
* present in the packet.
* 2. If the MN-AAA is present, then the MN-FA, the
* NAI and the challenge extensions MUST be present.
* 3. If MN-AAA is not present, MN-HA MUST be present.
* 4. If the MN-FA is present, it MUST be present after
* either the MN-HA or the MN-AAA extension.
*
* Returns: returns a Mobile IP error code, zero if successful.
* return -1 if packet needs to be dropped.
*
*/
/*
* The message parsing routines must be able to return
* a variety of Mobile IP error codes in order to support all error
* cases.
*/
static int
{
int i;
/* LINTED BAD_PTR_CAST_ALIGN */
/*
* According to the latest Challenge draft, here is the
* rule. If the challenge was advertised, then it MUST
* be present in ALL packets. If the Mobile-AAA authentication
* extension is present, then the NAI MUST be present.
*
* Normal RFC 2002 rules apply, with the exception that if
* the Mobile-Home authentication is NOT present, then the
* Mobile-AAA authentication extension MUST be present.
*/
for (i = 0; i < messageHdr->extCnt; i++) {
mipverbose(("IsPacketFromMnValid[%d] = %d\n", i,
messageHdr->extType[i]));
switch (messageHdr->extType[i]) {
case REG_MH_AUTH_EXT_TYPE:
/* we should not have seen any other auth extensions */
if (foundMHauth == _B_TRUE) {
"Multiple MH or MA Authentication Extensions");
return (FA_POORLY_FORMED_REQUEST);
} else {
}
break;
case REG_GEN_AUTH_EXT_TYPE:
/*
* supports a generalized authentication extension, similar
* to the MIER specification. When we receive the generalized
* authentication extension, we need to check the subtype
* field in order to determine the actual extension.
*/
switch (messageHdr->extSubType[i]) {
case GEN_AUTH_MN_AAA:
/*
* The challenge extension MUST be present prior to
* the MN-AAA Auth Ext.
*/
if (foundChallenge == _B_FALSE) {
"Mobile-AAA Authentication Extension");
/*
* If a challenge was expected,
* but not received, we must return a missing
* challenge error.
*/
return (FA_MISSING_CHALLENGE);
}
/*
* The draft states that the NAI SHOULD be present if
* the M-A authentication extension is present, so we
* will enforce this.
*/
"Authentication Extension");
/*
* Mipagent didn't return the
* error codes specified in the NAI
* specification. If an NAI was expected, and
* wasn't present, return a MISSING NAI error.
*/
return (FA_MISSING_NAI);
}
/*
* Fixed buffer overrun. mnNAI is not null
* terminated.
*/
/* we should not have seen any other auth extensions */
if (foundMAauth == _B_TRUE) {
"Multiple MH or MA Authentication Extensions");
return (FA_POORLY_FORMED_REQUEST);
} else {
}
break;
default:
"Unknown Generalized Authentication subtype found");
return (FA_POORLY_FORMED_REQUEST);
}
break;
case REG_MF_AUTH_EXT_TYPE:
/* we should have seen MHauth but no MFauth */
if (foundMFauth == _B_TRUE) {
"Extensions");
return (FA_POORLY_FORMED_REQUEST);
} else {
}
} else {
"No MH or MA before MF Authentication Extension");
return (FA_POORLY_FORMED_REQUEST);
}
break;
/*
* We should only see the challenge if we've
* advertised it.
*/
if (faChallengeAdv == _B_FALSE) {
return (FA_POORLY_FORMED_REQUEST);
}
if (foundMFauth == _B_TRUE) {
"MF Authentication Extension");
return (FA_POORLY_FORMED_REQUEST);
}
if (foundChallenge == _B_TRUE) {
return (FA_POORLY_FORMED_REQUEST);
} else {
}
break;
case REG_MN_NAI_EXT_TYPE:
/*
* The draft states that the NAI SHOULD be present if
* the M-A authentication extension is present, so we
* will enforce this.
*/
return (FA_POORLY_FORMED_REQUEST);
} else {
/*
* Save the pointer to the NAI for future
* reference.
*/
/*
* Protect against buffer overflows...
*/
/*
* Mipagent didn't return the
* error codes specified in the NAI
* specification. If an NAI was present, but
* larger than expected, return a MISSING NAI
* code (the draft doesn't actually state
* what should be returned here.
*/
return (FA_MISSING_NAI);
}
/*
* Fixed buffer overrun. mnNAI is not null
* terminated.
*/
messageHdr->mnNAI);
}
break;
/* Vendor-specific extension support */
/*
* haven't seen the MN-FA auth (yet).
*/
/*
* We haven't seen any mobile node authentication
* authenticator. These aren't for us, so skip them.
*/
break;
}
/* This extension is implicitly for us as FA... */
switch (messageHdr->extSubType[i]) {
/*
* MN-FA auth is not required to be put here by the
* authenticator, the implication is the MN wants us
* to look it. Even if we waited for an MN-FA auth
* we're not likely to be returning anything different.
*/
/*
* Vendor-specific extensions we understand go here!
*/
default:
/*
* RFC 3025 says if we understand this
* extension type, but we don't understand
* we MUST send the registration reply with
* a HA_UNKNOWN_CVSE_FROM_MN. Make sure,
* though, that this is for us as FA...
*/
if ((foundMHauth == _B_TRUE ||
foundMAauth == _B_TRUE) &&
foundMFauth != _B_TRUE) {
/*
* We've seen some form of Mobile-Home
* authentication, so it's not for the
* HA, and we haven't seen a MFauth, so
* it implies this is for us as FA.
*/
"Unrecognized CVSE subtype %d "
"from Mobile Node",
messageHdr->extSubType[i]);
return (FA_UNKNOWN_CVSE_FROM_MN);
}
break;
}
break;
/*
* haven't seen the MN-FA auth (yet).
*/
/*
* We haven't seen a mobile-home authenticator yet,
* This isn't for us, so skip them silently.
*/
break;
}
/* This extension is something the MN wants us to look at */
switch (messageHdr->extSubType[i]) {
/*
* As we understand specific vendor extensions,
* they go in here!
*/
default:
/*
* Non-critical vendor specific extensions are
* ignored if we don't understand it. Make
* sure we don't log this if it's really for
* the HA...
*/
if ((foundMHauth == _B_TRUE ||
foundMAauth == _B_TRUE) &&
foundMFauth != _B_TRUE) {
/*
* If we saw an MFauth, it'd be bad to
* process this. In that case it may
* be for someone, just not us...
*/
"Unrecognized NVSE subtype %d "
"from Mobile Node, ignoring!",
messageHdr->extSubType[i]);
}
break;
}
break;
/*
* If the Encapsulating Delivery Style Extension is present,
* the MN MUST be requesting reverse tunneling! It MUST also
* appear after the MN_HA_AUTHENTICATION extension, (and when
* we support it we MUST consume it so it isn't forward it to
* the HA (this last part can't be done here as we're just
* parsing a list of extensions)).
*
* Hopefully *everything* after the mn-ha auth in the regreq
* the mn sent us is removed somewhere before we add fa things,
* then the fa-ha auth (if applicable).
*
* At this time it's OK for a MN to put more than one of these
* in, so there's no need to set a foundEDS flag to be checked
* later.
*
* At this time, only IPv4inIPv4 tunnels are supported. If
* there ever comes a time when we support any other type, we
* may have to check the tunnel-type request bits to make sure
* we support that in the reverse direction too.
*/
/*
* We should have either found a mn-ha authenticator first,
* or a AAA MN authentication first and NOT a
* mn-fa authenticator (since this has to be between the two).
* Note: it may be nicer to break this into two cases if we
* want to provide a more specific syslog message.
*/
(foundMFauth == _B_TRUE)) {
"Found ENCAPSULATING_DELIVERY_TYPE"
" in the wrong location of registration request -"
" either before mn-ha or mn AAA authenticator,"
" or after mn-fa authenticator.");
return (FA_POORLY_FORMED_REQUEST);
}
/* The 'T' bit MUST be set. */
/* extension is here, but 'T' bit isn't set */
"Found ENCAPSULATING_DELIVERY_TYPE"
" but 'T' bit isn't set.");
return (FA_POORLY_FORMED_REQUEST);
}
/*
* OK, looks good, but we don't support this yet. This is the
* only place we can look for this extension, but until we
* support type 130 extensions, we'll have to be non-conformant
* for this function, too, and return something other than
* FA_POORLY_FORMED_REQUEST.
*/
return (FA_DELIVERY_STYLE_UNAVAILABLE);
default:
/*
* Unrecognized extensions in this range cause this
* packet be drooped.
*/
"Unrecognized ext (ext[%d]= %d) in range 0-127.",
i, messageHdr->extType[i]);
return (MA_DROP_PACKET);
}
/*
* Extensions in the range 128-255 should be
* skipped.
*/
break;
}
}
/*
* Acording to the challenge draft, the rules is as follow:
* 1. If the Mobile Node does not have a security association
* with the foreign agent, it MUST include the MN-AAA auth
* ext. The challenge must appear PRIOR to this extension.
* 2. If the Mobile Node has a security association with the
* foreign agent, it must include the MN-FA auth ext.
*
* So in order to enforce this, if the challenge is being
* advertised, we will ensure that either the MN-AAA is present
* OR the MN-HA AND the MN-FA.
*/
if (faChallengeAdv == _B_TRUE) {
foundMFauth == _B_FALSE)) {
"the MN-AAA or the MN-HA *and* the MN-FA must "
"be present");
return (FA_POORLY_FORMED_REQUEST);
}
}
/*
* The registration request must include either:
* 2. NAI.
*/
"Mobile Node NAI MUST be present if home address "
"is set to zero (0)");
/*
* Mipagent didn't return the error codes
* specified in the NAI specification. If an NAI was expected,
* and wasn't present, return a MISSING NAI error.
*/
return (FA_MISSING_NAI);
}
/* make sure we have one MHauth */
return (MIP_SUCCESSFUL_REGISTRATION);
} else {
return (FA_POORLY_FORMED_REQUEST);
}
}
/*
* Function: IsPacketFromCoaValid
*
* Arguments: messageHdr - Message Control Block
*
* Description: This function is called by the Home Agent when a
* registration request is received from a Foreign Agent
* and will step through each extension that was stored
* in the message header's extType to ensure that the
* packet contains the required extensions and that the
* message follows the protocol rules.
*
* The rules are:
* 1. If the MN-AAA is present, then the MN-FA, the
* NAI and the challenge extensions MUST be present.
* 3. If MN-AAA is not present, MN-HA MUST be present.
* 4. If the FA-HA is present, it must be preceeded by
* either the MN-HA or the MN-AAA.
*
* Returns: returns a Mobile IP error code, zero if successful.
* return -1 if packet needs to be dropped.
*
*/
static int
{
char addrstr[INET_ADDRSTRLEN];
int i;
/* LINTED BAD_PTR_CAST_ALIGN */
/*
* According to the latest Challenge draft, here is the
* rule. If the challenge was advertised, then it MUST
* be present in ALL packets. If the Mobile-AAA authentication
* extension is present, then the NAI MUST be present.
*
* Normal RFC 2002 rules apply, with the exception that if
* the Mobile-Home authentication is NOT present, then the
* Mobile-AAA authentication extension MUST be present.
*/
for (i = 0; i < messageHdr->extCnt; i++) {
mipverbose(("IsPacketFromCoaValid[%d] = %d\n", i,
messageHdr->extType[i]));
switch (messageHdr->extType[i]) {
case REG_MH_AUTH_EXT_TYPE:
/* we should not have seen any other auth extensions */
if (foundMHauth == _B_TRUE) {
"Multiple MH or MA Authentication Extensions");
return (HA_POORLY_FORMED_REQUEST);
} else {
}
break;
case REG_GEN_AUTH_EXT_TYPE:
/*
* supports a generalized authentication extension, similar to
* the MIER specification. When we receive the generalized
* authentication extension, we need to check the subtype
* field in order to determine the actual extension.
*/
switch (messageHdr->extSubType[i]) {
case GEN_AUTH_MN_AAA:
/*
* The challenge extension MUST be present prior to
* the MN-AAA Auth Ext.
*/
if (foundChallenge == _B_FALSE) {
"Mobile-AAA Authentication Extension");
return (HA_POORLY_FORMED_REQUEST);
}
/*
* The draft states that the NAI SHOULD be present if
* the M-A authentication extension is present, so we
* will enforce this.
*/
"Authentication Extension");
/*
* Mipagent didn't return the
* error codes specified in the NAI
* specification. If an NAI was expected, and
* wasn't present, return a MISSING NAI error.
*/
return (FA_MISSING_NAI);
}
/*
* Fixed buffer overrun. mnNAI is not null
* terminated.
*/
messageHdr->mnNAI);
/* we should not have seen any other auth extensions */
if (foundMAauth == _B_TRUE) {
"Multiple MH or MA Authentication Extensions");
return (HA_POORLY_FORMED_REQUEST);
} else {
}
break;
default:
"Unknown Generalized Authentication subtype found");
return (HA_POORLY_FORMED_REQUEST);
}
break;
if (foundChallenge == _B_TRUE) {
return (HA_POORLY_FORMED_REQUEST);
} else {
}
break;
case REG_FH_AUTH_EXT_TYPE:
/*
* We should at least make sure that we've seen
* the Mobile-Home Authentication Extension before
* we see this one.
*/
"Missing MH or MA Authentication Extension "
"before FHauth");
return (HA_POORLY_FORMED_REQUEST);
} else {
/*
* we should not have seen any other auth
* extensions
*/
if (foundFHauth == _B_TRUE) {
return (HA_POORLY_FORMED_REQUEST);
} else {
}
}
break;
case REG_MN_NAI_EXT_TYPE:
/*
* The draft states that the NAI SHOULD be present if
* the M-A authentication extension is present, so we
* will enforce this.
*/
return (HA_POORLY_FORMED_REQUEST);
} else {
/*
* Save the pointer to the NAI for future
* reference.
*/
/*
* Protect against buffer overflows...
*/
return (HA_POORLY_FORMED_REQUEST);
}
}
break;
/* Vendor-specific extension support */
/* Examine the subtype, and process accordingly */
switch (messageHdr->extSubType[i]) {
/*
* As we understand specific vendor extensions,
* they go in here!
*/
default:
/*
* RFC 3025 says if we understand this type,
* or Vendor-CVSE-Type, we MUST send a
* registration reply with either
* HA_UNKNOWN_CVSE_FROM_MN if it came from
* the mobile node, or HA_UNKNOWN_CVSE_FROM_FA
* if it came from the foreign agent.
*
* What we need to worry about now:
*
* Did this extension come from the MN, or was
* it added by an FA? Note (caveat!): if the
* 'D'-bit is set, if an FA was advertising
* the 'R'-bit, the MN sent the registration
* request to it, so it may have added these
* extensions in flight!
*/
if (foundMHauth != _B_TRUE &&
foundMAauth != _B_TRUE) {
/*
* authenticator, so this is in the
* MN-to-HA portion of the request
*/
"Unrecognized CVSE subtype %d from"
" Mobile Node",
messageHdr->extSubType[i]);
return (HA_UNKNOWN_CVSE_FROM_MN);
} else if (foundFHauth != _B_TRUE) {
/*
* We've seen some form of MN-home
* authenticator, so what we're
* looking at now appears after it,
* and must be from an FA (FA iGs
* supposed to strip out anything
* so this must have been FA-appended.
* That 'if' was a sanity check that we
* have NOT seen a FA-HA authenticator,
* which would imply this was NOT
* added by the FA.
*/
"Unrecognized CVSE subtype %d from"
" Foreign Agent",
messageHdr->extSubType[i]);
return (HA_UNKNOWN_CVSE_FROM_FA);
}
break;
}
break;
/* Examine the subtype, and process accordingly */
switch (messageHdr->extSubType[i]) {
/*
* As we understand specific vendor extensions,
* they go in here!
*/
default:
/*
* For non-critical vendor specific extensions,
* we ignore the entire extension if we don't
* understand the sub-type or vendor-ID.
*
* We need to know if it came from MN or FA...
*/
if (foundMHauth != _B_TRUE &&
foundMAauth != _B_TRUE) {
/*
* authenticator, so it's before it,
* and is from the mobile node.
*/
"Unrecognized NVSE subtype %d from"
" Mobile Node, ignoring!",
messageHdr->extSubType[i]);
} else if (foundFHauth != _B_TRUE) {
/*
* It's after MN-home authenticationon,
* but before FA-home authentication,
* so the implication is this was put
* here by the FA.
*/
"Unrecognized NVSE subtype %d from"
" Foreign Agent, ignoring!",
messageHdr->extSubType[i]);
}
break;
}
break;
/*
* If the MN included the Encapsulating Delivery Style
* Extension, the FA MUST consume it. If it didn't, we'll be
* nice and just log an error (there is no "official" error
* code which can help a MN figure this out anyway).
*
* We could make sure we've seen the MN-HA auth. If not, it's
* a poorly formed request (and perhaps why the FA didn't
* remove this extension, though it should have denied it with
* poorly formed request). Since this is an FA only thing,
* and clearly isn't a security problem, I don't think we
* should care. Denying is likely to lead to no service, so
* are we trying to service this guy, or look for reasons to
* deny service?
*
* The icing here is since it's type 130 it's in the ignore
* range. We shouldn't change the way the HA reacts to a FA
* only RT extension because it now supports RT.
*/
"Home Agent found ENCAPSULATING_DELIVERY_TYPE extension."
" FA (%s) should have removed it."
" Ignoring (as type>127), and processing registration.",
break;
default:
/*
* Unrecognized extensions in this range cause this
* packet be drooped.
*/
"Unrecognized ext (ext[%d]= %d) in range 0-127.",
i, messageHdr->extType[i]);
return (MA_DROP_PACKET);
}
/*
* Extensions in the range 128-255 should be
* skipped.
*/
break;
}
}
/*
* The registration request must include either:
* 2. NAI.
*/
"Mobile Node NAI MUST be present if home address "
"is set to zero (0)");
return (HA_POORLY_FORMED_REQUEST);
}
/* make sure we have one MHauth */
return (MIP_SUCCESSFUL_REGISTRATION);
} else {
return (HA_POORLY_FORMED_REQUEST);
}
}
/*
* Function: IsPacketFromHaValid
*
* Arguments: messageHdr - Message Control Block
*
* Description: This function is called by the Foreign Agent when a
* registration reply is received from a Home Agent
* and will step through each extension that was stored
* in the message header's extType to ensure that the
* packet contains the required extensions and that the
* message follows the protocol rules.
*
* The rules are:
* 1. The MN-HA MUST be present.
* 2. If the FA-HA is present and the challenge
* is being advertised, the challenge MUST be present.
* 3. If the FA-HA is present, it MUST appear after the
* the MN-HA extension.
*
* Returns: returns a Mobile IP error code, zero if successful.
* return -1 if packet needs to be dropped.
*
*/
static int
{
int i;
/* LINTED BAD_PTR_CAST_ALIGN */
/*
* The NAI MAY be necessary, but right now we have no
* way of knowing. This check will have to be handled
* later.
*/
for (i = 0; i < messageHdr->extCnt; i++) {
mipverbose(("IsPacketFromHaValid[%d] = %d\n", i,
messageHdr->extType[i]));
switch (messageHdr->extType[i]) {
case REG_MH_AUTH_EXT_TYPE:
/* we should not have seen any other auth extensions */
if (foundMHauth == _B_TRUE) {
"Multiple MH or MA Authentication Extensions");
return (FA_POORLY_FORMED_REPLY);
} else {
}
break;
case REG_FH_AUTH_EXT_TYPE:
/* If we are expecting a challenge, check for it. */
/*
* If a challenge was expected, but
* not received, we must return a missing challenge
* error.
*/
return (FA_MISSING_CHALLENGE);
}
/* we should have seen MHauth but no FHauth */
if (foundMHauth == _B_FALSE) {
"No MH or MA Authentication Extension before FHauth");
return (FA_POORLY_FORMED_REPLY);
} else if (foundFHauth == _B_TRUE) {
return (FA_POORLY_FORMED_REPLY);
} else {
}
break;
if (foundChallenge == _B_TRUE) {
return (FA_POORLY_FORMED_REPLY);
} else {
}
break;
case REG_MN_NAI_EXT_TYPE:
/*
* The draft states that the NAI SHOULD be present if
* the M-A authentication extension is present, so we
* will enforce this.
*/
return (FA_POORLY_FORMED_REPLY);
} else {
/*
* Save the pointer to the NAI for future
* reference.
*/
/*
* Protect against buffer overflows...
*/
return (FA_POORLY_FORMED_REPLY);
}
}
break;
/*
* The AAA Keys Internet Draft now supports
* a generalized key extension, similar to the MIER
* specification. When we receive the generalized key
* extension, we need to check the subtype field in order to
* determine the actual extension.
*/
switch (messageHdr->extSubType[i]) {
case GEN_KEY_MN_FA:
/*
* We just need to recognize the extension type,
* otherwise it will cause an error.
*/
break;
default:
"Unrecognized generalized key subtype %d",
messageHdr->extSubType[i]);
return (FA_POORLY_FORMED_REPLY);
}
break;
/*
* The AAA Keys Internet Draft now supports
* a generalized key extension, similar to the MIER
* specification. When we receive the generalized key
* extension, we need to check the subtype field in order to
* determine the actual extension.
*/
switch (messageHdr->extSubType[i]) {
case GEN_KEY_MN_HA:
/*
* We just need to recognize the extension type,
* otherwise it will cause an error.
*/
break;
default:
"Unrecognized generalized key subtype %d",
messageHdr->extSubType[i]);
return (FA_POORLY_FORMED_REPLY);
}
break;
/* Check the subtype and process accordingly */
switch (messageHdr->extSubType[i]) {
#ifdef KEY_DISTRIBUTION
/*
* KEY_DISTRIBUTION MUST ONLY BE COMPILED FOR TESTING!!!
*
* interface. The DIAMETER server generates keying
* material that is sent to the Home Agent. The keys
* sent are both for the Home Agent, and for the Mobile
* Node. The keys for the Mobile Nodes are added to the
* registration reply, and the keys for the Home Agent
* cause the Home Agent to create a local SA.
*
* distribution must still be tested, we have added some
* test code in mipagent. When KEY_DISTRIBUTION is enabled,
* the home agent creates and encrypts session keys for
* the Mobile Node (mimicking DIAMETER), and creates local
* SAs. Further, since the session keys MUST also be sent
* to the Foreign Agent, the session keys are sent in the
* clear to the Foreign Agent through Vendor Specific
* extensions.
*
* Again, this code is for testing purpose only and must not
* be enabled for production code, since it hasn't been
* fully tested.
*/
case REG_MN_FA_KEY_EXT:
case REG_FA_HA_KEY_EXT:
/*
* We just need to recognize the extension type,
* otherwise it will cause an error.
*/
break;
#endif /* KEY_DISTRIBUTION */
/*
* Insert understood REG_CRIT_VENDOR_SPEC_EXT_TYPEs here!
*/
default:
/*
* RFC 3025 says if we don't understand
* this subtype we MUST return
* FA_UNKNOWN_CVSE_FROM_HA in the
* registration reply (to the mobile node,
* who'll understand it MUST rereg, and
* hopefully do something to change the HA's
* mind about replying with that CVSE)!
* First, though, make sure it's for us!
*/
/*
* we've seen the MHAUTH, so this is
* after it, but not an FHauth, so it's
* for us from the HA.
*/
"Unrecognized CVSE subtype %d"
" from Home Agent.",
messageHdr->extSubType[i]);
return (FA_UNKNOWN_CVSE_FROM_HA);
}
}
break;
/* Check subtype, and process accordingly */
switch (messageHdr->extSubType[i]) {
/*
* Understood REG_NORMAL_VENDOR_SPEC_EXT_TYPEs go here!
*/
default:
/*
* RFC3025 says silently ignore, but we should
* at least log it if it's for us.
*/
if (foundMHauth == _B_TRUE &&
foundFHauth == _B_FALSE) {
/*
* We've seen the MHauth, so it's not
* for the MN, and we haven't seen an
* FHauth, so the implication is this
* is for us (if we had seen a FAauth,
* we'd KNOW it's NOT for us).
* Note: there's no check for an
* MN-AAAauth in this routine here!
*/
"Unrecognized NVSE subtype %d"
" from Home Agent, ignoring.",
messageHdr->extSubType[i]);
}
}
break;
default:
/*
* Unrecognized extensions in this range cause this
* packet be drooped.
*/
"Unrecognized ext (ext[%d]= %d) in range 0-127.",
i, messageHdr->extType[i]);
return (MA_DROP_PACKET);
}
/*
* Extensions in the range 128-255 should be
* skipped.
*/
break;
}
}
/*
* The Home Address MUST be provided.
*/
/*
* Mipagent didn't return the error
* codes specified in the NAI specification. If
* the reply didn't include a Home Address, we must return
* a MISSING HOME ADDRESS error code.
*/
return (FA_MISSING_HOMEADDR);
}
return (MIP_SUCCESSFUL_REGISTRATION);
} else {
return (FA_POORLY_FORMED_REPLY);
}
}
#ifdef RADIUS_ENABLED
{
struct hash_entry *p;
char ipString[30];
int rc;
char *sessionId;
struct hash_entry *hash;
char mipSecKey[MAX_KEY_LEN];
int i;
/* ToDo: Lock our node */
#ifdef RADIUS_DEBUG
"radiusCheckUpdate: Looking up 0x%08x\n", mnAddr);
#endif
#ifdef RADIUS_DEBUG
"radiusCheckUpdate: Finished Looking up 0x%08x rc=%d\n",
#endif
if (rc) {
/*
* Since we have nothing, we need to retun null . . .
*/
return (NULL);
}
if (hexConvert((char *)mipSecKey,
return (NULL);
}
/*
* Now we create the Security Assocation
* TODO: This DOES NOT belong here. We want
* to take care of this when the SPI is
* defined.
*/
"Unable to create MobileNode SA for %d",
return (NULL);
}
/*
* And we create the Mobile Node
*/
"Unable to create MobileNodeEntry for %d",
return (NULL);
}
} else {
/*
* We have a node already, check to see if it needs an
* update
*/
currentTime) {
/* Nope, return! */
return (dest);
}
#ifdef RADIUS_DEBUG
mnAddr);
#endif
#ifdef RADIUS_DEBUG
"radiusCheckUpdate: Finished Looking up 0x%08x rc=%d\n",
#endif
if (rc) {
/*
* This is either an error, or a timeout . . .either
* way, return what we already have.
*/
return (dest);
}
/*
* TODO: We need to update the timestamp.
*/
/*
* TODO: This is broken. if the SPI is the same as what
* we already had, then update it, otherwise create
* a new Security Association Entry.
*/
}
/* Now, update the fields -- everything went well. */
#ifdef RADIUS_DEBUG
#endif
#ifdef RADIUS_DEBUG
#endif
return (dest);
} /* radiusCheckUpdate */
#endif /* RADIUS_ENABLED */
#ifdef FIREWALL_SUPPORT
/*
* Find a binding entry for the specified mnAddr and coAddr pair in
* Hash Table. If a match is found findHABE returns _B_TRUE else _B_FALSE.
*/
int
{
char addrstr1[INET_ADDRSTRLEN];
while (entry) {
break;
}
}
} else {
}
return (found);
}
#endif /* FIREWALL_SUPPORT */
/*
* Function: findPendingFAVEHashLookup
*
* Arguments: entry - Pointer to visitor entry
* p1 - First parameter to match (low 32-bit ID)
* p2 - 2nd parameter to match (whether visitor is accepted)
* p3 - 3rd parameter to match (unused)
*
* Description: This function is used as the Hash Table Helper routine
* for findPendingFAVE() when looking for pending visitor
* entries in the Hash Table, and will be called by
* findHashTableEntryUint() and findHashTableEntryString().
*
* Returns: _B_TRUE if the entry matches the desired criteria,
* otherwise _B_FALSE.
*/
/* ARGSUSED */
static boolean_t
{
return (_B_TRUE);
}
return (_B_FALSE);
}
/*
* Function: findPendingFAVE
*
* Arguments: htbl - Pointer to Hash Table
* mnAddr - Mobile Node's Home Address.
* mnNAI - Mobile Node's NAI
* IDlo - Low order 32 bit identifier used by Mobile Node
*
* Description: Find a visitor entry with faVisitorHomeAddr equal to mnAddr,
* faVisitorRegIDLow equal to IDlo and faVisitorRegIsAccepted
* equal to _B_FALSE.
*
* Note: The entry returned will be write locked.
*
* Returns: Pointer to FaVisitorEntry. NULL if function failed.
*
*/
static FaVisitorEntry *
{
if (mnAddr) {
/*
* Let's see if we can find the entry using the Home
* Address.
*/
}
/*
* Perhaps we will be able to find the visitor entry
* using the NAI.
*/
}
return (entry);
}
/*
* Function: mkPendingFAVEHashLookup
*
* Arguments: entry - Pointer to visitor entry
* p1 - First parameter to match (whether visitor is accepted)
* p2 - 2nd parameter to match (inIfindex)
* p3 - 3rd parameter to match (unused)
*
* Description: This function is used as the Hash Table Helper routine
* for mkPendingFAVE() when looking for pending visitor
* entries in the Hash Table, and will be called by
* findHashTableEntryUint() and findHashTableEntryString().
*
* Returns: _B_TRUE if the entry matches the desired criteria,
* otherwise _B_FALSE.
*/
/* ARGSUSED */
{
return (_B_TRUE);
}
return (_B_FALSE);
}
/*
* Function: mkPendingFAVE
*
* Arguments: htbl - Pointer to Hash Table
* messageHdr - Message Control Block
* localAddress - Local Interface Address
* SPI - Mobile Node's SPI
* challenge - The Challenge value found in the Reg. Request
* challengeLen - The size of the challenge.
*
* Description: Create a pending visitor entry in hash table based on
* a registration request pointed to in the message header.
* The visitor is reachable through the interface iunformation
* found in the message header, such as the localAddr and the
* request was sent from visitor's port and source address.
*
* Note that the visitor entry, upon return, will be
* write locked.
*
* Returns: if successful, the function will return a pointer to
* a visitor entry, otherwise NULL.
*
*/
static FaVisitorEntry *
{
char addrstr1[INET_ADDRSTRLEN];
/* LINTED BAD_PTR_CAST_ALIGN */
/*
* First, let's check if we already have a visitor entry for this
* mobile node. We must match incoming interface, because we may
* have an entry for a MN with overlapping private address
*/
if (requestPtr->homeAddr) {
messageHdr->inIfindex, 0);
}
}
/*
* Since we did not find a hash entry, we need to
* re-initialize p to NULL.
*/
if ((entry =
== NULL) {
"Unable to allocate FaVisitorEntry");
return (NULL);
}
NULL)) {
}
} else {
}
if (messageHdr->isSllaValid)
sizeof (struct sockaddr_dl));
else
sizeof (struct sockaddr_dl));
/*
* Save the Mobile Node's NAI
*/
if (messageHdr->mnNAI) {
} else {
entry->faVisitorMnNAI[0] = 0;
}
/*
* If necessary, save the challenge
*/
if (challengeLen) {
}
if (requestPtr->homeAddr) {
/*
* We will link the entry in the hash table using
* the home address.
*/
entry, LOCK_WRITE)) {
"Unable to add visitor entry to hash tabl");
(void) rwlock_destroy(
return (NULL);
}
mipverbose(("Adding pending visitor entry for %s.%d " \
"at pos'n %p.\n",
} else if (messageHdr->mnNAI) {
/*
* We will link the entry in the has htable using
* the NAI. Note that this is a temporary measure
* and we will update the hash table to make use
* of the home address when the reply (which includes
* the home address) is received from the Home Agent.
*/
"Unable to add visitor entry to "
"hash table (NAI)");
(void) rwlock_destroy(
return (NULL);
}
mipverbose(("Adding pending visitor entry for %.*s (%d)"
(void *)entry));
} else {
/*
* Well, we need at LEAST a home address or an NAI.
*/
"no Home Address or NAI");
return (NULL);
}
}
return (entry);
}
/*
* Function: isAcceptedVisitorHashLookup
*
* Arguments: entry - Pointer to visitor entry
* p1 - First parameter to match (interface address)
* p2 - 2nd parameter to match (whether visitor is accepted)
* p3 - 3rd parameter to match (unused)
*
* Description: This function is used as the Hash Table Helper routine
* for isAcceptedVisitor() when looking for accepted visitor
* entries in the Hash Table, and will be called by
* findHashTableEntryUint() and findHashTableEntryString().
*
* Returns: _B_TRUE if the entry matches the desired criteria,
* otherwise _B_FALSE.
*/
/* ARGSUSED */
static boolean_t
{
return (_B_TRUE);
}
return (_B_FALSE);
}
/*
* Function: isAcceptedVisitor
*
* Arguments: htbl - Pointer to hash table.
* mnAddr - Mobile Node's Home Address
* ifaceAddr - Local Interface Address.
*
* Description: Check if mnAddr has an accepted visitor entry with
* VisitorIfaceAddr equal to IfaceAddr.
*
* Returns: boolean - _B_TRUE if the entry is in the hash table.
*
*/
static boolean_t
{
if (entry) {
return (_B_TRUE);
} else {
return (_B_FALSE);
}
}
/*
* Function: delFAVE
*
* Arguments: htbl - Pointer to the Hash Table
* NAIHash - Pointer to the NAI Hash Table
* entry - Pointer to the Visitor Entry
* mnAddr - Mobile Node's Home Address
*
* Description: Delete a visitor entry matching the specified mnAddr
* and coAddr in Hash Table. If the coAddr equals mnAddr,
* all entries for that mobile node are deleted.
*
* Returns:
*/
void
{
/*
* TODO: make this efficient, e.g. we could minimize our stay
* in the loop if we figure out that COAddr != mnAddr and we
* already deleted one entry.
*/
LOCK_NONE)) {
/*
* Found a match, delete it
*/
}
} else {
/*
* Found a match, delete it
*/
}
}
}
/*
* Function: appendExt
*
* Arguments: buffer - Pointer to offset in packet where extension is to
* be added.
* type - Extension type.
* data - Extension data.
* dataLen - Length of the extension data.
*
* Description: Append an extension to a registration message contained in
* buffer. Returns total number of bytes in the extension.
*
* Returns: size of the new data added to the packet.
*/
static size_t
{
}
/*
* Function: appendMierExt
*
* Arguments: buffer - Pointer to offset in packet where extension is to
* be added.
* type - Extension type.
* subType - MIER Extension subtype
* data - Pointer to extension data
* dataLen - Length of the data
*
* Description: Appends a MIER-style extension to the registration message.
* Returns total number of bytes in the extension.
*
* Returns: size of the new data added to the packet.
*/
static size_t
{
/*
* The latest AAA Keys draft now requires that the
* key extensions be added as generalized key extensions, so the
* code needs to support the MIER-style extension header.
*/
/* LINTED BAD_PTR_CAST_ALIGN */
/*
* We simply copy the blob at the end of the MIER structure.
*/
}
#ifdef KEY_DISTRIBUTION
/*
* Although this function is not intended only for testing purposes, we need
* to ifdef it, otherwise we will see some lint warnings. When non ifdef'ed
* code uses this function, we can remove the ifdef.
*/
/*
* Function: appendCritVendorSpecExt
*
* Arguments: buffer - Pointer to offset in packet where extension is to
* be added.
* vendorId - Vendor Id
* type - Extension type.
* data - Pointer to data
* keyLen - Length of the data
*
* Description: Support for vendor specific extensions.
*
* Returns: size of the new data added to the packet.
*/
static size_t
{
/*
* Grrr. This is ugly -- we should really fix this interface
* to ensure that `buffer' is correctly aligned. In the meantime,
* at least assert() that it's true and then placate lint.
*/
/* LINTED */
/*
* Set the extension type, and the reserved field MUST be set
* to zero.
*/
/*
* Set the length, vendor ID and subType. Make sure that they
* are in network order.
*/
/*
* We simply copy the blob at the end of the MIER structure.
*/
/*
* We need to return the size of the extension
*/
}
/*
* The following defines how long a session key is valid for, and is
* only used for testing purposes.
*/
#define KDC_KEY_LIFETIME 200
/*
* Function: createMNKeyExt
*
* Arguments: buffer - Pointer to offset in packet where extension is to
* be added.
* type - Extension type.
* subType - MIER SubType
* key - Pointer to the keys.
* keyLen - Length of the keys
* nodeSPI - The SPI the Agent will share with the MN
* mnAAASPI - SPI shared between the Mobile Node and the AAA
* mnNAI - The Mobile Node's NAI, needed for encryption purposes
* mnNAILen - Length of the Mobile Node's NAI
*
* Description: This function takes a previously generated session key for
* the Mobile Node, encrypts it as defined in the AAA-Key
* Internet-Draft, and adds the MIER-style extension.
* Returns total number of bytes in the extension.
*
* Returns: size of the new data added to the packet.
*/
static size_t
{
int length = 0;
char mnKey[128];
size_t i;
/*
* Allocate a temporary buffer
*/
return (0);
}
/*
* Add the AAA SPI to the extension. This SPI is used by
* the Mobile Node in order to identify the encryption
* method.
*/
/*
* Add the node SPI, which is the SPI that the Mobile Node
* will use to reference this key
*/
/*
* Add the lifetime of the session key.
*/
/*
* Find the AAA SPI that we will use to encrypt the data
*/
if ((msap =
/*
* Create a new Security Association Entry
*/
/* remove the READ lock */
return (0);
}
/*
* Create the hash...
*/
(unsigned int) msap->mipSecKeyLen);
(unsigned int) msap->mipSecKeyLen);
/*
* XOR the key in the hash output
*/
for (i = 0; i < keyLen; i++) {
}
/*
* Copy the key and set the length
*/
/*
* Create the MIER extension
*/
/*
* Unlock the AAA Security Association
*/
} else {
"No SPI defined");
}
/*
* Free the previously allocate memory.
*/
return (length);
}
/*
* Function: createFAKeyExt
*
* Arguments: buffer - Pointer to offset in packet where extension is to
* be added.
* vendorId - Vendor Identifier
* extId - Extension type.
* key - Pointer to the keys.
* keyLen - Length of the keys
* SPI - The SPI the Agent will share with the MN
*
* Description: This function takes a previously generated session key for
* the Foreign Agent, and adds it as a Critical Vendor Specific
* extension. This is only used for testing purposes, since
* the normal method for the Foreign Agent to retrieve it's
* keys is through the DIAMETER interface.
* Returns total number of bytes in the extension.
*
* Returns: size of the new data added to the packet.
*/
static int
{
int length = 0;
/*
* Allocate a temporary buffer
*/
return (0);
}
/*
* The keys aren't encrypted, so the AAA SPI is set to zero.
*/
/*
* Add the node SPI, which is the SPI that the Mobile Node
* will use to reference this key
*/
/*
* Add the lifetime of the session key.
*/
/*
* Copy the key and set the length
*/
/*
* Create the vendor specific extension
*/
/*
* We need to create the SA locally if this is for the FA-HA SA
*/
if (extId == REG_FA_HA_KEY_EXT) {
/*
* Create a new Security Association Entry
*/
return (0);
}
}
/*
* Free the previously allocate memory.
*/
return (length);
}
#endif /* KEY_DISTRIBUTION */
/*
* Function: findFAVEHashLookup
*
* Arguments: entry - Pointer to visitor entry
* p1 - First parameter to match (interface address)
* p2 - 2nd parameter to match (whether visitor is accepted)
* p3 - 3rd parameter to match (unused)
*
* Description: This function is used as the Hash Table Helper routine
* for isAcceptedVisitor() when looking for accepted visitor
* entries in the Hash Table, and will be called by
* findHashTableEntryUint() and findHashTableEntryString().
*
* Returns: _B_TRUE if the entry matches the desired criteria,
* otherwise _B_FALSE.
*/
/* ARGSUSED */
static boolean_t
{
return (_B_TRUE);
}
return (_B_FALSE);
}
/*
* Function: findAcceptedFAVE
*
* Arguments: htbl - Pointer to the Hash Table
* mnAddr - Mobile Node's Home Address
* haAddr - Home Agent Address
*
* Description: This function will look for an accepted
* visitor entry, and will return the entry.
*
* Returns: If successful, pointer to visitor entry
*/
static FaVisitorEntry *
{
/*
* Let's see if we can find the entry using the Home
* Address. Note that an accepted visitor entry MUST have
* a home address, so we do not need to worry about looking
* using the NAI.
*/
return (entry);
}
/*
* Function: FAprocessRegRequest
*
* Arguments: messageHdr - Pointer to the Message Control Block
* entry - Pointer to the Interface Entry.
* inAddr - IP address this request received on
*
* Description: Process a registration request received at a foreign
* agent. If successful, the request will be forwarded to
* the Home Agent. If unsuccessful an error will be returned
* to the Mobile Node.
*
* Returns: void
*/
void
{
int code = MIP_SUCCESSFUL_REGISTRATION;
/* not forwarded to the Home */
/* Agent, but is sent to the */
/* AAA infrastructure instead */
/*
* Support for generalized auth extensions.
*/
char addrstr1[INET_ADDRSTRLEN];
char addrstr2[INET_ADDRSTRLEN];
char addrstr3[INET_ADDRSTRLEN];
char currentTime[MAX_TIME_STRING_SIZE];
char relativeTime[MAX_TIME_STRING_SIZE];
unsigned char *challenge;
int mnAuthExtLen;
int index;
size_t challengeLen = 0;
/* LINTED E_BAD_PTR_CAST_ALIGN */
mipverbose(("\n---- %s (%s) ----\n",
mipverbose(("FA got reg req of length %d [MN %s, HA %s, COA %s]\n",
mipverbose((" [Lifetime %d sec, ID %0#10x : %0#10x]\n",
mipverbose(("FAprocessRegRequest called with packet:\n"));
if (logVerbosity > 2)
mipverbose(("\n"));
/*
* Validate the Care of Address
*/
/*
* It is legal for the Care of Address to be set to the
* Mobile Node's address, as long as the lifetime field is
* set to zero.
*/
(requestPtr->regLifetime != 0)) {
/*
* Invalid Care of Address.
*/
return;
}
}
/*
* If the packet has any of the bits that we do not currently
* support, return an error.
*/
return;
}
/*
* Support for new MIER-style extension header.
*
* Are extensions ok and in the right order?
*/
return;
}
/*
* Packet parsing routines now return error codes.
*
* Is the packet from the Mobile Node valid?
*/
/* We support Direct Delivery Style only */
if (code != FA_DELIVERY_STYLE_UNAVAILABLE) {
/*
* We're here because there was a type 130 extension
* in the RRQ, and we don't support the encapsulated
* delivery style! However, for scalability of the
* code, we set the faRTEncapUnavailableCnt counter
* in the IsPacketFromMnValid() function. Everything
* else increaments faPoorlyFormedRequests counter.
* Note: FA_MISSING_* error codes are also considered
* as poorly formatted request.
*/
}
return;
} else if (code == MA_DROP_PACKET) {
/* drop the packet */
return;
}
/*
* We now compare the lifetime
* received in the request with the value
* configured on the interface.
*/
/* Is lifetime too long? */
(unsigned short) entry->maAdvMaxRegLifetime) {
return;
}
/* Do we offer the requested encapsulation services? (Minimal Encap) */
return;
}
/* Do we offer the requested encapsulation services? (GRE) */
return;
}
/* Did the mobile request a reverse tunnel... */
/* ...but we're not advertising it! */
/*
* Note: we could have just as easily checked
* entry->maReverseTunnelAllowed & RT_FA, but
* it seems better to check the wire!
* entry->maAdvServiceFlags will be set only if
* (entry->maReverseTunnelAllowed & RT_FA).
*/
return;
}
/*
* Is the MN is too far away?
*
* Some discussion of this is necessary...
*
* This is a link-local check. Basically, if the TTL of the
* packet isn't 255, then the potential is there that some
* [other] node is trying to get us to setup a reverse tunnel
* to the [registered MN's home] subnet (the MN is
* required by RFC2344 to set the TTL to 255).
*/
return;
}
} else if (aaaProtocol != RADIUS) {
/*
* MN didn't request a Reverse Tunnel - do we require it?
* Note: don't make the user change 2 settings to turn off
* reverse tunnels. Make sure we're advertising, then
* check if it's being required. This way a user can [re]set
* reversetunnel=no, and we wont care if reversetunnelrequired
* is set (if the fa-bit in reversetunnelrequired is set).
*/
/*
* Again, we instead could have checked
* entry->maReverseTunnelAllowed & RT_FA instead of
* the AdvServiceFlags, but it's better to check the
* the wire. entry->maAdvServiceFlags will be set
* only if (entry->maReverseTunnelAllowed & RT_FA).
*/
return;
}
}
/* Do we offer the requested compression service? */
return;
}
/*
* TODO: If the HA address specified is the same as the arriving
* interface, we MUST not forward this packet. What about
* the case when this address belongs to another interface
* on this FA, one on which HA services are being offered.
*/
"Warning: FA dropping nasty reg req with HAaddr same as COA.");
return;
}
/*
* Let's retrieve the MN-FA SPI information.
*/
/*
* If a Mobile node Foreign agent authentication extension exists
* check it.
*/
/* LINTED E_BAD_PTR_CAST_ALIGN */
if (mnAuthExtLen) {
} else {
mnSPI = 0;
}
/* Try creating a visitor list entry ... */
return;
}
requestPtr->haAddr);
/*
*
* Check the message's authentication. This function will set the
* forwardToHaFlag field. If disabled, we will silently return
* because the Registration Request is being forwarded to the
* AAA infrastructure.
*/
if (acceptedFAVE) {
}
if (code) {
/*
* Since the visitor entry isn't accepted, and an
* error occured, we can delete it. Otherwise, we
* will let the visitor entry expire naturally.
*/
} else {
}
return;
}
if (forwardToHaFlag == _B_TRUE) {
/* send the registration request to the home agent */
} else {
mipverbose(("\n---- %s (%s) ----\n",
mipverbose(("FA relayed reg req from %s.%d to AAA for %.*s\n",
mipverbose(("Registration relayed by FA is:\n"));
if (logVerbosity > 2)
mipverbose(("\n"));
}
}
{
char tmp_buf[INET_ADDRSTRLEN];
/*
* NOTE: This function is called by aaaMainThread() and always
* expects non-NULL mnNAI, as AAA expects NAI.
* But we must search by key homeaddr since acceptFAVE() converts
* the indexing from NAI to homeaddr after acceptance of the
* mobilenode registration. We have to distinguish two private
* overlapping addresses. AAA does not have any notion of incoming
* interface index in the AVPcode, thus we are matching with
* homeagent address. It is expected that the mobilenode is already
* registered.
*/
return (_B_TRUE);
}
}
mipverbose(("Couldn't find MN with homeaddr %s to close "
"session per AAA's request\n",
sizeof (tmp_buf))));
return (_B_FALSE);
}
/*
* Function: openDeviceStream
*
* Arguments: Ifacename- name of the interface (eg: hme0) to which a device
* stream is to be opened in raw mode to send M_DATA.
*
* Description: This function opens a layer 2 raw socket
* Returns: -1 on failure, fd on success
*/
int openDeviceStream(char *IfaceName) {
int fd;
int ppa;
int rval;
mipverbose(("error opening device %s in openDeviceStream\n",
IfaceName));
return (-1);
}
/* Attach. */
mipverbose(("Error attaching to device in openDeviceStream"
return (-1);
}
mipverbose(("Error in DLPI ack from device in openDeviceStream"
return (-1);
}
/* Bind. Use sap=0x0800 for IP. */
mipverbose(("Error in DLPI bind in openDeviceStream"
return (-1);
}
mipverbose(("Error in DLPI bind ack from devicee in"
" openDeviceStream with errno %d\n",
(-1)*rval));
return (-1);
}
/* Issue DLIOCRAW ioctl */
mipverbose(("error processing DLIOCRAW ioctl in"
" openDeviceStream\n"));
return (-1);
}
return (fd);
}
/*
* Function: mip_in_cksum
*
* Arguments: addr- the starting address (eg: start of IP header)
* len- number of bytes over which the checksum is to be computed.
*
* Description: This function computes the one's complement checksum.
* Returns: The one's complement checksum
*/
static ushort_t
{
int sum = 0;
/*
* Our algorithm is simple, using a 32 bit accumulator (sum),
* we add sequential 16 bit words to it, and at the end, fold
* back all the carry bits from the top 16 bits into the lower
* 16 bits.
*/
while (nleft > 1) {
sum += *w++;
nleft -= 2;
}
/* mop up an odd byte, if necessary */
if (nleft == 1) {
}
/* add back carry outs from top 16 bits to low 16 bits */
return (answer);
}
/*
* Function: mip_strioctl
*
* Arguments: fd- the file descriptor
* cmd- the ioctl cmd (eg: DLIOCRAW)
* ptr- data pointer
* ilen- length of data
* olen- lenght of returned data
*
* Description: wrapper for STREAMS I_STR ioctl
* Returns: -1 on failure, 0 on success
*/
static int
{
return (-1);
}
return (-1);
}
return (0);
}
/*
* Function: sendRawPkt
*
* Arguments: messageHdr - the message control block.
* entry - the MAAdvConfigEntry of the interface to send the
* registration reply from, and the settings to return
* pktlen - length of the Mobile IP packet (eg: sizeof (regReply))
*
* Description: This function is used when sending a reject to the MN when the
* home address of the MN is not yet assigned. In this case, the
* packet is sent to an IP level broadcast but since this maps to
* a link level broadcast (for ethernet) and we don't want this
* message to be misinterpreted by other mobiles nodes (as a
* message meant for them), a raw packet is constructed with the
* IP destination being a broadcast and the link layer destination
* being unicast (i.e the correct mobile nodes L2 addr)
* Returns: -1 on failure, 0 on success
*/
int
int fd;
struct ether_header *ethp;
int flags;
return (-1);
/* Set up the ethernet header */
/* LINTED E_BAD_PTR_CAST_ALIGN */
/* Set up the IP header */
/* LINTED E_BAD_PTR_CAST_ALIGN */
/* Set up the UDP header */
/* LINTED E_BAD_PTR_CAST_ALIGN */
/* Set up the registration reply */
flags = 0;
return (-1);
} else {
return (0);
}
}
/*
* Function: rejectFromFAToMN
*
* Arguments: messageHdr - the message control block.
* entry - the MAAdvConfigEntry of the interface to send the
* registration reply from, and the settings to return. If
* NULL, indicates there are possibly multiple mobile nodes
* to return an error to due to an ICMP error we've received
* after attempting to pass a registration request onto an HA.
* The registration reply should be returned to all mobile
* nodes with a pending entry to the home agent identified by
* the destination address of the returned IP packet inside
* messageHdr->pkt.
* code - the error value to return.
*
* Description: This function will return a registration reply set with the
* error set to code on the interface from entry back to the
* address identified as the source address of the original
* registration reqeust (except when the home address of the MN is
* not assigned as yet i.e 0.0.0.0, in which case the packet is
* to an IP level broadcast and link layer unicast (i.e MN's L2
* addr)
*/
void
{
char addrstr1[INET_ADDRSTRLEN];
char addrstr2[INET_ADDRSTRLEN];
char currentTime[MAX_TIME_STRING_SIZE];
char relativeTime[MAX_TIME_STRING_SIZE];
struct ether_addr ether;
/*
* We will send a denial. Note that we can re-use the same
* message header (and buffer) to reply.
*/
/* LINTED BAD_PTR_CAST_ALIGN */
if (code == FA_REG_LIFETIME_TOO_LONG)
/*
* Copy the identifier from the original Registration Request
* into the Registration Reply. Since the headers are different
* this requires a bcopy.
*/
/*
* TODO: handle extensions? keep in mind that the request is
* poorly formed so we may not be able to do the right thing.
*/
if (visitor_entryExists == _B_FALSE) {
/*
* If the source link layer address is valid add an ARP
* entry else don't. The entry could be invalid for variety
* of reasons (See recvNetworkPacket)
*/
if (messageHdr->isSllaValid &&
/*
* Add a temporary ARP entry to prevent the FA from
* broadcast ARPing.
*/
messageHdr->inIfindex)) < 0) {
}
}
}
/*
* If the request was sent from a mobile node whose home address is not
* yet configured i.e 0.0.0.0, then the reply should be sent as an IP
* level broadcast but with the mobile nodes link layer address as the
* destination L2 i.e link layer unicast. This can be done by opening a
* link layer raw socket, constructing the various headers and sending
* the packet (cf. RFC 3220 section 3.7.2.3)
*/
mipverbose(("\n---- %s (%s) ----\n",
mipverbose(("FA denied reg req from %s.%d for "
"MN %s [MAC: %s] (Code %d)\n",
mipverbose(("Registration denial sent by FA is:\n"));
if (logVerbosity > 2)
mipverbose(("\n"));
return;
} else {
mipverbose(("rejectFromFAtoMN: raw send failed at FA to"
" send denial.\n"));
return;
}
}
/*
* Set socket option IP_XMIT_IF to get the registration reply
* unicast to the mobile node...
*/
/* There's a problem... */
mipverbose(("Can't set IP_XMIT_IF socket option for "
"registration reply error message to mobile node %s."
"at interface index %d\n",
}
mipverbose(("\n---- %s (%s) ----\n",
mipverbose(("FA denied reg req from %s.%d for MN %s (Code %d)\n",
mipverbose(("Registration denial sent by FA is:\n"));
if (logVerbosity > 2)
mipverbose(("\n"));
} else {
mipverbose(("sendto failed at FA while sending denial.\n"));
}
/* Reset IP_XMIT_IF option */
val = 0;
/* There's a problem... */
mipverbose(("Can't unset IP_XMIT_IF socket option"
}
if (visitor_entryExists == _B_FALSE) {
INADDR_ANY)) {
/*
* Delete the temporary ARP entry
*/
messageHdr->inIfindex)) < 0) {
/*
* If the deletion failed bcos there was no
* entry then we don't need to report it
*/
"SIOCDXARP failed... %s",
}
}
}
mipverbose(("\n\n"));
}
/*
* Function: rejectFromICMPToMN
*
* Arguments: messageHdr - the message control block. Currently contains
* in messageHdr->pkt an ICMP error generated by our forward
* of a registration request to an unreachable home agent.
* haAddr - the address of the home agent that ICMP is telling us
* is unreachable.
* code - the error value to return to the mobile node.
*
* Description: This function will return a registration reply with the error
* set to code to every *pending* mobile node which has
* identified haAddr as that of it's home agent.
*/
void
{
char srcaddrstr[INET_ADDRSTRLEN];
char dstaddrstr[INET_ADDRSTRLEN];
/* LINTED E_BAD_PTR_CAST_ALIGN */
/*
* Rationale: Who do we send the registration reply to?
* ----------------------------------------------------
*
* The ICMP error is known, send the regreP, but to whom? What do we
* have? [T]Here's the rub: there's nothing of the forwarded regreQ
* returned in the ICMP! RFC792 says ICMP returns the IP header, plus
* 64 bits, or in this case just enough to cover the UDP header! We do
* have the IP dstaddr that caused the error - the IPaddr the MN says
* is it's HA. We have the interface the ICMP came in on - the dstaddr
* of the ICMP, but we don't know if the MN was using that as CoA. To
* know that we'd need to know if the MN was colocated and using us as
* "relay", but simply knowing if the 'R' bit is set on this interface
* isn't enough. The MN could have colocated, and still be registering
* with us even if we aren't setting the 'R' bit! Therefore, our IPaddr
* on this interface doesn't give us anything else to search on.
*
* Summary: all we have to go on is the identified HAaddr, and that the
* MN MUST have (a pending?) registration on this interface (note: if
* the MN is reregistering, the FA will have a non-pending entry in its
* hash, and also a[nother] *pending* entry [for many a good reason]).
*
* The only thing we can do is send a registration reply to all the
* pending MNs [on this interface] requesting service to this HA. At
* least this way bound MNs wont be effected, and those with pending
* registrations to another HA are also not effected. All those that
* are registering (pending) to this HA on this interface may then have
* to reregister, but everything should eventually get worked out. In
* practice, the number of pending registrations to a particular HA
* should be low (in context), with the notable exception of FA-reset
* causing *every* MN that was registered [with this HA] to reregister
* simultaneously. Note also, though, that if this HA is unreachable
* for one MN, it's likely unreachable for them all!
*
* One more thing to figure out:
*
* We need a buffer to send (since we presume there's at least one MN
* awaiting our response). This is the only place in the code we don't
* have a regreQ to reuse the bits of. messageHdr->pkt is here, and
* will be free()'d when screenICMPpkt() return, so if it's long
* enough, let's us it!
*
* First order thoughts:
* plus we potentially need room for the FA-MN auth (authext and hash)
* if required which is another 6 + 16 bringing the total to 42 bytes.
*
* messageHdr->pkt MUST be enough for outerIPhdr, ICMPhdr,
* innerIPhdr, + 64bits [the UDP header], which is *at least*
* 20 + 8 + 20 + 8 or 56 bytes.
*
* At this time it appears any ICMP_UNREACH message that contains a
* returned registration request (up to the end of UDP) will be big
* enough. Note: at this time challenges don't have to be appended
* when there is a registration reply indicating an error.
*
* The big question is MUST we include an NAIext in this case? RFC2794
* etc, are unclear, but to be nice to multihommed MNs there is an
* argument to be made for including it, but it would likely mean a
* realloc() of messageHdr->pkt! For now, we'll skip it.
*
* Summary: reply is going to a set of pending MN(s) due to an ICMP
* error when attempting to forward a registration request to haAddr.
* Parse the FaVisitorHash for pending MNs [registering via this
* interface] using this HAaddr.
*
* OK, we're going with it. Make sure nothing survives of the ICMP!
*/
/* init the Enumerator State */
/* enumerateAllHashTableEntries() - will return NULL when we're out. */
/* LOCK_WRITE because we may accept this entry for removal! */
int val;
/*
* Is it pending to the same HA [on the same iface]? Recall,
* the HA is the original ip_dst that wasn't reachable.
*/
/* not a MN we need to reply to */
/* don't forget to unlock this one! */
/* read on McDuff. */
continue;
}
/* This is someone to reject. */
mipverbose(("...found a MN to reply to - IP address %s.\n",
/* Accept the entry for expiration (see delFAVEPtr())! */
/* set the important information */
replyPtr->regLifetime = 0;
/*
* this. For now, let's also include the NAI if it'll fit.
*/
if ((entry->faVisitorMnNAILen) &&
sizeof (entry->faVisitorMnNAILen))) {
(unsigned char *)entry->faVisitorMnNAI,
}
/*
* Don't forget the FA-MN authenticator (if configured).
* Note appendAuthExt() assumes the authenticator is always
* going to be AUTHENTICATOR_LEN bytes! If you change
* auth.c:appendAuthExt(), change this!!!
*/
/* formulate an authenticator... */
/* remove the READ lock */
}
/*
* If the source link layer address is valid add an ARP
* entry else don't. The entry could be invalid for variety
* of reasons (See recvNetworkPacket)
*/
if (messageHdr->isSllaValid) {
/*
* Add a temporary ARP entry to prevent the FA from
* broadcast ARPing.
*/
messageHdr->inIfindex)) < 0) {
}
}
/*
* Note: we're not including a challenge! That may mean we'll
* run out of buffer, and it's also NOT required by spec.
*/
/*
* Set socket option IP_XMIT_IF to get the regreP unicast
* to the mobile node...
*/
/* There's a problem... */
"Can't set IP_XMIT_IF socket option for"
" registration reply to mobile node %s.",
}
/* may as well try anyway (we do this elsewhere) */
entry->faVisitorPort) == 0) {
mipverbose(("\n---- %s (%s) ----\n",
mipverbose(("FA sent ICMP-reply to %s.%d (Code %d)\n",
mipverbose(("FA sent ICMP-reply packet:\n"));
if (logVerbosity > 2)
messageHdr->pktLen);
mipverbose(("\n"));
} else {
"sendto failed while sending ICMP-reply.");
}
/* Reset IP_XMIT_IF option on socket */
val = 0;
"Can't unset socket option IP_XMIT_IF"
"which was set for interface index %d",
}
/* cleanup */
if (messageHdr->isSllaValid) {
/*
* Delete the temporary ARP entry
*/
messageHdr->inIfindex)) < 0) {
/*
* If the deletion failed
* because there was no entry
* entry then we don't need to
* report it.
*/
"SIOCDXARP failed %s",
}
}
}
/*
* Should we delete this FAVisitorEntry? The reason to do so
* is if there's multiple MNs to reply to, we're going to send
* another ICMP comes back from another's registration request,
* it would be sloppy (at best) to generate another set of
* registration replies. Generating multiple registration
* replies to the same MN in response to a set of registration
* requests (in this case ICMPs) may also be considered a
* literal violation of 2002-bis:
*
* A foreign agent MUST NOT transmit a Registration
* Reply except when relaying a Registration Reply
* received from a mobile node's home agent, or when
* replying to a Registration Request received from
* a mobile node in the case in which the foreign
* agent is denying service to the mobile node.
*
* The counter-argument to NOT delete this entry, is (bug?)
* delFAVEptr() doesn't do anything for pending MNs; we could
* let the timers kill off these pending FAVE entries. These
* MNs are likely to re-regreQ anyway, so there's likely some
* [performance, etc.] advantage to leaving them around.
*/
/*
* Think: should we also generate an accounting stop request
* (_B_TRUE for now)? The MN is likely going to reregister
* either with the same HA (hopefully in time-fallback), or
* another. Deleting the record is likely only going to
* create more work for us when this happens, though it's
* unclear if leaving it around may cause AAA auditing issues.
* Better to spend the time to clear it up, which comes with
* deleting this pending entry. REASON_UNKNOWN is because
* there's no accounting reason for it.
*/
/* don't forget to unlock this one! */
} /* fin looping through pending entries */
/* we're out of MNs, so we're done reacting to the ICMP */
return;
} /* rejectFromICMPToMN() */
void
{
/* LINTED E_FUNC_SET_NOT_USED */
int mnAuthExtLen = 0;
int index, challengeindex;
char addrstr1[INET_ADDRSTRLEN];
char addrstr2[INET_ADDRSTRLEN];
char addrstr3[INET_ADDRSTRLEN];
char currentTime[MAX_TIME_STRING_SIZE];
char relativeTime[MAX_TIME_STRING_SIZE];
int code;
int maAuthExtLen;
/* LINTED E_FUNC_SET_NOT_USED */
/* LINTED E_FUNC_SET_NOT_USED */
unsigned char *challenge;
size_t challengeLen = 0;
mipverbose(("forwardFromFAToHA..."));
/* LINTED E_BAD_PTR_CAST_ALIGN */
/*
* RFC3012:
*
* Valid cases: MH FAC MN-AAA
* FAC MN-AAA
* MH FAC MF
* MH
*/
/*
* Is Foreign Agent Challenge present?
*/
if (!triggeredByRadius) {
if (challengeLen == 0) {
/* LINTED E_BAD_PTR_CAST_ALIGN */
}
}
if (mnAuthExtLen == 0 || triggeredByRadius) {
/*
* Support for the generalized
* authentication extension.
*/
/* LINTED BAD_PTR_CAST_ALIGN */
/*
* Case where we have:
*
* MH FAC MF
*/
if (maAuthExtLen == 0 && challengeLen != 0) {
}
}
/*
* Support for different extension header
* format.
*
* Initialize the basic length of the message, which is
* everything up to and including the MN Authentication
* Extension (index is assumed to be set from above).
*/
/*
* Increase the packet length.
*/
/*
* Do we need to add the FA-HA Auth Extension? Let's not
* forget the entry will be locked upon the return, so
* it's our responsibility to unlock the security
* assocation entry.
*/
if ((mipSecAssocEntry =
/*
* As promised, we unlock the SA
*/
} else {
/*
* Was authentication required?
*/
if (fhAuthRequired) {
return;
}
}
/*
* We may need to install an "IPsecRequest apply ..." policy that will
* protect the registration in the way our SA tells us to, as well as
* any "IPsecReply permit ..." policy in anticipation of a response.
* Since mobile nodes can share the same HA, we may have already done
* this, so check to make sure it's not already in place.
*/
/* Policy hasn't been installed for this agent-peer */
char peerAddr[IPv4_ADDR_LEN];
/* do whatever we do to install the ipsec policy */
< 0) {
/* failed, log it */
"Could not install %s for [Address %s]: %s",
/* unlock */
/* never ignore SAs - fail */
return;
}
/* set the flag */
}
/*
* We're forwarding the registration request to the home agent.
* We need to set the reply-permit policy in anticipation of a
* registration reply from the home agent.
*/
/* This SA hasn't been installed for this agent-peer */
char peerAddr[IPv4_ADDR_LEN];
/* this is for error reporting */
/* have ipsec add it */
< 0) {
/* Failed - log it. */
"Could not install %s for [Address %s]: %s",
/* unlock */
/* Never send if we can't enforce policy. */
return;
}
/* set the flag */
}
/* we're sending, so this agent is now officially an HA peer */
/* unlock */
}
/* forward to home agent */
MIP_PORT) == 0) {
mipverbose(("\n---- %s (%s) ----\n",
mipverbose(("FA relayed reg req from %s.%d to HA "
"%s.%d for MN homeaddr %s\n",
mipverbose(("Registration of length %d relayed by " \
if (logVerbosity > 2) {
messageHdr->pktLen);
}
mipverbose(("\n"));
} else {
"registration.");
}
mipverbose(("\n\n"));
}
/*
* Function: delHABE
*
* Arguments: hamnePtr - Pointer to a pointer to a mobile node entry.
* mnAddr - Mobile Node's Home Address
* COAddr - Mobile Node's care of address.
* sessionLifeTime - Duration of the session.
*
* Description: Delete a binding entry for the specified mnAddr in Hash
* Table. If the care-of address COAddr equals mnAddr, all
* bindings for the mobile node are deleted.
*
* Note: It is necessary that the Mobile Node Entry is in a
* write locked state when we enter this function.
*
* Returns: Upon successful completion, the sessionLifeTime argument
* will contain the number of session the session was active.
*/
static void
{
char addrstr1[INET_ADDRSTRLEN];
char addrstr2[INET_ADDRSTRLEN];
*sessionLifeTime = 0;
mipverbose(("delHABE called for mnAddr %s COAddr %s\n",
while (entry) {
/* Found a match, delete it */
if (prev_entry == NULL) {
(*hamnePtr)->bindingEntries =
} else {
}
*sessionLifeTime += currentTime -
break;
}
prev_entry = entry;
}
/*
* We need to delete the Mobile Node Entry if the
* entry was dynamic and has no more bindings.
*/
if ((*hamnePtr)->haMnBindingCnt == 0 &&
mipverbose(("Deleting Mobile Node #1"));
/* Expired */
} else {
}
}
}
/*
* Function: addHABE
*
* Arguments: hamnePtr - Pointer to Mobile Node Entry
* src - Source Address of the COA
* srcPort - Source Port of the COA
* ifEntry - Pointer to the Interface Entry (optional)
* regFlags - Registration Flags
* homeAddr - Home Address
* COAddr - Care of Address
* haAddr - Home Agent's Address
* lifetime - Registration Lifetime
* existingBinding - Boolean that is set to _B_TRUE if the
* request is renewing an exiting binding
* entry.
* sessionLifeTime - If the event of a binding renewal,
* this argument will return the number
* of seconds the binding entry has
* been active.
*
* Description: Add a binding for the specified pair of mobile node
* and care-of address. By the time we get here, we know
* that we are processing a registration and coAddr is
* not the same as mnAddr. Note that entry is the the
* mobility interface on the mobile node's home network.
*
* Note that this function no longer accepts the
* registration request as a parameter, but requires
* each individual fields. This is needed in order to
* have a single function that creates bindings for both
* when a request is received off the wire, and when the
* agent attempts to restore bindings from disk.
*
* Note: The caller MUST have write locked the Mobile Node
* Entry prior to calling this function.
*
* Returns: int - 0 if the binding entry was successfully added.
* Upon successful completion, the sessionLifeTime argument
* will contain the number of session the session was
* active, and the existingBinding field will be set if the
* request is renewing an existing binding entry.
*/
/* ARGSUSED */
int
{
int val;
char addrstr1[INET_ADDRSTRLEN];
char addrstr2[INET_ADDRSTRLEN];
char addrstr3[INET_ADDRSTRLEN];
*sessionLifeTime = 0;
#ifdef NO_SIMULTANEOUS
/*
* If NO_SIMULTANEOUS is defined, we do not allow simultaneous
* bindings. This means that a Mobile Node can only have a single
* binding. The reason why this feature is not currently supported
* is due to the architecture of the new 2.8 tunnel driver. By
* clearing this flag, we ensure that all previous bindings will
* be cleared
*/
#endif
/*
* If the interface was not provided, it is because we are trying
* to restore a binding entry... Let's find it.
*/
/*
* Get the matching maIfaceAddr from mnAdvConfigTable
*/
0)) == NULL) {
"table");
return (-1);
}
}
while (hentry) {
/*
* We now compare the lifetime
* received in the request with the value
* configured on the interface.
*/
(unsigned short)
(uint32_t)
} else {
lifetime);
}
"HA renewed binding %s@%s "
"for %ld sec (Binding cnt %d).\n",
} else {
/*
* found an entry for this MN with another COA
*/
if ((regFlags & REG_SIMULTANEOUS_BINDINGS)
== 0) {
/* Found a match, delete it */
if (prev_hentry == NULL) {
} else {
prev_hentry->next =
}
continue;
}
}
}
}
if (*existingBinding == _B_TRUE)
return (0);
/*
* We did not find an entry, now we create one.
*/
if ((hentry =
return (-1);
}
/*
* We need to create a new entry ...
* update binding count for this mobile node and total bindings
*/
mipverbose(("At %s, creating tunnel for %s through %s %s\n",
}
/*
* Proxy arp only works for non-PPP interfaces.
*/
mipverbose(("Enabling tunneling for %s.\n",
mipverbose(("Setting proxy arp for %s at %s\n",
}
/*
* Solaris 2.8 automatically sends out a gratuitous ARP
* when a publishable ARP entry is created and in another
* OS, we expect arpadd to do so explicitly.
*/
}
#ifdef FIREWALL_SUPPORT
/*
* If the care-of-address is outside the protected domain then
* encapsulate and redirect those packets to the firewall's internal
* address.
* TODO: This will likely change since we should not delete the
* tunneling of a COA through FW unless *ALL* mobile nodes using that
* COA have their bindings expire, i.e. we need to keep a count of
* the number of MNs using that COA. We should be OK as long as an
* external COA is not shared by multiple mobile nodes.
*/
mipverbose(("At %s, creating tunnel for %s through firewall %s 0\n",
}
}
#endif /* FIREWALL_SUPPORT */
/*
* We now compare the lifetime received in the request with the value
* configured on the interface.
*/
} else {
}
/*
* Add the node to the queue
*/
mipverbose(("HA added binding %s@%s at entry %p "
"for %ld sec (Binding cnt %d).\n",
return (0);
}
#ifdef RADIUS_ENABLED
void
{
char addr[20];
#ifdef RADIUS_DEBUG
#endif
#ifdef RADIUS_DEBUG
#endif
} /* radiusCloseSession */
#endif /* RADIUS_ENABLED */
/*
* Function: HAdispatchRadius
*
* Arguments: messageHdr - Pointer to the Message Control Block
* entry - Pointer to the Interface Entry.
* inAddr - IP address this request received on
*
* Description: The HA continues with the processing of the
* registration request after the Radius client
* responded with an ANSWER to the Open Session
* request.
*
* Returns:
*/
/* ARGSUSED */
void
{
int code = 0;
/* If Auth failure from checking radius Answer (e.g., AVP's wrong) */
}
if (code == 0) {
/* Assume no hamnePtr - no MobileNodeEntry (mnEntry) so far */
&faSPI);
}
}
/*
* Function: HAprocessRegRequest
*
* Arguments: messageHdr - Pointer to the Message Control Block
* entry - Pointer to the Interface Entry.
* inAddr - IP address this request received on
*
* Description: Process a registration request received at a home
* agent, and return the registration reply to the
* foreign agent.
*
* If the Mobile Node was not configured locally,
* and the Mobile Node node was successfully
* authenticated (either by using the default SPI,
* or VIA the AAA infrastructure), we will dynamically
* create a Mobile Node Entry.
*
* If the Mobile Node did not specify a Home Address,
* by including an NAI in the request and setting the
* home address to 0, we will allocate a Home Address
* out of an address pool (if configured). If the NAI
* was defined in the local configuration file, we will
* use the pool defined in the user's profile, otherwise
* we will use the default pool.
*
* If successful and this is a request for a new binding,
* we will setup the tunnel.
*
* records to the AAA.
*
* Returns:
*/
/* ARGSUSED */
void
{
int code = MIP_SUCCESSFUL_REGISTRATION;
char addrstr1[INET_ADDRSTRLEN];
char addrstr2[INET_ADDRSTRLEN];
char addrstr3[INET_ADDRSTRLEN];
char currentTime[MAX_TIME_STRING_SIZE];
char relativeTime[MAX_TIME_STRING_SIZE];
/* LINTED BAD_PTR_CAST_ALIGN */
mipverbose(("\n---- %s (%s) ----\n",
mipverbose(("HA got reg req [MN %s, HA %s, COA %s]\n",
mipverbose((" [Lifetime %d sec, ID %0#10x : %0#10x]\n",
mipverbose(("HAprocessRegRequest called for pkt:\n"));
if (logVerbosity > 2)
mipverbose(("\n"));
/*
* If we are not the home agent, then reject this request.
*/
_B_FALSE);
return;
}
/*
* If the packet has the unused bit set, or if the home address
* is set to the care of address AND the lifetime is not set to
* zero, this packet is bad. The addresses can be the same when
* the Mobile Node sends an explicit deregistration, which is does
* when it enters its home network.
*/
(requestPtr->regLifetime != 0))) {
_B_FALSE);
return;
}
/*
* Checking for an invalid packet, where the Home Agent's Address
* and the Care of Address are set to the same value, AND the lifetime
* is set to a non-zero address.
*/
(requestPtr->regLifetime != 0)) {
_B_FALSE);
return;
}
/*
* Support for new MIER-style extension header.
*
* Are extensions ok and in the right order?
*/
return;
}
/*
* Is the packet from Care-of address (FA or colocated MN) valid?
*/
0, _B_FALSE);
return;
} else if (code == MA_DROP_PACKET) {
/* drop the packet */
return;
}
/*
* Check the message's authentication. Note that this
* function will return the Mobile Node Entry in a write
* locked state. Therefore, we need to unlock the node
* when we are done with it.
*/
if (code == HA_MN_AUTH_FAILURE) {
_B_FALSE);
return;
}
if (aaaProtocol != RADIUS) {
faSPI);
}
}
/*
* Function: HAprocessRegRequestContinue
*
* Arguments: messageHdr - Pointer to the Message Control Block
* entry - Pointer to the Interface Entry.
* inAddr - IP address this request received on
* code - result code from HAprocessRegRequest().
* mnEntry - Mobile Node Entry
* mnSPI - Mobile Node SPI
* faSPI - FA SPI
*
* Description: Continue to Process a registration request received
* at a home agent, and return the registration reply
* to the foreign agent.
* If aaaProtocol is Radius, this function is called
* after the Radius client returns auth Answer.
*
* Otherwise, if not using Radius, just continue on from
* the HAprocessRegRequest() function until reg reply is
* sent.
*
* If the Mobile Node was not configured locally,
* and the Mobile Node node was successfully
* authenticated (either by using the default SPI,
* or VIA the AAA infrastructure), we will dynamically
* create a Mobile Node Entry.
*
* If the Mobile Node did not specify a Home Address,
* by including an NAI in the request and setting the
* home address to 0, we will allocate a Home Address
* out of an address pool (if configured). If the NAI
* was defined in the local configuration file, we will
* use the pool defined in the user's profile, otherwise
* we will use the default pool.
*
* If successful and this is a request for a new binding,
* we will setup the tunnel.
*
* records to the AAA.
*
* Returns:
*/
/* ARGSUSED */
static void
{
uint32_t sessionLifeTime = 0;
char addrstr1[INET_ADDRSTRLEN];
/* LINTED BAD_PTR_CAST_ALIGN */
if (code) {
goto reply;
}
/*
* If we do not have a Mobile Node entry, let's see if
* we can create one.
*/
if (requestPtr->regLifetime == 0) {
/*
* A Mobile Node entry is needed for deregistration
* purposes. Let's silently discard this one.
*/
"unknown Mobile Node");
return;
}
/*
* Is the Mobile Node requesting an IP Address?
*/
"from address pool %d",
goto reply;
}
}
/*
* So it's one of those special cases where we need
* to create the Mobile Node Entry dynamically. Please
* note that the Mobile Node Entry will be write locked
* upon return.
*/
mipverbose(("Created a dynamic Mobile Node Entry with SPI %d\n",
mnSPI));
/*
* We've got some bigger fish to fry...
*/
goto reply;
}
} else {
/*
* Is the Mobile Node requesting an IP Address?
*/
if (mnEntry->haPoolIdentifier &&
/*
* If we've already allocated an address, and
* the Mobile Node is still requesting one, let's
* free what we already have.
*/
} else {
"address from address "
"pool %d",
goto reply;
}
/*
* Save the allocated address
*/
}
}
}
/*
* Was HA a broadcast address?
*/
goto reply;
}
/*
* Check if the number of active bindings exceeds the
* maximum allowed.
*/
goto reply;
}
/*
* Get the Mobile Node's SA, remember that the entry
* returned will be read locked, so we need to unlock the
* entry when we are done.
*/
goto reply;
}
/*
* Check ID used for replay protection
*/
goto reply;
}
if (requestPtr->regLifetime == 0) {
/* Do Radius Close Session */
#ifdef RADIUS_ENABLED
if (radiusEnabled)
#endif /* RADIUS_ENABLED */
} else {
/*
* We need to make sure we're allowing reverse tunneling. The
* tunnel is bi-directional by default, but we need to make
* sure it's OK to set it up!
*/
/* MNs requesting, are we allowing? */
/*
* Note: we do NOT check ADV_REVERSE_TUNNEL
* because that's what we're advertising,
* which is FA-centric. ReverseTunnelAllowed
* is specifically designed to distinguish
* between HA allowing but FA isn't (and so
* reverseTunnel may not be being advertised).
*/
goto reply;
} /* OK to proceed with the usual tunnel setup... */
} else if (aaaProtocol != RADIUS) {
/*
* MNs not requesting, are we requiring!
* Note: don't check the advertisement bit here!
*/
} /* OK to proceed with the usual tunnel setup... */
}
&sessionLifeTime) < 0) {
goto reply;
}
}
#ifdef NO_SIMULTANEOUS
/*
* If simultaneous bindings was requested, set the appropriate
* acceptance code.
*/
}
#endif
}
static void
{
unsigned char *challenge;
unsigned char challengeBuffer[ADV_MAX_CHALLENGE_LENGTH];
size_t challengeLen = 0;
int index;
char NAIBuffer[ADV_MAX_NAI_LENGTH];
int repLen;
#ifdef FIREWALL_SUPPORT
#endif /* FIREWALL_SUPPORT */
char currentTime[MAX_TIME_STRING_SIZE];
char relativeTime[MAX_TIME_STRING_SIZE];
char addrstr1[INET_ADDRSTRLEN];
char addrstr2[INET_ADDRSTRLEN];
int val;
int rc;
int result;
mipverbose(("top of HABuildRegReply...\n"));
/* LINTED BAD_PTR_CAST_ALIGN */
/*
* Retrieve the Challenge
*/
/*
* Copy the challenge into a buffer so that we can manipulate it
* later...
*/
if (challengeLen > 0) {
if (challengeLen > ADV_MAX_CHALLENGE_LENGTH) {
"supported length");
} else {
}
}
/*
* For now, we'll create the new packet in place. But not before we
* save some of the fields that could get overwritten.
*/
#ifdef FIREWALL_SUPPORT
#endif
/*
* If we have an NAI, save it.
*/
if (messageHdr->mnNAILen) {
}
/* LINTED BAD_PTR_CAST_ALIGN */
} else {
}
if (code) {
} else {
}
}
/*
* The MN-HA MUST follow the MN-AAA Session Keys
*/
if (mnsae) {
/*
* Release the lock on the security association in order
* to eliminate a potential deadlock situation.
*/
}
if (messageHdr->mnNAILen) {
REG_MN_NAI_EXT_TYPE, (unsigned char *) NAIBuffer,
}
/*
* mnEntry is assumed to be set in some of the statements below.
* It is not set whenever authentication has failed.
*/
if (mnEntry) {
#ifdef KEY_DISTRIBUTION
messageHdr->mnHaKeyLen) ||
if (aaaProtocol == AAA_NONE) {
/*
* Support for the Generalized Key extension.
*
* We have some keying information to send to the Mobile
* Node from the AAA Server.
*/
} else {
#else /* KEY_DISTRIBUTION */
#endif /* KEY_DISTRIBUTION */
/*
* We received some keying information from DIAMETER,
* and we need to send this to the mobile node.
* Support for the Generalized Key extension.
*/
#ifdef KEY_DISTRIBUTION
}
#endif /* KEY_DISTRIBUTION */
}
#ifdef KEY_DISTRIBUTION
messageHdr->mnFaKeyLen) ||
if (aaaProtocol == AAA_NONE) {
/*
* Support for the Generalized Key extension.
*
* We have some keying information to send to the Mobile
* Node from the AAA Server.
*/
} else {
#else /* KEY_DISTRIBUTION */
#endif /* KEY_DISTRIBUTION */
/*
* We received some keying information from DIAMETER,
* and we need to send this to the mobile node.
* Support for the Generalized Key extension.
*/
#ifdef KEY_DISTRIBUTION
}
#endif /* KEY_DISTRIBUTION */
}
/*
* The MN-HA MUST follow the MN-AAA Session Keys
*/
if ((mnsae =
}
} /* Matches if (mnEntry) above */
/*
* If a challenge was present, it MUST be added after the MN-HA
* and prior to the MN-FA.
*/
if (challengeLen > 0) {
}
#ifdef KEY_DISTRIBUTION
if (messageHdr->mnFaKeyLen &&
/*
* Support for the Generalized Key extension.
*
* We have some keying information to send to the Mobile
* Node from the AAA Server.
*/
repLen +=
repLen +=
}
#endif /* KEY_DISTRIBUTION */
if (faSPI) {
/*
* Now we get the Foreign Agent's Security Association,
* which will be read locked upon return.
*/
if ((mipSecAssocEntry =
"defined", faSPI);
} else {
/*
* And now we must unlock the entry.
*/
}
} else {
if (fhAuthRequired) {
faSPI);
}
}
/*
* First assume nothing special is needed to ensure that unsuccessful
* registrations reach the mobile node.
*/
#ifdef FIREWALL_SUPPORT
#endif /* FIREWALL_SUPPORT */
/* Is this really the case? */
/*
* For "deregister all" requests, ignore the tunnel to
* ensure unsuccessful registrations are sent on the
* local (home) network.
*/
if ((replyPtr->regLifetime == 0) &&
#ifdef RADIUS_ENABLED
/* Do Radius Close Session */
if (radiusEnabled)
#endif /* RADIUS_ENABLED */
}
#ifdef FIREWALL_SUPPORT
/*
* If MN is using an external COA and there isn't a tunnel
* to FW already, create one temporarily.
*/
}
#endif /* FIREWALL_SUPPORT */
/*
* Do we have an assigned Home Address that we need
* to free?
*/
"from pool %d",
}
}
}
#ifdef FIREWALL_SUPPORT
/*
* If needed, set up temporary tunnel to redirect packets for
* external COAs at FW.
* TODO: Note that this works only when the destination of the
* registration request is the COAddr. This is the case
* for an MN operating in colocated state so we are fine
* for now.
*/
if (encapToFw) {
mipverbose(("At %s, creating a temporary tunnel for %s through "
tFlags & REG_REVERSE_TUNNEL)) < 0) {
}
}
#endif /* FIREWALL_SUPPORT */
/* If needed, ignore existing tunnel for MN to COA */
if (ignoreTunnel) {
/* make sure response will be sent locally */
mipverbose(("Temporarily deleting ARP entry for %s\n",
}
mipverbose(("Temporarily suspending tunneling for %s\n",
}
/* If the packet was from AAA, send it back there. */
} else {
/*
* AAA isn't in charge - use IPsec SA's we're configured with.
*/
/*
* Is there an IPSEC_REPLY_APPLY policy
* configured that isn't already?
*/
/* pass it down */
char peerAddr[IPv4_ADDR_LEN];
if (installIPsecPolicy(
/* problems writing the policy */
"for [Address %s]: %s",
/* unlock */
/* don't send a regreP in the clear! */
return;
}
/* set the flag */
}
/*
* We're sending a reply, *now* this is an FA-peer.
* We didn't do this when setting IPsecRequest permit
* because there isn't a binding to this guy at init
* (recall, as HA we have to be laying-in-wait for
* registration requests from FAs we have an SA with).
*/
/* unlock */
}
}
if (rc == 0) {
mipverbose(("\n---- %s (%s) ----\n",
mipverbose(("HA sent reg reply to %s.%d (Code %d)\n",
" "
"[Lifetime %d sec, ID %0#10x : %0#10x]\n",
if (logVerbosity > 2) {
mipverbose(("HA's reply is:\n"));
repLen);
mipverbose(("\n"));
}
if (replyPtr->regLifetime != 0)
else
} else {
}
/*
* Undo any temporary changes related to "deregistration all"
* messages.
* Proxy arp works only for non-PPP interfaces.
*/
/* restore prior state */
mipverbose(("Re-enabling tunneling for %s\n",
mipverbose(("Restoring proxy ARP for %s at %s\n",
}
}
/*
* If we successfully deregistered all bindings for a MN
* we MUST also send out a gratuitous ARP with the MN's correct
* mapping taken from our ARP cache.
*/
/*
* A successful request, we must generate the
* appropriate accounting record.
*/
if (replyPtr->regLifetime == 0) {
(mnEntry->haMnBindingCnt == 0)) {
"arprefresh failed ... %s",
}
if (aaaProtocol != AAA_NONE) {
/*
* An accounting stop record must be sent.
*/
(unsigned char *)NAIBuffer,
if (result) {
"send accounting "
"stop record");
}
}
} else {
/*
* Is this a new session, or an existing one?
*/
if (aaaProtocol != AAA_NONE) {
if (existingBindings == _B_TRUE) {
/*
* An interim accounting
* record must be sent.
*/
result =
(unsigned char *)
sessionLifeTime, 0);
if (result) {
/*
* PRC: Here we must disconnect
* the mobile node since we can
* not account for services
* rendered.
*/
"Unable to send "
"accounting interim "
"record");
if (mnEntry) {
}
}
} else {
/*
* An accounting start record must
* be sent.
*/
result =
(unsigned char *)NAIBuffer,
if (result) {
/*
* PRC: Here we must disconnect
* the mobile node since we can
* not account for services
* rendered.
*/
"Unable to send "
"accounting start "
"record");
if (mnEntry) {
}
}
}
}
}
} else if (aaaProtocol != AAA_NONE) {
/*
* An accounting stop record must be sent to log the
* failed request.
*/
(unsigned char *)NAIBuffer,
if (result) {
}
}
/*
* If we've made it this far, if we have a mobile node
* entry, we need to unlock it.
*/
if (mnEntry) {
}
mipverbose(("\n\n"));
}
/*
* Function: acceptFAVEHashLookup
*
* Arguments: entry - Pointer to visitor entry
* p1 - First parameter to match (interface address)
* p2 - 2nd parameter to match (whether visitor is accepted)
* p3 - 3rd parameter to match (homeagentaddr)
*
* Description: This function is used as the Hash Table Helper routine
* for isAcceptedVisitor() when looking for accepted visitor
* entries in the Hash Table, and will be called by
* findHashTableEntryUint() and findHashTableEntryString().
*
* Returns: _B_TRUE if the entry matches the desired criteria,
* otherwise _B_FALSE.
*/
/* ARGSUSED */
static boolean_t
{
return (_B_TRUE);
}
return (_B_FALSE);
}
/*
* Function: acceptFAVE
*
* Arguments: htbl - Pointer to the Hash Table
* replyPtr - Pointer to the registration reply
* favep - Pointer to a pointer to a visitor entry
*
* Description: If we find an ACCEPTED visitor entry for this MN-COA
* pair, update that entry and delete the pending entry.
* Otherwise, change the "pending" entry pointed to by
* favep to "accepted" with specified lifetime.
*
* If accepted, we will add a host specific route to be
* able to forward packets to the Mobile Node and we
* will create a tunnel interface for the Home Agent.
*
* NOTE: COA is available in the faVisitorCOAddr field.
*
* Returns:
*/
static void
{
int val;
int in_Ifindex = 0;
int out_Ifindex = 0;
int tun_num;
char addrstr1[INET_ADDRSTRLEN];
char addrstr2[INET_ADDRSTRLEN];
/*
* Let's see if we can find the entry using the Home
* Address. Note that an accepted visitor entry MUST have
* a home address, so we do not need to worry about looking
* using the NAI.
*/
if (entry) {
/*
* We've found a Visitor Entry already accepted in the
* Hash Table. We will update the old entry, and delete
* this new entry (since we only need one).
*/
mipverbose(("FA renewed visitor %s on iface %s (%d sec).\n",
lifetime));
sizeof (struct sockaddr_dl));
&(*favep)->faVisitorChallengeAdv,
/*
* Unlocking the entry here could cause deadlock.
* (void) rw_unlock(&entry->faVisitorNodeLock);
*/
/*
* Found a match, delete it
*/
}
/*
* Return the pointer to the old entry.
*/
return;
}
/*
* OK, we did not find an existing entry. If this entry was
* found using the NAI, we need to update the hash table to
* use the Mobile Node's Home Address instead.
*/
(*favep)->faVisitorHomeAddr == 0) {
/*
* If our Visitor Entry has been hashed using the Mobile Node's
* NAI, we want to change it so we can hash it using the Home
* Address. From now on we will be using the Home Agent to
* find the Visitor Entry.
*
* This *was* computing strlen(fanai) +1, which added space
* for the null. Since it was not up to spec, and would not
* interoperate with other vendors, it was removed.
*/
mipverbose(("Could not find our visitor entry in the " \
"hash table\n"));
return;
}
/*
* Update the visitor entry with the Mobile Node's
* Home Address, and add it to the Hash Table.
*/
mipverbose(("Moved pending visitor entry for %.*s to %s " \
"at pos'n %p.\n",
}
/*
* We did not find an existing ACCEPTED entry.
*/
(*favep)->faVisitorTimeExpires =
mipverbose(("FA accepted visitor %s on iface %s (expires %ld).\n",
(*favep)->faVisitorTimeExpires));
/*
* If the source link layer address is valid add an ARP
* entry else don't. The entry could be invalid for variety
* of reasons (See recvNetworkPacket)
*/
if ((*favep)->faVisitorIsSllaValid) {
/*
* Add an ARP entry to prevent the FA from broadcast ARPing
*/
(*favep)->faVisitorInIfindex)) < 0) {
}
}
mipverbose(("Enabling decapsulation of inner pkts sent to %s\n",
(*favep)->faVisitorCOAddr)) < 0) {
/*
* The following reply code is a close approximation of why
* things might have failed. The main purpose is to let the
* MN know.
*/
return;
}
(*favep)->faVisitorCOAddr);
if (tun_num < 0) {
/*
* The following reply code is a close approximation of why
* things might have failed. The main purpose is to let the MN
* know.
*/
return;
}
if (in_Ifindex == 0) {
/* if_nametoindex fails... */
/*
* The following reply code is a close approximation of why
* things might have failed. The main purpose is to let the MN
* know.
*/
return;
}
/*
* Create forward route to MN and specify that only
* packets from in_Ifindex will be forwarded to MN.
*/
mipverbose(("Adding direct, local route for visitor %s through %s.\n",
(*favep)->faVisitorInIfindex)) < 0) {
"for visitor %s from interface index %d",
/*
* The following reply code is a close approximation of why
* things might have failed. The main purpose is to let the MN
* know.
*/
return;
}
/*
* If 'T' bit is set, create reverse tunnel route in the MIPRTUN
* table. In this routing table the routing selection is based
* on visitor's homeaddr and it's incoming interface index.
* Outgoing interface index provided in the routeadd function
* determines reverse tunnel to visitor's home-agent.
*/
/* Do we apply an IPsec policy for the reverse tunnel? */
!= NULL) {
/* is there something we shoud set that isn't? */
/*
* forward and reverse tunnels share a policy
* (socket), so we can't support asymmetric
* tunnel policies until ipsec supports
* multiple socket policies! If we install a
* global reverse tunnel policy, it will get
* processed before we pass it through our
* route table, which will indicate it's to go
* into the tunnel, but then it'll get dropped
* by the forward tunnel policy (presuming it's
* a different policy). Just set the reverse
* bit flag to indicate what's being applied.
*/
mae->maIPsecFlags |=
/* unlock */
}
/* Add reverse tunnel route for MIPRTUN table */
mipverbose(("Adding reverse tunnel route for visitor %s at"
"interface index %d to tunnel index %d\n",
(*favep)->faVisitorHomeAddr,
(*favep)->faVisitorInIfindex,
out_Ifindex)) < 0) {
" for visitor %s from interface index %d to %d",
/*
* The following reply code is a close approximation
* of why things might have failed. The main purpose
* is to let the MN know.
*/
}
}
}
/*
* Function: FAprocessRegReply
*
* Arguments: messageHdr - Pointer to the Message Control Block
* entry - Pointer to the Interface Entry.
*
* Description: Process a registration reply received at a foreign
* agent, and forward the reply to the Mobile Node.
*
* If AAA was enabled, we will issue accounting
* records to the AAA.
*
* Returns:
*/
void
{
int code = MIP_SUCCESSFUL_REGISTRATION;
int val;
int index;
int result;
/* LINTED E_FUNC_SET_NOT_USED */
int mnAuthExtLen;
uint32_t sessionLifeTime = 0;
char addrstr1[INET_ADDRSTRLEN];
char addrstr2[INET_ADDRSTRLEN];
char currentTime[MAX_TIME_STRING_SIZE];
char relativeTime[MAX_TIME_STRING_SIZE];
char NAIBuffer[ADV_MAX_NAI_LENGTH];
struct ether_addr ether;
/* LINTED BAD_PTR_CAST_ALIGN */
mipverbose(("\n---- %s (%s) ----\n",
mipverbose(("FA got reg reply [MN %s, HA %s, Code %d]\n",
mipverbose((" [Lifetime %d sec, ID %0#10x : %0#10x]\n",
mipverbose(("FAprocessRegReply called for pkt:\n"));
if (logVerbosity > 2)
mipverbose(("\n"));
/*
* Support for new MIER-style extension header.
*
* Are extensions ok and in the right order?
*/
mipverbose(("FAprocessRegReply: poorly formed reply\n"));
/*
* We no longer return here, instead we
* continue, and we will end up returning a failed
* reply to the mobile node.
*/
}
/*
* Packet parsing routines now return error codes.
*
* Is the packet from the Home Agent valid?
*/
/*
* We no longer return here, instead we
* continue, and we will end up returning a failed
* reply to the mobile node.
*/
} else if (code == MA_DROP_PACKET) {
/* drop the packet */
return;
}
/*
* Now we retrieve the pending Visitor Entry. Note that the
* entry will be write locked upon return, and it is our
* responsibility to unlock it before we return.
*/
/* we wouldn't likewise find a matching ipsec SA anyway. */
return;
}
/*
* If the code is set to poor request, we will
* return a failed reply to the mobile node
*/
if (code == FA_POORLY_FORMED_REQUEST) {
goto reply;
}
/*
* If we have an NAI, save it.
*/
if (messageHdr->mnNAILen) {
}
/*
* Check the message's authentication
*/
if (code) {
goto reply;
}
/* ... it is a good reply. No need to change the code in pkt. */
/*
* TODO: Remove everything after the MN-HA auth ext, add any new
* ones and relay the request. For now, we simply strip everything
* beyond the MN-HA auth.
*/
/* LINTED E_BAD_PTR_CAST_ALIGN */
if (mnAuthExtLen) {
/*
* If any extensions appear following the Mobile-Node
* Home Agent Extension, let's remove them.
*/
}
/*
* Foreign Agent MAY include a new challenge value in the registration
* reply, protected by the MN-FA authentication extension (if present).
* In our case, if challenge is present, we will always add a new
* challenge to the reply.
*/
if (faChallengeAdv == _B_TRUE) {
/*
* Generate the challenge value.
*/
challengeBuffer[0] = getRandomValue();
(unsigned char *)&challengeBuffer, ADV_CHALLENGE_LENGTH);
}
/*
* Get our visitor's Security Association, but keep in mind
* that the node will be locked upon return.
*/
if ((mipSecAssocEntry =
/*
* TODO: Is this extension required?
*/
if (mfAuthRequired) {
"Error: no SA in Visitor Entry");
goto reply;
}
} else {
/*
* We need to unlock the node
*/
}
/*
* Check the result code in the messageHdr. If it is
* non zero, and the registrationRequest result is zero,
* then set the registration request's code to the code
* in the header.
*/
aaaProtocol != AAA_NONE &&
messageHdr->aaaResultCode != 0 &&
}
/* Check for HA returning duplicate homeaddr */
if ((acceptedFAVE != NULL) &&
/*
* Compare to see that homeaddr and NAI
* match and it's not due to some problem
* with misbehaving HA assigning duplicate addr
*/
(const char *)favePtr->faVisitorMnNAI,
if (code == 0) {
/* Set to reason unspecified */
}
}
}
if (acceptedFAVE != NULL)
/* Check for assigned homeaddr validity */
if (code == 0) {
/* Set to reason unspecified */
}
}
/* Do we need to overwrite the code field? */
if (code)
/*
* We need to accept the pending entry before sending the reply
* to the MN. The reason being: if the acceptance fails (due
* to lack of resources for example) then we need to indicate
* this to the MN with the appropriate code set in the reply
*/
(replyPtr->regLifetime != 0)) {
/*
* Delete prior accepted entries for this MN and
* COA pair and make the "pending" entry "accepted".
* The COA is available in the faVisitorCOAddr
* field of favePtr.
*/
}
/*
* TODO: Handle extensions properly. For now, we include no
* extensions in denials and therefore don't need to change
* newLen.
*/
if (visitor_entryExists == _B_FALSE) {
/*
* If the source link layer address is valid add an ARP
* entry else don't. The entry could be invalid for variety
* of reasons (See recvNetworkPacket)
*/
if (favePtr->faVisitorIsSllaValid &&
/*
* Add a temporary ARP entry to prevent the FA from
* broadcast ARPing. This entry is deleted when the
* MN is removed from the visitors list. Note, the entry
* is marked permanent so the FA does not have worry
* about ARP blowing the entry away when it refreshes
* it's cache.
*/
favePtr->faVisitorInIfindex)) < 0) {
}
}
}
/*
* If the request was sent from a mobile node whose home address is not
* yet configured i.e 0.0.0.0, then the reply should be sent as an IP
* level broadcast but with the mobile nodes link layer address as the
* destination L2 i.e link layer unicast. This can be done by opening a
* link layer raw socket, constructing the various headers and sending
* the packet (cf. RFC 3220 section 3.7.2.3)
*/
mipverbose(("\n---- %s (%s) ----\n",
mipverbose(("FA relayed reg reply to "
"255.255.255.255.%d for MN 0.0.0.0 "
"[MAC: %s] (Code %d)\n",
ether_ntoa(ðer),
mipverbose(("FA relayed reply packet:\n"));
if (logVerbosity > 2)
messageHdr->pktLen);
mipverbose(("\n"));
return;
} else {
mipverbose(("FAprocessRegReply: raw send failed at FA"
" to relay reply.\n"));
return;
}
}
/*
* Set socket option IP_XMIT_IF to get the registration reply
* unicast to the mobile node...
*/
/* There's a problem... */
"registration reply to mobile node %s.",
}
favePtr->faVisitorPort) == 0) {
mipverbose(("\n---- %s (%s) ----\n",
mipverbose(("FA relayed reg reply to %s.%d (Code %d)\n",
mipverbose(("FA relayed reply packet:\n"));
if (logVerbosity > 2)
mipverbose(("\n"));
} else {
}
/* Reset IP_XMIT_IF option on socket */
val = 0;
"which was set for interface index %d",
}
if (visitor_entryExists == _B_FALSE) {
if (favePtr->faVisitorIsSllaValid) {
/*
* Delete the temporary ARP entry
*/
favePtr->faVisitorInIfindex)) < 0) {
/*
* If the deletion failed bcos there was no
* entry then we don't need to report it
*/
"SIOCDXARP failed... %s",
}
}
}
}
if (replyPtr->regLifetime == 0) {
/*
* Deregistration ... delete visitor entries for
* this MN
*/
if (aaaProtocol != AAA_NONE) {
/*
* An accounting stop record must be sent.
*/
(unsigned char *)NAIBuffer,
if (result) {
"stop record");
}
}
} else {
if (visitor_entryExists == _B_FALSE &&
aaaProtocol != AAA_NONE) {
/*
* An accounting start record must be sent.
*/
(unsigned char *)NAIBuffer,
if (result) {
/*
* PRC: Here we must disconnect the
* mobile node since we cannot bill
* for services rendered, but I am
* not sure how this can be done.
*/
"Unable to send accounting "
"start record");
}
} else if (aaaProtocol != AAA_NONE) {
/*
* An accounting start record must be sent.
*/
result =
(unsigned char *)NAIBuffer,
(favePtr) ?
favePtr->faVisitorCOAddr : 0,
((favePtr) ?
0), 0);
if (result) {
/*
* PRC: Here we must disconnect the
* mobile node since we cannot bill
* for services rendered, but I am
* not sure how this can be done.
*/
"accounting interim record");
}
}
}
} else {
/*
* For denials, simply delete pending entry unless it
* corresponds to an HA discovery request; In that case
* let the periodic timer delete the request.
* TODO: It is better to look at the HA field in the
* request but since we don't have the MN's home
* netmask, we rely on the returned code.
*/
/*
* Found a match, delete it
*/
(void) rwlock_destroy(
}
if (aaaProtocol != AAA_NONE) {
/*
* An accounting stop record must be sent
* to log a failed request.
*/
(unsigned char *)NAIBuffer,
if (result) {
"stop record");
}
}
}
}
if (favePtr) {
}
mipverbose(("\n\n"));
}
#ifdef RADIUS_ENABLED
void
{
void *handle;
int result;
/*
* Open the dynamic library
*/
"Unable to open dynamic library %s (%s)\n",
radiusEnabled = 0;
return;
}
/*
* Setup our function pointers.
*/
if (radInitializeApi == NULL) {
"Unable to resolve initialization function %s (%s)\n",
radiusEnabled = 0;
return;
}
"LookupData");
if (radLookupData == NULL) {
"Unable to resolve lookup function %s (%s)\n",
radiusEnabled = 0;
return;
}
"CloseSession");
if (radLookupData == NULL) {
radiusEnabled = 0;
return;
}
/*
* Call the module's initialization function.
*/
result = radInitializeApi();
if (result) {
radiusEnabled = 0;
return;
}
} /* loadRadiusLibrary */
#endif /* RADIUS_ENABLED */
/*
* Function: formIPsecBits(int type, char *nodeID, char *ipsecPolicy_p,
* char *Filename)
*
* Arguments: type - type of IPsec SA we want to install.
* nodeID - nodeID this policy is for (dotted ipAddr).
* ipsecPolicy_p - a pointer to the policy string. The format's
* identical to ipsec's "<action> {properties}"
* as set, and parsed, in mipagent.conf.
* ipsecPolicy - the storage for the FULL policy, that is
* "{<pattern>} action {<properties>}".
* ipsecPolicySize - size of the ipsecPolicy buffer
* Description: This function builds the complete IPsec Policy for install and
* remove functions to ensure consistency between them.
* Note: this is the current functional solution until IPsec
* supports multiple per-socket policies, or provides an API.
*
* Returns: -1 if bad pointers were passed, or if their was some other
* problem building things. 0 on success, in which case
* ipsecPolicy is presumed to contain a good ipsec policy.
*
* Note: this function will be unnecessary when ipsec has an API.
*/
int
{
/* a quick sanity check */
(ipsecPolicy == NULL))
/* caller's confused */
return (-1);
/* build the complete ipSec policy */
switch (type) {
case IPSEC_REQUEST_APPLY:
/* IPsec Policy - FA apply policy for sending regreQ */
"{daddr %s ulp udp dport %d} %s\n",
break;
case IPSEC_REQUEST_PERMIT:
/* IPsec Policy - HA permit policy for receiving regreQ */
"{saddr %s ulp udp dport %d} %s\n",
break;
case IPSEC_REPLY_APPLY:
/* IPsec Policy - HA apply policy for sending regreP */
"{daddr %s ulp udp sport %d} %s\n",
break;
case IPSEC_REPLY_PERMIT:
/* IPsec Policy - FA permit policy for receiving regreQ */
"{saddr %s ulp udp dport %d} %s\n",
break;
/*
* tunnel policies are passed directly down via the ipsec_req_t structs
* in the MobilityAgentEntry struct and ioctl(). Keep these tags here,
* though, for debugging.
*/
case IPSEC_TUNNEL_APPLY:
case IPSEC_TUNNEL_PERMIT:
/* syslog() in case we're actually trying to do this! */
"Attempt to set global policy for tunnels incorrect.");
return (-1);
/* catch all for anything we don't understand! */
default:
/* we don't know this type */
"Attempt to set global policy for unknown policy type.");
return (-1);
}
return (0);
}
/*
* Function: installIPsecPolicy
*
* Arguments: char *policy - a pointer to the policy string. The format's
* "{pattern} <action> {properties}" as per ipsec.
*
* Description: This function does what it takes to install the ipsecPolicy of
* the type passed in. Right now, that means calling popen() to
* get "ipsecconf -(a | r) -" going (note: this is a S9 option
* but it should be symmetric with 'removeIPsecPolicy()', which
* also uses an S9-only option, namely -r, see its description)!
* In this way we don't need to create a temporary file only to
* delete it. Once "ipsecconf -a -" is up, we write the policy
* to it, then pclose().
*
* Returns: -1 if bad pointers were passed, or if their was some other problem
* invoking the ipSec policy. 0 on success.
*/
int
installIPsecPolicy(char *policy) {
int ret;
return (-1);
return (-1);
}
/* send the policy to fp == stdin */
/* pclose() will flush, and send the EOF */
/* if pclose returned 1, there was a problem */
if (ret == 1)
/* return in defeat */
return (-1);
/* fin */
return (0);
}
/*
* Function: removeIPsecPolicy
*
* Arguments: char *policy - a pointer to the policy string. The format is
* identical to ipsec's "<action> {properties}"
* as set, and parsed, in mipagent.conf.
*
* Description: This function does what it takes to remove the ipsecPolicy of
* the type passed in. Right now, that means calling popen() to
* get ipsecconf running, and waiting for the policy to remove,
* then passing the policy to have it deleted from IPsec's
* pattern table, and finally calling pclose(). Note: ipsecconf's
* -r[emove] option is only supported in S9 or later!
*
* Returns: -1 if bad pointers were passed, or if their was some other problem
* removeing the ipSec policy. 0 on success.
*/
int
removeIPsecPolicy(char *policy) {
int ret;
/* caller's confused... */
return (-1);
/* pass to ipsec */
return (-1);
/* write policy to fp == stdin */
/* only write one at a time */
if (WEXITSTATUS(ret) != 0) {
return (-1);
}
/* fin */
return (0);
} /* removeIPsecPolicy */
/*
* Function: main
*
* Arguments: argc - Number of runtime arguments
* argv - Pointer to runtime arguments
*
* Description: This function is the main agent routine that gets
* called upon startup. This function will:
* 1. Read the initialization file.
* 2. Start the SNMP sub-agent thread.
* 3. Start the periodic task Thread.
* 4. Start the AAA thread.
* 5. Start the message dispatching Thread.
*
* This thread will then wait for an incoming signal
* (INT and TERM), and will call the shutdown procedure
* once such a signal is received.
*
* Returns: exits
*/
#ifndef TEST_AAA
int
{
int signal = 0;
int c;
int rc;
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
switch (c) {
case 'd':
/* private debugging argument */
break;
default:
/* mipagent has no public arguments */
exit(-1);
}
}
/*
* Read the config file name and create internal data
* structures.
*/
if (Initialize(CONF_FILE_NAME)) {
exit(-1);
}
#ifdef RADIUS_ENABLED
if (radiusEnabled) {
}
#endif /* RADIUS_ENABLED */
(void) restoreAgentState();
/*
* We need to unblock the signals that we care about.
*/
(void) sigemptyset(&thread_signals);
exit(-1);
}
if (disableSNMP == _B_FALSE) {
/*
* Initialize the SNMP Thread.
*/
if (startSNMPTaskThread()) {
exit(-1);
}
}
/*
* Start the AAA thread.
*/
if (aaaProtocol != AAA_NONE) {
if ((rc = startAAATaskThread()) != 0) {
"Error: rc = %d when calling startAAATaskThread\n",
rc);
exit(-1);
}
}
/*
* Start a thread which will handle all periodic tasks.
*/
if (startPeriodicTaskThread()) {
exit(-1);
}
/*
* Initialize the multi-thread message dispatcher.
*/
if (startDispatcherTaskThread()) {
"dispatcher");
exit(-1);
}
/*
* If DynamicInterface global variable is set, then
* start DynamicInterface process thread
*/
if (DynamicInterface) {
/* Make a list of existing interfaces first */
if (CreateListOfExistingIntfce() != 0) {
"Unable to create a list of interfaces: %m");
exit(-1);
}
if (startDynamicInterfaceThread()) {
"Unable to start Dynamic Interface Thread");
exit(-1);
}
}
/*
* Start stat door server.
*/
if (startStatServer()) {
}
/*
* Let's start the performance test thread
*/
if (performanceInterval) {
if (startPerfTestServer()) {
}
}
/*
* We need to unblock the signals that we care about.
*/
(void) sigemptyset(&thread_signals);
exit(-1);
}
return (0);
}
#endif
static void
{
char buffer[PERF_MSG_SIZE];
while (faCounters.faRegReqRecvdCnt == 0 &&
haCounters.haRegReqRecvdCnt == 0) {
(void) sleep(1);
}
/* CONSTCOND */
while (_B_TRUE) {
if (haCounters.haRegReqRecvdCnt) {
}
if (faCounters.faRegReqRecvdCnt) {
}
}
}
static int
{
int result;
if (result) {
return (-1);
}
/*
* We now create a thread to deal with all periodic task.
*/
(void *(*)()) perf_thread,
(void *)NULL);
if (result) {
return (-1);
}
/*
* In order for system resources the be properly cleaned up,
* we need to detach the thread. Otherwise, we need to wait for
* a pthread_join(), which we do not want.
*/
if (result) {
return (-1);
}
return (0);
}
/*
* Function : ConfigEntryHashLookup
*
* Description:
* This lookup function matches the interface index of the
* entry with the passed value.
* Returns _B_TRUE if the entry matches the desired criteria
* else _B_FALSE
*/
/* ARGSUSED */
{
return (_B_TRUE);
else
return (_B_FALSE);
}