agentPeriodic.c revision 5c0b7edee9bd9fad49038456b16972ff28fa4187
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 1999-2002 Sun Microsystems, Inc.
* All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* file: agentPeriodic.c
*
* This file includes the routines that are periodically called
* for agent advertisement and garbage collection of data structures
* such as visitor entries, mobile node entries, security
* assocations, etc.
*/
#include <stdio.h>
#include <netinet/in_systm.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <assert.h>
#include "mip.h"
#include "agent.h"
#include "pool.h"
#include "agentKernelIntfce.h"
#include "conflib.h"
#include "mipagentstat_door.h"
static pthread_t periodicThreadId = 0;
/* global variables declared here */
/*
* if need to disable mobility service, set
* advBusy so that agent advertisement B(usy)
* Bit is set. This informs MNs not to make
* a registration request per RFC2002.
*/
/* our NAI */
/* challenges */
/*
* Common to all mobility agents
*/
extern struct hash_table maAdvConfigHash;
/* Counters common to all Mobility Agents */
extern CommonCounters commonCounters;
extern char maNai[MAX_NAI_LENGTH];
/* Foreign Agent specific data structures. */
extern struct hash_table faVisitorHash;
/* Counters maintained by Foreign Agents */
extern ForeignAgentCounters faCounters;
/* The last two challenges advertised */
/* Home Agent specific data structures. */
extern struct hash_table haMobileNodeHash;
/*
* This table has one entry for each known Mobility Agent
*/
extern struct hash_table mipAgentHash;
/*
* This table stores all of the Security Associations
*/
extern HashTable mipSecAssocHash;
#ifdef FIREWALL_SUPPORT
extern DomainInfo domainInfo;
#endif /* FIREWALL_SUPPORT */
/* Other external declarations */
extern int logVerbosity;
extern int advLifetime;
extern int periodicInterval;
extern AAA_Protocol_Code aaaProtocol;
extern unsigned short inChecksum(unsigned short *, int);
extern void sendICMPmessage(int, ipaddr_t, unsigned char *, int);
extern char *err2str(int);
#ifdef FIREWALL_SUPPORT
#endif /* FIREWALL_SUPPORT */
extern uint32_t getRandomValue();
extern int removeIPsecPolicy(char *);
#define LOWEST_ROUTER_PRIORITY 0x80000000
static void doPeriodicTask();
/*
* Function: disableService
*
* Arguments:
*
*
* Description: Function will set a flag to indicate
* that all agent advertisements on all
* interfaces will have the B(usy) Bit
* set. In addition, the Agent Advertisement
* sequence number for all interfaces will
* be set to zero. This function is called
* to disable mobility service while keeping
* the mobility agent up and running. NOTE: A
* corresponding function enableService()
* is called to reenable mobility service.
*
* Returns:
*/
void
{
struct hash_entry *p;
while (p) {
nentry++;
entry->maAdvSeqNum = 0;
p = p->next;
}
}
}
/*
* Function: enableService
*
* Arguments:
*
* Description: Function will set a flag to indicate
* that all agent advertisements on all
* interfaces should not have the
* B(usy) bit set.
*
* Returns:
*/
void
{
}
/*
* Function: maSendAdvertisement
*
* Arguments: entry - Pointer to MaAdvConfigEntry
* dst - Destination addr of the advertisement
* AdvType - Type of advertisement -solicited or
* unsolicited
* faBusy - boolean dictating whether we are
* busy.
*
* Description: Prepare and send agent advertisement on
* specified interface.
*
* Returns:
*/
void
{
int j;
static unsigned char advPkt[512];
int naiLength;
unsigned char *randomValuePtr;
int len;
unsigned char *cp;
/* We don't do unsolicited adv if AdvInitCount = 0 */
mipverbose(("maSendAdvertisement: zero InitCount\n"));
return;
}
/* Fill out the ICMP header for a router advertisement */
/* LINTED BAD_PTR_CAST_ALIGN */
icmpPtr->icmpAdvNumAddr = 0;
/* create advertisement ... */
/* LINTED BAD_PTR_CAST_ALIGN */
/*
* ... fill (optional) addresses in the RFC 1256 portion
* we only fill out one address.
*/
/*
* ... fill out the mobility agent advertisement extension
* we only advertise one address
*/
/* LINTED BAD_PTR_CAST_ALIGN */
/*
* We set the advertisement sequence number. Note that this
* value wraps around at 255. This is used by Mobile Nodes
* to determine whether the Foreign Agent has rebooted.
*/
if (++entry->maAdvSeqNum == 0)
/* set the busy bit, if appropriate */
ADV_IS_FOREIGN_AGENT))) {
}
/* fill out the advertised care-of address */
/* LINTED BAD_PTR_CAST_ALIGN */
/*
* We only advertise our NAI if we were
* configured to do so.
*/
/* Add the Mobility Agent NAI */
*cp++ = ADV_AGENT_NAI_EXT_TYPE;
len += 2;
}
/*
* We only advertise challenges
* if we were configured to do so.
*/
if (faChallengeAdv == _B_TRUE) {
if (advType == UNSOLICITED_ADV) {
/* Add the Foreign Agent Challenge Value */
*cp++ = ADV_CHALLENGE_EXT_TYPE;
*cp++ = ADV_CHALLENGE_LENGTH;
len += 2;
/*
* Save the last Challenge issued
*/
randomValuePtr = cp;
/* We want a 16 octet (128 bit) challenge */
for (j = 0; j < ADV_CHALLENGE_LENGTH; j += 4) {
sizeof (randomValue));
len += sizeof (randomValue);
cp += sizeof (randomValue);
}
/* We want a 16 octet (128 bit) challenge */
/*
* Save the New Challenge issued
*/
} else if (advType == SOLICITED_ADV) {
/* Add the Foreign Agent Challenge Value */
*cp++ = ADV_CHALLENGE_EXT_TYPE;
*cp++ = ADV_CHALLENGE_LENGTH;
len += 2;
/* We use the last advertised challenge */
}
}
/* fill out prefix length extension, if required */
*cp++ = ADV_PREFIX_EXT_TYPE;
len += 2;
/* fill out prefix len for each addr in RFC1256 portion */
for (j = 0; j < icmpPtr->icmpAdvNumAddr; j++) {
len++;
}
}
/* pad ICMP message to even length, if required */
if (len % 2) {
*cp++ = ADV_PADDING_EXT_TYPE;
len++;
}
/* fill out ICMP checksum */
/* ship it! */
/*
* IP_XMIT_IF or IP_MULTICAST_IF are set on this socket
* during initiation time in InitSockets().
*/
/*
* Now update maAdvInitCount for limited unsolicited advertisement
* case. Note, we need to update this value to make sure that
* we don't send unsolicited advertisements beyond maAdvInitCount
* value specified in the mipagent.conf file.
* I am updating this value, otherwise we need to keep another
* data structure for each dynamic interface, which can grow large
* with the number of interfaces. Besides, there is no reason I find
* at present, to preserve it's initial value.
*/
/* update maAdvInitCount */
entry->maAdvInitCount--;
mipverbose(("maSendAdvertisement: updating maAdvInitCount "
}
/*
* Note that the mipverbose format is different here.
* We want to just print the interface index with each
* advertisement.
*/
}
/*
* Function: delHABEent
*
* Arguments: mnePtr - Pointer to a Mobile Node Entry
* entry - Pointer to a Binding Entry
*
* Description: This function will delete a binding entry.
* If a Home Address was assigned to the Mobile
* Node via a local pool, and the number of
* bindings is set to zero (0), we will free
* the Home Address.
*
* Note that the caller MUST have locked the
* Mobile Node Entry prior to calling this
* function.
*
* Returns:
*/
void
{
char addrstr1[INET_ADDRSTRLEN];
char addrstr2[INET_ADDRSTRLEN];
int val;
int result;
/*
* Disable encapsulation to this coaddr. Decrease
* binding count for MN. If zero, cancel proxy ARP & route
*/
#ifdef FIREWALL_SUPPORT
/*
* If the care-of-address was outside protected domain remove
* the encapsulation through the firewall's internal address.
* TODO: This works only if we assume that a single external
* COAddr is never shared by multiple mobile nodes. For now,
* that's always the case.
*/
if (isOutsideProtectedDomain(coAddr)) {
mipverbose(("Removing tunnel for %s through FW %s\n",
}
}
#endif /* FIREWALL_SUPPORT */
/*
* Terminate encapsulation and decapsulation of MN's
* packets to COA. For now, this also handles reverse
* tunneling
*/
mipverbose(("Removing tunnel for %s through %s\n",
}
/* if encaprem() returned 0, there are no more MNs using this tunnel */
if (val == 0) {
/* kill off any ipsec SA we have with this agent-peer */
/* note: this should work for colocated MNs too! */
/*
* We're the HA, so we look for IPSEC_REPLY_APPLY to
* remove. NOTE: we NEVER remove IPSEC_REQUEST_PERMIT,
* (unless shutting down), as these come unannounced.
* See agentInit.c: deleteIPsecSAHashHelper()
*/
/* off it */
if (removeIPsecPolicy(
/* whine about it */
char peerAddr[IPv4_ADDR_LEN];
"ipsec regisration reply apply.",
peerAddr);
} else
/* it's gone, unset the flag bit */
mae->maIPsecFlags &=
}
/* The tunnels are down, so just unset those bits */
/* more importantly, this is no longer an agent peer */
/* unlock */
}
}
if (--mnePtr->haMnBindingCnt == 0) {
/*
* Notify AAA server that the MN is going away.
*/
if (result) {
"stop record");
}
}
mipverbose(("Terminating arp service for %s\n",
/*
* TODO:
* Solaris gets confused if it has two ARP entries
* for the same host on different interfaces. This
* needs further looking into(at least it tries to
* keep a separate ARP table for each interface).
*/
mipverbose(("Removing proxy ARP entry for %s\n",
}
/*
* Do we have an assigned Home Address that we need
* to free?
*/
"Unable to free address from pool %d",
}
}
}
"HA binding removed for %s@%s at entry %p (Binding Cnt %d).\n",
mnePtr->haMnBindingCnt));
}
/*
* Function: delFAVEptr
*
* Arguments: entry - Foreign Agent Visitor Entry
* sendASR - whether to send Accounting Stop Request
*
* Description: This function will delete a Foreign Agent's
* Visitor entry. If the visitor entry was in
* the ACCEPTED state (meaning that service was
* provided to the Mobile Node), we must remove
* the route, delete the tunnel interface and
* the MN's ARP entry.
*
* Note that the caller MUST have locked the
* Mobile Node Entry prior to calling this
* function.
*
* Returns:
*/
void
{
int val;
int tun_num;
int in_index;
char addrstr1[INET_ADDRSTRLEN];
char addrstr2[INET_ADDRSTRLEN];
int result;
#if 0
/*
* Of course, this causes us a heart ache if we are called from
* an interrupt handler, since we will not be locking
*/
/*
* Let's just make sure that the caller did indeed
* lock the visitor entry...
*/
assert(0);
}
#endif
mipverbose(("FA expired %s visitor entry for %s\n",
"accepted" : "pending"),
/* For accepted requests, kill route and disable decapsulation. */
if (tun_num < 0) {
return;
}
tun_num);
if (in_index == 0) {
/* if_nametoindex fails... */
tun_name);
}
"Removing direct, local route for visitor %s thru %s\n",
entry->faVisitorInIfindex)) < 0) {
"routedel failed ...for visitor %s: %s\n",
}
/* delete Reverse Tunnel route */
"Removing Reverse tunnel route for visitor %s at"
" interface index %d\n",
in_index)) < 0) {
"Reverse Tunnel route delete failed: %s:"
" for visitor %s at interface index %d",
}
}
/*
* Notify AAA server that the MN is going away.
* In the case we are here because of a Close Session Request
* received from AAA, AAA already knows it should stop
* accounting.
*/
(unsigned char *)entry->faVisitorMnNAI,
if (result) {
"stop record");
}
}
/*
* TODO: this behavior is incorrect if multiple coaddrs can be
* registered for a mobile node at a FA. Decaprem should occur
* ONLY after a mobile node has NO accepted registrations.
*/
"Disabling decapsulation of inner pkts sent to %s\n",
entry->faVisitorIfaceAddr)) < 0) {
}
/* if decaprem() returns 0 there are no MNs using the tunnel */
if (val == 0) {
/* kill any tunnel ipsec SAs we have with this peer */
if ((mae =
/*
* We're the FA, so we look for
* IPSEC_REPLY_PERMIT, and
* IPSEC_REQUEST_APPLY policies.
*/
/* off it */
if (removeIPsecPolicy(
< 0) {
/* whine about it */
char peerAddr[IPv4_ADDR_LEN];
peerAddr);
"Could not remove %s's "
"ipsec reply permit.",
peerAddr);
} else
/* unset the flag bit */
mae->maIPsecFlags &=
}
/*
* The tunnel policy itself is 'freed'
* when the tunnel is unplumbed, but
* we need to unset the flag bits.
*
* We don't care if *this* MN's got a reverse
* tunnel, but if *any* happenned to get one.
*/
mae->maIPsecFlags &=
/* this is no longer an agent peer */
/* unlock */
}
}
/*
* If the entry is accepted we should have set up an ARP
* cache entry (marked with the permanent flag). Since this
* is the common entry point to deleting the FAVE, we delete
* the ARP entry here too. The other deletions are done in
* the registration request and reply processing code on the
* FA side. The ARP cache entry was set up to prevent the FA
* from broadcast ARPing. PVTODO: May need some special
* handling for 2 hosts with same addr (private overlapping
* address) on the same interface index, eg: specify link
* layer address here too. May need to modify ARP to delete
* based on ether addr too.
*/
if (entry->faVisitorIsSllaValid &&
entry->faVisitorInIfindex)) < 0)) {
/*
* If deletion failed bcos there was'nt an entry
* mipagent need not report it
*/
}
}
}
/*
* Function: haAgeBindingsHashHelper
*
* Arguments: entry - Pointer to Mobile Node Entry
* p1 - First parameter to match (current time)
*
* Description: This function is used as the Hash Table Helper routine
* for haAgeBinding() when looking for binding entries
* in the Hash Table that have expired, and will be
* called by getAllHashTableEntries().
*
* Returns: _B_TRUE if the entry matches the desired criteria,
* otherwise _B_FALSE.
*/
static boolean_t
{
while (bindingEntry) {
/*
* We want to keep this one, so setup the pointer.
*/
} else {
if (prev_entry) {
} else {
}
}
}
/*
* We need to delete the Mobile Node Entry if the
* entry was dynamic and has no more bindings.
*/
if (hentry->haMnBindingCnt == 0 &&
/*
* Returning _B_FALSE here informs the caller that
* the entry was freed.
*/
return (_B_FALSE);
}
return (_B_TRUE);
}
/*
* Function: haAgeBindings
*
* Arguments: htbl - Pointer to Hash Table
* currentTime - The current Time (absolute)
*
* Description: This function will step through each
* Mobile Node's Binding Entries and will
* delete expired entries.
*
* If the Mobile Node Entry is marked as a
* DYNAMIC entry, and the number of binding
* entries is set to zero (0), we will free
* the Mobile Node Entry as well.
*
* Returns:
*/
static void
{
}
/*
* Function: faAgeVisitorsHashHelper
*
* Arguments: entry - Pointer to Mobile Node Entry
* p1 - First parameter to match (current time)
*
* Description: This function is used as the Hash Table Helper routine
* for faAgeVisitors() when looking for visitor entries
* in the Hash Table that have expired, and will be
* called by getAllHashTableEntries().
*
* Returns: _B_TRUE if the entry matches the desired criteria,
* otherwise _B_FALSE.
*/
static boolean_t
{
/* Expired */
return (_B_FALSE);
}
return (_B_TRUE);
}
/*
* Function: faAgeVisitors
*
* Arguments: htbl - Pointer to Hash Table
* currentTime - The current Time (absolute)
*
* Description: This function will step through each
* Foreign Agent Visitor Entries and will
* delete expired entries.
*
* Returns:
*/
static void
{
}
/*
* Function: mipAgeSecAssocHashHelper
*
* Arguments: entry - Pointer to Mobile Node Entry
* p1 - First parameter to match (current time)
*
* Description: This function is used as the Hash Table Helper routine
* for mipAgeSecAssoc() when looking for visitor entries
* in the Hash Table that have expired, and will be
* called by getAllHashTableEntries().
*
* Returns: _B_TRUE if the entry matches the desired criteria,
* otherwise _B_FALSE.
*/
static boolean_t
{
"Deleting Security Assocation entry!!\n");
/* Expired */
return (_B_FALSE);
}
return (_B_TRUE);
}
/*
* Function: mipAgeSecAssoc
*
* Arguments: htbl - Pointer to Hash Table
* currentTime - The current Time (absolute)
*
* Description: This function will step through each
* Security Association Entries and will
* delete the SAs marked as DYNAMIC that
* have expired.
*
* Returns:
*/
static void
{
}
/*
* Function: mipAgeMobilityAgentsHashHelper
*
* Arguments: entry - Pointer to Mobile Node Entry
* p1 - First parameter to match (current time)
*
* Description: This function is used as the Hash Table Helper routine
* for mipAgeMobilityAgents() when looking for visitor entries
* in the Hash Table that have expired, and will be
* called by getAllHashTableEntries().
*
* Returns: _B_TRUE if the entry matches the desired criteria,
* otherwise _B_FALSE.
*/
static boolean_t
{
/* Expired */
return (_B_FALSE);
}
return (_B_TRUE);
}
/*
* Function: mipAgeMobilityAgents
*
* Arguments: htbl - Pointer to Hash Table
* currentTime - The current Time (absolute)
*
* Description: This function will step through each
* Mobility Agent Entries and will
* delete the ones marked as DYNAMIC that
* have expired.
*
* Returns:
*/
static void
{
}
/*
* Function: startPeriodicTaskThread
*
* Arguments:
*
* Description: This function is called to start the
* periodic task handling thread.
*
* Returns: int, 0 if successful.
*/
int
startPeriodicTaskThread(void)
{
int result;
if (result) {
return (-1);
}
/*
* We now create a thread to deal with all periodic task.
*/
(void *(*)()) doPeriodicTask,
(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: killPeriodicTaskThread
*
* Arguments:
*
* Description: This function is called during the agent
* shutdown procedure in order to kill the
* periodic task handling thread.
*
* Returns:
*/
int
{
int result;
if (periodicThreadId) {
/*
* Next we need to kill the dispatching thread.
*/
if (result) {
/*
* Well, there's not much we can do here..
*/
return (-1);
}
}
return (0);
}
/*
* Function: doPeriodicTask
*
* Arguments: void
*
* Description: This function is called by a thread
* and will periodically call the functions
* that free any expired control blocks, such
* as visitor entries, bindings, etc.
*
* The frequency that these clean up tasks
* get called is configurable through the
* configuration file, but this feature is
* undocumented.
*
* This function never returns, but will be
* killed if the master thread calls
* killPeriodicTaskThread()
*
* Returns: never!
*/
static void
doPeriodicTask(void)
{
time_t nextPeriodicTime = 0;
/* CONSTCOND */
while (_B_TRUE) {
if (currentTime < nextPeriodicTime) {
}
if (currentTime >= nextPeriodicTime) {
mipverbose(("*"));
}
}
}