diff options
author | seb <none@none> | 2007-08-07 12:40:31 -0700 |
---|---|---|
committer | seb <none@none> | 2007-08-07 12:40:31 -0700 |
commit | 5c0b7edee9bd9fad49038456b16972ff28fa4187 (patch) | |
tree | 82cd98417351f3ea1b246973d9b08b6d910d7cd8 /deleted_files | |
parent | aebbbe55b51fd70e2ec4f8938210eb1772eb623b (diff) | |
download | illumos-gate-5c0b7edee9bd9fad49038456b16972ff28fa4187.tar.gz |
PSARC 2007/311 EOF of Mobile IP
6479886 mipagent and related kernel interfaces should be removed
6511070 mobile IP code in onnv is in dubious state.
6574880 route is missing the FIXEDMTU, VIRTUAL, and DUPLICATE interface flags
--HG--
rename : usr/src/cmd/cmd-inet/common/mipagentstat_door.h => deleted_files/usr/src/cmd/cmd-inet/common/mipagentstat_door.h
rename : usr/src/cmd/cmd-inet/etc/init.d/mipagent => deleted_files/usr/src/cmd/cmd-inet/etc/init.d/mipagent
rename : usr/src/cmd/cmd-inet/etc/mipagent.conf-sample => deleted_files/usr/src/cmd/cmd-inet/etc/mipagent.conf-sample
rename : usr/src/cmd/cmd-inet/etc/mipagent.conf.fa-sample => deleted_files/usr/src/cmd/cmd-inet/etc/mipagent.conf.fa-sample
rename : usr/src/cmd/cmd-inet/etc/mipagent.conf.ha-sample => deleted_files/usr/src/cmd/cmd-inet/etc/mipagent.conf.ha-sample
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/Makefile => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/Makefile
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/THIRDPARTYLICENSE => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/THIRDPARTYLICENSE
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/THIRDPARTYLICENSE.descrip => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/THIRDPARTYLICENSE.descrip
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/aaa.c => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/aaa.c
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/aaa.h => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/aaa.h
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/agent.c => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agent.c
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/agent.h => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agent.h
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/agentID.c => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agentID.c
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/agentInit.c => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agentInit.c
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/agentKernelIntfce.c => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agentKernelIntfce.c
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/agentKernelIntfce.h => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agentKernelIntfce.h
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/agentNet.c => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agentNet.c
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/agentPeriodic.c => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agentPeriodic.c
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/agentSaveState.c => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agentSaveState.c
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/auth.c => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/auth.c
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/auth.h => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/auth.h
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/fakeDiameter.pl => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/fakeDiameter.pl
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/hash.c => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/hash.c
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/hash.h => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/hash.h
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/inc.flg => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/inc.flg
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/mip.h => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/mip.h
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/mipagent.acl => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/mipagent.acl
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/mipagent.reg => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/mipagent.reg
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/mipagentstat_server.c => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/mipagentstat_server.c
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/pool.c => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/pool.c
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/pool.h => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/pool.h
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/setup.c => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/setup.c
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/setup.h => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/setup.h
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_appl.c => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_appl.c
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_faCOAEntry.c => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_faCOAEntry.c
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_faVisitorEntry.c => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_faVisitorEntry.c
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_haCounterEntry.c => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_haCounterEntry.c
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_haMobilityBindingEntry.c => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_haMobilityBindingEntry.c
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_maAdvConfigEntry.c => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_maAdvConfigEntry.c
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_mipSecAssocEntry.c => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_mipSecAssocEntry.c
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_mipSecViolationEntry.c => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_mipSecViolationEntry.c
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_stub.c => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_stub.c
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_stub.h => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_stub.h
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_trap.c => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_trap.c
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_tree.c => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_tree.c
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/thq.c => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/thq.c
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/thq.h => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/thq.h
rename : usr/src/cmd/cmd-inet/usr.lib/mipagent/utils.c => deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/utils.c
rename : usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/Makefile => deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/Makefile
rename : usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/addr.c => deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/addr.c
rename : usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/addr.h => deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/addr.h
rename : usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/advertisements.c => deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/advertisements.c
rename : usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/advertisements.h => deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/advertisements.h
rename : usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/general.c => deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/general.c
rename : usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/general.h => deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/general.h
rename : usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/gsp.c => deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/gsp.c
rename : usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/gsp.h => deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/gsp.h
rename : usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/inc.flg => deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/inc.flg
rename : usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/mipagentconfig.c => deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/mipagentconfig.c
rename : usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/mipagentconfig.h => deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/mipagentconfig.h
rename : usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/pool.c => deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/pool.c
rename : usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/pool.h => deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/pool.h
rename : usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/spi.c => deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/spi.c
rename : usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/spi.h => deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/spi.h
rename : usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/utils.c => deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/utils.c
rename : usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/utils.h => deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/utils.h
rename : usr/src/cmd/cmd-inet/usr.sbin/mipagentstat/Makefile => deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentstat/Makefile
rename : usr/src/cmd/cmd-inet/usr.sbin/mipagentstat/inc.flg => deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentstat/inc.flg
rename : usr/src/cmd/cmd-inet/usr.sbin/mipagentstat/main.c => deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentstat/main.c
rename : usr/src/pkgdefs/SUNWmipr/Makefile => deleted_files/usr/src/pkgdefs/SUNWmipr/Makefile
rename : usr/src/pkgdefs/SUNWmipr/depend => deleted_files/usr/src/pkgdefs/SUNWmipr/depend
rename : usr/src/pkgdefs/SUNWmipr/pkginfo.tmpl => deleted_files/usr/src/pkgdefs/SUNWmipr/pkginfo.tmpl
rename : usr/src/pkgdefs/SUNWmipr/prototype_com => deleted_files/usr/src/pkgdefs/SUNWmipr/prototype_com
rename : usr/src/pkgdefs/SUNWmipr/prototype_i386 => deleted_files/usr/src/pkgdefs/SUNWmipr/prototype_i386
rename : usr/src/pkgdefs/SUNWmipr/prototype_sparc => deleted_files/usr/src/pkgdefs/SUNWmipr/prototype_sparc
rename : usr/src/pkgdefs/SUNWmipu/Makefile => deleted_files/usr/src/pkgdefs/SUNWmipu/Makefile
rename : usr/src/pkgdefs/SUNWmipu/depend => deleted_files/usr/src/pkgdefs/SUNWmipu/depend
rename : usr/src/pkgdefs/SUNWmipu/pkginfo.tmpl => deleted_files/usr/src/pkgdefs/SUNWmipu/pkginfo.tmpl
rename : usr/src/pkgdefs/SUNWmipu/prototype_com => deleted_files/usr/src/pkgdefs/SUNWmipu/prototype_com
rename : usr/src/pkgdefs/SUNWmipu/prototype_i386 => deleted_files/usr/src/pkgdefs/SUNWmipu/prototype_i386
rename : usr/src/pkgdefs/SUNWmipu/prototype_sparc => deleted_files/usr/src/pkgdefs/SUNWmipu/prototype_sparc
Diffstat (limited to 'deleted_files')
81 files changed, 37641 insertions, 0 deletions
diff --git a/deleted_files/usr/src/cmd/cmd-inet/common/mipagentstat_door.h b/deleted_files/usr/src/cmd/cmd-inet/common/mipagentstat_door.h new file mode 100644 index 0000000000..8a650f35e7 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/common/mipagentstat_door.h @@ -0,0 +1,145 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999-2001 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ifndef _MIPAGENTSTAT_DOOR_H +#define _MIPAGENTSTAT_DOOR_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * This header defines constants and structures common to the + * mipagentstat door client and server. That stat client + * can retrieve and display information about mobile nodes + * from mipagent by making enumeration RPCs to the stat server + * in mipagent. Each door call effects a single enumeration + * transaction, so the stat client is in effect a sliding + * window across the registration tables in mipagent. + * + * The client / server protocol is defined by the DoorStatsArgs + * structure. The same structure is used for both call and reply + * information, and no memory needs to be allocated for the + * IPC by either the client or server. All address information + * about mobile nodes and agents is communicated via buffers + * large enough to hold an IPv6 address, and each address is + * tagged with an address family so that it can be processed + * by the stat client. + * + * The client keeps track of all enumeration state by passing + * an opaque state handle to the server for each enumeration + * transaction. This state handle is the enum_state field in + * DoorStatArgs. The server is stateless, and simply conducts + * the enumeration operation based on the information in the + * state handle and updates the handle each call before passing + * it back to the client. The client indicates that it wishes to + * start an enumeration setting the op field to FIRST_ENT; all + * successive enumeration calls should set the op to NEXT_ENT. + * + * The stat client can enumerate either the home or foreign agent + * tables. Which agent to get stats for is indicated by setting + * the type field to either HOME_AGENT or FOREIGN_AGENT. + * + * The last two fields of DoorStatArgs are the time granted and + * time remaining for the mobile node being displayed. These times + * are absolute times, in seconds. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Stat door rendezvous point */ +#define MIPAGENTSTAT_DOOR "/var/run/.mipagentstat_door" + +/* Bits for tracking command-line arguments for HA / FA stats */ +#define DO_HA 0x01 +#define DO_FA 0x02 +#define DO_BOTH 0x03 + +/* + * Enum describing which agent to get stats for, and if our output should be + * be mn-centric, or mobility agent peer-centric. + */ +typedef enum { HOME_AGENT, + FOREIGN_AGENT, + HOME_AGENT_PEER, + FOREIGN_AGENT_PEER } enum_stat_type; + +/* + * Define peer-flags so we know our place in the peer relationship. + */ +#define HA_PEER 0x01 /* identifies this agent as an HA peer */ +#define FA_PEER 0x02 /* identifies this agent as an FA peer */ + +/* Enum describing which enumeration operation to do */ +typedef enum { FIRST_ENT, NEXT_ENT } enum_op; + +/* Call / reply buffer; defines the mipagentstat protocol */ +typedef struct door_stat_args { + /* control (call) fields */ + enum_stat_type type; /* home agent or foreign agent */ + enum_op op; /* first or next entry */ + uint8_t enum_state[16]; /* 128 bits of enumerator state */ + /* data (reply) fields */ + int node_af; /* mobile node addr address family */ + int agent_af; /* agent addr address family */ + uint8_t node[sizeof (struct in6_addr)]; + /* mobile node address */ + uint8_t agent[sizeof (struct in6_addr)]; + /* home/foreign agent name */ + uint32_t granted; /* time granted */ + uint32_t expires; /* time remaining */ + /* flags - indicate services, and security */ + uint8_t service_flags; /* special services for the mn */ +} DoorStatArgs; + +/* service flags - keep it tightly anologous to the registration */ +#define SERVICE_BIT_UNUSED 0x01 /* placeholder */ +#define SERVICE_REVERSE_TUNNEL 0x02 /* ReverseTunnel Service */ +#define SERVICE_VJ_COMPRESSION 0x04 /* VJ Compression Service */ +#define SERVICE_GRE_ENCAP 0x08 /* GRE Encapsulation Service */ +#define SERVICE_MIN_ENCAP 0x10 /* MIN Encapsulation Service */ +#define SERVICE_DECAPSULATION_BY_MN 0x20 /* MN is Colocated */ +#define SERVICE_FWD_BROADCASTS 0x40 /* [multi/broad]cast service */ +#define SERVICE_SIMULTANEOUS_BINDINGS 0x80 /* Simultaneous binding service */ + +/* + * These should be indicated in the Flags column (of mipagentstat) by the flag + * identifiers in the becon/registration for consistency (when supported): + * + * Simultaneous Bindings = S + * Forwarding Broadcasts = B + * Decapsulation by MN = D + * Minimim Encapsulation = M + * Generic Encapsulation = G + * Van Jacobson Compress = V + * Reverse Tunneling = T - supported + */ + +#ifdef __cplusplus +} +#endif + +#endif /* _MIPAGENTSTAT_DOOR_H */ diff --git a/deleted_files/usr/src/cmd/cmd-inet/etc/init.d/mipagent b/deleted_files/usr/src/cmd/cmd-inet/etc/init.d/mipagent new file mode 100644 index 0000000000..e30c7028a2 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/etc/init.d/mipagent @@ -0,0 +1,42 @@ +#!/sbin/sh +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 +# +# +# ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1999 by Sun Microsystems, Inc. +# All rights reserved. +# + +case "$1" in +'start') + [ -f /etc/inet/mipagent.conf ] && /usr/lib/inet/mipagent >/dev/msglog 2>&1 & + ;; +'stop') + /usr/bin/pkill -x -u 0 -P 1 mipagent + ;; +*) + echo "Usage: $0 { start | stop }" + exit 1 + ;; +esac +exit 0 diff --git a/deleted_files/usr/src/cmd/cmd-inet/etc/mipagent.conf-sample b/deleted_files/usr/src/cmd/cmd-inet/etc/mipagent.conf-sample new file mode 100644 index 0000000000..3400ba17a9 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/etc/mipagent.conf-sample @@ -0,0 +1,190 @@ +# +#pragma ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 +# +# Sample configuration file for mobility agents. Lines starting with the hash +# character are treated as comments. Blank lines are ignored. All the time +# values are in seconds unless stated otherwise. For the variable names that +# are composed of multiple words, the practice is each word should start with +# upper-case letter, and each value should start with lower-case. + +[General] + Version = 1.0 # version number for the configuration file. (required) + + +# +# One section for all interfaces supported by mipagent. +# The section name must be [Advertisements <intf-name>] +# +# HomeAgent yes, no (Determines whether mipagent will provide +# Home Agent functionality) +# ForeignAgent yes, no (Determines whether mipagent will provide +# Foreign Agent functionality) +# PrefixFlags yes, no (Specifies whether advertisements will include +# the prefix extension). +# AdvertiseOnBcast yes, no (If yes, advertisements are sent on +# 255.255.255.255, rather than 224.0.0.1) +# RegLifetime n (maximum lifetime value accepted in registration +# requests). +# AdvLifetime n (Lifetime advertised in the RFC1256 portion) +# AdvFrequency n (The frequency of mobility advertisements, in +# seconds) +# ReverseTunnel yes, no (Determines whether mipagent has reverse tunnel +# decapsulation/encapsulation capability. In +# case of foreign-agent it also means that the +# foreign agent is advertising reverse tunnel) +# +# ReverseTunnelRequired yes, no (Determines local policy of the mipagent +# on registration request, i.e whether a mobile +# should/must request reverse tunnel) + +[Advertisements hme0] + HomeAgent = yes + ForeignAgent = yes + PrefixFlags = yes + AdvertiseOnBcast = yes + RegLifetime = 200 + AdvLifetime = 200 + AdvFrequency = 5 + ReverseTunnel = no + ReverseTunnelRequired = no + +# Advertisement section for dynamic interfaces: +# The interface with '*' suffix determines dynamic interfaces to mipagent. +# Additional parameters which may control Advertisement frequency in a newly +# created mobility interface are useful when a mobility +# interface does not want to have a periodic advertisement all the time. +# The following configuration is useful for foreign agents. +# AdvInitCount n Initial Advertisement count when +# Unsolicited advertisements are limited. +# AdvLimitUnsolicited yes, no Determines the local policy of the mipagent +# (FA) if it sends limited or unlimited +# unsolicited advertisement. +# For more details on dynamic interface configuration, visit mipagent.conf(1M) + +#[Advertisements sppp*] +# HomeAgent = no +# ForeignAgent = yes +# AdvertiseOnBcast = no +# PrefixFlags = yes +# RegLifetime = 300 +# AdvLifetime = 300 +# AdvFrequency = 3 +# ReverseTunnel = yes +# ReverseTunnelRequired = no +# AdvInitCount = 5 +# AdvLimitUnsolicited = yes + + +# +# The GlobalSecurityParameters contains all security related configuration +# parameters. +# +# MaxClockSkew n (The number of seconds that mipagent will +# accept as a difference between its own local +# time and the time found in Registration Requets) +# HA-FAAuth yes, no (Specifies whether HA-FA Authentication +# extensions must be present in Registration +# Requests and Replies) +# MN-FAAuth yes, no (Specifies whether MN-FA Authentication +# extensions must be present in Registration +# Requests and Replies) +# Challenge yes, no (Specifies whether the Foreign Agent will +# include Challenges in it's mobility +# advertisements) +# KeyDistribution files (must be set to files) + +[GlobalSecurityParameters] + MaxClockSkew = 300 + HA-FAauth = yes + MN-FAauth = yes + Challenge = no + KeyDistribution = files + +# +# The Address Pools are defined via numerical identifiers, and contain + +# BaseAddress n.n.n.n (The first address in the address pool) +# Size n (The number of addresses in the pool) + +[Pool 1] + BaseAddress = 10.68.30.7 + Size = 4 + +# +# The SPIs must be configured. An SPI entry contains a numerical value +# the replay method and keying information. +# +# ReplyMethod none, timestamp (Specifies the type of replay +# authentication for the SPI) +# Key x (Authentication key in hexadecimal) + +[SPI 257] + ReplayMethod = none + Key= 11111111111111111111111111111111 + +[SPI 258] + ReplayMethod = none + Key= 15111111111111111111111111111111 + +# +# The Address section contains configuration information for mobility +# nodes (foreign and home agents) as well as mobile nodes. +# +# The # Node-Default keyword in the section header is used to define a +# default SPI for all mobile nodes. This allows an administrator to +# simply include a single entry for all mobile nodes, assuming that +# they all use the same SPI. The Default-Node entry must include the +# pool entry. +# +# The Address section may also contain an NAI as opposed to +# the home address. These entries must also include the Pool +# entry. +# +# Type node, agent (Specifies whether the entry is for +# a mobile node, or a mobility agent) +# SPI n (The SPI value associated with the +# entry, which must be configured above) +# Pool n (If the section header contained an NAI, +# an address will be allocated for the +# mobile node from the pool defined) + +[Address 10.1.1.1] + Type = node + SPI = 258 + +[Address mobilenode@sun.com] + Type = node + SPI = 257 + Pool = 1 + +[Address Node-Default] + Type = node + SPI = 258 + Pool = 1 + +[Address 10.68.30.36] + Type = agent + SPI = 257 diff --git a/deleted_files/usr/src/cmd/cmd-inet/etc/mipagent.conf.fa-sample b/deleted_files/usr/src/cmd/cmd-inet/etc/mipagent.conf.fa-sample new file mode 100644 index 0000000000..dfe8355a78 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/etc/mipagent.conf.fa-sample @@ -0,0 +1,173 @@ +# +#pragma ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 +# +# Sample configuration file for mobility agents. Lines starting with the hash +# character are treated as comments. Blank lines are ignored. All the time +# values are in seconds unless stated otherwise. For the variable names that +# are composed of multiple words, the practice is each word should start with +# upper-case letter, and each value should start with lower-case. + +[General] + Version = 1.0 # version number for the configuration file. (required) + + +# +# One section for all interfaces supported by mipagent. +# The section name must be [Advertisements <intf-name>] +# +# HomeAgent yes, no (Determines whether mipagent will provide +# Home Agent functionality) +# ForeignAgent yes, no (Determines whether mipagent will provide +# Foreign Agent functionality) +# PrefixFlags yes, no (Specifies whether advertisements will include +# the prefix extension). +# AdvertiseOnBcast yes, no (If yes, advertisements are sent on +# 255.255.255.255, rather than 224.0.0.1) +# RegLifetime n (maximum lifetime value accepted in registration +# requests). +# AdvLifetime n (Lifetime advertised in the RFC1256 portion) +# AdvFrequency n (The frequency of mobility advertisements, in +# seconds) +# ReverseTunnel yes, no (Determines whether mipagent has reverse tunnel +# decapsulation/encapsulation capability. In +# case of foreign-agent it also means that the +# foreign agent is advertising reverse tunnel) +# +# ReverseTunnelRequired yes, no (Determines local policy of the mipagent +# on registration request, i.e whether a mobile +# should/must request reverse tunnel) + + + +[Advertisements hme0] + HomeAgent = no + ForeignAgent = yes + PrefixFlags = yes + AdvertiseOnBcast = yes + RegLifetime = 200 + AdvLifetime = 200 + AdvFrequency = 5 + ReverseTunnel = yes + ReverseTunnelRequired = no + +# Advertisement section for dynamic interfaces: +# The interface with '*' suffix determines dynamic interfaces to mipagent. +# Additional parameters which may control Advertisement frequency in a newly +# created mobility interface are useful when a mobility +# interface does not want to have a periodic advertisement all the time. +# The following configuration is useful for foreign agents. +# AdvInitCount n Initial Advertisement count when +# Unsolicited advertisements are limited. +# AdvLimitUnsolicited yes, no Determines the local policy of the mipagent +# (foreign agent) if it sends limited or +# unlimited unsolicited advertisement. +# Uncomment the following section, if your foreign agent allows mobility +# service through newly created Solaris PPP interfaces. For more information +# on dynamic interface support, please check mipagent.conf(1M). + +#[Advertisements sppp*] +# HomeAgent = no +# ForeignAgent = yes +# AdvertiseOnBcast = no +# PrefixFlags = yes +# RegLifetime = 300 +# AdvLifetime = 300 +# AdvFrequency = 2 +# ReverseTunnel = yes +# ReverseTunnelRequired = no +# AdvInitCount = 5 +# AdvLimitUnsolicited = yes + +# +# The GlobalSecurityParameters contains all security related configuration +# parameters. +# +# MaxClockSkew n (The number of seconds that mipagent will +# accept as a difference between its own local +# time and the time found in Registration Requets) +# HA-FAAuth yes, no (Specifies whether HA-FA Authentication +# extensions must be present in Registration +# Requests and Replies) +# MN-FAAuth yes, no (Specifies whether MN-FA Authentication +# extensions must be present in Registration +# Requests and Replies) +# Challenge yes, no (Specifies whether the Foreign Agent will +# include Challenges in it's mobility +# advertisements) +# KeyDistribution files (must be set to files) + +[GlobalSecurityParameters] + MaxClockSkew = 300 + HA-FAauth = yes + MN-FAauth = yes + Challenge = no + KeyDistribution = files + +# +# The SPIs must be configured. An SPI entry contains a numerical value +# the replay method and keying information. +# +# ReplyMethod none, timestamp (Specifies the type of replay +# authentication for the SPI) +# Key x (Authentication key in hexadecimal) + +[SPI 257] + ReplayMethod = none + Key= 11111111111111111111111111111111 + +[SPI 258] + ReplayMethod = none + Key= 15111111111111111111111111111111 + +# +# The Address section contains configuration information for mobility +# nodes (foreign and home agents) as well as mobile nodes. +# +# The # Node-Default keyword in the section header is used to define a +# default SPI for all mobile nodes. This allows an administrator to +# simply include a single entry for all mobile nodes, assuming that +# they all use the same SPI. The Default-Node entry must include the +# pool entry. +# +# The Address section may also contain an NAI as opposed to +# the home address. These entries must also include the Pool +# entry. +# +# Type node, agent (Specifies whether the entry is for +# a mobile node, or a mobility agent) +# SPI n (The SPI value associated with the +# entry, which must be configured above) +# Pool n (If the section header contained an NAI, +# an address will be allocated for the +# mobile node from the pool defined) + +[Address 10.1.1.1] + Type = node + SPI = 258 + +[Address 10.68.30.36] + Type = agent + SPI = 257 diff --git a/deleted_files/usr/src/cmd/cmd-inet/etc/mipagent.conf.ha-sample b/deleted_files/usr/src/cmd/cmd-inet/etc/mipagent.conf.ha-sample new file mode 100644 index 0000000000..5863ae0cfc --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/etc/mipagent.conf.ha-sample @@ -0,0 +1,164 @@ +# +#pragma ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 +# +# Sample configuration file for mobility agents. Lines starting with the hash +# character are treated as comments. Blank lines are ignored. All the time +# values are in seconds unless stated otherwise. For the variable names that +# are composed of multiple words, the practice is each word should start with +# upper-case letter, and each value should start with lower-case. + +[General] + Version = 1.0 # version number for the configuration file. (required) + + +# +# One section for all interfaces supported by mipagent. +# The section name must be [Advertisements <intf-name>] +# +# HomeAgent yes, no (Determines whether mipagent will provide +# Home Agent functionality) +# ForeignAgent yes, no (Determines whether mipagent will provide +# Foreign Agent functionality) +# PrefixFlags yes, no (Specifies whether advertisements will include +# the prefix extension). +# AdvertiseOnBcast yes, no (If yes, advertisements are sent on +# 255.255.255.255, rather than 224.0.0.1) +# RegLifetime n (maximum lifetime value accepted in registration +# requests). +# AdvLifetime n (Lifetime advertised in the RFC1256 portion) +# AdvFrequency n (The frequency of mobility advertisements, in +# seconds) +# ReverseTunnel yes, no (Determines whether mipagent has reverse tunnel +# decapsulation/encapsulation capability. In +# case of foreign-agent it also means that the +# foreign agent is advertising reverse tunnel) +# +# ReverseTunnelRequired yes, no (Determines local policy of the mipagent +# on registration request, i.e whether a mobile +# should/must request reverse tunnel) + + +[Advertisements hme0] + HomeAgent = yes + ForeignAgent = no + PrefixFlags = yes + AdvertiseOnBcast = yes + RegLifetime = 200 + AdvLifetime = 200 + AdvFrequency = 5 + ReverseTunnel = yes + ReverseTunnelRequired = no + +# +# The GlobalSecurityParameters contains all security related configuration +# parameters. +# +# MaxClockSkew n (The number of seconds that mipagent will +# accept as a difference between its own local +# time and the time found in Registration Requets) +# HA-FAAuth yes, no (Specifies whether HA-FA Authentication +# extensions must be present in Registration +# Requests and Replies) +# MN-FAAuth yes, no (Specifies whether MN-FA Authentication +# extensions must be present in Registration +# Requests and Replies) +# Challenge yes, no (Specifies whether the Foreign Agent will +# include Challenges in it's mobility +# advertisements) +# KeyDistribution files (must be set to files) + +[GlobalSecurityParameters] + MaxClockSkew = 300 + HA-FAauth = yes + MN-FAauth = yes + Challenge = no + KeyDistribution = files + +# +# The Address Pools are defined via numerical identifiers, and contain + +# BaseAddress n.n.n.n (The first address in the address pool) +# Size n (The number of addresses in the pool) + +[Pool 1] + BaseAddress = 10.68.30.7 + Size = 4 + +# +# The SPIs must be configured. An SPI entry contains a numerical value +# the replay method and keying information. +# +# ReplyMethod none, timestamp (Specifies the type of replay +# authentication for the SPI) +# Key x (Authentication key in hexadecimal) + +[SPI 257] + ReplayMethod = none + Key= 11111111111111111111111111111111 + +[SPI 258] + ReplayMethod = none + Key= 15111111111111111111111111111111 + +# +# The Address section contains configuration information for mobility +# nodes (foreign and home agents) as well as mobile nodes. +# +# The # Node-Default keyword in the section header is used to define a +# default SPI for all mobile nodes. This allows an administrator to +# simply include a single entry for all mobile nodes, assuming that +# they all use the same SPI. The Default-Node entry must include the +# pool entry. +# +# The Address section may also contain an NAI as opposed to +# the home address. These entries must also include the Pool +# entry. +# +# Type node, agent (Specifies whether the entry is for +# a mobile node, or a mobility agent) +# SPI n (The SPI value associated with the +# entry, which must be configured above) +# Pool n (If the section header contained an NAI, +# an address will be allocated for the +# mobile node from the pool defined) + +[Address 10.1.1.1] + Type = node + SPI = 258 + +[Address mobilenode@sun.com] + Type = node + SPI = 257 + Pool = 1 + +[Address Node-Default] + Type = node + SPI = 258 + Pool = 1 + +[Address 10.68.30.36] + Type = agent + SPI = 257 diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/Makefile b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/Makefile new file mode 100644 index 0000000000..17beee0787 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/Makefile @@ -0,0 +1,151 @@ +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include $(SRC)/cmd/Makefile.cmd +include $(SRC)/cmd/cmd-inet/Makefile.cmd-inet + +PROG= mipagent + +LCLOBJS=aaa.o \ + agent.o \ + agentID.o \ + agentInit.o \ + agentKernelIntfce.o \ + agentNet.o \ + agentPeriodic.o \ + agentSaveState.o \ + auth.o \ + utils.o \ + snmp_tree.o \ + snmp_stub.o \ + snmp_trap.o \ + snmp_appl.o \ + snmp_faCOAEntry.o \ + snmp_faVisitorEntry.o \ + snmp_haCounterEntry.o \ + snmp_haMobilityBindingEntry.o \ + snmp_maAdvConfigEntry.o \ + snmp_mipSecAssocEntry.o \ + snmp_mipSecViolationEntry.o \ + mipagentstat_server.o \ + pool.o \ + hash.o \ + thq.o \ + setup.o + +COMOBJS= conflib.o + +OBJS= $(LCLOBJS) $(COMOBJS) + +HDRS= aaa.h \ + agent.h \ + agentKernelIntfce.h \ + auth.h \ + hash.h \ + mip.h \ + snmp_stub.h \ + pool.h \ + setup.h \ + thq.h + +# Auxiliary files for the SNMP subagent +SNMP_FILES= mipagent.acl mipagent.reg +SNMP_CONF_DIR= $(ROOT)/etc/snmp/conf +INS_SNMP_FILES= $(SNMP_FILES:%=$(SNMP_CONF_DIR)/%) +$(SNMP_CONF_DIR)/mipagent.acl:= FILEMODE= 600 +$(SNMP_CONF_DIR)/mipagent.reg:= FILEMODE= 644 +$(INS_SNMP_FILES):= OWNER= root +$(INS_SNMP_FILES):= GROUP= sys +$(SNMP_CONF_DIR):= OWNER= root +$(SNMP_CONF_DIR):= GROUP= sys + +SRCS= $(LCLOBJS:%.o=%.c) $(COMOBJS:%.o=$(CMDINETCOMMONDIR)/%.c) + +SNMPINC = -I$(SRC)/cmd/agents/snmp/snmplib -I$(SRC)/cmd/agents/snmp/agent + +LDLIBS += -lxnet -lnsl -lsocket -lssagent -lmd5 +CPPFLAGS += -DMIP_DEBUG -I$(CMDINETCOMMONDIR) $(SNMPINC) -DNO_SIMULTANEOUS \ + -DINI -D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT + +# mipagent uses the ancillary data feature which is available +# only through UNIX 98 standards version of Socket interface. +# these #defines are required to use UNIX 98 interfaces +CPPFLAGS += -D_XOPEN_SOURCE=500 -D__EXTENSIONS__ + +# +# Note that we include KEY_DISTRIBUTION in LINTFLAGS because otherwise +# lint thinks aaaCreateKey() can be static, which is really not right. +# +LINTFLAGS += -DKEY_DISTRIBUTION + +# +# Turn off some of lint's argument checking to workaround the fact +# that we use both libsocket *and* libxnet interfaces (whose prototypes +# don't always agree). +# +LINTFLAGS += -erroff=E_INCONS_ARG_DECL2 -erroff=E_INCONS_ARG_USED2 \ + -erroff=E_INCONS_VAL_TYPE_DECL2 + +# +# We turn off these errors work around brokenness in the snmp interfaces +# (specifically: they require us to define and export data for their +# use, which lint has no clue about). +# +LINTFLAGS += -erroff=E_NAME_DEF_NOT_USED2 -erroff=E_GLOBAL_COULD_BE_STATIC2 + +.KEEP_STATE: + +.PARALLEL: $(OBJS) $(INS_SNMP_FILES) + +all: $(PROG) + +$(PROG): $(OBJS) + $(LINK.c) -o $@ $(OBJS) $(LDLIBS) + $(POST_PROCESS) + +include ../Makefile.lib + +install: all $(ROOTLIBINETPROG) $(SNMP_CONF_DIR) .WAIT $(INS_SNMP_FILES) + +$(SNMP_CONF_DIR): + $(INS.dir) + +$(SNMP_CONF_DIR)/%: % + $(INS.file) + +clean: + $(RM) $(OBJS) + +check: $(HDRS:%.h=%.check) $(SRCS:%.c=%.check) + +%.check: %.c + $(DOT_C_CHECK) + +lint: lint_SRCS + +include $(SRC)/cmd/Makefile.targ diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/THIRDPARTYLICENSE b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/THIRDPARTYLICENSE new file mode 100644 index 0000000000..e82c613ac4 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/THIRDPARTYLICENSE @@ -0,0 +1,14 @@ + * 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. diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/THIRDPARTYLICENSE.descrip b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/THIRDPARTYLICENSE.descrip new file mode 100644 index 0000000000..2dd359deab --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/THIRDPARTYLICENSE.descrip @@ -0,0 +1 @@ +PORTIONS OF MIPAGENT FUNCTIONALITY diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/aaa.c b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/aaa.c new file mode 100644 index 0000000000..678d8fcba6 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/aaa.c @@ -0,0 +1,2687 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 1999-2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * file: aaa.c + * + * This file processes the Diameter AAA requests from mipagent. + * This file also contains the routines used to parse and process the + * Diameter messages. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <errno.h> +#include <syslog.h> + +#include "mip.h" +#include "agent.h" +#include "setup.h" +#include "hash.h" +#include "aaa.h" + +static int gbl_TCPSocket = -1; /* Global socket */ + +static int gbl_hashInitialized = 0; +in_port_t gbl_aaaPort = AAA_PORT; +char gbl_aaaHost[MAX_SERVER_NAME_LEN]; +static HashTable naiHash; + +extern char maNai[]; +extern HashTable mipAgentHash; +extern HashTable faVisitorHash; +extern AAA_Protocol_Code aaaProtocol; +extern ForeignAgentCounters faCounters; + +static pthread_t aaaThreadId = 0; + +/* External prototypes . . . this should be somewhere else -- WORK:todo */ +extern int hexdump(char *, unsigned char *, int); +extern void forwardFromFAToHA(MessageHdr *, MaAdvConfigEntry *, boolean_t); +extern void rejectFromFAToMN(MessageHdr *, MaAdvConfigEntry *, int); +extern void FreeMessageHdr(MessageHdr *); +MessageHdr *AllocateMessageHdr(); +extern boolean_t forcefullyDeregisterMN(ipaddr_t *, ipaddr_t, ipaddr_t); +extern boolean_t mkPendingFAVEHashLookup(void *, uint32_t, uint32_t, uint32_t); +extern void delFAVE(HashTable *, FaVisitorEntry **, ipaddr_t, uint32_t); +extern void enableService(); +/* + * Internal Prototypes + */ + +static int sendCloseSessionAnswer(AAA_Packet *, char *, size_t, boolean_t); +static size_t aaaAddAvp(AAA_AVPCode avpCode, unsigned char *dest, + size_t destLen, void *data, size_t dataLen); +static AAA_AVP *aaaFindAvpByCode(AAA_Packet *packet, AAA_AVPCode avpCode); + +static int readTCPPacket(unsigned char *buffer, uint32_t bufLen); +static void *mainAAAThread(); +static int sendTCPPacket(unsigned char *buffer, uint32_t length); +static void processAuthFailure(MessageHdr *msgHdr, + char *mnNAI, size_t mnNAILen, uint32_t result); +#ifdef TEST_DIAMETER +static void processOpenSessionRequest(AAA_Packet *packet, char *mnNAI, + size_t mnNAILen); +static void processOpenSessionIndicationResponse(AAA_Packet *packet, + char *mnNAI, size_t mnNAILen); +static void aaaGenerateKey(unsigned char *buffer, size_t buffLen); +static uint32_t aaaGenerateSpi(); +#endif +static void processOpenSessionAnswer(AAA_Packet *packet, char *mnNAI, + size_t mnNAILen, uint32_t resultCode); +static void processOpenSessionAnswerRadius(AAA_Packet *packet, char *mnNAI, + size_t mnNAILen, AAA_HashEntry *); +static void processOpenSessionAnswerRadiusHA(AAA_Packet *packet, char *mnNAI, + size_t mnNAILen, AAA_HashEntry *, uint32_t resultCode); +static void processOpenSessionIndication(AAA_Packet *packet, char *mnNAI, + size_t mnNAILen); +static void *aaaFindAvpPtr(AAA_Packet *packet, AAA_AVPCode avpCode, + size_t *length); +static boolean_t aaaFindAvpInt(AAA_Packet *, AAA_AVPCode, int32_t *); +static int sendCloseSession(AAA_Packet *srcPacket, char *mnNAI, + size_t mnNAILen); +static void aaaSendErrorResponse(uint32_t commandCode, int32_t returnCode, + char *mnNAI, size_t mnNAILen, uint32_t handle); + +/* Not prototyped in .h file for cyclic dependency problems */ +int aaaSendRegistrationReply(MessageHdr *, size_t, ipaddr_t, ipaddr_t); + + +extern int logVerbosity; /* WORK -- This should be in a .h file. PRC? */ +extern ipaddr_t getClosestInterfaceAddr(ipaddr_t dest); /* Where? WORK */ +extern MaAdvConfigEntry *getFirstInterface(); /* Where? WORK */ +extern int dispatchMsgToThread(MessageHdr **messageHdr); +extern boolean_t advBusy; +extern struct hash_table maAdvConfigHash; + +/* + * Function: aaaAddAvp + * + * Arguments: unsigned char *dest, size_t destLen, uint32_t avpCode, + * void *data, size_t dataLen + * + * Description: This function will build an AVP perform all byte-ordering/ + * copying operations, and will return the length of the + * destination AVP. + * + * Returns: size_t (length of block added, zero on error) + */ +static size_t +aaaAddAvp(AAA_AVPCode avpCode, unsigned char *dest, size_t destLen, + void *data, size_t dataLen) +{ + AAA_AVP staticAvp; + AAA_AVP *avp; + int32_t TempInt; + + /* First, check to make sure it will fit */ + if ((dataLen + (2 * sizeof (uint32_t))) > destLen) { + syslog(LOG_ERR, "ERROR: avp will not fit in dest! (" + "avpSize = %d, destSize = %d, avpCode = %d)", + dataLen + (2 * sizeof (uint32_t)), destLen, avpCode); + return (0); + } + + /* Now, build the avp */ + staticAvp.avpCode = htonl(avpCode); + + /* Note: dataLen = size of header */ + staticAvp.length = htonl(2 * sizeof (uint32_t) + dataLen); + + /* LINTED E_BAD_PTR_CAST_ALIGN */ + avp = (AAA_AVP *)dest; + (void) memcpy(avp, &staticAvp, 2 * sizeof (uint32_t)); + + switch (avpCode) { + /* These fields require no mangling */ + case MOBILE_NODE_NAI: + case FOREIGN_AGENT_NAI: + case REGISTRATION_REQUEST: + case MOBILE_NODE_RESPONSE: + case REGISTRATION_REPLY: + case MN_FA_KEY: + case FA_HA_KEY: + case HA_FA_KEY: + case FA_MN_KEY: + case MN_HA_KEY: + case HA_MN_KEY: + case MN_FA_CHALLENGE_VALUE: + (void) memcpy(avp->data, data, dataLen); + break; + + /* These fields require mangling (They're 32 bit numbers) */ + case NUMBER_OF_CHALLENGE_BYTES_IN_RR: + case MOBILE_NODE_HOME_ADDRESS: + case HOME_AGENT_ADDRESS: + case RESULT_CODE: + case MN_FA_SPI: + case FA_HA_SPI: + case SESSION_TIMEOUT: + case MN_HA_SPI: + case SESSION_TIMEOUT_1: + case SESSION_TIME: + case FOREIGN_AGENT_ADDRESS: + case IS_FROM_HA: + case MN_AAA_SPI: + case REV_TUN: + case MN_HANDLE: + case RELEASE_INDICATOR: + if (dataLen != sizeof (uint32_t)) { + syslog(LOG_ERR, "Internal error: avp should have a " + "length of %d, not %d!", sizeof (uint32_t), + dataLen); + return (0); + } + (void) memcpy(&TempInt, data, sizeof (uint32_t)); + TempInt = htonl(TempInt); + (void) memcpy(avp->data, &TempInt, sizeof (uint32_t)); + break; + + default: /* Error! */ + syslog(LOG_ERR, "ERROR: Invalid AVP Code! <%d>\n", avpCode); + return (0); + } /* switch (avpCode) */ + + return (ntohl(staticAvp.length)); +} /* aaaAddAvp */ + +/* + * Function: addNaiToHash + * + * Arguments: char *mnNAI, size_t mnNAILen, + * unsigned char *mnChallenge, uint32_t mnChallengeLen, + * ipaddr_t homeAddress, ipaddr_t homeAgentAddress, + * void *messageHdr + * + * Description: This function will add the nai to our local hash. It + * checks to make sure the add was successful (value unique) + * It is called from the foreign agent or home agent when it first + * receives a NAI that it has not seen before. The has entry is + * used to store any interim data that is needed for either + * the home or foreign agents. + * + * Returns: int (zero on success) + */ +static int +addNaiToHash(char *mnNAI, size_t mnNAILen, + unsigned char *mnChallenge, uint32_t mnChallengeLen, + ipaddr_t homeAddress, ipaddr_t homeAgentAddress, + void *messageHdr) +{ + AAA_HashEntry *p; + int rc; + + /* Allocate and initialize HashEntry */ + p = (AAA_HashEntry *)malloc(sizeof (AAA_HashEntry)); + if (!p) { + syslog(LOG_CRIT, "FATAL: Unable to allocate memory!"); + return (-1); + } + + (void) memset(p, 0, sizeof (AAA_HashEntry)); + (void) strncpy(p->mnNAI, mnNAI, MIN(MAX_NAI_LEN - 1, mnNAILen)); + p->mnNAI[MIN(MAX_NAI_LEN - 1, mnNAILen)] = '\0'; + (void) memcpy(p->mnChallenge, mnChallenge, MIN(MAX_CHALLENGE_LEN - 1, + mnChallengeLen)); + + p->homeAddress = homeAddress; + p->homeAgentAddress = homeAgentAddress; + p->timeOut = 0; + p->handle = 0; + p->messageHdr = messageHdr; + + /* Now link it. */ + rc = linkHashTableEntryString(&naiHash, (unsigned char *)mnNAI, + mnNAILen, p, LOCK_NONE); + if (rc != 0) { + syslog(LOG_ERR, + "ERROR: Unable to add entry to hash! (unique?)"); + free(p); + return (-2); + } + + return (0); + +} /* addNaiToHash */ + +/* + * Function: removeFromHash + * + * Arguments: char *mnNAI, size_t mnNAILen + * + * Description: This function will delete the nai from our local hash. + * It is called in the foreign agent when the CloseSession + * Answer returns. It should be called in the home agent when + * the Accounting Stop arrives. + * + * Returns: int (zero on success) + */ +static int +removeFromHash(char *mnNAI, size_t mnNAILen) +{ + int rc; + AAA_HashEntry *p; + + /* + * Lock it for writing. + */ + p = (AAA_HashEntry *)findHashTableEntryString(&naiHash, + (unsigned char *)mnNAI, mnNAILen, LOCK_WRITE, NULL, NULL, NULL, + NULL); + if (!p) { + syslog(LOG_ERR, "ERROR: Unable to find NAI <%.*s> in hash!", + mnNAILen, mnNAI); + return (-1); + } + rc = delHashTableEntryString(&naiHash, p, (unsigned char *)mnNAI, + mnNAILen, LOCK_NONE); + + /* And, finally, free our data */ + /* WARNING: Check return value xxx WORK */ + (void) rw_unlock(&p->aaaNodeLock); + (void) rwlock_destroy(&p->aaaNodeLock); + free(p); + + return (rc); + +} /* removeFromHash */ + +/* + * Function: aaaUpdateHash + * + * Arguments: AAA_Packet *packet, char *mnNAI, size_t mnNAILen + * + * Description: This function will update the hash information for the + * given node. It gets called when any response comes from the + * AAA server. The only field that is currently updated is the + * handle. The handle is ONLY updated if our current copy is a + * zero. + * + * Also, since we probably sent out accounting messages with a + * handle of zero, it accepts any response that contains a handle + * of zero (but does not update our local information). + * + * Returns: int + */ +static AAA_HashEntry * +aaaUpdateHash(AAA_Packet *packet, char *mnNAI, size_t mnNAILen) +{ + AAA_HashEntry *p; + + /* + * Since we only have one thread reading from the socket, and + * that thread is the only thread that will update these data + * items, no locking is necessary. + */ + p = (AAA_HashEntry *)findHashTableEntryString(&naiHash, + (unsigned char *)mnNAI, mnNAILen, LOCK_WRITE, NULL, NULL, + NULL, NULL); + + if (p) { + if (p->handle) { + /* + * We already have a handle .. . check it + * But, it's ok if we get a zero . . .just means that + * the sender doesn't know that the handle is set yet. + */ + if ((p->handle != ntohl(packet->handle)) && + (ntohl(packet->handle) != 0)) { + /* Error! */ + syslog(LOG_ERR, + "Error: incoming handle does not match" + " handle in hash: (%d <> %d)\n", + ntohl(packet->handle), + p->handle); + (void) rw_unlock(&p->aaaNodeLock); + return (NULL); + } + } else { + /* Since we don't have a handle on file, update it */ + p->handle = ntohl(packet->handle); + } + } else { + syslog(LOG_ERR, "Error: Unable to find nai (%*s) in hash!", + mnNAILen, mnNAI); + return (NULL); + } + + return (p); + +} /* aaaUpdateHash */ + +/* + * Function: aaaLookupHandle + * + * Arguments: unsigned char *mnNAI, size_t mnNAILen + * + * Description: This function will lookup the NAI in the hash, and will return + * the handle associated with it. + * + * Returns: int32_t (-1 on error) + */ +static int32_t +aaaLookupHandle(char *mnNAI, size_t mnNAILen) +{ + AAA_HashEntry *p; + int32_t handle; + + /* + * Since we only have one thread reading from the socket, and + * that thread is the only thread that will update these data + * items, no locking is necessary. + */ + p = (AAA_HashEntry *)findHashTableEntryString(&naiHash, (unsigned + char *)mnNAI, mnNAILen, LOCK_READ, NULL, NULL, NULL, NULL); + + if (p) { + handle = p->handle; + (void) rw_unlock(&p->aaaNodeLock); + + return (handle); + } else { + syslog(LOG_ERR, "Error: Unable to find nai (%.*s) in hash!", + mnNAILen, mnNAI); + return (-1); + } + +} /* aaaLookupHandle */ + +/* + * Function: aaaFindAvpInt + * + * Arguments: AAA_Packet *packet, AAA_AVPCode avpCode, int32_t *dest + * + * Description: This routine will return the long specified by avpCode. + * On error, it will return _B_FALSE. + * + * Returns: boolean_t (B_FALSE on error) + */ +static boolean_t +aaaFindAvpInt(AAA_Packet *packet, AAA_AVPCode avpCode, int32_t *dest) +{ + AAA_AVP *avp, staticAvp; + + avp = aaaFindAvpByCode(packet, avpCode); + if (!avp) + return (_B_FALSE); + + /* Make our static copy */ + (void) memcpy(&staticAvp, avp, 2 * sizeof (uint32_t)); + staticAvp.length = ntohl(staticAvp.length); + + /* subtract the header size */ + staticAvp.length -= sizeof (uint32_t) * 2; + + if (staticAvp.length != sizeof (uint32_t)) { + syslog(LOG_ERR, "Error: aaaFindAvpInt: bad length for int." + " avp code = %d, length = %d", staticAvp.avpCode, + staticAvp.length); + return (_B_FALSE); + } + + (void) memcpy(dest, avp->data, sizeof (uint32_t)); + + return (_B_TRUE); + +} /* aaaFindAvpInt */ + +/* + * Function: aaaFindAvpPtr + * + * Arguments: AAA_Packet *packet, AAA_AVPCode avpCode, size_t *length + * + * Description: This routine will return the data specified by avpCode. + * It will set the length to the length of the data. + * On error, it will return null. + * + * Returns: uint32_t (defaultValue on error) + */ +static void * +aaaFindAvpPtr(AAA_Packet *packet, AAA_AVPCode avpCode, size_t *length) +{ + AAA_AVP *avp, staticAvp; + + *length = 0; /* Initialize this first */ + + avp = aaaFindAvpByCode(packet, avpCode); + if (!avp) + return (NULL); + + /* Make our static copy */ + (void) memcpy(&staticAvp, avp, 2 * sizeof (uint32_t)); + staticAvp.length = ntohl(staticAvp.length); + + /* subtract the header size */ + staticAvp.length -= sizeof (uint32_t) * 2; + + *length = staticAvp.length; + + return (avp->data); + +} /* aaaFindAvpPtr */ + +/* + * Function: aaaFindAvpByCode + * + * Arguments: packet containing avps, avpCode + * + * Description: This function will walk through the AVPS and return a + * pointer to the avp that matches the given code. + * This function is not efficient, so if the number of + * avps expected grows over 15 or so, we should index them + * once, then call an indexed lookup. + * + * Returns: pointer to the avp, or NULL + * + */ +static AAA_AVP * +aaaFindAvpByCode(AAA_Packet *packet, AAA_AVPCode avpCode) +{ + AAA_AVP *avp; + uint32_t packetLength; + uint32_t currentPosition; + AAA_AVP staticAVP; + unsigned char *buffer; + + /* First, get the length of the packet, so we don't overshoot */ + packetLength = ntohl(packet->length); + + /* Now, set buffer to point to the start of the AVPs */ + buffer = (unsigned char *)&packet[1]; + + currentPosition = 0; + while (currentPosition < (packetLength - (sizeof (AAA_AVP)))) { + /* LINTED E_BAD_PTR_CAST_ALIGN */ + avp = (AAA_AVP*)&buffer[currentPosition]; + + /* + * now avp points to the right place. copy the + * data somewhere byte aligned. + */ + + (void) memcpy(&staticAVP, avp, sizeof (uint32_t)*2); + staticAVP.length = ntohl(staticAVP.length); + staticAVP.avpCode = ntohl(staticAVP.avpCode); + + if (staticAVP.length <= (2 * sizeof (uint32_t))) { + /* Bad packet */ + syslog(LOG_ERR, "Error: bad packet avp code = %d, " + "length = %d", staticAVP.avpCode, + staticAVP.length); + return (NULL); + } + + if (staticAVP.avpCode == avpCode) { + /* We found it! return our position */ + return (avp); + } + + + /* That wasn't it, so move on to the next one */ + currentPosition += staticAVP.length; + + } + + /* We didn't find it! */ + return (NULL); +} /* aaaFindAvpByCode */ + +/* + * Function: aaaCreateKey + * + * Arguments: AAA_Packet *packet, int spiTag, int keyTag + * + * Description: This routine will create the SA for the given key / SPI. + * If the SA already exists, and it is dynamic, then replace the + * key information. + * + * Returns: int (zero on success) + */ +int +aaaCreateKey(int spi, unsigned char *key, size_t keyLen, + uint32_t sessionTimeout) +{ + MipSecAssocEntry *entry; + + entry = CreateSecAssocEntry(_B_TRUE, spi, TIMESTAMPS, MD5, PREFIXSUFFIX, + keyLen, (char *)key, sessionTimeout); + + if (entry == NULL) { + syslog(LOG_ERR, + "Unable to create SA for Mobile Node (SPI %d)\n", spi); + return (-1); + } + + /* + * The Create function ends up locking the node, so + * we need to free it. + */ + (void) rw_unlock(&entry->mipSecNodeLock); + return (0); + +} /* aaaCreateKey */ + +/* + * Function: aaaCreateAgent + * + * Arguments: AAA_Packet *packet, int addrTag, uint32_t spi, + * uint32_t SessionTimeout + * + * Description: This function will create an agent from the data in the + * packet. It is used to create bothe the foreign and home + * agent entries. (The FA would create a corresponding HA entry, + * and vice versa) + * + * Returns: void + */ +static void +aaaCreateAgent(AAA_Packet *packet, int addrTag, uint32_t spi, + uint32_t sessionTimeout) +{ + MobilityAgentEntry *maEntry; + ipaddr_t peerAddress; + + /* Check the Agent Address */ + if (!aaaFindAvpInt(packet, addrTag, (int *)&peerAddress)) { + /* BAD error . . . malformed packet */ + syslog(LOG_ERR, "ERROR: bad packet (no ADDR:%d)", addrTag); + return; + } + + /* + * On the Foreign Agent, we will need to create the Mobility + * Agent entry so that we can find the Home Agent's SPI + * when forwarding messages to it. + */ + maEntry = CreateMobilityAgentEntry(_B_TRUE, peerAddress, spi, + sessionTimeout); + if (maEntry == NULL) { + /* Find it. */ + maEntry = findHashTableEntryUint(&mipAgentHash, peerAddress, + LOCK_WRITE, NULL, 0, 0, 0); + if (maEntry == NULL) { + /* Error! */ + syslog(LOG_ERR, "Error: Unable to create the maEntry!"); + return; + } + } + + /* + * Now, make sure the entry is a dynamic one, and update the SPI + */ + if (maEntry->maSPI != spi) { + if (maEntry->maIsEntryDynamic) { + maEntry->maSPI = spi; + } else { + syslog(LOG_ERR, + "Error: received an SPI that does not match static" + " Agent entry"); + } + } + + /* + * The Create function ends up locking the node, so + * we need to free it. + */ + (void) rw_unlock(&maEntry->maNodeLock); + +} /* aaaCreateAgent */ + +/* + * Function: checkResultCode + * + * Arguments: AAA_Packet *packet + * + * Description: This routine checks the ResultCode field of the packet, and + * returns it (or -1 or -2 on error) + * + * Returns: int (resultCode, -1 or -2 on error) + */ +static int +checkResultCode(AAA_Packet *packet) +{ + int32_t resultCode; + + if (!aaaFindAvpInt(packet, RESULT_CODE, &resultCode)) { + /* BAD error . . . malformed packet */ + syslog(LOG_ERR, "ERROR: bad packet (no RESULT_CODE)"); + } + + return (resultCode); +} /* checkResultCode */ + +/* + * Function: startAAATaskThread + * + * Arguments: + * + * Description: This function starts our AAA thread. + * + * Returns: int (zero on success) + */ +int +startAAATaskThread() +{ + pthread_attr_t pthreadAttribute; + int result; + + result = pthread_attr_init(&pthreadAttribute); + + if (result) { + syslog(LOG_CRIT, "Error Initializing AAA pthread."); + return (-1); + } + + /* + * We now create a thread to deal with all periodic task. + */ + result = pthread_create(&aaaThreadId, &pthreadAttribute, + (void *(*)()) mainAAAThread, (void *)NULL); + + if (result) { + syslog(LOG_CRIT, "pthread_create() failed."); + 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. + */ + result = pthread_detach(aaaThreadId); + + if (result) { + syslog(LOG_CRIT, "pthread_detach() failed."); + return (-1); + } + + return (0); +} /* StartAAATaskThread */ + +/* + * Function: killAAATaskThread + * + * Arguments: + * + * Description: This function kills our AAA task thread. + * + * Returns: int + */ +int +killAAATaskThread() +{ + int result; + + if (aaaThreadId) { + /* + * Next we need to kill the dispatching thread. + */ + result = pthread_cancel(aaaThreadId); + + if (result) { + /* + * Well, there's not much we can do here.. + */ + syslog(LOG_CRIT, "Unable to kill AAA thread"); + return (-1); + } + } + + return (0); +} /* killAAATaskThread */ + +/* + * Function: mainAAAThread + * + * Arguments: + * + * Description: This is our main AAA thread. It receives the messages, and + * processes them based on command code. + * + * Returns: void * + */ +static void * +mainAAAThread() +{ + unsigned char buffer[MAX_TCP_LEN]; + uint32_t commandCode; + AAA_Packet *packet; + AAA_HashEntry *NaiEntry; + uint32_t resultCode; + boolean_t result; + char *mobileNodeNAI; + size_t mobileNodeNAILen; + ipaddr_t *homeaddr = NULL; + ipaddr_t *homeAgentaddr = NULL; + size_t homeaddrLen; + MessageHdr *msgHdr; + int rc; + uint32_t forHA; + + /* The below is an endless loop that will not give any lint warnings */ + for (; ; ) { + if ((rc = readTCPPacket(buffer, MAX_TCP_LEN - 1)) <= 0) { + syslog(LOG_ERR, "Error: <%d> reading packet (%d:%s)", + rc, errno, strerror(errno)); + mipverbose(("readTCPPacket Failed errno is %d\n", + errno)); + (void) sleep(1); + /* + * Clean up MN binding & visitor entries and tunnels + * when a down link between mobility agent and AAA + * infrastructure is down. readTCPPacket will only + * return 0 when this link is initally down. A + * reconnection try will result in rc being -1 so + * docleanup will only be called once - when link + * goes down. + */ + if (rc == 0) { + syslog(LOG_ERR, "AAA readTCPPacket returned 0"); + mipverbose(("AAA readTCPPacket returned 0\n")); + docleanup(); + disableService(&maAdvConfigHash); + /* + * need to reconnect + */ + (void) close(gbl_TCPSocket); + gbl_TCPSocket = -1; + } + continue; + } + + /* LINTED E_BAD_PTR_CAST_ALIGN */ + packet = (AAA_Packet *)buffer; + + commandCode = ntohl(packet->commandCode); + /* + * First, lookup this in our hash, and update the handle + * if necessary. + */ + mobileNodeNAI = aaaFindAvpPtr(packet, MOBILE_NODE_NAI, + &mobileNodeNAILen); + if ((mobileNodeNAI == NULL) || (mobileNodeNAILen == 0)) { + /* Malformed packet */ + syslog(LOG_ERR, + "Error: bad packet(no MOBILE_NODE_NAI)"); + continue; + } + + switch (commandCode) { + case MOBILE_IP_OPEN_SESSION_ANSWER: + /* Update the handle in the hash */ + + NaiEntry = aaaUpdateHash(packet, mobileNodeNAI, + mobileNodeNAILen); + if (NaiEntry == NULL) { + syslog(LOG_ERR, + "Error: Received packet for " + "non-pending NAI (ANSWER)"); + continue; + } + (void) rw_unlock(&NaiEntry->aaaNodeLock); + + /* Check for a good result code */ + resultCode = checkResultCode(packet); + if (resultCode != 0) { + mipverbose(("result code was %d\n", + resultCode)); + + + /* + * Remember we had preserved the messageHdr + * if Radius used, let's free it now. + */ + if (aaaProtocol == RADIUS) { + (void) rw_wrlock(&NaiEntry->aaaNodeLock); + msgHdr = (MessageHdr *)NaiEntry->messageHdr; + processAuthFailure(msgHdr, mobileNodeNAI, + mobileNodeNAILen, resultCode); + + msgHdr->dontDeleteNow = _B_FALSE; + FreeMessageHdr(msgHdr); + NaiEntry->messageHdr = NULL; + (void) rw_unlock(&NaiEntry->aaaNodeLock); + } + + + } + if (aaaProtocol == RADIUS) { + + /* + * MOBILE_IP_OPEN_SESSION_ANSWER && RADIUS: + * + * IS_FROM_HA must be present so that + * the mobility agent will know that + * this is for the Home Agent vs the + * Foreign Agent. + * + * In this case the IS_FROM_HA means + * that this packet is for the Home + * Agent (if the value of the AVP is 1). + * If the packet is for the Home Agent, + * call processOpenSessionAnswerRadiusHA. + * If the packet is for the Foreign Agent, + * callprocessOpenSessionAnswerRadius(). + */ + + if (!aaaFindAvpInt(packet, IS_FROM_HA, (int *)&forHA)) { + syslog(LOG_ERR, "ERROR: bad packet" + " (no IS_FROM_HA)"); + continue; + } + if (forHA == 1) { /* HA */ + processOpenSessionAnswerRadiusHA(packet, + mobileNodeNAI, mobileNodeNAILen, + NaiEntry, resultCode); + } else { /* FA */ + processOpenSessionAnswerRadius(packet, + mobileNodeNAI, mobileNodeNAILen, + NaiEntry); + } + + } else { + processOpenSessionAnswer(packet, mobileNodeNAI, + mobileNodeNAILen, resultCode); + } + break; + + case MOBILE_IP_ACCOUNTING_START_ANSWER: + case MOBILE_IP_ACCOUNTING_INTERIM_ANSWER: + case MOBILE_IP_ACCOUNTING_STOP_ANSWER: + /* Check the handle in the hash */ + NaiEntry = aaaUpdateHash(packet, mobileNodeNAI, + mobileNodeNAILen); + if (NaiEntry == NULL) { + syslog(LOG_ERR, + "Error: Received packet for " + "non-pending NAI"); + continue; + } + (void) rw_unlock(&NaiEntry->aaaNodeLock); + + /* Check the result code */ + resultCode = checkResultCode(packet); + if (resultCode != 0) { + syslog(LOG_ERR, "Error: commandCode: %d" + " resultCode = %d", commandCode, + resultCode); + } + if (commandCode == MOBILE_IP_ACCOUNTING_STOP_ANSWER) { + (void) sendCloseSession(packet, mobileNodeNAI, + mobileNodeNAILen); + } + break; + + case MOBILE_IP_CLOSE_SESSION_ANSWER: + /* Check the handle */ + if ((NaiEntry = aaaUpdateHash(packet, mobileNodeNAI, + mobileNodeNAILen)) == NULL) { + syslog(LOG_ERR, + "Error: Received packet for " + "non-pending NAI"); + continue; + } + (void) rw_unlock(&NaiEntry->aaaNodeLock); + /* Check the result code */ + resultCode = checkResultCode(packet); + if (resultCode != 0) { + syslog(LOG_ERR, + "Error: ACCOUNTING_START_ANSWER" + " resultCode = %d", resultCode); + } + /* And finally, remove the hash entry */ + (void) removeFromHash(mobileNodeNAI, mobileNodeNAILen); + break; + + case MOBILE_IP_OPEN_SESSION_INDICATION: + if (aaaProtocol != DIAMETER) { + syslog(LOG_ERR, + "Error: " + "MOBILE_IP_OPEN_SESSION_INDICATION " + "AAA protocol should be DIAMETER not " + "%d", aaaProtocol); + break; + } + /* + * We get this message from diameter when we are + * acting as a home agent. + */ + processOpenSessionIndication(packet, mobileNodeNAI, + mobileNodeNAILen); + break; + + /* We should not get these. */ +#ifdef TEST_DIAMETER + case MOBILE_IP_OPEN_SESSION_REQUEST: + /* + * We are faking a diameter connection. Accept the + * OPEN_SESSION, and respond with an OPEN_SESSION + * response. Generate keys too. + */ + processOpenSessionRequest(packet, mobileNodeNAI, + mobileNodeNAILen); + break; + + case MOBILE_IP_OPEN_SESSION_INDICATION_RESPONSE: + /* + * We are faking a diameter connection. Accept the + * OPEN_SESSION_INDICATION_RESPONSE as the foreign + * agent, and convert it to a OpenSessionAnswer + */ + processOpenSessionIndicationResponse(packet, + mobileNodeNAI, mobileNodeNAILen); + break; +#else + case MOBILE_IP_OPEN_SESSION_REQUEST: + case MOBILE_IP_OPEN_SESSION_INDICATION_RESPONSE: +#endif + case MOBILE_IP_CLOSE_SESSION_REQUEST: + /* + * AAA server can force mipagent to de-register + * a MN. No need to send a Accounting Stop, since + * AAA already knows this MN is de-registering. + * This message applies to both AAAH and AAAF. + */ + homeaddr = aaaFindAvpPtr(packet, + MOBILE_NODE_HOME_ADDRESS, &homeaddrLen); + homeAgentaddr = aaaFindAvpPtr(packet, + HOME_AGENT_ADDRESS, &homeaddrLen); + + if (homeaddr == NULL || homeAgentaddr == NULL) { + result = 1; + syslog(LOG_ERR, + "ERROR: bad packet " + "(no agent addresses or homeaddr)"); + } else { + result = forcefullyDeregisterMN(homeaddr, + 0, *homeAgentaddr); + } + result = sendCloseSessionAnswer(packet, mobileNodeNAI, + mobileNodeNAILen, result); + if (result != 0) { + syslog(LOG_ERR, "sendto failed at mipagent " + "while replying to AAA. "); + } + break; + + case MOBILE_IP_ACCOUNTING_START_REQUEST: + case MOBILE_IP_ACCOUNTING_INTERIM_REQUEST: + case MOBILE_IP_ACCOUNTING_STOP_REQUEST: + default: + syslog(LOG_ERR, + "Error: Received invalid commandCode <%d>", + commandCode); + } + } + + /* LINTED E_STMT_NOT_REACHED */ + return (NULL); +} /* mainAAAThread */ + +#ifdef TEST_DIAMETER +/* + * Function: processOpenSessionRequest + * + * Arguments: AAA_Packet *packet, char *mnNAI, size_t mnNAILen + * + * Description: This is a DEBUG ONLY routine used to test the code without + * DIAMETER. It should normally be conditionally compiled + * OUT of the code. This routine takes an OpenSessionRequest, + * and generates a OpenSessionIndication. It then calls + * processOpenSessionIndication. + * THIS ROUTINE DISTRUCTIVELY MODIFIES packet IN PLACE + * + * Returns: void + */ +static void +processOpenSessionRequest(AAA_Packet *packet, char *mnNAI, size_t mnNAILen) +{ + unsigned char buffer[MAX_TCP_LEN]; + AAA_Packet *response; + size_t length; + unsigned char *regReq; + size_t regReqLen; + char *faNai; + size_t faNaiLen; + uint32_t numChallengeBytes; + unsigned char *mnResponse; + size_t mnResponseLen; + ipaddr_t homeAddress, homeAgentAddress, foreignAgentAddress; + uint32_t sessionTimeout; + uint32_t MNFASpi, FAHASpi, MNHASpi; + unsigned char MNFAKey[MAX_GENERATE_KEY_LEN]; + unsigned char FAHAKey[MAX_GENERATE_KEY_LEN]; + unsigned char MNHAKey[MAX_GENERATE_KEY_LEN]; + /* These are encrypted versions of the above */ + unsigned char HAFAKey[MAX_GENERATE_KEY_LEN]; + unsigned char FAMNKey[MAX_GENERATE_KEY_LEN]; + unsigned char HAMNKey[MAX_GENERATE_KEY_LEN]; + + /* FOREIGN_AGENT_NAI */ + faNai = aaaFindAvpPtr(packet, FOREIGN_AGENT_NAI, &faNaiLen); + if (!faNai || !faNaiLen) { + syslog(LOG_ERR, "ERROR: bad packet (no FOREIGN_AGENT_NAI)"); + return; + } + + /* REGISTRATION_REQUEST */ + regReq = aaaFindAvpPtr(packet, REGISTRATION_REQUEST, ®ReqLen); + if (!regReq || !regReqLen) { + syslog(LOG_ERR, "ERROR: bad packet (no REGISTRATION_REQUEST)"); + return; + } + + /* NUMBER_OF_CHALLENGE_BYTES_IN_RR */ + if (!aaaFindAvpInt(packet, + NUMBER_OF_CHALLENGE_BYTES_IN_RR, &numChallengeBytes)) { + syslog(LOG_ERR, "ERROR: bad packet (no " + "NUMBER_OF_CHALLENGE_BYTES_IN_RR)"); + return; + } + + /* MOBILE_NODE_RESPONSE */ + mnResponse = aaaFindAvpPtr(packet, MOBILE_NODE_RESPONSE, + &mnResponseLen); + if (!mnResponse || !mnResponseLen) { + syslog(LOG_ERR, "ERROR: bad packet (no MOBILE_NODE_RESPONSE)"); + return; + } + + /* MOBILE_NODE_HOME_ADDRESS */ + if (!aaaFindAvpInt(packet, MOBILE_NODE_HOME_ADDRESS, + &homeAddress)) { + syslog(LOG_ERR, + "ERROR: bad packet (no MOBILE_NODE_HOME_ADDRESS)"); + return; + } + + /* HOME_AGENT_ADDRESS */ + if (!aaaFindAvpInt(packet, HOME_AGENT_ADDRESS, + &homeAgentAddress)) { + syslog(LOG_ERR, "ERROR: bad packet (no HOME_AGENT_ADDRESS)"); + return; + } + + /* FOREIGN_AGENT_ADDRESS */ + if (!aaaFindAvpInt(packet, FOREIGN_AGENT_ADDRESS, + &foreignAgentAddress)) { + syslog(LOG_ERR, + "ERROR: bad packet (no FOREIGN_AGENT_ADDRESS)"); + return; + } + + /* ******** Build Fake Packet ******** */ + + /* + * Generate our keys + */ + aaaGenerateKey(FAHAKey, MAX_GENERATE_KEY_LEN); + aaaGenerateKey(MNFAKey, MAX_GENERATE_KEY_LEN); + aaaGenerateKey(MNHAKey, MAX_GENERATE_KEY_LEN); + + /* These should be computed. (MD5?) */ + aaaGenerateKey(HAFAKey, MAX_GENERATE_KEY_LEN); + aaaGenerateKey(FAMNKey, MAX_GENERATE_KEY_LEN); + aaaGenerateKey(HAMNKey, MAX_GENERATE_KEY_LEN); + + MNFASpi = aaaGenerateSpi(); + FAHASpi = aaaGenerateSpi(); + MNHASpi = aaaGenerateSpi(); + + + /* Build our response (An OpenSessionIndication) */ + /* LINTED E_BAD_PTR_CAST_ALIGN */ + response = (AAA_Packet *)buffer; + response->commandCode = htonl(MOBILE_IP_OPEN_SESSION_INDICATION); + response->handle = packet->handle; /* assume ordered correctly */ + + length = sizeof (AAA_Packet); + + /* Mobile Node NAI */ + length += aaaAddAvp(MOBILE_NODE_NAI, &buffer[length], + MAX_TCP_LEN - length, mnNAI, mnNAILen); + + /* Foreign Agent NAI */ + length += aaaAddAvp(FOREIGN_AGENT_NAI, &buffer[length], + MAX_TCP_LEN - length, maNai, strlen(maNai)); + + /* Foreign Agent Address */ + length += aaaAddAvp(FOREIGN_AGENT_ADDRESS, &buffer[length], + MAX_TCP_LEN - length, &foreignAgentAddress, sizeof (uint32_t)); + + /* Registration Request Packet */ + length += aaaAddAvp(REGISTRATION_REQUEST, &buffer[length], + MAX_TCP_LEN - length, regReq, regReqLen); + + /* Mobile Node Home Address */ + length += aaaAddAvp(MOBILE_NODE_HOME_ADDRESS, &buffer[length], + MAX_TCP_LEN - length, &homeAddress, sizeof (uint32_t)); + + /* Home Agent Address */ + length += aaaAddAvp(HOME_AGENT_ADDRESS, &buffer[length], + MAX_TCP_LEN - length, &homeAgentAddress, sizeof (uint32_t)); + + /* fa-ha spi */ + length += aaaAddAvp(FA_HA_SPI, &buffer[length], + MAX_TCP_LEN - length, &FAHASpi, sizeof (uint32_t)); + + /* FA-HA key */ + length += aaaAddAvp(FA_HA_KEY, &buffer[length], + MAX_TCP_LEN - length, &FAHAKey, MAX_GENERATE_KEY_LEN); + + /* HA-FA Key */ + length += aaaAddAvp(HA_FA_KEY, &buffer[length], + MAX_TCP_LEN - length, &HAFAKey, MAX_GENERATE_KEY_LEN); + + /* MN-FA SPI */ + length += aaaAddAvp(MN_FA_SPI, &buffer[length], + MAX_TCP_LEN - length, &MNFASpi, sizeof (uint32_t)); + + /* MN-FA key */ + length += aaaAddAvp(MN_FA_KEY, &buffer[length], + MAX_TCP_LEN - length, &MNFAKey, MAX_GENERATE_KEY_LEN); + + /* FA-MN Key */ + length += aaaAddAvp(FA_MN_KEY, &buffer[length], + MAX_TCP_LEN - length, &FAMNKey, MAX_GENERATE_KEY_LEN); + + /* MN-HA SPI */ + length += aaaAddAvp(MN_HA_SPI, &buffer[length], + MAX_TCP_LEN - length, &MNHASpi, sizeof (uint32_t)); + + /* MN-HA key */ + length += aaaAddAvp(MN_HA_KEY, &buffer[length], + MAX_TCP_LEN - length, &MNHAKey, MAX_GENERATE_KEY_LEN); + + /* HA-MN Key */ + length += aaaAddAvp(HA_MN_KEY, &buffer[length], + MAX_TCP_LEN - length, &HAMNKey, MAX_GENERATE_KEY_LEN); + + /* Send a fake session time out */ + sessionTimeout = 60; + length += aaaAddAvp(SESSION_TIMEOUT, &buffer[length], + MAX_TCP_LEN - length, &sessionTimeout, sizeof (uint32_t)); + + response->length = htonl(length); + + + processOpenSessionIndication(response, mnNAI, mnNAILen); +} /* processOpenSessionRequest */ + +/* + * Function: processOpenSessionIndicationResponse + * + * Arguments: AAA_Packet *packet + * + * Description: This function will handle converting packets from + * OpenSessionIndicationResponses into OpenSessionAnswers, + * for testing without diameter. (This is the foreign agent + * side catching the home agent's response.) + * + * Returns: void + */ +static void +processOpenSessionIndicationResponse(AAA_Packet *packet, char *mnNAI, + size_t mnNAILen) +{ + mipverbose(("Processing OpenSessionIndicationResponse (DEBUG)\n")); + + processOpenSessionAnswer(packet, mnNAI, mnNAILen, 0); +} /* processOpenSessionIndicationResponse */ +#endif /* TEST_DIAMETER */ + +/* + * Setup the basic message handling fields. I think that we + * could possibly re-use ifEntry here as a pointer back to the + * AAA server. Otherwise, we can create a new field in the + * message header structure. + */ + +static void +aaaSetupMessageHdr(MessageHdr *messageHdr, uint32_t resultCode) +{ + messageHdr->pktSource = MIP_PKT_FROM_AAA; + messageHdr->ifType = ON_UNICAST_SOCK; + messageHdr->pktType = PKT_UDP; + messageHdr->ifEntry = getFirstInterface(); + messageHdr->aaaResultCode = resultCode; + +} /* aaaSetupMessageHdr */ + +/* + * Function: processOpenSessionAnswer + * + * Arguments: AAA_Packet *packet + * + * Description: This function handles the message to the foreign node, from + * DIAMETER. + * + * Returns: void + */ +static void +/* LINTED E_FUNC_ARG_UNUSED */ +processOpenSessionAnswer(AAA_Packet *packet, char *mnNAI, size_t mnNAILen, + uint32_t resultCode) +{ + static MessageHdr *messageHdr = NULL; + unsigned char *FAMNKey, *FAHAKey; + size_t FAMNKeyLen = 0, FAHAKeyLen = 0; + uint32_t FAHASpi = 0, FAMNSpi = 0; + uint32_t sessionTimeout = 0; + unsigned char *regResponse; + size_t regResponseLen; + + /* Check the SessionTimeout */ + if (!aaaFindAvpInt(packet, SESSION_TIMEOUT, (int *)&sessionTimeout)) { + /* BAD error . . . malformed packet */ + syslog(LOG_ERR, "ERROR: bad packet (no SESSION_TIMEOUT)"); + } + + /* Now, make sure we have a response field */ + regResponse = aaaFindAvpPtr(packet, REGISTRATION_REPLY, + ®ResponseLen); + + if (!regResponse) { + syslog(LOG_ERR, "ERROR: bad packet (no REGISTRATION_REPLY)"); + } + + /* FA-HA Spi */ + if (!aaaFindAvpInt(packet, FA_HA_SPI, (int *)&FAHASpi)) { + syslog(LOG_ERR, "ERROR: bad packet (no FA_HA_SPI)"); + } + /* FA-HA Key */ + FAHAKey = aaaFindAvpPtr(packet, FA_HA_KEY, &FAHAKeyLen); + if (!FAHAKey || !FAHAKeyLen) { + syslog(LOG_ERR, "ERROR: bad packet (no FA_HA_KEY)"); + } + /* MN-FA Spi */ + if (!aaaFindAvpInt(packet, MN_FA_SPI, (int *)&FAMNSpi)) { + syslog(LOG_ERR, "ERROR: bad packet (no MN_FA_SPI)"); + } + /* MN-FA Key */ + FAMNKey = aaaFindAvpPtr(packet, FA_MN_KEY, &FAMNKeyLen); + if (!FAMNKey || !FAMNKeyLen) { + syslog(LOG_ERR, "ERROR: bad packet (no MN_FA_KEY)"); + } + + /* Session Timeout */ + if (!aaaFindAvpInt(packet, SESSION_TIMEOUT, (int *)&sessionTimeout)) { + /* BAD error . . . malformed packet */ + syslog(LOG_ERR, "ERROR: bad packet (no SESSION_TIMEOUT)"); + } + + /* + * Create our keys + */ + if ((FAMNKeyLen != 0) && + (aaaCreateKey(FAMNSpi, FAMNKey, FAMNKeyLen, sessionTimeout) < 0)) { + syslog(LOG_ERR, "Error: Invalid MN-FA SPI/Key pair"); + } + + if ((FAHAKeyLen != 0) && + (aaaCreateKey(FAHASpi, FAHAKey, FAHAKeyLen, sessionTimeout) < 0)) { + syslog(LOG_ERR, "Error: Invalid FA-HA SPI/Key pair"); + } + + aaaCreateAgent(packet, HOME_AGENT_ADDRESS, FAHASpi, sessionTimeout); + + /* + * If we don't already have a message header, + * allocate one. + */ + if (messageHdr == NULL) { + if ((messageHdr = AllocateMessageHdr()) == NULL) { + syslog(LOG_CRIT, + "Unable to allocate a message header"); + return; + } + } + aaaSetupMessageHdr(messageHdr, resultCode); + (void) memcpy(messageHdr->pkt, regResponse, regResponseLen); + messageHdr->pktLen = regResponseLen; + + messageHdr->mnFaSPI = FAMNSpi; + messageHdr->aaaSessionTimeout = sessionTimeout; + + /* + * Dispatch the message! + */ + (void) dispatchMsgToThread(&messageHdr); +} /* processOpenSessionAnswer */ + +/* + * Function: processOpenSessionAnswerRadius + * + * Arguments: AAA_Packet *packet, char *mnNAI, size_t mnNAILen + * + * Description: This function handles the message to the FA, from + * RADIUS. + * + * Returns: void + */ +static void +processOpenSessionAnswerRadius(AAA_Packet *packet, char *mnNAI, size_t mnNAILen, + AAA_HashEntry *NaiEntry) +{ + MessageHdr *msgHdr; + regRequest *requestPtr; + uint32_t revtun; + int code = 0; + + mipverbose(("Processing OpenSessionAnswer for RADIUS (FA Side)\n")); + + /* + * We are here after seeing that the FA received a positive response + * from the RADIUS server. That completes the auth check for the MN + * which is attempting to register through this FA. Now we need to go + * back and forward this registration request to HA. + * + * We shouldn't get any lifetime info from Radius server. FA has been + * advertising the lifetime value it's willing to support. It has also + * already rejected if MN was asking more than that. Now Radius server + * coming along and forcing FA to lower the lifetime doesn't make sense, + * and not compliant with RFC2002. + * + * If we use this function for HA, it's a different story. Radius has + * the authority to dictate lifetime. + */ + + /* + * Let's make sure this is not a replay of an already recevied + * OpenSessionAnswer. If we had freed the msgHdr before, that means + * this is a replay (not necessarily an attack :). + */ + (void) rw_rdlock(&(NaiEntry->aaaNodeLock)); + msgHdr = (MessageHdr *)NaiEntry->messageHdr; + if (msgHdr == NULL) { + mipverbose(("This was a repeat OpenSessionAnswer\n")); + (void) rw_unlock(&NaiEntry->aaaNodeLock); + return; + } + + /* REV_TUN */ + if (!aaaFindAvpInt(packet, REV_TUN, (int *)&revtun) || + (revtun != REVTUN_REQUIRED && revtun != REVTUN_NOTREQUIRED)) { + syslog(LOG_ERR, + "ERROR: OpenSessionAnswer (no or bad REV_TUN)"); + if (revtun != 0) { + syslog(LOG_ERR, + "ERROR: OpenSessionAnswer bad REV_TUN value %d\n", + revtun); + } else { + syslog(LOG_ERR, + "ERROR: OpenSessionAnswer (no REV_TUN)"); + } + (void) rw_unlock(&NaiEntry->aaaNodeLock); + return; + } + /* + * Check if revtun value matches with T bit value of request. + * FAprocessRegRequest already checks first whether + * FA supports Reverse tunnel when there is a request + * with T bit. According to IS-835, the rule for radius: + * revtun = 0; Reverse tunnel is not required + * revtun = 1; Reverse tunnel is required + * So, if FA is reverse tunnel capable, we allow reverse tunnel + * when revtun = REVTUN_NOTREQUIRED(0) and MN requests reverse tunnel + */ + mipverbose(("Radius returned REV_TUN value %d", revtun)); + /* LINTED */ + requestPtr = (regRequest *) msgHdr->pkt; + if (!(requestPtr->regFlags & REG_REVERSE_TUNNEL) && + revtun == REVTUN_REQUIRED) { + /* + * AAA recommends reverse tunnel for this MN, it must + * request reverse tunnel in registration request + */ + mipverbose(("Mobile node must request reverse tunnel\n")); + code = FA_REVERSE_TUNNEL_REQUIRED; + faCounters.faReverseTunnelRequiredCnt++; + } + /* Release Read lock now */ + (void) rw_unlock(&NaiEntry->aaaNodeLock); + + if (code == FA_REVERSE_TUNNEL_REQUIRED) { + FaVisitorEntry *visitor_entry = NULL; + + (void) rw_wrlock(&NaiEntry->aaaNodeLock); + (void) rejectFromFAToMN(msgHdr, msgHdr->ifEntry, code); + + /* Cleanup the pending visitor entry now */ + visitor_entry = findHashTableEntryString(&faVisitorHash, + (unsigned char *)mnNAI, mnNAILen, LOCK_WRITE, + mkPendingFAVEHashLookup, _B_FALSE, 0, 0); + if (visitor_entry != NULL) { + /* Pending entry found */ + delFAVE(&faVisitorHash, &visitor_entry, + requestPtr->homeAddr, REG_REVOKED); + } + msgHdr->dontDeleteNow = _B_FALSE; + FreeMessageHdr(msgHdr); + NaiEntry->messageHdr = NULL; + (void) rw_unlock(&NaiEntry->aaaNodeLock); + return; + } + + + (void) forwardFromFAToHA(msgHdr, msgHdr->ifEntry, _B_TRUE); + + /* + * Now we are done with the messageHdr stored in NaiEntry, let's + * free it, as we promised before. + */ + (void) rw_wrlock(&NaiEntry->aaaNodeLock); + msgHdr->dontDeleteNow = _B_FALSE; + FreeMessageHdr(msgHdr); + NaiEntry->messageHdr = NULL; + (void) rw_unlock(&NaiEntry->aaaNodeLock); + +} /* processOpenSessionAnswerRadius */ + + +/* + * Function: processOpenSessionAnswerRadiusHA + * + * Arguments: AAA_Packet *packet, char *mnNAI, size_t mnNAILen, uint32_t + * resultCode + * + * Description: This function handles the message to the HA, from + * RADIUS client. + * + * Returns: void + */ +/* ARGSUSED */ +static void +processOpenSessionAnswerRadiusHA(AAA_Packet *packet, char *mnNAI, + size_t mnNAILen, AAA_HashEntry *NaiEntry, uint32_t resultCode) +{ + static MessageHdr *messageHdr = NULL; + regRequest *requestPtr; + uint32_t sessionTimeout = 0; + uint32_t revtun; + uint32_t MNHASpi; + unsigned char *MNHAKey; + size_t MNHAKeyLen; + int code = 0; + + /* + * AVPs expected to receive: + * + * SESSION_TIMEOUT + * MN_HA_SPI + * MN_HA_KEY + * HOME AGENT ADDRESS + * Mobile Node Home Address + */ + mipverbose(("Processing OpenSessionAnswer for RADIUS (HA Side)\n")); + + /* + * Let's make sure this is not a replay of an already recevied + * OpenSessionAnswer. If we had freed the messsageHdr before, that means + * this is a replay (not necessarily an attack :). + */ + (void) rw_rdlock(&(NaiEntry->aaaNodeLock)); + messageHdr = (MessageHdr *)NaiEntry->messageHdr; + if (messageHdr == NULL) { + mipverbose(("This was a repeat OpenSessionAnswer\n")); + (void) rw_unlock(&NaiEntry->aaaNodeLock); + return; + } + (void) rw_unlock(&NaiEntry->aaaNodeLock); + + /* Check the SessionTimeout */ + if (!aaaFindAvpInt(packet, SESSION_TIMEOUT, (int *)&sessionTimeout)) { + /* BAD error . . . malformed packet */ + syslog(LOG_ERR, "ERROR: bad packet (no SESSION_TIMEOUT)"); + code = HA_MN_AUTH_FAILURE; + } + + /* MN-HA Spi */ + if (!aaaFindAvpInt(packet, MN_HA_SPI, (int *)&MNHASpi)) { + syslog(LOG_ERR, "ERROR: bad packet (no MN_HA_SPI)"); + code = HA_MN_AUTH_FAILURE; + } + /* MN-HA Key */ + MNHAKey = aaaFindAvpPtr(packet, MN_HA_KEY, &MNHAKeyLen); + if (!MNHAKey || !MNHAKeyLen) { + syslog(LOG_ERR, "ERROR: bad packet (no MN_HA_KEY)"); + code = HA_MN_AUTH_FAILURE; + } + + /* REV_TUN */ + if (!aaaFindAvpInt(packet, REV_TUN, (int *)&revtun) || + (revtun != REVTUN_REQUIRED && revtun != REVTUN_NOTREQUIRED)) { + syslog(LOG_ERR, + "ERROR: bad packet (no or bad REV_TUN from RADIUS)"); + if (revtun != 0) { + syslog(LOG_ERR, + "ERROR: REV_TUN value %d\n", revtun); + } else { + syslog(LOG_ERR, + "ERROR: (no REV_TUN from RADIUS)"); + } + code = HA_MN_AUTH_FAILURE; + } else { + mipverbose(("processOpenSessionAnswerHA:" + "HA received reverse tunnel value from RADIUS %d\n", + revtun)); + /* Found valid revtun entry */ + (void) rw_rdlock(&NaiEntry->aaaNodeLock); + /* LINTED */ + requestPtr = (regRequest *) messageHdr->pkt; + if (!(requestPtr->regFlags & REG_REVERSE_TUNNEL) && + revtun == REVTUN_REQUIRED) { + mipverbose(("processOpenSessionAnswerHA:" + "T bit required in regRequest\n")); + code = HA_REVERSE_TUNNEL_REQUIRED; + } + (void) rw_unlock(&NaiEntry->aaaNodeLock); + } + + if (aaaCreateKey(MNHASpi, MNHAKey, MNHAKeyLen, sessionTimeout) < 0) { + syslog(LOG_ERR, "Error: Invalid MN-HA SPI/Key pair"); + code = HA_MN_AUTH_FAILURE; + } + + if (code == 0) + code = resultCode; /* resultCode is from pkt from Radius */ + + (void) rw_wrlock(&NaiEntry->aaaNodeLock); + messageHdr->pktSource = MIP_PKT_FROM_RADIUS; + messageHdr->ifType = ON_UNICAST_SOCK; + messageHdr->pktType = PKT_UDP; + messageHdr->aaaResultCode = code; + + messageHdr->mnAAASPI = 0; + messageHdr->algorithm = MD5; + messageHdr->mnHaSPI = MNHASpi; + (void) memcpy(messageHdr->mnHaKey, MNHAKey, MNHAKeyLen); + messageHdr->mnHaKeyLen = MNHAKeyLen; + + messageHdr->aaaSessionTimeout = sessionTimeout; + + (void) rw_unlock(&NaiEntry->aaaNodeLock); + + /* + * Dispatch the message! + */ + (void) dispatchMsgToThread(&messageHdr); +} /* processOpenSessionAnswerRadiusHA */ + +/* + * Function: processOpenSessionIndication + * + * Arguments: AAA_Packet *packet, char *mnNAI, size_t mnNAILen + * + * Description: This routine will handle the OPEN_SESSION_INDICATION message. + * (The message from Diameter to the Home Agent) + * + * Returns: void + */ +static void +processOpenSessionIndication(AAA_Packet *packet, char *mnNAI, size_t mnNAILen) +{ + static MessageHdr *messageHdr = NULL; + unsigned char *regReq; + size_t regReqLen; + char *faNai; + size_t faNaiLen; + ipaddr_t homeAddress, homeAgentAddress, foreignAgentAddress; + uint32_t sessionTimeout; + uint32_t FAHASpi, MNHASpi; + unsigned char *MNFAKey; + size_t MNFAKeyLen; + unsigned char *MNHAKey; + size_t MNHAKeyLen; + /* These are encrypted versions of the above */ + unsigned char *HAFAKey; + size_t HAFAKeyLen; + unsigned char *HAMNKey; + size_t HAMNKeyLen; + + /* + * Initialize hash on HA side. + */ + /* Check to see if we are initialized */ + if (!gbl_hashInitialized) { + (void) InitHash(&naiHash); + naiHash.uniqueData = 1; /* Set our unique flag */ + gbl_hashInitialized = 1; + } + + (void) hexdump("Got message:", (unsigned char *)packet, + ntohl(packet->length)); + + /* FOREIGN_AGENT_NAI */ + faNai = aaaFindAvpPtr(packet, FOREIGN_AGENT_NAI, &faNaiLen); + if (!faNai || !faNaiLen) { + syslog(LOG_ERR, "ERROR: bad packet (no FOREIGN_AGENT_NAI)"); + aaaSendErrorResponse(MOBILE_IP_OPEN_SESSION_INDICATION_RESPONSE, + -1, mnNAI, mnNAILen, packet->handle); + return; + } + + /* REGISTRATION_REQUEST */ + regReq = aaaFindAvpPtr(packet, REGISTRATION_REQUEST, ®ReqLen); + if (!regReq || !regReqLen) { + syslog(LOG_ERR, "ERROR: bad packet (no REGISTRATION_REQUEST)"); + aaaSendErrorResponse(MOBILE_IP_OPEN_SESSION_INDICATION_RESPONSE, + -2, mnNAI, mnNAILen, packet->handle); + return; + } + + /* MOBILE_NODE_HOME_ADDRESS */ + if (!aaaFindAvpInt(packet, MOBILE_NODE_HOME_ADDRESS, + (int *)&homeAddress)) { + syslog(LOG_ERR, + "ERROR: bad packet (no MOBILE_NODE_HOME_ADDRESS)"); + aaaSendErrorResponse(MOBILE_IP_OPEN_SESSION_INDICATION_RESPONSE, + -3, mnNAI, mnNAILen, packet->handle); + return; + } + + /* HOME_AGENT_ADDRESS */ + if (!aaaFindAvpInt(packet, + HOME_AGENT_ADDRESS, (int *)&homeAgentAddress)) { + syslog(LOG_ERR, "ERROR: bad packet (no HOME_AGENT_ADDRESS)"); + aaaSendErrorResponse(MOBILE_IP_OPEN_SESSION_INDICATION_RESPONSE, + -4, mnNAI, mnNAILen, packet->handle); + return; + } + + /* FOREIGN_AGENT_ADDRESS */ + if (!aaaFindAvpInt(packet, FOREIGN_AGENT_ADDRESS, + (int *)&foreignAgentAddress)) { + syslog(LOG_ERR, + "ERROR: bad packet (no FOREIGN_AGENT_ADDRESS)"); + aaaSendErrorResponse(MOBILE_IP_OPEN_SESSION_INDICATION_RESPONSE, + -5, mnNAI, mnNAILen, packet->handle); + return; + } + + /* FA-HA Spi */ + if (!aaaFindAvpInt(packet, FA_HA_SPI, (int *)&FAHASpi)) { + syslog(LOG_ERR, "ERROR: bad packet (no " + "FA_HA_SPI)"); + aaaSendErrorResponse(MOBILE_IP_OPEN_SESSION_INDICATION_RESPONSE, + -6, mnNAI, mnNAILen, packet->handle); + return; + } + + /* HA-FA Key */ + HAFAKey = aaaFindAvpPtr(packet, HA_FA_KEY, &HAFAKeyLen); + if (!HAFAKey || !HAFAKeyLen) { + syslog(LOG_ERR, "ERROR: bad packet (no HA_FA_KEY)"); + aaaSendErrorResponse(MOBILE_IP_OPEN_SESSION_INDICATION_RESPONSE, + -8, mnNAI, mnNAILen, packet->handle); + return; + } + + + /* MN-FA Key */ + MNFAKey = aaaFindAvpPtr(packet, MN_FA_KEY, &MNFAKeyLen); + if (!MNFAKey || !MNFAKeyLen) { + syslog(LOG_ERR, "ERROR: bad packet (no MN_FA_KEY)"); + aaaSendErrorResponse(MOBILE_IP_OPEN_SESSION_INDICATION_RESPONSE, + -10, mnNAI, mnNAILen, packet->handle); + return; + } + /* MN-HA Spi */ + if (!aaaFindAvpInt(packet, MN_HA_SPI, (int *)&MNHASpi)) { + syslog(LOG_ERR, "ERROR: bad packet (no MN_HA_SPI)"); + aaaSendErrorResponse(MOBILE_IP_OPEN_SESSION_INDICATION_RESPONSE, + -12, mnNAI, mnNAILen, packet->handle); + return; + } + /* MN-HA Key */ + MNHAKey = aaaFindAvpPtr(packet, MN_HA_KEY, &MNHAKeyLen); + if (!MNHAKey || !MNHAKeyLen) { + syslog(LOG_ERR, "ERROR: bad packet (no MN_HA_KEY)"); + aaaSendErrorResponse(MOBILE_IP_OPEN_SESSION_INDICATION_RESPONSE, + -13, mnNAI, mnNAILen, packet->handle); + return; + } + /* HA-MN Key */ + HAMNKey = aaaFindAvpPtr(packet, HA_MN_KEY, &HAMNKeyLen); + if (!HAMNKey || !HAMNKeyLen) { + syslog(LOG_ERR, "ERROR: bad packet (no HA_MN_KEY)"); + aaaSendErrorResponse(MOBILE_IP_OPEN_SESSION_INDICATION_RESPONSE, + -14, mnNAI, mnNAILen, packet->handle); + return; + } + + /* Session Timeout */ + if (!aaaFindAvpInt(packet, SESSION_TIMEOUT, (int *)&sessionTimeout)) { + /* BAD error . . . malformed packet */ + syslog(LOG_ERR, "ERROR: bad packet (no SESSION_TIMEOUT)"); + aaaSendErrorResponse(MOBILE_IP_OPEN_SESSION_INDICATION_RESPONSE, + -15, mnNAI, mnNAILen, packet->handle); + return; + } + + /* + * + * Add NAI to hash on home agent side so accounting messages + * can be generated. + */ + (void) addNaiToHash(mnNAI, mnNAILen, NULL, 0, homeAddress, + homeAgentAddress, messageHdr); + + /* + * Create our keys + */ + if (aaaCreateKey(FAHASpi, HAFAKey, HAFAKeyLen, sessionTimeout) < 0) { + syslog(LOG_ERR, "Error: Invalid FA-HA SPI/Key pair"); + aaaSendErrorResponse(MOBILE_IP_OPEN_SESSION_INDICATION_RESPONSE, + -17, mnNAI, mnNAILen, packet->handle); + return; + } + + if (aaaCreateKey(MNHASpi, HAMNKey, HAMNKeyLen, sessionTimeout) < 0) { + syslog(LOG_ERR, "Error: Invalid MN-HA SPI/Key pair"); + aaaSendErrorResponse(MOBILE_IP_OPEN_SESSION_INDICATION_RESPONSE, + -18, mnNAI, mnNAILen, packet->handle); + return; + } + aaaCreateAgent(packet, HOME_AGENT_ADDRESS, FAHASpi, sessionTimeout); + + /* + * If we don't already have a message header, + * allocate one. + */ + if (messageHdr == NULL) { + if ((messageHdr = AllocateMessageHdr()) == NULL) { + syslog(LOG_CRIT, + "Unable to allocate a message header"); + aaaSendErrorResponse( + MOBILE_IP_OPEN_SESSION_INDICATION_RESPONSE, + -19, mnNAI, mnNAILen, packet->handle); + return; + } + } + aaaSetupMessageHdr(messageHdr, 0); + (void) memcpy(messageHdr->pkt, regReq, regReqLen); + messageHdr->pktLen = regReqLen; + + /* Don't worry about byte ordering this. */ + messageHdr->messageHandle = packet->handle; + + /* Copy our fa NAI */ + messageHdr->faNAI = malloc(faNaiLen + 1); + if (messageHdr->faNAI == NULL) { + syslog(LOG_CRIT, + "Unable to allocate a faNAI in message header"); + aaaSendErrorResponse( + MOBILE_IP_OPEN_SESSION_INDICATION_RESPONSE, + -20, faNai, faNaiLen, packet->handle); + return; + } + + (void) memcpy(messageHdr->faNAI, faNai, faNaiLen); + messageHdr->faNAI[faNaiLen] = 0; /* Drop the null */ + messageHdr->faNAILen = faNaiLen; + + messageHdr->mnAAASPI = 0; /* WORK - PRC - where do we get this */ + messageHdr->algorithm = MD5; + messageHdr->mnHaSPI = MNHASpi; + (void) memcpy(messageHdr->mnHaKey, MNHAKey, MNHAKeyLen); + messageHdr->mnHaKeyLen = MNHAKeyLen; + + (void) memcpy(messageHdr->mnFaKey, MNFAKey, MNFAKeyLen); + messageHdr->mnFaKeyLen = MNFAKeyLen; + + + messageHdr->faHaSPI = FAHASpi; + + messageHdr->aaaSessionTimeout = sessionTimeout; + /* + * Dispatch the message! + */ + (void) dispatchMsgToThread(&messageHdr); +} /* processOpenSessionIndication */ + +/* + * Function: processAuthFailure + * + * Arguments: + * MessageHdr * - pointer to message hdr + * mnNAI - nai + * mnNAILen - nai len + * result - result code returned by RADIUS + * + * Description: This function will handle a failure. (will send an error) + * + * Returns: void + */ +static void +processAuthFailure(MessageHdr *msgHdr, char *mnNAI, size_t mnNAILen, + uint32_t result) +{ + uint32_t code; + + syslog(LOG_ERR, "Error: processAuthFailure: %*.*", + mnNAILen, mnNAILen, mnNAI); + + switch (result) { + case MIP_ADMINISTRATIVELY_PROHIBITED: + code = FA_ADM_PROHIBITED; + break; + case MIP_INSUFFICIENT_RESOURCES: + code = FA_INSUFFICIENT_RESOURCES; + break; + case MIP_FAILED_AUTHENTICATION: + code = FA_MN_AUTH_FAILURE; + break; + case MIP_REASON_UNSPECIFIED: + default: + code = FA_REASON_UNSPECIFIED; + break; + } + + rejectFromFAToMN(msgHdr, msgHdr->ifEntry, code); + + +} /* processAuthFailure */ + +#ifdef TEST_DIAMETER +static void +aaaGenerateKey(unsigned char *key, size_t keyLen) +{ + static boolean_t initialized = _B_FALSE; + int32_t *intPtr; + int i; + + /* Seed the random number generator once */ + if (initialized == _B_FALSE) { + srand(time(NULL)); + initialized = _B_TRUE; + } + + if (keyLen % 4) { + syslog(LOG_ERR, + "ERROR: Key length must be a multiple of 4 (len = %d)", + keyLen); + } + + /* LINTED E_BAD_PTR_CAST_ALIGN */ + intPtr = (int32_t *)key; + + /* Build the key, 4 bytes at a time */ + for (i = 0; i < (keyLen / 4); i++) { + intPtr[i] = rand(); + } +} /* aaaGenerateKey */ + +static uint32_t +aaaGenerateSpi() +{ + static uint32_t SPI = 0x80000000; + return (SPI++); +} /* return a psuedo random spi */ +#endif /* TEST_DIAMETER */ + +/* + * Function: aaaSendRegistrationReply + * + * Arguments: MessageHdr *messageHdr + * + * Description: This function will lookup the relivant data, and send + * a response back to DIAMETER. This function is called from + * the HomeAgent, in response to a OpenSessionIndication. + * + * Returns: int + */ +int +aaaSendRegistrationReply(MessageHdr *messageHdr, size_t replyLen, + ipaddr_t homeAddress, ipaddr_t homeAgentAddress) +{ + unsigned char buffer[MAX_TCP_LEN]; + AAA_Packet *packet; + uint32_t length; + int resultCode = 0; /* WORK -- pass this in */ + + /* Check to see if we are initialized */ + if (!gbl_hashInitialized) { + (void) InitHash(&naiHash); + naiHash.uniqueData = 1; /* Set our unique flag */ + gbl_hashInitialized = 1; + } + + /* Build the message */ + /* LINTED E_BAD_PTR_CAST_ALIGN */ + packet = (AAA_Packet *)buffer; + packet->protocol = htonl(DIAMETER); + packet->commandCode = + htonl(MOBILE_IP_OPEN_SESSION_INDICATION_RESPONSE); + + packet->handle = messageHdr->messageHandle; + + length = sizeof (AAA_Packet); + + /* Add our AVPs */ + + /* Mobile Node NAI */ + length += aaaAddAvp(MOBILE_NODE_NAI, &buffer[length], + MAX_TCP_LEN - length, messageHdr->mnNAI, + messageHdr->mnNAILen); + + /* Foreign Agent NAI */ + length += aaaAddAvp(FOREIGN_AGENT_NAI, &buffer[length], + MAX_TCP_LEN - length, messageHdr->faNAI, + messageHdr->faNAILen); + + /* Registration Reply */ + length += aaaAddAvp(REGISTRATION_REPLY, &buffer[length], + MAX_TCP_LEN - length, messageHdr->pkt, + replyLen); + + /* Mobile Node Home Address */ + length += aaaAddAvp(MOBILE_NODE_HOME_ADDRESS, &buffer[length], + MAX_TCP_LEN - length, &homeAddress, + sizeof (ipaddr_t)); + + /* Home Agent Address */ + length += aaaAddAvp(HOME_AGENT_ADDRESS, &buffer[length], + MAX_TCP_LEN - length, &homeAgentAddress, + sizeof (ipaddr_t)); + + /* Session Timeout */ + length += aaaAddAvp(SESSION_TIMEOUT, &buffer[length], + MAX_TCP_LEN - length, &messageHdr->aaaSessionTimeout, + sizeof (uint32_t)); + + /* Result Code */ + length += aaaAddAvp(RESULT_CODE, &buffer[length], + MAX_TCP_LEN - length, &resultCode, + sizeof (uint32_t)); + + packet->length = htonl(length); + + return (sendTCPPacket(buffer, length)); +} /* sendRegistrationReply */ + +/* + * Function: AAAAuthenticateRegReq + * + * Arguments: + * + * Description: This function is called from the foreign agent. It is the + * first function that is called for a given mobile node, so + * we do all startup code here. (We add the entry to the + * hash.) + * + * Returns: int + * + */ +int +AAAAuthenticateRegReq(unsigned char *reqPtr, uint32_t reqLen, + unsigned char *mnNAI, size_t mnNAILen, uint32_t aaaSPI, + unsigned char *mnChallengeResponse, uint32_t mnChallengeResponseLen, + uint32_t mnChallengeLen, + ipaddr_t homeAddress, ipaddr_t homeAgentAddress, boolean_t isFromHA, + uint32_t inIfindex, void *messageHdr, unsigned char *MNFAChallengeValue, + uint32_t MNFAChallengeValueLen) +{ + unsigned char buffer[MAX_TCP_LEN]; + AAA_Packet *packet; + uint32_t length; + ipaddr_t faAddr; + uint32_t one = 1; + uint32_t zero = 0; + + + /* Check to see if we are initialized */ + if (!gbl_hashInitialized) { + (void) InitHash(&naiHash); + naiHash.uniqueData = 1; /* Set our unique flag */ + } + + /* Build the message */ + /* LINTED E_BAD_PTR_CAST_ALIGN */ + packet = (AAA_Packet *)buffer; + packet->protocol = htonl(aaaProtocol); + packet->commandCode = htonl(MOBILE_IP_OPEN_SESSION_REQUEST); + packet->handle = htonl(0); + + length = sizeof (AAA_Packet); + + /* Add our AVPs */ + + /* + * Radius server needs to know if this is coming from HA, + * in which case it'll send back the MN-HA key. + */ + if (aaaProtocol == RADIUS) { + length += aaaAddAvp(IS_FROM_HA, &buffer[length], + MAX_TCP_LEN - length, + (isFromHA) ? &one : &zero, sizeof (uint32_t)); + } + + /* Mobile Node NAI */ + length += aaaAddAvp(MOBILE_NODE_NAI, &buffer[length], + MAX_TCP_LEN - length, mnNAI, mnNAILen); + + /* Foreign Agent NAI */ + length += aaaAddAvp(FOREIGN_AGENT_NAI, &buffer[length], + MAX_TCP_LEN - length, maNai, strlen(maNai)); + + /* Foreign Agent Address */ + faAddr = getClosestInterfaceAddr(homeAgentAddress); + length += aaaAddAvp(FOREIGN_AGENT_ADDRESS, &buffer[length], + MAX_TCP_LEN - length, &faAddr, sizeof (uint32_t)); + + /* Registration Request Packet */ + length += aaaAddAvp(REGISTRATION_REQUEST, &buffer[length], + MAX_TCP_LEN - length, reqPtr, reqLen); + + /* Challenge Bytes */ + length += aaaAddAvp(NUMBER_OF_CHALLENGE_BYTES_IN_RR, + &buffer[length], MAX_TCP_LEN - length, + &mnChallengeLen, sizeof (uint32_t)); + + /* Mobile Node Response */ + length += aaaAddAvp(MOBILE_NODE_RESPONSE, + &buffer[length], MAX_TCP_LEN - length, + mnChallengeResponse, mnChallengeResponseLen); + + + /* Mobile Node Home Address */ + length += aaaAddAvp(MOBILE_NODE_HOME_ADDRESS, &buffer[length], + MAX_TCP_LEN - length, &homeAddress, sizeof (uint32_t)); + + /* Home Agent Address */ + length += aaaAddAvp(HOME_AGENT_ADDRESS, &buffer[length], + MAX_TCP_LEN - length, &homeAgentAddress, sizeof (uint32_t)); + + /* MN-AAA SPI */ + length += aaaAddAvp(MN_AAA_SPI, &buffer[length], + MAX_TCP_LEN - length, &aaaSPI, sizeof (uint32_t)); + + /* Radius needs MN-FA Challenge Value for authentication */ + if (aaaProtocol == RADIUS) { + length += aaaAddAvp(MN_FA_CHALLENGE_VALUE, &buffer[length], + MAX_TCP_LEN - length, MNFAChallengeValue, + MNFAChallengeValueLen); + } + + /* MN_HANDLE (only send if from FA in which case inIfindex is nonzero */ + if (inIfindex != 0) { + length += aaaAddAvp(MN_HANDLE, &buffer[length], + MAX_TCP_LEN - length, &inIfindex, sizeof (uint32_t)); + } + + packet->length = htonl(length); + + /* Add entry to hash */ + if (addNaiToHash((char *)mnNAI, mnNAILen, mnChallengeResponse, + mnChallengeResponseLen, homeAddress, homeAgentAddress, + messageHdr)) { + /* Error! */ + return (-1); + } + return (sendTCPPacket(buffer, length)); +} /* AAAAuthenticateRegReq */ + +/* + * Function: sendCloseSession + * + * Arguments: AAA_Packet *packet, unsigned char *nai, size_t naiLen + * + * Description: This function will send the CLOSE_SESSION message + * to AAA server. It is called by the main thread when an + * MOBILE_IP_ACCOUNTING_STOP_ANSWER is received. + * + * Returns: int + */ +static int +sendCloseSession(AAA_Packet *srcPacket, char *mnNAI, size_t mnNAILen) +{ + unsigned char buffer[MAX_TCP_LEN]; + AAA_Packet *destPacket; + size_t length; + int32_t handle; + char *faNai; + size_t faNaiLen; + ipaddr_t homeAgentAddress, homeAddress; + uint32_t sessionTime; + + /* Lookup the NAI to make sure it exists. */ + handle = aaaLookupHandle(mnNAI, mnNAILen); + if (handle < 0) { + syslog(LOG_ERR, "Error: NAI not found!"); + return (handle); + } + + /* Retrieve Our Fields */ + faNai = (char *)aaaFindAvpPtr(srcPacket, FOREIGN_AGENT_NAI, &faNaiLen); + if (!faNai) { + syslog(LOG_ERR, "Error: Foreign Agent NAI not found!"); + return (-1); + } + + if (!aaaFindAvpInt(srcPacket, MOBILE_NODE_HOME_ADDRESS, + (int *)&homeAddress)) { + syslog(LOG_ERR, "Error: Home Address not found!"); + return (-1); + } + if (!aaaFindAvpInt(srcPacket, HOME_AGENT_ADDRESS, + (int *)&homeAgentAddress)) { + syslog(LOG_ERR, "Error: Home Agent Address not found!"); + return (-1); + } + if (!aaaFindAvpInt(srcPacket, SESSION_TIME, (int *)&sessionTime)) { + syslog(LOG_ERR, "Error: Session Time not found!"); + return (-1); + } + + /* Build the message */ + /* LINTED E_BAD_PTR_CAST_ALIGN */ + destPacket = (AAA_Packet *)buffer; + destPacket->protocol = htonl(aaaProtocol); + destPacket->commandCode = htonl(MOBILE_IP_CLOSE_SESSION_REQUEST); + destPacket->handle = htonl(handle); + + length = sizeof (AAA_Packet); + + /* Add our AVPs */ + /* Mobile Node NAI */ + length += aaaAddAvp(MOBILE_NODE_NAI, &buffer[length], + MAX_TCP_LEN - length, mnNAI, mnNAILen); + + /* Foreign Agent NAI */ + length += aaaAddAvp(FOREIGN_AGENT_NAI, &buffer[length], + MAX_TCP_LEN - length, faNai, faNaiLen); + + /* Mobile Node Home Address */ + length += aaaAddAvp(MOBILE_NODE_HOME_ADDRESS, &buffer[length], + MAX_TCP_LEN - length, &homeAddress, sizeof (uint32_t)); + + /* Home Agent Address */ + length += aaaAddAvp(HOME_AGENT_ADDRESS, &buffer[length], + MAX_TCP_LEN - length, &homeAgentAddress, sizeof (uint32_t)); + + /* Mobile Node Session Time */ + length += aaaAddAvp(SESSION_TIME, &buffer[length], + MAX_TCP_LEN - length, &sessionTime, sizeof (uint32_t)); + + destPacket->length = htonl(length); + + return (sendTCPPacket(buffer, length)); +} /* sendCloseSession */ + +static int +sendCloseSessionAnswer(AAA_Packet *srcPacket, char *mnNAI, size_t mnNAILen, + boolean_t result) +{ + unsigned char buffer[MAX_TCP_LEN]; + AAA_Packet *destPacket; + size_t length; + uint32_t resultCode; + + /* LINTED */ + destPacket = (AAA_Packet *)buffer; + destPacket->protocol = htonl(srcPacket->protocol); + destPacket->commandCode = htonl(MOBILE_IP_CLOSE_SESSION_ANSWER); + destPacket->handle = srcPacket->handle; + + length = sizeof (AAA_Packet); + + /* Add our AVPs */ + + /* Mobile Node NAI */ + length += aaaAddAvp(MOBILE_NODE_NAI, &buffer[length], + MAX_TCP_LEN - length, mnNAI, mnNAILen); + + /* Result code */ + resultCode = result ? 0 : 1; + length += aaaAddAvp(RESULT_CODE, &buffer[length], MAX_TCP_LEN - length, + &resultCode, sizeof (uint32_t)); + + destPacket->length = htonl(length); + + return (sendTCPPacket(buffer, length)); +} + + + + +/* + * Function: sendAccountingRecord + * + * Arguments: commandCode record, unsigned char *mnNAI, size_t mnNAILen, + * ipaddr_t homeAddr, ipaddr_t coaAddr, + * ipaddr_t homeAgentAddr, int32_t sessionLifetime) + * + * Description: This function will send an accounting start record. + * ToDo: coaAddr is specified in this function calls' prototype, + * but it is not in the diameter api protocol. (PRC TODO) + * + * Returns: int + * + */ +int +sendAccountingRecord(AAA_CommandCode code, unsigned char *mnNAI, + /* LINTED E_FUNC_ARG_UNUSED */ + size_t mnNAILen, ipaddr_t homeAddress, ipaddr_t coaAddr, + ipaddr_t homeAgentAddress, uint32_t sessionTime, int32_t relindicator) +{ + unsigned char buffer[MAX_TCP_LEN]; + AAA_Packet *packet; + uint32_t length; + int32_t handle; + + /* Lookup the NAI to make sure it exists. */ + handle = aaaLookupHandle((char *)mnNAI, mnNAILen); + if (handle < 0) { + syslog(LOG_ERR, "Error: NAI not found!"); + return (handle); + } + + switch (code) { + /* These codes are good */ + case MOBILE_IP_ACCOUNTING_START_REQUEST: + case MOBILE_IP_ACCOUNTING_INTERIM_REQUEST: + case MOBILE_IP_ACCOUNTING_STOP_REQUEST: + break; + /* Everything else is an error */ + default: + syslog(LOG_ERR, "ERROR: invalid code passed to " + "sendAccountingRecord (%d)", code); + return (-1); + } /* switch code */ + + /* Build the message */ + /* LINTED E_BAD_PTR_CAST_ALIGN */ + packet = (AAA_Packet *)buffer; + packet->protocol = htonl(aaaProtocol); + packet->commandCode = htonl(code); + packet->handle = htonl(handle); + + length = sizeof (AAA_Packet); + + /* Add our AVPs */ + + /* Mobile Node NAI */ + length += aaaAddAvp(MOBILE_NODE_NAI, &buffer[length], + MAX_TCP_LEN - length, mnNAI, mnNAILen); + + /* Foreign Agent NAI */ + length += aaaAddAvp(FOREIGN_AGENT_NAI, &buffer[length], + MAX_TCP_LEN - length, maNai, strlen(maNai)); + + /* Mobile Node Home Address */ + length += aaaAddAvp(MOBILE_NODE_HOME_ADDRESS, &buffer[length], + MAX_TCP_LEN - length, &homeAddress, sizeof (uint32_t)); + + /* Home Agent Address */ + length += aaaAddAvp(HOME_AGENT_ADDRESS, &buffer[length], + MAX_TCP_LEN - length, &homeAgentAddress, sizeof (uint32_t)); + + /* Mobile Node Session Time */ + length += aaaAddAvp(SESSION_TIME, &buffer[length], + MAX_TCP_LEN - length, &sessionTime, sizeof (uint32_t)); + + /* Release Indicator (RADIUS ONLY) */ + if (aaaProtocol == RADIUS) { + length += aaaAddAvp(RELEASE_INDICATOR, &buffer[length], + MAX_TCP_LEN - length, &relindicator, sizeof (uint32_t)); + } + packet->length = htonl(length); + + return (sendTCPPacket(buffer, length)); + +} /* sendAccountingRecord */ + +void +aaaSendErrorResponse(uint32_t commandCode, int32_t returnCode, char *mnNAI, + size_t mnNAILen, uint32_t handle) +{ + unsigned char buffer[MAX_TCP_LEN]; + AAA_Packet *packet; + uint32_t length; + + /* + * If we don't already have a handle, look for it. + */ + if (handle == 0) { + /* Lookup the NAI to make sure it exists. */ + handle = aaaLookupHandle(mnNAI, mnNAILen); + if (((int)handle) < 0) { + syslog(LOG_ERR, "Error: NAI not found!"); + handle = 0; + } + } + + /* Build the message */ + /* LINTED E_BAD_PTR_CAST_ALIGN */ + packet = (AAA_Packet *)buffer; + /* this function is only used for DIAMETER */ + packet->protocol = htonl(DIAMETER); + packet->commandCode = htonl(commandCode); + packet->handle = htonl(handle); + + length = sizeof (AAA_Packet); + + /* Mobile Node NAI */ + length += aaaAddAvp(MOBILE_NODE_NAI, &buffer[length], + MAX_TCP_LEN - length, mnNAI, mnNAILen); + + /* resultCode */ + length += aaaAddAvp(RESULT_CODE, &buffer[length], + MAX_TCP_LEN - length, &returnCode, sizeof (uint32_t)); + + packet->length = htonl(length); + + /* Send packet */ + (void) sendTCPPacket(buffer, length); +} /* aaaSendErrorResponse */ + +/* + * Function: initTCPSocket + * + * Arguments: in_port_t port + * + * Description: This routine binds a TCP socket to the specified port. + * + * Returns: int (the socket fd) + * + */ +static int +initTCPSocket(in_port_t port) +{ + struct sockaddr_in sin; + int sinLength; + static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + int rc; + + /* + * Make sure only one thread at a time executes this code. + */ + + rc = pthread_mutex_lock(&lock); + if (rc < 0) { + /* Wierd error! */ + syslog(LOG_CRIT, "initTCPSocket: Error: Unable to lock mutex!"); + return (-1); + } + + if (gbl_TCPSocket != -1) { + /* We are already initialized. Exit */ + syslog(LOG_WARNING, + "initTCPSocket: Warning: socket already initialized"); + (void) pthread_mutex_unlock(&lock); + return (gbl_TCPSocket); + } + + /* + * Get a socket. + */ + if ((gbl_TCPSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + syslog(LOG_CRIT, + "initTCPSocket: socket failed (%d:%s)", errno, + strerror(errno)); + gbl_TCPSocket = -1; + (void) pthread_mutex_unlock(&lock); + return (gbl_TCPSocket); + } + + /* + * Initialize the sockaddr. + */ + sinLength = sizeof (struct sockaddr_in); + (void) memset((char *)&sin, '\0', sinLength); + + /* + * Get server's listening port number + */ + sin.sin_port = htons(port); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = inet_addr(gbl_aaaHost); + + if (connect(gbl_TCPSocket, (struct sockaddr *)&sin, sinLength) < 0) { + syslog(LOG_ERR, + "initTCPSocket: connect failed (%d:%s)", errno, + strerror(errno)); + (void) close(gbl_TCPSocket); + gbl_TCPSocket = -1; + (void) pthread_mutex_unlock(&lock); + return (gbl_TCPSocket); + } + + /* + * If connected, advBusy flag should be set to True. + * This code will only be invoked when the connection + * is first started or a reconnection happens. Thus, + * advBusy can be set/unset for other future purposes + * in mipagent. + */ + if (advBusy == _B_TRUE) { + enableService(); + } + + /* Success! */ + (void) pthread_mutex_unlock(&lock); + return (gbl_TCPSocket); + +} /* initTCPSocket */ + + +/* + * Function: sendTCPPacket + * + * Arguments: buffer, length + * + * Description: Sends the buffer on the TCP socket, and adds it to the queue + * + * Returns: int (zero on success) + * + */ +static int +sendTCPPacket(unsigned char *buffer, uint32_t length) +{ + + int rc; + + /* Make sure the socket is open */ + if (gbl_TCPSocket == -1) { + (void) initTCPSocket(gbl_aaaPort); + if (gbl_TCPSocket == -1) { + return (-1); + } + } + + /* finally, send it */ + do { + rc = send(gbl_TCPSocket, buffer, length, 0); + } while ((rc == -1) && (errno == EINTR)); + + if (rc < 0) { + syslog(LOG_ERR, "sendTCPPacket: Error: send: !(%d:%s)", errno, + strerror(errno)); + (void) close(gbl_TCPSocket); + gbl_TCPSocket = -1; /* Force a re-connect */ + return (rc); + } + return (0); +} /* sendTCPPacket */ + +/* + * Function: readTCPPacket + * + * Arguments: unsigned char *buffer, uint32_t bufLen + * + * Description: Reads from the socket, ignoring EINTR, until a record is + * read. If it gets an error, it closes the socket, which will + * be re-opened on the next read or write. + * + * Returns: int + */ +static int +readTCPPacket(unsigned char *buffer, uint32_t bufLen) +{ + int rc; + + /* Make sure the socket is open */ + if (gbl_TCPSocket == -1) { + (void) initTCPSocket(gbl_aaaPort); + if (gbl_TCPSocket == -1) { + return (-1); + } + } + + /* Read, ignoring EINTRs */ + do { + rc = recv(gbl_TCPSocket, buffer, bufLen, 0); + } while ((rc == -1) && (errno == EINTR)); + + if (rc == -1) { + syslog(LOG_ERR, "Error %d reading socket (%d:%s)", rc, errno, + strerror(errno)); + (void) close(gbl_TCPSocket); + gbl_TCPSocket = -1; /* Force a re-connect */ + } + + return (rc); +} /* readTCPPacket */ + + + + +#ifdef TEST_AAA + +#define TEST_NAI1 "test@sun.com" +#define TEST_NAI2 "test2@sun.com" +#define FA_NAI "foreignAgent@agents.everywhere.com" + +int +main(int argc, char *argv[]) +{ + int rc; + unsigned char reqPtr[] = { + /* Just some random data for testing */ + 0x1, 0x3, 0x1, 0x3, 0x1, 0x3, 0x1, 0x3, 0x1, 0x3, + 0x1, 0x3, 0x1, 0x3, 0x1, 0x3, 0x1, 0x3, 0x1, 0x3, + 0x1, 0x3, 0x1, 0x3, 0x1, 0x3, 0x1, 0x3, 0x1, 0x3, + 0x1, 0x3 }; + unsigned char mnChallenge[] = { + 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa + }; + ipaddr_t homeAddress; + ipaddr_t homeAgentAddress; + + if (argc != 2) { + (void) fprintf(stderr, "USAGE: %s <port>\n", argv[0]); + return (-1); + } + + homeAddress = inet_addr("192.168.168.2"); + homeAgentAddress = inet_addr("192.168.168.1"); + gbl_aaaPort = (in_port_t)atoi(argv[1]); + + (void) strcpy(maNai, FA_NAI); + + if ((rc = startAAATaskThread()) != 0) { + (void) fprintf(stderr, + "Error: rc = %d when calling startAAATaskThread\n", + rc); + return (rc); + } + + rc = AAAAuthenticateRegReq(reqPtr, sizeof (reqPtr), + TEST_NAI1, strlen(TEST_NAI1), + mnChallenge, sizeof (mnChallenge), + homeAddress, homeAgentAddress, _B_FALSE, NULL); + if (rc != 0) { + (void) fprintf(stderr, + "Error: rc = %d when calling" + " AAAAuthenticatateRegReq\n", rc); + /* return (rc); */ + } + + rc = sendAccountingStartRecord((unsigned char *)TEST_NAI1, + strlen(TEST_NAI1), 0, 1, 2, 3); + if (rc != 0) { + (void) fprintf(stderr, + "Error: rc = %d when calling" + " sendAccountingStartRecord\n", + rc); + } + + (void) fprintf(stderr, "Sleeping for 1\n"); fflush(stderr); + (void) sleep(1); + rc = sendAccountingInterimRecord((unsigned char *)TEST_NAI1, + strlen(TEST_NAI1), 0, 1, 2, 3); + if (rc != 0) { + (void) fprintf(stderr, "Error: rc = %d when calling " + "sendAccountingInterimRecord\n", rc); + } + + rc = sendAccountingInterimRecord((unsigned char *)TEST_NAI2, + strlen(TEST_NAI1), 0, 1, 2, 3); + if (rc == 0) { + (void) fprintf(stderr, "Error: rc = %d when calling " + "sendAccountingInterimRecord\n", rc); + } + + rc = sendAccountingStopRecord((unsigned char *)TEST_NAI1, + strlen(TEST_NAI1), 0, 1, 2, 3); + if (rc != 0) { + (void) fprintf(stderr, "Error: rc = %d when calling " + "sendAccountingStopRecord\n", rc); + } + + (void) fprintf(stderr, "Sleeping for a sec . . . "); + (void) sleep(2); + (void) fprintf(stderr, + "Sending a straggling message . . . should be an error\n"); + rc = sendAccountingInterimRecord((unsigned char *)TEST_NAI1, + strlen(TEST_NAI1), 0, 1, 2, 3); + if (rc == 0) { + (void) fprintf(stderr, "Error: rc = %d when calling " + "sendAccountingInterimRecord\n", rc); + } + + (void) fprintf(stderr, "Thread hanging . . .\n"); fflush(stderr); + for (;;) { + (void) sleep(1); fflush(stderr); fflush(stdout); + } + + return (rc); +} /* main */ + +#endif /* TEST_AAA */ + +/* fin aaa.c */ diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/aaa.h b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/aaa.h new file mode 100644 index 0000000000..07b01cdad7 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/aaa.h @@ -0,0 +1,245 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999-2001 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ifndef _AAA_H +#define _AAA_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * aaa.h -- AAA defines and structures (Diameter interface) + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * If the following is defined, the foreign agent will communicate directly + * with the home agent, (using a proxy) but will still use the diameter API + * protocol. The only changes to the code will be the handling the different + * messages, and the generation of keys. + * + * #define TEST_DIAMETER + */ + +/* + * These constants are used to control where AAA looks for the diameter + * server. + */ +#define LOOPBACK "127.0.0.1" +#define AAA_PORT 769 +#define MAX_SERVER_NAME_LEN 1024 + +#ifndef MIN +#define MIN(x, y) (((x) > (y))?(y):(x)) +#endif + +/* + * Maximum lengths of NAIs and challenges + */ +#define MAX_NAI_LEN 256 +#define MAX_CHALLENGE_LEN 16 + +/* Max size of an incomming or outgoing tcp packet. */ +#define MAX_TCP_LEN 4096 + +/* biggest key to generate (for debug testing) */ +#define MAX_GENERATE_KEY_LEN 16 + +/* + * SPI values to be used with AAA protocols. + * Currently only Radius is used. + */ +#define RADIUS_SPI 2 + +/* + * Diameter API defines. (from the specification + */ +typedef enum { + MOBILE_IP_OPEN_SESSION_REQUEST = 1, /* 01 */ + MOBILE_IP_OPEN_SESSION_ANSWER, /* 02 */ + MOBILE_IP_OPEN_SESSION_INDICATION, /* 03 */ + MOBILE_IP_OPEN_SESSION_INDICATION_RESPONSE, /* 04 */ + MOBILE_IP_ACCOUNTING_START_REQUEST, /* 05 */ + MOBILE_IP_ACCOUNTING_START_ANSWER, /* 06 */ + MOBILE_IP_ACCOUNTING_INTERIM_REQUEST, /* 07 */ + MOBILE_IP_ACCOUNTING_INTERIM_ANSWER, /* 08 */ + MOBILE_IP_ACCOUNTING_STOP_REQUEST, /* 09 */ + MOBILE_IP_ACCOUNTING_STOP_ANSWER, /* 10 */ + MOBILE_IP_CLOSE_SESSION_REQUEST, /* 11 */ + MOBILE_IP_CLOSE_SESSION_ANSWER /* 12 */ +} AAA_CommandCode; + +typedef enum { + MOBILE_NODE_NAI = 1, /* 01 */ + FOREIGN_AGENT_NAI, /* 02 */ + REGISTRATION_REQUEST, /* 03 */ + NUMBER_OF_CHALLENGE_BYTES_IN_RR, /* 04 */ + MOBILE_NODE_RESPONSE, /* 05 */ + MOBILE_NODE_HOME_ADDRESS, /* 06 */ + HOME_AGENT_ADDRESS, /* 07 */ + RESULT_CODE, /* 08 */ + REGISTRATION_REPLY, /* 09 */ + MN_FA_SPI, /* 10 */ + MN_FA_KEY, /* 11 */ + FA_HA_SPI, /* 12 */ + FA_HA_KEY, /* 13 */ + SESSION_TIMEOUT, /* 14 */ + HA_FA_KEY, /* 15 */ + FA_MN_KEY, /* 16 */ + MN_HA_SPI, /* 17 */ + MN_HA_KEY, /* 18 */ + HA_MN_KEY, /* 19 */ + SESSION_TIMEOUT_1, /* 20 */ + SESSION_TIME, /* 21 */ + FOREIGN_AGENT_ADDRESS, /* 22 */ + MN_AAA_SPI, /* 23 */ + IS_FROM_HA, /* 24 */ + REV_TUN, /* 25 */ + MN_HANDLE, /* 26 */ + RELEASE_INDICATOR, /* 27 */ + MN_FA_CHALLENGE_VALUE /* 28 */ +} AAA_AVPCode; + +/* + * This structure is the header of a diameter API message. + * All items are sent in network-byte-ordering. + */ +typedef struct { + uint32_t protocol; + uint32_t commandCode; + uint32_t handle; + uint32_t length; +} AAA_Packet; + +/* + * AAA protocols API defines. (from the specification) + */ +typedef enum { + AAA_NONE = 0, /* 00 */ + DIAMETER, /* 01 */ + RADIUS /* 02 */ +} AAA_Protocol_Code; + +/* + * MIPResultCode is used in the protocol to communicate Mobile-IP + * specific errors. Per AAA specification. + */ +typedef enum { + MIP_SUCCESS = 0, + MIP_REASON_UNSPECIFIED = 1, + MIP_ADMINISTRATIVELY_PROHIBITED = 2, + MIP_INSUFFICIENT_RESOURCES = 3, + MIP_FAILED_AUTHENTICATION = 4 +} MIPResultCode; + +/* + * This structure refers to an Attribute Value Pair. The last field, data + * is really a place holder, rather than a data item. This structure is either + * allocated without a sizeof: malloc( sizeof(uint32_t) * 2 + dataLen), + * or it is used to point to the structure being returned: + * avpPtr = (AAA_AVP *)buffer; + * + * When this is used to point to a buffer, it can be moved along, byte by byte + * and the data place holder will be able to retrieve the data. This is + * necessary, since packets are variable length: + * + * + * Buffer: + * + * +-----------------------+ + * | Header | + * +-----------------------+ + * | First Record | + * | | + * |_________|-------------| + * | Second Record | + * |______________|--------| + * + * So, to parse the above, an AAA_AVP pointer would be set to the first record, + * the avpCode and Length would be read, and the data copied form the data + * portion of the record. Basically, this method is used so that the data + * Can be read as follows: + * + * AAA_Avp_p = (AAA_AVP *)&buffer[offset]; + * code = AAA_Avp_p->code; + * length = AAA_Avp_p->length); + * memcpy(data, AAA_Avp_p->data, length - (2 * sizeof (uint32_t)); + * offset += length; + * + * It could have also been done with pointer arrithmetic, but I thought it + * was harder to read/understand: + * + * code = *((uint32_t *)&buffer[offset]); + * ofset += sizeof (uint32_t); + * length = *((uint32_t *)&buffer[offset]); + * offset += sizeof (uint32_t); + * memcpy(data, &buffer[offset], length - (2 * sizeof (uint32_t)); + * offset += length; + * + * (by the way -- the above code does not take into account byte alignment or + * network byte ordering, so don't cut and paste from these comments!) + */ +typedef struct { + uint32_t avpCode; + uint32_t length; + unsigned char data[1]; +} AAA_AVP; + +/* This enum defines the current state of the hash node */ +typedef enum { + Initialized = 0, + WaitingForAuthorization, + Authorized +} AAA_State; + + +/* This structure is the structure that is kept in the hash */ +typedef struct { + rwlock_t aaaNodeLock; + int32_t handle; + char mnNAI[MAX_NAI_LEN]; + AAA_State State; + unsigned char mnChallenge[MAX_CHALLENGE_LEN]; + ipaddr_t homeAddress; + ipaddr_t homeAgentAddress; + uint32_t timeOut; + void *messageHdr; /* RegReq from MN, used for Radius */ +} AAA_HashEntry; + +int startAAATaskThread(); +int sendAccountingRecord(AAA_CommandCode, unsigned char *, uint32_t, + ipaddr_t, ipaddr_t, ipaddr_t, uint32_t, int32_t); +int AAAAuthenticateRegReq(unsigned char *, uint32_t, unsigned char *, + unsigned int, uint32_t, unsigned char *, uint32_t, uint32_t, ipaddr_t, + ipaddr_t, boolean_t, uint32_t, void *, unsigned char *, uint32_t); + +#ifdef __cplusplus +} +#endif + +#endif /* _AAA_H */ diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agent.c b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agent.c new file mode 100644 index 0000000000..e2c1521bcf --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agent.c @@ -0,0 +1,6816 @@ +/* + * 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 <sys/types.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 <arpa/inet.h> +#include <netinet/in.h> +#include <sys/wait.h> +#include <fcntl.h> +#include <sys/dlpi.h> +#include <stropts.h> +#include <netinet/ip.h> +#include <netinet/udp.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; + +int IDfreshnessSlack = DEFAULT_FRESHNESS_SLACK; +/* + * We no longer use regLifetime global + */ +int advLifetime = DEFAULT_MAX_ADV_TIME; +int periodicInterval = DEFAULT_GARBAGE_COLLECTION_INTERVAL; + +int visitorEntryHighWaterMark = DEFAULT_HIGH_VISITORS; +int visitorEntryLowWaterMark = DEFAULT_LOW_VISITORS; +int performanceInterval = 0; +boolean_t faNAIadv = _B_FALSE; /* Determines whether we advertise */ + /* our NAI */ +boolean_t faChallengeAdv = _B_FALSE; /* Determines whether we advertise */ + /* challenges */ +boolean_t mfAuthRequired = _B_FALSE; /* Is the MF Authentication Ext */ + /* Required? */ +boolean_t fhAuthRequired = _B_FALSE; /* Is the FH Authentication Ext */ + /* Required? */ +AAA_Protocol_Code aaaProtocol = AAA_NONE; /* AAA_NONE, DIAMETER, RADIUS */ + +boolean_t shutdown_flag = _B_FALSE; /* Are we shutting down? */ +boolean_t daemonize = _B_TRUE; /* By default, we are a daemon */ +boolean_t disableSNMP = _B_FALSE; /* By default, SNMP is enabled */ + +/* these are the IPsec install and remove policy commands */ +char *ipsec_policy_action[] = { + "/usr/sbin/ipsecconf -a /dev/stdin -q", + "/usr/sbin/ipsecconf -r /dev/stdin -q", + NULL +}; + +/* 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", + NULL +}; + +#define BUCKET 0 /* Bucket in hashtable to start enumeration at */ +#define OFFSET 1 /* Offset within BUCKET 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)(); +int (*radLookupData)(char **sessionId, char *key, RadData *dest); +int (*radCloseSession)(char *sessionId, char *key, void *accountingInfo); +#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. + */ +HashTable maAdvConfigHash; + +/* + * This table stores all of the Security Violations + */ +HashTable mipSecViolationHash; + +/* + * This table stores all of the Security Assocations + */ +HashTable mipSecAssocHash; + +/* + * This table has one entry for each known Mobility Agent + */ +HashTable mipAgentHash; + +/* + * This table has one entry for each active tunnel number + */ +HashTable mipTunlHash; + +/* + * Counters common to all Mobility Agents + */ +CommonCounters commonCounters; + + +char maNai[MAX_NAI_LENGTH]; + +/* + * This table has one entry for each pool defined in the config file + */ +HashTable mipPoolHash; + +/* ------------------ 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. + */ +HashTable faVisitorHash; + +/* + * Counters maintained by Foreign Agents + */ +ForeignAgentCounters faCounters; + +/* + * We need to keep track of the last two Challenge Values that + * we have advertised in order to check for replays. + */ +char faLastChallengeIssued[2][ADV_CHALLENGE_LENGTH]; + +/* ------------------ Specific to home agents -------------------- */ +/* + * This table has one entry for each mobile node for which a mobility + * agent offers Home Agent services. + */ + +HashTable haMobileNodeHash; + + +/* + * Counters maintained by Home Agents + */ +HomeAgentCounters haCounters; + +/* Security related stuff */ +#ifdef FIREWALL_SUPPORT +DomainInfo domainInfo; +#endif /* FIREWALL_SUPPORT */ +/* ----------------------------------------------------------------- */ + +extern int Initialize(char *configFile); +extern void printBuffer(unsigned char *, int); +extern int sendUDPmessage(int, unsigned char *, int, ipaddr_t, in_port_t); +extern boolean_t HAisIDok(uint32_t, uint32_t, uint32_t, uint32_t, int); +extern void HAnewID(uint32_t *, uint32_t *, uint32_t, uint32_t, int, boolean_t); +extern void HAstoreID(uint32_t *, uint32_t *, uint32_t, uint32_t, int, + boolean_t); +extern char *hwAddrWrite(unsigned char *, char *); +extern char *ntoa(uint32_t, char *); +extern char *sprintTime(char *, int); +extern char *sprintRelativeTime(char *, int); +extern char *err2str(int); +extern int restoreAgentState(void); +extern void Finalize(int); +extern void delFAVEptr(FaVisitorEntry *, boolean_t, uint32_t); +extern void delHABEent(HaMobileNodeEntry *, HaBindingEntry *); +extern int startPeriodicTaskThread(void); +extern int startSNMPTaskThread(void); +extern int startDispatcherTaskThread(void); +extern int startStatServer(); +static int startPerfTestServer(void); +extern int aaaSendRegistrationReply(MessageHdr *, size_t, + ipaddr_t, ipaddr_t); +extern MobilityAgentEntry *findMaeFromIp(ipaddr_t address, int lockType); + +void forwardFromFAToHA(MessageHdr *, MaAdvConfigEntry *, boolean_t); +void rejectFromFAToMN(MessageHdr *, MaAdvConfigEntry *, int); +void rejectFromICMPToMN(MessageHdr *, ipaddr_t, int); +extern uint32_t getRandomValue(); +extern int gettunnelno(ipaddr_t, ipaddr_t); +extern int arpIfadd(ipaddr_t, char *, uint32_t); +extern int arpIfdel(ipaddr_t, char *, uint32_t); +extern void ifname2devppa(char *, char *, int *); +extern int dlattachreq(int, int); +extern int dlokack(int, char *); +extern int dlbindreq(int, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); +extern int dlbindack(int, char *); +static int mip_strioctl(int, int, void *, int, int); +static void HAprocessRegRequestContinue(MessageHdr *, MaAdvConfigEntry *, + ipaddr_t *, int, HaMobileNodeEntry *, uint32_t, uint32_t); +static void HABuildRegReply(MessageHdr *, MaAdvConfigEntry *, + int, HaMobileNodeEntry *, uint32_t, MipSecAssocEntry *, int, + boolean_t, uint32_t, boolean_t); +static boolean_t acceptFAVEHashLookup(void *, uint32_t, uint32_t, uint32_t); + +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. + * + */ +boolean_t +isInsideProtectedDomain(ipaddr_t addr) +{ + int i; + + if (domainInfo.addrIntervalCnt == 0) + return (_B_TRUE); + + for (i = 0; i < domainInfo.addrIntervalCnt; i++) { + if (((addr ^ domainInfo.addr[i]) & domainInfo.netmask[i]) == 0) + 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 +mkRegExtList(MessageHdr *messageHdr, size_t headerLength) +{ + unsigned char *currentPos; + /* + * Support for different extension header formats + */ + uint16_t longLength; + uint8_t shortLength; + size_t bufLength; + size_t bytesSeen = 0; + size_t extSeen = 0; + + currentPos = (unsigned char *)(((char *)messageHdr->pkt) + + headerLength); + bufLength = (int)(((char *)messageHdr->pktLen) - headerLength); + + /* + * Protection against packets that have no extensions. + */ + if (bufLength == 0) { + return (0); + } + + mipverbose(("Found extensions:")); + + while ((bytesSeen < (bufLength - 1)) && + (extSeen < MAX_EXPECTED_EXTENSIONS)) { + messageHdr->extType[extSeen] = *currentPos; + messageHdr->extIdx[extSeen] = currentPos; + mipverbose((" <%d, %d, ...>", messageHdr->extType[extSeen], + *(messageHdr->extIdx[extSeen] + MIP_EXT_LENGTH))); + + /* + * 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. + */ + switch (messageHdr->extType[extSeen]) { + case REG_GEN_AUTH_EXT_TYPE: + case REG_GEN_MN_FA_KEY_EXT_TYPE: + case REG_GEN_MN_HA_KEY_EXT_TYPE: + /* + * The following handles the generalized Authentication + * extension as well as the generalized keying + * extensions. + */ + messageHdr->extSubType[extSeen] = + *(currentPos + MIP_EXT_GEN_SUB_TYPE); + (void) memcpy(&longLength, + currentPos + MIP_EXT_LONG_LENGTH, + sizeof (uint16_t)); + longLength = ntohs(longLength); + messageHdr->extHdrLength[extSeen] = + sizeof (mierLongExt); + messageHdr->extLength[extSeen] = longLength; + messageHdr->extData[extSeen] = + currentPos + MIP_EXT_LONG_LENGTH_DATA; + break; + + case REG_CRIT_VENDOR_SPEC_EXT_TYPE: + /* + * 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. + */ + (void) memcpy(&messageHdr->extSubType[extSeen], + currentPos + MIP_EXT_CVSE_VENDOR_SUB_TYPE, + sizeof (uint16_t)); + messageHdr->extSubType[extSeen] = + ntohs(messageHdr->extSubType[extSeen]); + (void) memcpy(&messageHdr->extVendorId[extSeen], + currentPos + MIP_EXT_CVSE_VENDOR_ID_TYPE, + sizeof (uint32_t)); + messageHdr->extVendorId[extSeen] = + ntohl(messageHdr->extVendorId[extSeen]); + (void) memcpy(&longLength, + currentPos + MIP_EXT_LONG_LENGTH, + sizeof (uint16_t)); + longLength = ntohs(longLength); +#ifdef KEY_DISTRIBUTION + messageHdr->extHdrLength[extSeen] = + sizeof (vendorSpecExt); +#else /* KEY_DISTRIBUTION */ + messageHdr->extHdrLength[extSeen] = + VENDOR_SPEC_EXT_HDR_LEN; +#endif /* KEY_DISTRIBUTION */ + messageHdr->extLength[extSeen] = longLength; + messageHdr->extData[extSeen] = + currentPos + MIP_EXT_CVSE_VENDOR_ID_DATA; + break; + + case REG_NORMAL_VENDOR_SPEC_EXT_TYPE: + /* + * 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. + */ + (void) memcpy(&shortLength, currentPos + MIP_EXT_LENGTH, + sizeof (uint8_t)); + messageHdr->extHdrLength[extSeen] = sizeof (regExt); + messageHdr->extLength[extSeen] = shortLength; + messageHdr->extSubType[extSeen] = + *(currentPos + MIP_EXT_NVSE_VENDOR_SUB_TYPE); + messageHdr->extVendorId[extSeen] = + *(currentPos + MIP_EXT_NVSE_VENDOR_ID_TYPE); + messageHdr->extData[extSeen] = + currentPos + MIP_EXT_NVSE_VENDOR_ID_DATA; + break; + + default: + /* + * The following code supports the traditional + * extensions. + */ + (void) memcpy(&shortLength, currentPos + MIP_EXT_LENGTH, + sizeof (uint8_t)); + messageHdr->extHdrLength[extSeen] = sizeof (regExt); + messageHdr->extLength[extSeen] = shortLength; + messageHdr->extData[extSeen] = currentPos + + MIP_EXT_DATA; + break; + } + + + /* + * protect against bogus packets. + */ + if ((messageHdr->extLength[extSeen] + + messageHdr->extHdrLength[extSeen]) > + (bufLength - bytesSeen)) { + messageHdr->extCnt = extSeen; + return (-1); + } + bytesSeen += messageHdr->extLength[extSeen] + + messageHdr->extHdrLength[extSeen]; + currentPos += messageHdr->extLength[extSeen] + + messageHdr->extHdrLength[extSeen]; + + extSeen++; + } + mipverbose((" (%d exts)\n", messageHdr->extCnt)); + + + if ((bytesSeen < (bufLength - 1)) && + (extSeen >= MAX_EXPECTED_EXTENSIONS)) { + syslog(LOG_ERR, "Too many extensions."); + return (-1); + } else if (bytesSeen != bufLength) { + syslog(LOG_ERR, "Extensions buffer too small."); + return (-1); + } else { + messageHdr->extCnt = extSeen; + 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 +IsPacketFromMnValid(MessageHdr *messageHdr) +{ + regRequest *requestPtr; + boolean_t foundMHauth = _B_FALSE; + boolean_t foundMFauth = _B_FALSE; + boolean_t foundMAauth = _B_FALSE; + boolean_t foundNAI = _B_FALSE; + boolean_t foundChallenge = _B_FALSE; + int i; + + /* LINTED BAD_PTR_CAST_ALIGN */ + requestPtr = (regRequest *) messageHdr->pkt; + + /* + * 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) { + syslog(LOG_ERR, + "Multiple MH or MA Authentication Extensions"); + return (FA_POORLY_FORMED_REQUEST); + } else { + foundMHauth = _B_TRUE; + } + break; + + case REG_GEN_AUTH_EXT_TYPE: + /* + * The Challenge/Response Internet Draft now + * 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) { + syslog(LOG_ERR, "Missing Challenge before " \ + "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. + */ + + if (foundNAI == _B_FALSE) { + syslog(LOG_ERR, "Missing NAI before Mobile-AAA " + "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. + */ + (void) fprintf(stderr, "Got an NAI of %.*s!\n", + messageHdr->mnNAILen, messageHdr->mnNAI); + + /* we should not have seen any other auth extensions */ + if (foundMAauth == _B_TRUE) { + syslog(LOG_ERR, + "Multiple MH or MA Authentication Extensions"); + return (FA_POORLY_FORMED_REQUEST); + } else { + foundMAauth = _B_TRUE; + } + break; + + default: + syslog(LOG_ERR, + "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 (foundMHauth == _B_TRUE || foundMAauth == _B_TRUE) { + if (foundMFauth == _B_TRUE) { + syslog(LOG_ERR, "Multiple MF Authentication " + "Extensions"); + return (FA_POORLY_FORMED_REQUEST); + } else { + foundMFauth = _B_TRUE; + } + } else { + syslog(LOG_ERR, + "No MH or MA before MF Authentication Extension"); + return (FA_POORLY_FORMED_REQUEST); + } + break; + + case REG_MF_CHALLENGE_EXT_TYPE: + /* + * We should only see the challenge if we've + * advertised it. + */ + if (faChallengeAdv == _B_FALSE) { + syslog(LOG_ERR, "Challenge should not be present"); + return (FA_POORLY_FORMED_REQUEST); + } + if (foundMFauth == _B_TRUE) { + syslog(LOG_ERR, "Challenge should be before " + "MF Authentication Extension"); + return (FA_POORLY_FORMED_REQUEST); + } + if (foundChallenge == _B_TRUE) { + syslog(LOG_ERR, "Multiple Challenges"); + return (FA_POORLY_FORMED_REQUEST); + } else { + foundChallenge = _B_TRUE; + } + 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. + */ + if (foundNAI == _B_TRUE) { + syslog(LOG_ERR, "Multiple NAIs"); + return (FA_POORLY_FORMED_REQUEST); + } else { + /* + * Save the pointer to the NAI for future + * reference. + */ + messageHdr->mnNAI = messageHdr->extData[i]; + messageHdr->mnNAILen = messageHdr->extLength[i]; + + if (messageHdr->mnNAILen > MAX_NAI_LENGTH) { + /* + * Protect against buffer overflows... + */ + syslog(LOG_ERR, "Excessively large NAI"); + /* + * 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. + */ + (void) fprintf(stderr, "Received NAI (%*.*s)!\n", + messageHdr->mnNAILen, messageHdr->mnNAILen, + messageHdr->mnNAI); + foundNAI = _B_TRUE; + } + break; + + /* Vendor-specific extension support */ + case REG_CRIT_VENDOR_SPEC_EXT_TYPE: + /* + * We only care if we've seen the MN-HA/AAA auth, but + * haven't seen the MN-FA auth (yet). + */ + if (foundMHauth == _B_FALSE && foundMAauth == _B_FALSE) { + /* + * We haven't seen any mobile node authentication + * extensions yet, so we're still inside the MN-HA/AAA + * 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 + * MN. By putting this extension after the MN-HA/AAA + * 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 + * the Vendor/Org-ID or Vendor-CVSE-Type, + * 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. + */ + syslog(LOG_ERR, + "Unrecognized CVSE subtype %d " + "from Mobile Node", + messageHdr->extSubType[i]); + return (FA_UNKNOWN_CVSE_FROM_MN); + } + break; + } + break; + + case REG_NORMAL_VENDOR_SPEC_EXT_TYPE: + /* + * We only care if we've seen the MN-HA/AAA auth, but + * haven't seen the MN-FA auth (yet). + */ + if (foundMHauth != _B_TRUE && foundMAauth != _B_TRUE) { + /* + * We haven't seen a mobile-home authenticator yet, + * so we're still inside the MN-HA/AAA authenticator. + * 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... + */ + syslog(LOG_ERR, + "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. + */ + case ENCAPSULATING_DELIVERY_TYPE: + /* + * 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. + */ + if (((foundMHauth != _B_TRUE) && (foundMAauth != _B_TRUE)) || + (foundMFauth == _B_TRUE)) { + syslog(LOG_ERR, + "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. */ + if (!(requestPtr->regFlags & REG_REVERSE_TUNNEL)) { + /* extension is here, but 'T' bit isn't set */ + syslog(LOG_ERR, + "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. + */ + faCounters.faRTEncapUnavailableCnt++; + return (FA_DELIVERY_STYLE_UNAVAILABLE); + + default: + if (messageHdr->extType[i] <= 127) { + /* + * Unrecognized extensions in this range cause this + * packet be drooped. + */ + syslog(LOG_ERR, + "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) { + if (foundMAauth == _B_FALSE && (foundMHauth == _B_FALSE || + foundMFauth == _B_FALSE)) { + syslog(LOG_ERR, "When Challenge is present, either " + "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: + * 1. Home Address, and/or + * 2. NAI. + */ + if (requestPtr->homeAddr == INADDR_ANY && foundNAI == _B_FALSE) { + syslog(LOG_ERR, + "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 */ + if (foundMAauth == _B_TRUE || foundMHauth == _B_TRUE) { + return (MIP_SUCCESSFUL_REGISTRATION); + } else { + syslog(LOG_ERR, "MH or MA Authentication Extension missing"); + 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 +IsPacketFromCoaValid(MessageHdr *messageHdr) +{ + regRequest *requestPtr; + char addrstr[INET_ADDRSTRLEN]; + boolean_t foundMHauth = _B_FALSE; + boolean_t foundFHauth = _B_FALSE; + boolean_t foundMAauth = _B_FALSE; + boolean_t foundNAI = _B_FALSE; + boolean_t foundChallenge = _B_FALSE; + int i; + + /* LINTED BAD_PTR_CAST_ALIGN */ + requestPtr = (regRequest *) messageHdr->pkt; + + /* + * 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) { + syslog(LOG_ERR, + "Multiple MH or MA Authentication Extensions"); + return (HA_POORLY_FORMED_REQUEST); + } else { + foundMHauth = _B_TRUE; + } + break; + + case REG_GEN_AUTH_EXT_TYPE: + /* + * The Challenge/Response Internet Draft now + * 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) { + syslog(LOG_ERR, "Missing Challenge before " \ + "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. + */ + + if (foundNAI == _B_FALSE) { + syslog(LOG_ERR, "Missing NAI before Mobile-AAA " + "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. + */ + (void) fprintf(stderr, "Got an NAI of (%*.*s)!\n", + messageHdr->mnNAILen, messageHdr->mnNAILen, + messageHdr->mnNAI); + + /* we should not have seen any other auth extensions */ + if (foundMAauth == _B_TRUE) { + syslog(LOG_ERR, + "Multiple MH or MA Authentication Extensions"); + return (HA_POORLY_FORMED_REQUEST); + } else { + foundMAauth = _B_TRUE; + } + break; + + default: + syslog(LOG_ERR, + "Unknown Generalized Authentication subtype found"); + return (HA_POORLY_FORMED_REQUEST); + } + break; + + + case REG_MF_CHALLENGE_EXT_TYPE: + if (foundChallenge == _B_TRUE) { + syslog(LOG_ERR, "Multiple Challenges"); + return (HA_POORLY_FORMED_REQUEST); + } else { + foundChallenge = _B_TRUE; + } + 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. + */ + if (foundMAauth == _B_FALSE && foundMHauth == _B_FALSE) { + syslog(LOG_ERR, + "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) { + syslog(LOG_ERR, "Multiple FHauth"); + return (HA_POORLY_FORMED_REQUEST); + } else { + foundFHauth = _B_TRUE; + } + } + 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. + */ + if (foundNAI == _B_TRUE) { + syslog(LOG_ERR, "Multiple NAIs"); + return (HA_POORLY_FORMED_REQUEST); + } else { + /* + * Save the pointer to the NAI for future + * reference. + */ + messageHdr->mnNAI = messageHdr->extData[i]; + messageHdr->mnNAILen = messageHdr->extLength[i]; + + if (messageHdr->mnNAILen > MAX_NAI_LENGTH) { + /* + * Protect against buffer overflows... + */ + syslog(LOG_ERR, "Excessively large NAI"); + return (HA_POORLY_FORMED_REQUEST); + } + foundNAI = _B_TRUE; + } + break; + + /* Vendor-specific extension support */ + case REG_CRIT_VENDOR_SPEC_EXT_TYPE: + /* 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, + * but we don't understand the Vendor/Org-ID + * 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) { + /* + * We haven't seen a MN-HA/AAA + * authenticator, so this is in the + * MN-to-HA portion of the request + */ + syslog(LOG_ERR, + "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 + * after MN-HA/AAA auth from the MN, + * 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. + */ + syslog(LOG_ERR, + "Unrecognized CVSE subtype %d from" + " Foreign Agent", + messageHdr->extSubType[i]); + return (HA_UNKNOWN_CVSE_FROM_FA); + } + break; + } + break; + + case REG_NORMAL_VENDOR_SPEC_EXT_TYPE: + /* 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) { + /* + * We haven't seen an MN-HA/AAA + * authenticator, so it's before it, + * and is from the mobile node. + */ + syslog(LOG_ERR, + "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. + */ + syslog(LOG_ERR, + "Unrecognized NVSE subtype %d from" + " Foreign Agent, ignoring!", + messageHdr->extSubType[i]); + } + break; + } + break; + + case ENCAPSULATING_DELIVERY_TYPE: + /* + * 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. + */ + syslog(LOG_WARNING, + "Home Agent found ENCAPSULATING_DELIVERY_TYPE extension." + " FA (%s) should have removed it." + " Ignoring (as type>127), and processing registration.", + ntoa(requestPtr->COAddr, addrstr)); + + break; + + default: + if (messageHdr->extType[i] <= 127) { + /* + * Unrecognized extensions in this range cause this + * packet be drooped. + */ + syslog(LOG_ERR, + "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: + * 1. Home Address, and/or + * 2. NAI. + */ + if (requestPtr->homeAddr == INADDR_ANY && foundNAI == _B_FALSE) { + syslog(LOG_ERR, + "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 */ + if (foundMAauth == _B_TRUE || foundMHauth == _B_TRUE) { + return (MIP_SUCCESSFUL_REGISTRATION); + } else { + syslog(LOG_ERR, "MH or MA Authentication Extension missing"); + 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 +IsPacketFromHaValid(MessageHdr *messageHdr) +{ + regReply *replyPtr; + boolean_t foundMHauth = _B_FALSE; + boolean_t foundFHauth = _B_FALSE; + boolean_t foundNAI = _B_FALSE; + boolean_t foundChallenge = _B_FALSE; + int i; + + /* LINTED BAD_PTR_CAST_ALIGN */ + replyPtr = (regReply *) messageHdr->pkt; + + /* + * 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) { + syslog(LOG_ERR, + "Multiple MH or MA Authentication Extensions"); + return (FA_POORLY_FORMED_REPLY); + } else { + foundMHauth = _B_TRUE; + } + break; + + case REG_FH_AUTH_EXT_TYPE: + /* If we are expecting a challenge, check for it. */ + if (faChallengeAdv == _B_TRUE && foundChallenge == _B_FALSE) { + syslog(LOG_ERR, "Challenge Missing in Reply"); + /* + * 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) { + syslog(LOG_ERR, + "No MH or MA Authentication Extension before FHauth"); + return (FA_POORLY_FORMED_REPLY); + } else if (foundFHauth == _B_TRUE) { + syslog(LOG_ERR, "Multiple FHauth"); + return (FA_POORLY_FORMED_REPLY); + } else { + foundFHauth = _B_TRUE; + } + break; + + case REG_MF_CHALLENGE_EXT_TYPE: + if (foundChallenge == _B_TRUE) { + syslog(LOG_ERR, "Multiple Challenges"); + return (FA_POORLY_FORMED_REPLY); + } else { + foundChallenge = _B_TRUE; + } + 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. + */ + if (foundNAI == _B_TRUE) { + syslog(LOG_ERR, "Multiple NAIs"); + return (FA_POORLY_FORMED_REPLY); + } else { + /* + * Save the pointer to the NAI for future + * reference. + */ + messageHdr->mnNAI = messageHdr->extData[i]; + messageHdr->mnNAILen = messageHdr->extLength[i]; + + if (messageHdr->mnNAILen > MAX_NAI_LENGTH) { + /* + * Protect against buffer overflows... + */ + syslog(LOG_ERR, "Excessively large NAI"); + return (FA_POORLY_FORMED_REPLY); + } + foundNAI = _B_TRUE; + } + break; + + case REG_GEN_MN_FA_KEY_EXT_TYPE: + /* + * 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: + syslog(LOG_ERR, + "Unrecognized generalized key subtype %d", + messageHdr->extSubType[i]); + return (FA_POORLY_FORMED_REPLY); + } + break; + + case REG_GEN_MN_HA_KEY_EXT_TYPE: + /* + * 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: + syslog(LOG_ERR, + "Unrecognized generalized key subtype %d", + messageHdr->extSubType[i]); + return (FA_POORLY_FORMED_REPLY); + } + break; + + case REG_CRIT_VENDOR_SPEC_EXT_TYPE: + /* Check the subtype and process accordingly */ + switch (messageHdr->extSubType[i]) { +#ifdef KEY_DISTRIBUTION + /* + * KEY_DISTRIBUTION MUST ONLY BE COMPILED FOR TESTING!!! + * + * This version of mipagent supports a AAA/DIAMETER + * 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. + * + * Since DIAMETER/AAA is not currently a product, and key + * 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! + */ + if (foundMHauth == _B_TRUE && foundFHauth == _B_FALSE) { + /* + * we've seen the MHAUTH, so this is + * after it, but not an FHauth, so it's + * for us from the HA. + */ + syslog(LOG_ERR, + "Unrecognized CVSE subtype %d" + " from Home Agent.", + messageHdr->extSubType[i]); + return (FA_UNKNOWN_CVSE_FROM_HA); + } + } + break; + + case REG_NORMAL_VENDOR_SPEC_EXT_TYPE: + /* 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! + */ + syslog(LOG_ERR, + "Unrecognized NVSE subtype %d" + " from Home Agent, ignoring.", + messageHdr->extSubType[i]); + } + } + break; + + default: + if (messageHdr->extType[i] <= 127) { + /* + * Unrecognized extensions in this range cause this + * packet be drooped. + */ + syslog(LOG_ERR, + "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. + */ + if (replyPtr->homeAddr == INADDR_ANY) { + syslog(LOG_ERR, "Mobile Node 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); + } + + + if (foundMHauth == _B_TRUE) { /* make sure we have one MHauth */ + return (MIP_SUCCESSFUL_REGISTRATION); + } else { + syslog(LOG_ERR, "MH Authentication Extension missing"); + return (FA_POORLY_FORMED_REPLY); + } +} + + +#ifdef RADIUS_ENABLED +HaMobileNodeEntry * +radiusCheckUpdate(HaMobileNodeEntry *dest, struct hash_table *htbl, + ipaddr_t mnAddr) +{ + struct hash_entry *p; + MipSecAssocEntry *saEntry; + RadData result; + char ipString[30]; + int rc; + char *sessionId; + struct hash_entry *hash; + char mipSecKey[MAX_KEY_LEN]; + int i; + time_t currentTime; + + (void) ntoa(mnAddr, ipString); + (void) memset(&result, 0, sizeof (result)); + + GET_TIME(currentTime); + + /* ToDo: Lock our node */ + + if (dest == NULL) { +#ifdef RADIUS_DEBUG + (void) fprintf(stderr, + "radiusCheckUpdate: Looking up 0x%08x\n", mnAddr); +#endif + rc = radLookupData(&sessionId, ipString, &result); +#ifdef RADIUS_DEBUG + (void) fprintf(stderr, + "radiusCheckUpdate: Finished Looking up 0x%08x rc=%d\n", + mnAddr, rc); +#endif + if (rc) { + /* + * Since we have nothing, we need to retun null . . . + */ + return (NULL); + } + + if (hexConvert((char *)mipSecKey, + result.mipSecretLen/2, result.mipSecret) < 0) { + 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. + */ + saEntry = CreateSecAssocEntry(_B_TRUE, result.mipSPI, + result.mipSecretReplayMethod, MD5, + PREFIXSUFFIX, result.mipSecretLen/2, mipSecKey, 0); + + if (saEntry == NULL) { + syslog(LOG_ERR, + "Unable to create MobileNode SA for %d", + result.mipMnAddr); + return (NULL); + } + + /* + * And we create the Mobile Node + */ + dest = CreateMobileNodeEntry(_B_TRUE, + result.mipMnAddr, NULL, 0, result.mipBindingIfAddress, + result.mipSPI, sessionId, 0); + + if (dest == NULL) { + syslog(LOG_ERR, + "Unable to create MobileNodeEntry for %d", + result.mipMnAddr)); + return (NULL); + } + } else { + /* + * We have a node already, check to see if it needs an + * update + */ + if (dest->haRadiusLastLookupTime + RADIUS_LOOKUP_TIME < + currentTime) { + /* Nope, return! */ + return (dest); + } +#ifdef RADIUS_DEBUG + (void) fprintf(stderr, "radiusCheckUpdate: Looking up 0x%08x\n", + mnAddr); +#endif + rc = radLookupData(&sessionId, ipString, &result); +#ifdef RADIUS_DEBUG + (void) fprintf(stderr, + "radiusCheckUpdate: Finished Looking up 0x%08x rc=%d\n", + mnAddr, rc); +#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. + */ + dest->haRadiusLastLookupTime = currentTime; + + /* + * 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 + (void) fprintf(stderr, "radiusCheckUpdate: Updating 0x%p\n", dest); +#endif + + + dest->haRadiusState = sessionId; + dest->haRadiusLastLookupTime = currentTime; + +#ifdef RADIUS_DEBUG + (void) fprintf(stderr, "haMnAddr = 0x%08x\n", + dest->haMnAddr); + (void) fprintf(stderr, "haBindingIfaceAddr = 0x%08x\n", + dest->haBindingIfaceAddr); + (void) fprintf(stderr, "haMnBindingCnt = %d\n", + dest->haMnBindingCnt); + (void) fprintf(stderr, "\n"); + (void) fprintf(stderr, + "haRadiusState = 0x%08x\n", dest->haRadiusState); + (void) fprintf(stderr, + "haRadiusLastLookupTime = 0x%08x\n", dest->haRadiusLastLookupTime); + + (void) fprintf(stderr, "radiusCheckUpdate: exiting\n"); +#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 +findHABE(HashTable *htbl, ipaddr_t mnAddr, ipaddr_t COAddr) +{ + boolean_t found = _B_FALSE; + HaMobileNodeEntry *hamnePtr; + HaBindingEntry *entry; + char addrstr1[INET_ADDRSTRLEN]; + + if ((hamnePtr = (HaMobileNodeEntry *)findHashTableEntryUint(htbl, + mnAddr, LOCK_READ, NULL, 0, 0, 0)) != NULL) { + + entry = hamnePtr->bindingEntries; + + while (entry) { + if ((entry->haBindingMN == mnAddr) && + (entry->haBindingCOA == COAddr)) { + found = _B_TRUE; + break; + } + entry = entry->next; + } + + (void) rw_unlock(&hamnePtr->nodeLock); + } else { + syslog(LOG_ERR, "Unable to find Mobile Node Entry %s", + ntoa(mnAddr, addrstr1)); + } + + 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 +findPendingFAVEHashLookup(void *entry, uint32_t p1, uint32_t p2, uint32_t p3) +{ + FaVisitorEntry *faveEntry = entry; + + if ((faveEntry->faVisitorRegIDLow == p1) && + ((uint32_t)faveEntry->faVisitorRegIsAccepted == p2)) { + 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 * +findPendingFAVE(HashTable *htbl, ipaddr_t mnAddr, unsigned char *mnNAI, + uint32_t mnNAILen, uint32_t IDlo) +{ + FaVisitorEntry *entry = NULL; + + if (mnAddr) { + /* + * Let's see if we can find the entry using the Home + * Address. + */ + entry = findHashTableEntryUint(htbl, mnAddr, LOCK_WRITE, + findPendingFAVEHashLookup, IDlo, _B_FALSE, 0); + } + + if (entry == NULL && mnNAI) { + /* + * Perhaps we will be able to find the visitor entry + * using the NAI. + */ + entry = findHashTableEntryString(htbl, mnNAI, mnNAILen, + LOCK_WRITE, findPendingFAVEHashLookup, IDlo, _B_FALSE, 0); + } + + 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 */ +boolean_t +mkPendingFAVEHashLookup(void *entry, uint32_t p1, uint32_t p2, uint32_t p3) +{ + FaVisitorEntry *faveEntry = entry; + + if (((uint32_t)faveEntry->faVisitorRegIsAccepted == p1) && + (p2 == 0 || (uint32_t)faveEntry->faVisitorInIfindex == p2)) { + 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 * +mkPendingFAVE(HashTable *htbl, MessageHdr *messageHdr, ipaddr_t localAddr, + uint32_t SPI, unsigned char *challenge, size_t challengeLen) +{ + boolean_t found; + regRequest *requestPtr; + FaVisitorEntry *entry = NULL; + char addrstr1[INET_ADDRSTRLEN]; + time_t currentTime; + + /* LINTED BAD_PTR_CAST_ALIGN */ + requestPtr = (regRequest *)messageHdr->pkt; + + found = _B_FALSE; + + /* + * 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) { + entry = findHashTableEntryUint(htbl, requestPtr->homeAddr, + LOCK_WRITE, mkPendingFAVEHashLookup, _B_FALSE, + messageHdr->inIfindex, 0); + } + + if (entry == NULL && messageHdr->mnNAI) { + entry = findHashTableEntryString(htbl, messageHdr->mnNAI, + messageHdr->mnNAILen, LOCK_WRITE, mkPendingFAVEHashLookup, + _B_FALSE, messageHdr->inIfindex, 0); + } + + if (entry == NULL) { + /* + * Since we did not find a hash entry, we need to + * re-initialize p to NULL. + */ + if ((entry = + (FaVisitorEntry *)calloc(1, sizeof (FaVisitorEntry))) + == NULL) { + syslog(LOG_CRIT, + "Unable to allocate FaVisitorEntry"); + return (NULL); + } + + if (rwlock_init(&entry->faVisitorNodeLock, USYNC_THREAD, + NULL)) { + syslog(LOG_ERR, "Unable to init visitor lock"); + } + } else { + found = _B_TRUE; + } + + entry->faVisitorAddr = messageHdr->src; + entry->faVisitorIfaceAddr = localAddr; + entry->faVisitorRegIsAccepted = _B_FALSE; + entry->faVisitorRegFlags = requestPtr->regFlags; + entry->faVisitorPort = messageHdr->srcPort; + entry->faVisitorHomeAddr = requestPtr->homeAddr; + entry->faVisitorHomeAgentAddr = requestPtr->haAddr; + entry->faVisitorCOAddr = requestPtr->COAddr; + GET_TIME(currentTime) + entry->faVisitorTimeExpires = currentTime + + DEFAULT_VISITOR_EXPIRY; + entry->faVisitorRegIDHigh = ntohl(requestPtr->IDHigh); + entry->faVisitorRegIDLow = ntohl(requestPtr->IDLow); + entry->faVisitorSPI = SPI; + entry->faVisitorInIfindex = messageHdr->inIfindex; + entry->faVisitorIsSllaValid = messageHdr->isSllaValid; + if (messageHdr->isSllaValid) + (void) memcpy(&entry->faVisitorSlla, &messageHdr->slla, + sizeof (struct sockaddr_dl)); + else + (void) memset(&entry->faVisitorSlla, 0, + sizeof (struct sockaddr_dl)); + + /* + * Save the Mobile Node's NAI + */ + entry->faVisitorMnNAILen = messageHdr->mnNAILen; + if (messageHdr->mnNAI) { + (void) strncpy((char *)entry->faVisitorMnNAI, + (char *)messageHdr->mnNAI, messageHdr->mnNAILen); + } else { + entry->faVisitorMnNAI[0] = 0; + } + + /* + * If necessary, save the challenge + */ + if (challengeLen) { + (void) memcpy(entry->faVisitorChallengeToHA, challenge, + challengeLen); + } + entry->faVisitorChallengeToHALen = challengeLen; + + if (found == _B_FALSE) { + if (requestPtr->homeAddr) { + /* + * We will link the entry in the hash table using + * the home address. + */ + if (linkHashTableEntryUint(htbl, requestPtr->homeAddr, + entry, LOCK_WRITE)) { + syslog(LOG_ERR, + "Unable to add visitor entry to hash tabl"); + (void) rwlock_destroy( + &entry->faVisitorNodeLock); + free(entry); + return (NULL); + } + mipverbose(("Adding pending visitor entry for %s.%d " \ + "at pos'n %p.\n", + ntoa(requestPtr->homeAddr, addrstr1), + messageHdr->srcPort, (void *)entry)); + } 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. + */ + if (linkHashTableEntryString(htbl, messageHdr->mnNAI, + messageHdr->mnNAILen, entry, LOCK_WRITE)) { + syslog(LOG_ERR, + "Unable to add visitor entry to " + "hash table (NAI)"); + (void) rwlock_destroy( + &entry->faVisitorNodeLock); + free(entry); + return (NULL); + } + mipverbose(("Adding pending visitor entry for %.*s (%d)" + "at pos'n %p.\n", messageHdr->mnNAILen, + messageHdr->mnNAI, messageHdr->mnNAILen, + (void *)entry)); + } else { + /* + * Well, we need at LEAST a home address or an NAI. + */ + syslog(LOG_ERR, "Unable to add visitor entry " + "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 +isAcceptedVisitorHashLookup(void *entry, uint32_t p1, uint32_t p2, uint32_t p3) +{ + FaVisitorEntry *faveEntry = entry; + + if ((faveEntry->faVisitorIfaceAddr == p1) && + ((uint32_t)faveEntry->faVisitorRegIsAccepted == p2)) { + 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 +isAcceptedVisitor(HashTable *htbl, ipaddr_t mnAddr, ipaddr_t ifaceAddr) +{ + FaVisitorEntry *entry; + + entry = findHashTableEntryUint(htbl, mnAddr, + LOCK_NONE, isAcceptedVisitorHashLookup, ifaceAddr, _B_TRUE, 0); + + 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 +delFAVE(HashTable *htbl, FaVisitorEntry **entry, ipaddr_t mnAddr, + uint32_t relind) +{ + /* + * 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. + */ + if ((*entry)->faVisitorMnNAI[0] != '\0' && + (*entry)->faVisitorHomeAddr == INADDR_ANY) { + + if (delHashTableEntryString(htbl, *entry, + (*entry)->faVisitorMnNAI, (*entry)->faVisitorMnNAILen, + LOCK_NONE)) { + /* + * Found a match, delete it + */ + delFAVEptr(*entry, _B_TRUE, relind); + (void) rw_unlock(&(*entry)->faVisitorNodeLock); + (void) rwlock_destroy(&(*entry)->faVisitorNodeLock); + free(*entry); + *entry = NULL; + } + } else { + if (delHashTableEntryUint(htbl, *entry, mnAddr, LOCK_NONE)) { + /* + * Found a match, delete it + */ + delFAVEptr(*entry, _B_TRUE, relind); + (void) rw_unlock(&(*entry)->faVisitorNodeLock); + (void) rwlock_destroy(&(*entry)->faVisitorNodeLock); + free(*entry); + *entry = NULL; + } + } + +} + + +/* + * 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 +appendExt(unsigned char *buffer, int type, unsigned char *data, + size_t dataLen) +{ + regExt *ext; + + ext = (regExt *)buffer; + ext->type = (uint8_t)type; + ext->length = dataLen; + (void) memcpy(ext + 1, data, dataLen); + + return (dataLen + sizeof (regExt)); +} + +/* + * 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 +appendMierExt(unsigned char *buffer, int type, int subType, + unsigned char *data, uint16_t dataLen) +{ + mierLongExt *ext; + + /* + * 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 */ + ext = (mierLongExt *)buffer; + ext->type = (uint8_t)type; + ext->subType = (uint8_t)subType; + + dataLen = htons(dataLen); + (void) memcpy(&ext->length, &dataLen, sizeof (uint16_t)); + + /* + * We simply copy the blob at the end of the MIER structure. + */ + (void) memcpy(ext + 1, data, ntohs(dataLen)); + + return (ntohs(dataLen) + sizeof (mierLongExt)); +} + +#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 +appendCritVendorSpecExt(unsigned char *buffer, uint32_t vendorId, uint16_t type, + unsigned char *data, uint16_t dataLen) +{ + vendorSpecExt *ext; + + /* + * 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. + */ + assert(IS_P2ALIGNED(buffer, sizeof (uintptr_t))); + /* LINTED */ + ext = (vendorSpecExt *)buffer; + + /* + * Set the extension type, and the reserved field MUST be set + * to zero. + */ + ext->type = (uint8_t)REG_CRIT_VENDOR_SPEC_EXT_TYPE; + ext->reserved = 0; + + /* + * Set the length, vendor ID and subType. Make sure that they + * are in network order. + */ + dataLen = htons(dataLen); + (void) memcpy(&ext->length, &dataLen, sizeof (uint16_t)); + + vendorId = htonl(vendorId); + (void) memcpy(&ext->vendorId, &vendorId, sizeof (uint32_t)); + + type = htons(type); + (void) memcpy(&ext->vendorType, &type, sizeof (uint16_t)); + + /* + * We simply copy the blob at the end of the MIER structure. + */ + (void) memcpy(buffer + sizeof (vendorSpecExt), data, ntohs(dataLen)); + + /* + * We need to return the size of the extension + */ + return (ntohs(dataLen) + sizeof (vendorSpecExt)); +} + +/* + * 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 +createMNKeyExt(uint8_t *buffer, int type, int subType, uint8_t *key, + size_t keyLen, uint32_t nodeSPI, uint32_t mnAAASPI, uint8_t *mnNAI, + size_t mnNAILen) +{ + keyDataExt *ext; + MipSecAssocEntry *msap; + MD5_CTX context; + time_t currentTime; + uint32_t spi; + uint32_t lifetime; + int length = 0; + char mnKey[128]; + size_t i; + + /* + * Allocate a temporary buffer + */ + ext = (keyDataExt *)malloc(sizeof (keyDataExt) + keyLen); + + if (ext == NULL) { + syslog(LOG_CRIT, "Unable to allocate memory"); + return (0); + } + + + /* + * Add the AAA SPI to the extension. This SPI is used by + * the Mobile Node in order to identify the encryption + * method. + */ + mnAAASPI = htonl(mnAAASPI); + (void) memcpy(&ext->mnAAASPI, &mnAAASPI, sizeof (uint32_t)); + + /* + * Add the node SPI, which is the SPI that the Mobile Node + * will use to reference this key + */ + spi = nodeSPI; + nodeSPI = htonl(nodeSPI); + (void) memcpy(&ext->nodeSPI, &nodeSPI, sizeof (uint32_t)); + + /* + * Add the lifetime of the session key. + */ + GET_TIME(currentTime); + lifetime = currentTime + KDC_KEY_LIFETIME; + lifetime = htonl(lifetime); + (void) memcpy(&ext->lifetime, &lifetime, sizeof (uint32_t)); + + /* + * Find the AAA SPI that we will use to encrypt the data + */ + if ((msap = + findSecAssocFromSPI(mnAAASPI, LOCK_READ)) != NULL) { + /* + * Create a new Security Association Entry + */ + if (aaaCreateKey(spi, key, keyLen, lifetime) < 0) { + syslog(LOG_CRIT, "Unable to create MN SA"); + free(ext); + /* remove the READ lock */ + (void) rw_unlock(&msap->mipSecNodeLock); + return (0); + } + + /* + * Create the hash... + */ + MD5Init(&context); + MD5Update(&context, msap->mipSecKey, + (unsigned int) msap->mipSecKeyLen); + MD5Update(&context, mnNAI, mnNAILen); + MD5Update(&context, msap->mipSecKey, + (unsigned int) msap->mipSecKeyLen); + MD5Final((uint8_t *)&mnKey, &context); + + /* + * XOR the key in the hash output + */ + for (i = 0; i < keyLen; i++) { + mnKey[i] ^= key[i]; + } + + /* + * Copy the key and set the length + */ + keyLen = sizeof (mnKey); + length = sizeof (keyDataExt) + keyLen; + (void) memcpy(ext + sizeof (keyDataExt), mnKey, keyLen); + + /* + * Create the MIER extension + */ + length = appendMierExt(buffer, type, subType, + (unsigned char *)ext, length); + + /* + * Unlock the AAA Security Association + */ + (void) rw_unlock(&msap->mipSecNodeLock); + } else { + syslog(LOG_ERR, "Failed MN-HA authentication - " + "No SPI defined"); + haCounters.haMNAuthFailureCnt++; + } + + /* + * Free the previously allocate memory. + */ + free(ext); + + 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 +createFAKeyExt(char *buffer, uint32_t vendorId, uint32_t extId, + char *key, size_t keyLen, uint32_t SPI) +{ + keyDataExt *ext; + time_t currentTime; + uint32_t spi; + uint32_t lifetime; + int length = 0; + + /* + * Allocate a temporary buffer + */ + + ext = (keyDataExt *)malloc(sizeof (keyDataExt) + keyLen); + + if (ext == NULL) { + syslog(LOG_CRIT, "Unable to allocate memory"); + return (0); + } + + /* + * The keys aren't encrypted, so the AAA SPI is set to zero. + */ + spi = htonl(0); + (void) memcpy(&ext->mnAAASPI, &spi, sizeof (uint32_t)); + + /* + * Add the node SPI, which is the SPI that the Mobile Node + * will use to reference this key + */ + spi = SPI; + SPI = htonl(SPI); + (void) memcpy(&ext->nodeSPI, &SPI, sizeof (uint32_t)); + + /* + * Add the lifetime of the session key. + */ + GET_TIME(currentTime); + lifetime = currentTime + KDC_KEY_LIFETIME; + lifetime = htonl(lifetime); + (void) memcpy(&ext->lifetime, &lifetime, sizeof (uint32_t)); + + /* + * Copy the key and set the length + */ + length = sizeof (keyDataExt) + keyLen; + (void) memcpy(ext + sizeof (keyDataExt), key, keyLen); + + /* + * Create the vendor specific extension + */ + length = appendCritVendorSpecExt((uint8_t *)buffer, vendorId, extId, + (unsigned char *)ext, length); + + /* + * 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 + */ + if (aaaCreateKey(spi, (uint8_t *)key, keyLen, lifetime) < 0) { + syslog(LOG_CRIT, "Unable to create key"); + free(ext); + return (0); + } + } + + /* + * Free the previously allocate memory. + */ + free(ext); + + 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 +findFAVEHashLookup(void *entry, uint32_t p1, uint32_t p2, uint32_t p3) +{ + FaVisitorEntry *faveEntry = entry; + + if ((faveEntry->faVisitorHomeAgentAddr == p1) && + ((uint32_t)faveEntry->faVisitorRegIsAccepted == p2)) { + 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 * +findAcceptedFAVE(HashTable *htbl, ipaddr_t mnAddr, ipaddr_t haAddr) +{ + FaVisitorEntry *entry; + + /* + * 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. + */ + entry = findHashTableEntryUint(htbl, mnAddr, LOCK_WRITE, + findFAVEHashLookup, haAddr, _B_TRUE, 0); + + 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 +FAprocessRegRequest(MessageHdr *messageHdr, MaAdvConfigEntry *entry, + ipaddr_t *inAddr) +{ + int code = MIP_SUCCESSFUL_REGISTRATION; + uint32_t mnSPI; + boolean_t forwardToHaFlag = _B_TRUE; /* If FALSE, the request is */ + /* not forwarded to the Home */ + /* Agent, but is sent to the */ + /* AAA infrastructure instead */ + authExt *mnAuthExt; + /* + * Support for generalized auth extensions. + */ + regRequest *requestPtr; + FaVisitorEntry *favePtr; + FaVisitorEntry *acceptedFAVE; + 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 */ + requestPtr = (regRequest *) messageHdr->pkt; + + mipverbose(("\n---- %s (%s) ----\n", + sprintTime(currentTime, MAX_TIME_STRING_SIZE), + sprintRelativeTime(relativeTime, MAX_TIME_STRING_SIZE))); + mipverbose(("FA got reg req of length %d [MN %s, HA %s, COA %s]\n", + messageHdr->pktLen, ntoa(requestPtr->homeAddr, addrstr1), + ntoa(requestPtr->haAddr, addrstr2), + ntoa(requestPtr->COAddr, addrstr3))); + mipverbose((" [Lifetime %d sec, ID %0#10x : %0#10x]\n", + (uint32_t)ntohs(requestPtr->regLifetime), + ntohl(requestPtr->IDHigh), + ntohl(requestPtr->IDLow))); + + mipverbose(("FAprocessRegRequest called with packet:\n")); + if (logVerbosity > 2) + printBuffer(messageHdr->pkt, messageHdr->pktLen); + mipverbose(("\n")); + + /* + * Validate the Care of Address + */ + if ((requestPtr->COAddr != *inAddr) && + (messageHdr->ifType != ON_MCAST_SOCK)) { + /* + * 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. + */ + if ((requestPtr->homeAddr == requestPtr->COAddr) && + (requestPtr->regLifetime != 0)) { + /* + * Invalid Care of Address. + */ + code = FA_INVALID_CARE_OF_ADDR; + faCounters.faInvalidCareOfAddrCnt++; + (void) rejectFromFAToMN(messageHdr, entry, code); + return; + } + } + + /* + * If the packet has any of the bits that we do not currently + * support, return an error. + */ + if (requestPtr->regFlags & REG_BIT_UNUSED) { + code = FA_POORLY_FORMED_REQUEST; + faCounters.faPoorlyFormedRequestsCnt++; + (void) rejectFromFAToMN(messageHdr, entry, code); + return; + } + + /* + * Support for new MIER-style extension header. + * + * Are extensions ok and in the right order? + */ + if (mkRegExtList(messageHdr, sizeof (regRequest)) < 0) { + code = FA_POORLY_FORMED_REQUEST; + faCounters.faPoorlyFormedRequestsCnt++; + (void) rejectFromFAToMN(messageHdr, entry, code); + return; + } + + + /* + * Packet parsing routines now return error codes. + * + * Is the packet from the Mobile Node valid? + */ + if ((code = IsPacketFromMnValid(messageHdr)) > 0) { + /* 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. + */ + faCounters.faPoorlyFormedRequestsCnt++; + } + (void) rejectFromFAToMN(messageHdr, entry, code); + 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? */ + if (ntohs(requestPtr->regLifetime) > + (unsigned short) entry->maAdvMaxRegLifetime) { + code = FA_REG_LIFETIME_TOO_LONG; + faCounters.faRegLifetimeTooLongCnt++; + (void) rejectFromFAToMN(messageHdr, entry, code); + return; + } + + /* Do we offer the requested encapsulation services? (Minimal Encap) */ + if ((requestPtr->regFlags & REG_MIN_ENCAP) && + ((entry->maAdvServiceFlags & ADV_MIN_ENCAP) == 0)) { + code = FA_ENCAP_UNAVAILABLE; + faCounters.faEncapUnavailableCnt++; + (void) rejectFromFAToMN(messageHdr, entry, code); + return; + } + + /* Do we offer the requested encapsulation services? (GRE) */ + if ((requestPtr->regFlags & REG_GRE_ENCAP) && + ((entry->maAdvServiceFlags & ADV_GRE_ENCAP) == 0)) { + code = FA_ENCAP_UNAVAILABLE; + faCounters.faEncapUnavailableCnt++; + (void) rejectFromFAToMN(messageHdr, entry, code); + return; + } + + /* Did the mobile request a reverse tunnel... */ + if (requestPtr->regFlags & REG_REVERSE_TUNNEL) { + /* ...but we're not advertising it! */ + if ((entry->maAdvServiceFlags & ADV_REVERSE_TUNNEL) == 0) { + /* + * 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). + */ + code = FA_REVERSE_TUNNEL_UNAVAILABLE; + faCounters.faReverseTunnelUnavailableCnt++; + (void) rejectFromFAToMN(messageHdr, entry, code); + 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). + */ + if (messageHdr->ttl != 255) { + code = FA_MN_TOO_DISTANT; + faCounters.faMNTooDistantCnt++; + (void) rejectFromFAToMN(messageHdr, entry, code); + 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). + */ + if ((entry->maAdvServiceFlags & ADV_REVERSE_TUNNEL) && + (entry->maReverseTunnelRequired & RT_FA)) { + /* + * 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). + */ + code = FA_REVERSE_TUNNEL_REQUIRED; + faCounters.faReverseTunnelRequiredCnt++; + (void) rejectFromFAToMN(messageHdr, entry, code); + return; + } + } + + /* Do we offer the requested compression service? */ + if ((requestPtr->regFlags & REG_VJ_COMPRESSION) && + ((entry->maAdvServiceFlags & ADV_VJ_COMPRESSION) == 0)) { + code = FA_VJ_UNAVAILABLE; + faCounters.faVJCompUnavailableCnt++; + (void) rejectFromFAToMN(messageHdr, entry, code); + 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. + */ + if (requestPtr->haAddr == requestPtr->COAddr) { + syslog(LOG_ERR, + "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 */ + GET_AUTH_EXT(messageHdr, index, REG_MF_AUTH_EXT_TYPE, + mnAuthExt, mnAuthExtLen); + + if (mnAuthExtLen) { + GET_SPI(mnSPI, mnAuthExt); + } else { + mnSPI = 0; + } + + GET_EXT_DATA(messageHdr, index, REG_MF_CHALLENGE_EXT_TYPE, + challenge, challengeLen); + + /* Try creating a visitor list entry ... */ + if ((favePtr = mkPendingFAVE(&faVisitorHash, messageHdr, + entry->maIfaceAddr, mnSPI, challenge, challengeLen)) == NULL) { + code = FA_INSUFFICIENT_RESOURCES; + faCounters.faInsufficientResourceCnt++; + (void) rejectFromFAToMN(messageHdr, entry, code); + return; + } + + acceptedFAVE = findAcceptedFAVE(&faVisitorHash, requestPtr->homeAddr, + requestPtr->haAddr); + + /* + * Support for the latest Challenge/Response I-D. + * + * 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. + */ + code = faCheckRegReqAuth(messageHdr, favePtr, acceptedFAVE, challenge, + challengeLen, &forwardToHaFlag); + + if (acceptedFAVE) { + (void) rw_unlock(&acceptedFAVE->faVisitorNodeLock); + } + + if (code) { + if (favePtr->faVisitorRegIsAccepted == _B_FALSE) { + /* + * Since the visitor entry isn't accepted, and an + * error occured, we can delete it. Otherwise, we + * will let the visitor entry expire naturally. + */ + delFAVE(&faVisitorHash, &favePtr, requestPtr->homeAddr, + REG_REVOKED); + } else { + (void) rw_unlock(&favePtr->faVisitorNodeLock); + } + (void) rejectFromFAToMN(messageHdr, entry, code); + return; + } + + (void) rw_unlock(&favePtr->faVisitorNodeLock); + + + faCounters.faRegReqRecvdCnt++; + + if (forwardToHaFlag == _B_TRUE) { + /* send the registration request to the home agent */ + (void) forwardFromFAToHA(messageHdr, entry, _B_FALSE); + } else { + mipverbose(("\n---- %s (%s) ----\n", + sprintTime(currentTime, MAX_TIME_STRING_SIZE), + sprintRelativeTime(relativeTime, MAX_TIME_STRING_SIZE))); + mipverbose(("FA relayed reg req from %s.%d to AAA for %.*s\n", + ntoa(messageHdr->src, addrstr1), messageHdr->srcPort, + (messageHdr == NULL) ? 1 : messageHdr->mnNAILen, + (messageHdr == NULL) ? "-" : (char *)messageHdr->mnNAI)); + + mipverbose(("Registration relayed by FA is:\n")); + if (logVerbosity > 2) + printBuffer(messageHdr->pkt, messageHdr->pktLen); + mipverbose(("\n")); + + faCounters.faRegReqRelayedCnt++; + + } +} + +boolean_t +forcefullyDeregisterMN(ipaddr_t *homeaddr, ipaddr_t COAaddr, + ipaddr_t homeAgentaddr) +{ + FaVisitorEntry *entry = NULL; + char tmp_buf[INET_ADDRSTRLEN]; + boolean_t result; + + + /* + * 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. + */ + + entry = findHashTableEntryUint(&faVisitorHash, *homeaddr, + LOCK_WRITE, acceptFAVEHashLookup, COAaddr, _B_TRUE, + homeAgentaddr); + + + if (entry != NULL) { + result = delHashTableEntryUint(&faVisitorHash, entry, + *homeaddr, LOCK_NONE); + if (result == _B_TRUE) { + delFAVEptr(entry, _B_FALSE, REG_REVOKED); + (void) rw_unlock(&entry->faVisitorNodeLock); + (void) rwlock_destroy(&entry->faVisitorNodeLock); + free(entry); + + return (_B_TRUE); + } + } + + mipverbose(("Couldn't find MN with homeaddr %s to close " + "session per AAA's request\n", + inet_ntop(AF_INET, (const void*)homeaddr, tmp_buf, + 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; + char device[MAX_IFNAME_LEN + 5]; + int ppa; + char buf[MAXDLBUF]; + int rval; + + ifname2devppa(IfaceName, device, &ppa); + if ((fd = open(device, (O_RDWR | O_NDELAY))) < 0) { + mipverbose(("error opening device %s in openDeviceStream\n", + IfaceName)); + return (-1); + } + + /* Attach. */ + if ((rval = dlattachreq(fd, ppa)) != 0) { + mipverbose(("Error attaching to device in openDeviceStream" + " with errno %d\n", (-1)*rval)); + (void) close(fd); + return (-1); + } + + if ((rval = dlokack(fd, buf)) != 0) { + mipverbose(("Error in DLPI ack from device in openDeviceStream" + " with errno %d\n", (-1)*rval)); + (void) close(fd); + return (-1); + } + + /* Bind. Use sap=0x0800 for IP. */ + if ((rval = dlbindreq(fd, 0x800, 0, DL_CLDLS, 0, 0)) != 0) { + mipverbose(("Error in DLPI bind in openDeviceStream" + " with errno %d\n", (-1)*rval)); + (void) close(fd); + return (-1); + } + + if ((rval = dlbindack(fd, buf)) != 0) { + mipverbose(("Error in DLPI bind ack from devicee in" + " openDeviceStream with errno %d\n", + (-1)*rval)); + (void) close(fd); + return (-1); + } + + /* Issue DLIOCRAW ioctl */ + if (mip_strioctl(fd, DLIOCRAW, NULL, 0, 0) < 0) { + (void) close(fd); + 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 +mip_in_cksum(ushort_t *addr, int len) +{ + int nleft = len; + ushort_t *w = addr; + ushort_t answer; + ushort_t odd_byte = 0; + 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) { + *(uchar_t *)(&odd_byte) = *(uchar_t *)w; + sum += odd_byte; + } + + /* add back carry outs from top 16 bits to low 16 bits */ + sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ + sum += (sum >> 16); /* add carry */ + answer = ~sum; /* truncate to 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 +mip_strioctl(int fd, int cmd, void *ptr, int ilen, int olen) +{ + struct strioctl str; + + str.ic_cmd = cmd; + str.ic_timout = 0; /* Use default timer; 15 seconds */ + str.ic_len = ilen; + str.ic_dp = ptr; + + if (ioctl(fd, I_STR, &str) == -1) { + return (-1); + } + if (str.ic_len != olen) { + 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 +sendRawPkt(MessageHdr *msgHdr, MaAdvConfigEntry *entry, uint_t pktlen) { + int fd; + char pkt[MAX_PKT_SIZE], *destaddr; + struct ether_header *ethp; + struct ip *ipp; + struct udphdr *udpp; + struct strbuf data; + int flags; + uchar_t *mipp; + + if ((fd = openDeviceStream(entry->maIfaceName)) < 0) + return (-1); + + /* Set up the ethernet header */ + /* LINTED E_BAD_PTR_CAST_ALIGN */ + ethp = (struct ether_header *)pkt; + bcopy(msgHdr->slla.sdl_data, ethp->ether_dhost.ether_addr_octet, + ETHERADDRL); + bcopy(entry->maIfaceHWaddr, ethp->ether_shost.ether_addr_octet, + ETHERADDRL); + ethp->ether_type = htons(ETHERTYPE_IP); + + /* Set up the IP header */ + /* LINTED E_BAD_PTR_CAST_ALIGN */ + ipp = (struct ip *)(pkt + sizeof (struct ether_header)); + ipp->ip_v = IPVERSION; + ipp->ip_hl = 5; /* 5 32-bit words == 20 bytes */ + ipp->ip_tos = 0; + ipp->ip_len = htons(20 + sizeof (struct udphdr) + pktlen); + ipp->ip_id = htons(1); + ipp->ip_off = 0; + ipp->ip_ttl = 1; + ipp->ip_p = IPPROTO_UDP; + ipp->ip_sum = mip_in_cksum((ushort_t *)ipp, 20); + destaddr = "255.255.255.255"; /* IP broadcast */ + (void) inet_pton(AF_INET, destaddr, &ipp->ip_dst.s_addr); + bcopy(&entry->maIfaceAddr, &ipp->ip_src.s_addr, sizeof (ipaddr_t)); + + /* Set up the UDP header */ + /* LINTED E_BAD_PTR_CAST_ALIGN */ + udpp = (struct udphdr *)((uchar_t *)ipp + sizeof (struct ip)); + udpp->uh_sport = htons(MIP_PORT); + udpp->uh_dport = htons(MIP_PORT); + udpp->uh_ulen = htons(sizeof (struct udphdr) + pktlen); + udpp->uh_sum = 0; /* udp chksum is optional */ + + /* Set up the registration reply */ + mipp = (uchar_t *)((uchar_t *)udpp + sizeof (struct udphdr)); + bcopy(msgHdr->pkt, mipp, pktlen); + + data.buf = (char *)pkt; + data.maxlen = MAX_PKT_SIZE; + data.len = sizeof (struct ether_header) + sizeof (struct ip) + + + sizeof (struct udphdr) + pktlen; + flags = 0; + + if (putmsg(fd, NULL, &data, flags) != 0) { + (void) close(fd); + return (-1); + } else { + (void) close(fd); + 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 +rejectFromFAToMN(MessageHdr *messageHdr, MaAdvConfigEntry *entry, int code) +{ + regReply *replyPtr; + boolean_t visitor_entryExists; + int val, replyLen = sizeof (regReply); /* for now... */ + 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 */ + replyPtr = (regReply *) messageHdr->pkt; + replyPtr->type = REG_REPLY_TYPE; + replyPtr->code = (uint8_t)code; + if (code == FA_REG_LIFETIME_TOO_LONG) + replyPtr->regLifetime = htons(entry->maAdvMaxRegLifetime); + + /* + * Copy the identifier from the original Registration Request + * into the Registration Reply. Since the headers are different + * this requires a bcopy. + */ + bcopy(messageHdr->pkt+16, messageHdr->pkt+12, 8); + + /* + * TODO: handle extensions? keep in mind that the request is + * poorly formed so we may not be able to do the right thing. + */ + visitor_entryExists = isAcceptedVisitor(&faVisitorHash, + replyPtr->homeAddr, entry->maIfaceAddr); + 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 && + (replyPtr->homeAddr != INADDR_ANY)) { + /* + * Add a temporary ARP entry to prevent the FA from + * broadcast ARPing. + */ + if ((val = arpIfadd(replyPtr->homeAddr, + messageHdr->slla.sdl_data, + messageHdr->inIfindex)) < 0) { + syslog(LOG_ERR, "SIOCSXARP failed... %s", + err2str(val)); + } + } + } + + /* + * 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) + */ + if ((replyPtr->homeAddr == INADDR_ANY) && messageHdr->isSllaValid) { + if (sendRawPkt(messageHdr, entry, replyLen) == 0) { + mipverbose(("\n---- %s (%s) ----\n", + sprintTime(currentTime, + MAX_TIME_STRING_SIZE), + sprintRelativeTime(relativeTime, + MAX_TIME_STRING_SIZE))); + (void) memcpy(ether.ether_addr_octet, + messageHdr->slla.sdl_data, ETHERADDRL); + mipverbose(("FA denied reg req from %s.%d for " + "MN %s [MAC: %s] (Code %d)\n", + ntoa(messageHdr->src, addrstr1), + messageHdr->srcPort, + ntoa(replyPtr->homeAddr, addrstr2), + ether_ntoa(ðer), replyPtr->code)); + mipverbose(("Registration denial sent by FA is:\n")); + if (logVerbosity > 2) + printBuffer(messageHdr->pkt, replyLen); + 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... + */ + val = messageHdr->inIfindex; + if (setsockopt(entry->maIfaceUnicastSock, IPPROTO_IP, IP_XMIT_IF, + &val, sizeof (val)) < 0) { + /* 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", + ntoa(messageHdr->src, addrstr2), val)); + } + + + if (sendUDPmessage(entry->maIfaceUnicastSock, messageHdr->pkt, + replyLen, messageHdr->src, messageHdr->srcPort) == 0) { + mipverbose(("\n---- %s (%s) ----\n", + sprintTime(currentTime, MAX_TIME_STRING_SIZE), + sprintRelativeTime(relativeTime, MAX_TIME_STRING_SIZE))); + mipverbose(("FA denied reg req from %s.%d for MN %s (Code %d)\n", + ntoa(messageHdr->src, addrstr1), messageHdr->srcPort, + ntoa(replyPtr->homeAddr, addrstr2), replyPtr->code)); + + mipverbose(("Registration denial sent by FA is:\n")); + if (logVerbosity > 2) + printBuffer(messageHdr->pkt, replyLen); + mipverbose(("\n")); + + } else { + mipverbose(("sendto failed at FA while sending denial.\n")); + } + + /* Reset IP_XMIT_IF option */ + + val = 0; + if (setsockopt(entry->maIfaceUnicastSock, IPPROTO_IP, IP_XMIT_IF, + &val, sizeof (val)) < 0) { + /* There's a problem... */ + mipverbose(("Can't unset IP_XMIT_IF socket option" + "for socket id %d\n", entry->maIfaceUnicastSock)); + } + if (visitor_entryExists == _B_FALSE) { + + if (messageHdr->isSllaValid && (replyPtr->homeAddr != + INADDR_ANY)) { + /* + * Delete the temporary ARP entry + */ + if ((val = arpIfdel(replyPtr->homeAddr, + messageHdr->slla.sdl_data, + messageHdr->inIfindex)) < 0) { + /* + * If the deletion failed bcos there was no + * entry then we don't need to report it + */ + if (val != (-1)*ENXIO) + syslog(LOG_ERR, + "SIOCDXARP failed... %s", + err2str(val)); + } + } + } + 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 +rejectFromICMPToMN(MessageHdr *messageHdr, ipaddr_t haAddr, int code) +{ + FaVisitorEntry *entry = NULL; + char srcaddrstr[INET_ADDRSTRLEN]; + char dstaddrstr[INET_ADDRSTRLEN]; + /* LINTED E_BAD_PTR_CAST_ALIGN */ + regReply *replyPtr = (regReply *)messageHdr->pkt; /* reuse it */ + int replyLen = sizeof (regReply); /* Size of registration reply */ + MipSecAssocEntry *mipSAE; + uint32_t state[2]; /* For hash-table enumeration */ + char currentTime[MAX_TIME_STRING_SIZE]; /* syslog messages */ + char relativeTime[MAX_TIME_STRING_SIZE]; /* syslog messages */ + + /* + * 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: + * A regreP takes 20 bytes (we don't need to include UDP/IP headers), + * 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! + */ + bzero(&messageHdr->pkt, messageHdr->pktLen); + + /* init the Enumerator State */ + initEnumeratorState(&state, sizeof (*(state))); + + /* enumerateAllHashTableEntries() - will return NULL when we're out. */ + while ((entry = enumerateAllHashTableEntries(&faVisitorHash, + &(state[BUCKET]), &(state[OFFSET]), LOCK_WRITE)) != NULL) { + /* 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. + */ + if ((entry->faVisitorRegIsAccepted != _B_FALSE) || + (entry->faVisitorHomeAgentAddr != haAddr)) { + /* not a MN we need to reply to */ + + /* don't forget to unlock this one! */ + (void) rw_unlock(&entry->faVisitorNodeLock); + + /* read on McDuff. */ + continue; + } + + /* This is someone to reject. */ + mipverbose(("...found a MN to reply to - IP address %s.\n", + ntoa(entry->faVisitorAddr, dstaddrstr))); + + /* Accept the entry for expiration (see delFAVEPtr())! */ + entry->faVisitorRegIsAccepted = _B_TRUE; + + /* set the important information */ + replyPtr->type = REG_REPLY_TYPE; + replyPtr->code = (uint8_t)code; + replyPtr->regLifetime = 0; + replyPtr->homeAddr = entry->faVisitorHomeAddr; + replyPtr->haAddr = entry->faVisitorHomeAgentAddr; + replyPtr->IDHigh = entry->faVisitorRegIDHigh; + replyPtr->IDLow = entry->faVisitorRegIDLow; + + /* + * The jury's out as to whether we want/should/need/MUST do + * this. For now, let's also include the NAI if it'll fit. + */ + if ((entry->faVisitorMnNAILen) && + (messageHdr->pktLen - replyLen >= + sizeof (entry->faVisitorMnNAILen))) { + replyLen += appendExt((messageHdr->pkt + replyLen), + REG_MN_NAI_EXT_TYPE, + (unsigned char *)entry->faVisitorMnNAI, + entry->faVisitorMnNAILen); + } + + /* + * 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!!! + */ + if ((messageHdr->pktLen - replyLen >= AUTHENTICATOR_LEN) && + ((mipSAE = findSecAssocFromSPI(entry->faVisitorSPI, + LOCK_READ)) != NULL)) { + /* formulate an authenticator... */ + replyLen += appendAuthExt(messageHdr->pkt, + replyLen, REG_MF_AUTH_EXT_TYPE, mipSAE); + + /* remove the READ lock */ + (void) rw_unlock(&mipSAE->mipSecNodeLock); + } + + /* + * 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. + */ + if ((val = arpIfadd(replyPtr->homeAddr, + messageHdr->slla.sdl_data, + messageHdr->inIfindex)) < 0) { + syslog(LOG_ERR, "SIOCSXARP failed... %s", + err2str(val)); + } + } + + /* + * 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... + */ + val = entry->faVisitorInIfindex; + if (setsockopt(messageHdr->ifEntry->maIfaceUnicastSock, + IPPROTO_IP, IP_XMIT_IF, &val, sizeof (val)) < 0) { + /* There's a problem... */ + syslog(LOG_ERR, + "Can't set IP_XMIT_IF socket option for" + " registration reply to mobile node %s.", + ntoa(messageHdr->src, srcaddrstr)); + } + + /* may as well try anyway (we do this elsewhere) */ + if (sendUDPmessage(messageHdr->ifEntry->maIfaceUnicastSock, + messageHdr->pkt, messageHdr->pktLen, entry->faVisitorAddr, + entry->faVisitorPort) == 0) { + mipverbose(("\n---- %s (%s) ----\n", + sprintTime(currentTime, + MAX_TIME_STRING_SIZE), + sprintRelativeTime(relativeTime, + MAX_TIME_STRING_SIZE))); + mipverbose(("FA sent ICMP-reply to %s.%d (Code %d)\n", + ntoa(entry->faVisitorAddr, dstaddrstr), + entry->faVisitorPort, replyPtr->code)); + mipverbose(("FA sent ICMP-reply packet:\n")); + if (logVerbosity > 2) + printBuffer(messageHdr->pkt, + messageHdr->pktLen); + mipverbose(("\n")); + + } else { + syslog(LOG_ERR, + "sendto failed while sending ICMP-reply."); + } + + /* Reset IP_XMIT_IF option on socket */ + val = 0; + if (setsockopt(messageHdr->ifEntry->maIfaceUnicastSock, + IPPROTO_IP, IP_XMIT_IF, &val, sizeof (val)) < 0) { + syslog(LOG_ERR, + "Can't unset socket option IP_XMIT_IF" + "which was set for interface index %d", + entry->faVisitorInIfindex); + } + + /* cleanup */ + if (messageHdr->isSllaValid) { + /* + * Delete the temporary ARP entry + */ + if ((val = arpIfdel(replyPtr->homeAddr, + messageHdr->slla.sdl_data, + messageHdr->inIfindex)) < 0) { + /* + * If the deletion failed + * because there was no entry + * entry then we don't need to + * report it. + */ + if (val != (-1)*ENXIO) { + syslog(LOG_ERR, + "SIOCDXARP failed %s", + err2str(val)); + } + } + } + + /* + * Should we delete this FAVisitorEntry? The reason to do so + * is if there's multiple MNs to reply to, we're going to send + * registration replies to all of them at this time. When/if + * 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. + */ + delFAVEptr(entry, _B_TRUE, REASON_UNKNOWN); + + /* don't forget to unlock this one! */ + (void) rw_unlock(&entry->faVisitorNodeLock); + + } /* fin looping through pending entries */ + + + /* we're out of MNs, so we're done reacting to the ICMP */ + return; + +} /* rejectFromICMPToMN() */ + + +void +forwardFromFAToHA(MessageHdr *messageHdr, MaAdvConfigEntry *entry, + boolean_t triggeredByRadius) +{ + regRequest *requestPtr; + /* LINTED E_FUNC_SET_NOT_USED */ + authExt *mnAuthExt; + MipSecAssocEntry *mipSecAssocEntry; + MobilityAgentEntry *mae; + 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 */ + genAuthExt *maAuthExt; + /* LINTED E_FUNC_SET_NOT_USED */ + unsigned char *challenge; + size_t challengeLen = 0; + + mipverbose(("forwardFromFAToHA...")); + /* LINTED E_BAD_PTR_CAST_ALIGN */ + requestPtr = (regRequest *) messageHdr->pkt; + + /* + * RFC3012: + * + * Valid cases: MH FAC MN-AAA + * FAC MN-AAA + * MH FAC MF + * MH + */ + + /* + * Is Foreign Agent Challenge present? + */ + GET_EXT_DATA(messageHdr, index, REG_MF_CHALLENGE_EXT_TYPE, + challenge, challengeLen); + challengeindex = index; + + if (!triggeredByRadius) { + if (challengeLen == 0) { + /* LINTED E_BAD_PTR_CAST_ALIGN */ + GET_AUTH_EXT(messageHdr, index, REG_MH_AUTH_EXT_TYPE, + mnAuthExt, mnAuthExtLen); + } + } + if (mnAuthExtLen == 0 || triggeredByRadius) { + /* + * Support for the generalized + * authentication extension. + */ + + /* LINTED BAD_PTR_CAST_ALIGN */ + GET_GEN_AUTH_EXT(messageHdr, index, + GEN_AUTH_MN_AAA, maAuthExt, maAuthExtLen); + /* + * Case where we have: + * + * MH FAC MF + */ + if (maAuthExtLen == 0 && challengeLen != 0) { + index = challengeindex; + } + } + + /* + * 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). + */ + messageHdr->pktLen = (messageHdr->extIdx[index] - messageHdr->pkt); + + /* + * Increase the packet length. + */ + messageHdr->pktLen += messageHdr->extHdrLength[index] + + messageHdr->extLength[index]; + + /* + * 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 = + findSecAssocFromIp(requestPtr->haAddr, + LOCK_READ)) != NULL) { + + messageHdr->pktLen += appendAuthExt(messageHdr->pkt, + messageHdr->pktLen, REG_FH_AUTH_EXT_TYPE, + mipSecAssocEntry); + + /* + * As promised, we unlock the SA + */ + (void) rw_unlock(&mipSecAssocEntry->mipSecNodeLock); + } else { + /* + * Was authentication required? + */ + if (fhAuthRequired) { + syslog(LOG_ERR, "Error: No Sa for Home Agent"); + code = HA_FA_AUTH_FAILURE; + faCounters.faHAAuthFailureCnt++; + rejectFromFAToMN(messageHdr, entry, code); + 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. + */ + if ((mae = findMaeFromIp(requestPtr->haAddr, LOCK_READ)) != NULL) { + if (((mae->maIPsecFlags & IPSEC_REQUEST_APPLY) == 0) && + (IPSEC_REQUEST_ANY(mae->maIPsecSAFlags[IPSEC_APPLY]))) { + /* Policy hasn't been installed for this agent-peer */ + char peerAddr[IPv4_ADDR_LEN]; + + (void) ntoa(mae->maAddr, peerAddr); + + /* do whatever we do to install the ipsec policy */ + if (installIPsecPolicy(mae->maIPsecRequest[IPSEC_APPLY]) + < 0) { + /* failed, log it */ + syslog(LOG_CRIT, + "Could not install %s for [Address %s]: %s", + IPSEC_POLICY_STRING(IPSEC_REQUEST_APPLY), + peerAddr, mae->maIPsecRequest[IPSEC_APPLY]); + + /* unlock */ + (void) rw_unlock(&mae->maNodeLock); + + /* never ignore SAs - fail */ + return; + } + + /* set the flag */ + mae->maIPsecFlags |= IPSEC_REQUEST_APPLY; + } + + /* + * 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. + */ + if (((mae->maIPsecFlags & IPSEC_REPLY_PERMIT) == 0) && + (IPSEC_REPLY_ANY(mae->maIPsecSAFlags[IPSEC_PERMIT]))) { + /* This SA hasn't been installed for this agent-peer */ + char peerAddr[IPv4_ADDR_LEN]; + + /* this is for error reporting */ + (void) ntoa(mae->maAddr, peerAddr); + + /* have ipsec add it */ + if (installIPsecPolicy(mae->maIPsecReply[IPSEC_PERMIT]) + < 0) { + /* Failed - log it. */ + syslog(LOG_CRIT, + "Could not install %s for [Address %s]: %s", + IPSEC_POLICY_STRING(IPSEC_REPLY_PERMIT), + peerAddr, mae->maIPsecReply[IPSEC_PERMIT]); + + /* unlock */ + (void) rw_unlock(&mae->maNodeLock); + + /* Never send if we can't enforce policy. */ + return; + } + /* set the flag */ + mae->maIPsecFlags |= IPSEC_REPLY_PERMIT; + } + + /* we're sending, so this agent is now officially an HA peer */ + mae->maPeerFlags |= HA_PEER; + + /* unlock */ + (void) rw_unlock(&mae->maNodeLock); + } + + /* forward to home agent */ + if (sendUDPmessage(entry->maIfaceUnicastSock, + messageHdr->pkt, messageHdr->pktLen, requestPtr->haAddr, + MIP_PORT) == 0) { + mipverbose(("\n---- %s (%s) ----\n", + sprintTime(currentTime, MAX_TIME_STRING_SIZE), + sprintRelativeTime(relativeTime, + MAX_TIME_STRING_SIZE))); + mipverbose(("FA relayed reg req from %s.%d to HA " + "%s.%d for MN homeaddr %s\n", + ntoa(messageHdr->src, addrstr1), + messageHdr->srcPort, + ntoa(requestPtr->haAddr, addrstr2), MIP_PORT, + ntoa(requestPtr->homeAddr, addrstr3))); + + mipverbose(("Registration of length %d relayed by " \ + "FA is:\n", messageHdr->pktLen)); + if (logVerbosity > 2) { + printBuffer(messageHdr->pkt, + messageHdr->pktLen); + } + mipverbose(("\n")); + + faCounters.faRegReqRelayedCnt++; + } else { + syslog(LOG_ERR, "sendto failed at FA while relaying " + "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 +delHABE(HaMobileNodeEntry **hamnePtr, ipaddr_t mnAddr, ipaddr_t COAddr, + uint32_t *sessionLifeTime) +{ + HaBindingEntry *entry; + HaBindingEntry *prev_entry = NULL; + time_t currentTime; + char addrstr1[INET_ADDRSTRLEN]; + char addrstr2[INET_ADDRSTRLEN]; + + *sessionLifeTime = 0; + + mipverbose(("delHABE called for mnAddr %s COAddr %s\n", + ntoa(mnAddr, addrstr1), + ntoa(COAddr, addrstr2))); + + entry = (*hamnePtr)->bindingEntries; + + while (entry) { + if ((entry->haBindingMN == mnAddr) && + (entry->haBindingCOA == COAddr)) { + /* Found a match, delete it */ + if (prev_entry == NULL) { + (*hamnePtr)->bindingEntries = + entry->next; + } else { + prev_entry->next = entry->next; + } + + delHABEent(*hamnePtr, entry); + + GET_TIME(currentTime); + *sessionLifeTime += currentTime - + entry->haBindingTimeGranted; + free(entry); + break; + } + prev_entry = entry; + entry = entry->next; + } + + /* + * We need to delete the Mobile Node Entry if the + * entry was dynamic and has no more bindings. + */ + if ((*hamnePtr)->haMnBindingCnt == 0 && + (*hamnePtr)->haMnIsEntryDynamic == TRUE) { + mipverbose(("Deleting Mobile Node #1")); + /* Expired */ + if (delHashTableEntryUint(&haMobileNodeHash, *hamnePtr, + mnAddr, LOCK_NONE) == _B_FALSE) { + syslog(LOG_ERR, "Unable to delete Mobile Node Entry"); + } else { + (void) rw_unlock(&(*hamnePtr)->haMnNodeLock); + (void) rwlock_destroy(&(*hamnePtr)->haMnNodeLock); + free(*hamnePtr); + *hamnePtr = NULL; + } + } +} + + +/* + * 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 +addHABE(HaMobileNodeEntry *hamnePtr, ipaddr_t src, in_port_t srcPort, + MaAdvConfigEntry *ifEntry, uint8_t regFlags, ipaddr_t homeAddr, + ipaddr_t COAddr, ipaddr_t haAddr, uint32_t lifetime, + boolean_t *existingBinding, uint32_t *sessionLifeTime) +{ + int val; + time_t currentTime; + HaBindingEntry *hentry; + HaBindingEntry *prev_hentry = NULL; + HaBindingEntry *tmp; + char addrstr1[INET_ADDRSTRLEN]; + char addrstr2[INET_ADDRSTRLEN]; + char addrstr3[INET_ADDRSTRLEN]; + + + *existingBinding = _B_FALSE; + *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 + */ + regFlags &= ~REG_SIMULTANEOUS_BINDINGS; +#endif + + /* + * If the interface was not provided, it is because we are trying + * to restore a binding entry... Let's find it. + */ + if (ifEntry == NULL) { + /* + * Get the matching maIfaceAddr from mnAdvConfigTable + */ + if ((ifEntry = (MaAdvConfigEntry *)findHashTableEntryUint( + &maAdvConfigHash, hamnePtr->haBindingIfaceAddr, + LOCK_NONE, NULL, 0, 0, + 0)) == NULL) { + syslog(LOG_ERR, "Unable to find interface in hash " \ + "table"); + return (-1); + } + } + + hentry = hamnePtr->bindingEntries; + + while (hentry) { + if (hentry->haBindingMN == homeAddr) { + if (hentry->haBindingCOA == COAddr) { + *existingBinding = _B_TRUE; + hentry->haBindingSrcAddr = src; + hentry->haBindingHaAddr = haAddr; + + /* + * We now compare the lifetime + * received in the request with the value + * configured on the interface. + */ + GET_TIME(currentTime); + if ((ntohs(lifetime) > + (unsigned short) + ifEntry->maAdvMaxRegLifetime)) { + hentry->haBindingTimeExpires = + currentTime + + (uint32_t) + ifEntry->maAdvMaxRegLifetime; + } else { + hentry->haBindingTimeExpires = + currentTime + + (uint32_t)ntohs( + lifetime); + } + hentry->haBindingSrcPort = srcPort; + hentry->haBindingRegFlags = regFlags; + + mipverbose(( + "HA renewed binding %s@%s " + "for %ld sec (Binding cnt %d).\n", + ntoa(homeAddr, addrstr1), + ntoa(COAddr, addrstr2), + hentry->haBindingTimeGranted, + hamnePtr->haMnBindingCnt)); + + GET_TIME(currentTime); + *sessionLifeTime = currentTime - + hentry->haBindingTimeGranted; + hentry->haBindingTimeGranted = currentTime; + } 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) { + hamnePtr->bindingEntries = + hentry->next; + } else { + prev_hentry->next = + hentry->next; + } + + tmp = hentry->next; + + delHABEent(hamnePtr, hentry); + + free(hentry); + hentry = tmp; + continue; + } + } + } + + prev_hentry = hentry; + hentry = hentry->next; + } + + if (*existingBinding == _B_TRUE) + return (0); + + /* + * We did not find an entry, now we create one. + */ + if ((hentry = + (HaBindingEntry *)calloc(1, sizeof (HaBindingEntry))) == NULL) { + return (-1); + } + + /* + * We need to create a new entry ... + * update binding count for this mobile node and total bindings + */ + hamnePtr->haMnBindingCnt++; + + mipverbose(("At %s, creating tunnel for %s through %s %s\n", + ntoa(haAddr, addrstr1), ntoa(homeAddr, addrstr2), + ntoa(COAddr, addrstr3), + (regFlags & REG_SIMULTANEOUS_BINDINGS) ? "(simultaneous)":"")); + + if ((val = encapadd(homeAddr, haAddr, COAddr, + (uint8_t)regFlags & REG_REVERSE_TUNNEL)) < 0) { + syslog(LOG_ERR, "encapadd failed ... %s", err2str(val)); + } + + /* + * Proxy arp only works for non-PPP interfaces. + */ + if (((ifEntry->maIfaceFlags & IFF_POINTOPOINT) == 0) && + (hamnePtr->haMnBindingCnt == 1)) { + mipverbose(("Enabling tunneling for %s.\n", + ntoa(homeAddr, addrstr1))); + + mipverbose(("Setting proxy arp for %s at %s\n", + ntoa(homeAddr, addrstr1), + hwAddrWrite(ifEntry->maIfaceHWaddr, addrstr2))); + + if ((val = arpadd(homeAddr, + ifEntry->maIfaceHWaddr, ATF_PUBL)) < 0) { + syslog(LOG_ERR, "First arpadd (proxy) failed ... %s", + err2str(val)); + } + + /* + * 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. + */ + haCounters.haGratuitousARPsSentCnt++; + } + +#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. + */ + if (isInsideProtectedDomain(COAddr) == FALSE) { + mipverbose(("At %s, creating tunnel for %s through firewall %s 0\n", + ntoa(haAddr, addrstr1), ntoa(COAddr, addrstr2), + ntoa(domainInfo.fwAddr[0], addrstr3))); + + if ((val = encapadd(COAddr, haAddr, domainInfo.fwAddr[0], + (uint8_t)regFlags & REG_REVERSE_TUNNEL)) < 0) { + syslog(LOG_ERR, "encapadd failed ... %s", err2str(val)); + } + } +#endif /* FIREWALL_SUPPORT */ + + hentry->haBindingMN = homeAddr; + hentry->haBindingCOA = COAddr; + hentry->haBindingSrcAddr = src; + hentry->haBindingHaAddr = haAddr; + + /* + * We now compare the lifetime received in the request with the value + * configured on the interface. + */ + GET_TIME(hentry->haBindingTimeGranted); + if (ntohs(lifetime) > (unsigned short) ifEntry->maAdvMaxRegLifetime) { + hentry->haBindingTimeExpires = + hentry->haBindingTimeGranted + + (uint32_t)ifEntry->maAdvMaxRegLifetime; + } else { + hentry->haBindingTimeExpires = + hentry->haBindingTimeGranted + + (uint32_t)ntohs(lifetime); + } + hentry->haBindingSrcPort = srcPort; + hentry->haBindingRegFlags = regFlags; + + /* + * Add the node to the queue + */ + hentry->next = hamnePtr->bindingEntries; + hamnePtr->bindingEntries = hentry; + + mipverbose(("HA added binding %s@%s at entry %p " + "for %ld sec (Binding cnt %d).\n", + ntoa(homeAddr, addrstr1), ntoa(COAddr, addrstr2), (void *)hentry, + hentry->haBindingTimeGranted, hamnePtr->haMnBindingCnt)); + + return (0); +} + +#ifdef RADIUS_ENABLED +void +radiusCloseSession(HaMobileNodeEntry *hamnePtr) +{ + char addr[20]; +#ifdef RADIUS_DEBUG + (void) fprintf(stderr, "Closing Session %p\n", hamnePtr->haRadiusState); +#endif + radCloseSession(hamnePtr->haRadiusState, + ntoa(hamnePtr->haMnAddr, addr), NULL); +#ifdef RADIUS_DEBUG + (void) fprintf(stderr, "Finished Closing Session %p\n", + hamnePtr->haRadiusState); +#endif + hamnePtr->haRadiusState = NULL; +} /* 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 +HAdispatchRadius(MessageHdr *messageHdr, MaAdvConfigEntry *entry, + ipaddr_t *inAddr) +{ + HaMobileNodeEntry *mnEntry = NULL; + uint32_t mnSPI = 0; + uint32_t faSPI = 0; + int code = 0; + + /* If Auth failure from checking radius Answer (e.g., AVP's wrong) */ + if (messageHdr->aaaResultCode == HA_MN_AUTH_FAILURE) { + haCounters.haMNAuthFailureCnt++; + code = HA_MN_AUTH_FAILURE; + } else if (messageHdr->aaaResultCode == HA_REVERSE_TUNNEL_REQUIRED) { + haCounters.haReverseTunnelRequiredCnt++; + code = HA_REVERSE_TUNNEL_REQUIRED; + } + if (code == 0) { + /* Assume no hamnePtr - no MobileNodeEntry (mnEntry) so far */ + code = haCheckRegReqAuthContinue(messageHdr, &mnEntry, &mnSPI, + &faSPI); + } + (void) HAprocessRegRequestContinue(messageHdr, messageHdr->ifEntry, + inAddr, code, mnEntry, mnSPI, 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. + * + * If DIAMETER/RADIUS was enabled, we will issue accounting + * records to the AAA. + * + * Returns: + */ +/* ARGSUSED */ +void +HAprocessRegRequest(MessageHdr *messageHdr, MaAdvConfigEntry *entry, + ipaddr_t *inAddr) +{ + int code = MIP_SUCCESSFUL_REGISTRATION; + uint32_t faSPI = 0; + uint32_t mnSPI = 0; + regRequest *requestPtr; + HaMobileNodeEntry *mnEntry = NULL; + 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 okID = _B_FALSE; + + /* LINTED BAD_PTR_CAST_ALIGN */ + requestPtr = (regRequest *) messageHdr->pkt; + + mipverbose(("\n---- %s (%s) ----\n", + sprintTime(currentTime, MAX_TIME_STRING_SIZE), + sprintRelativeTime(relativeTime, MAX_TIME_STRING_SIZE))); + mipverbose(("HA got reg req [MN %s, HA %s, COA %s]\n", + ntoa(requestPtr->homeAddr, addrstr1), + ntoa(requestPtr->haAddr, addrstr2), + ntoa(requestPtr->COAddr, addrstr3))); + mipverbose((" [Lifetime %d sec, ID %0#10x : %0#10x]\n", + (uint32_t)ntohs(requestPtr->regLifetime), + ntohl(requestPtr->IDHigh), + ntohl(requestPtr->IDLow))); + + mipverbose(("HAprocessRegRequest called for pkt:\n")); + if (logVerbosity > 2) + printBuffer(messageHdr->pkt, messageHdr->pktLen); + mipverbose(("\n")); + + /* + * If we are not the home agent, then reject this request. + */ + if ((requestPtr->haAddr != *inAddr) && + (messageHdr->ifType != ON_BCAST_SOCK)) { + code = HA_UNKNOWN_HOME_AGENT; + haCounters.haUnknownHACnt++; + HABuildRegReply(messageHdr, messageHdr->ifEntry, + code, mnEntry, faSPI, NULL, okID, _B_FALSE, 0, + _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. + */ + if ((requestPtr->regFlags & REG_BIT_UNUSED) || + ((requestPtr->homeAddr == requestPtr->COAddr) && + (requestPtr->regLifetime != 0))) { + code = HA_POORLY_FORMED_REQUEST; + haCounters.haPoorlyFormedRequestsCnt++; + HABuildRegReply(messageHdr, messageHdr->ifEntry, + code, mnEntry, faSPI, NULL, okID, _B_FALSE, 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. + */ + if ((requestPtr->haAddr == requestPtr->COAddr) && + (requestPtr->regLifetime != 0)) { + code = HA_POORLY_FORMED_REQUEST; + haCounters.haPoorlyFormedRequestsCnt++; + HABuildRegReply(messageHdr, messageHdr->ifEntry, + code, mnEntry, faSPI, NULL, okID, _B_FALSE, 0, + _B_FALSE); + return; + } + + /* + * Support for new MIER-style extension header. + * + * Are extensions ok and in the right order? + */ + if (mkRegExtList(messageHdr, sizeof (regRequest)) < 0) { + code = HA_POORLY_FORMED_REQUEST; + haCounters.haPoorlyFormedRequestsCnt++; + HABuildRegReply(messageHdr, messageHdr->ifEntry, + code, mnEntry, faSPI, NULL, okID, _B_FALSE, 0, _B_FALSE); + return; + } + + /* + * Is the packet from Care-of address (FA or colocated MN) valid? + */ + if ((code = IsPacketFromCoaValid(messageHdr)) > 0) { + haCounters.haPoorlyFormedRequestsCnt++; + HABuildRegReply(messageHdr, messageHdr->ifEntry, + code, mnEntry, faSPI, NULL, okID, _B_FALSE, + 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. + */ + code = haCheckRegReqAuth(messageHdr, &mnEntry, &mnSPI, &faSPI); + + if (code == HA_MN_AUTH_FAILURE) { + HABuildRegReply(messageHdr, messageHdr->ifEntry, + code, mnEntry, faSPI, NULL, okID, _B_FALSE, 0, + _B_FALSE); + return; + } + + if (aaaProtocol != RADIUS) { + HAprocessRegRequestContinue(messageHdr, + messageHdr->ifEntry, inAddr, code, mnEntry, mnSPI, + 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. + * + * If DIAMETER/RADIUS was enabled, we will issue accounting + * records to the AAA. + * + * Returns: + */ + +/* ARGSUSED */ +static void +HAprocessRegRequestContinue(MessageHdr *messageHdr, MaAdvConfigEntry *entry, + ipaddr_t *inAddr, int code, HaMobileNodeEntry *mnEntry, uint32_t mnSPI, + uint32_t faSPI) +{ + regRequest *requestPtr; + boolean_t locallyAssignedAddress = _B_FALSE; + MipSecAssocEntry *mnsae = NULL; + int okID = _B_FALSE; + boolean_t existingBindings = _B_FALSE; + uint32_t sessionLifeTime = 0; + char addrstr1[INET_ADDRSTRLEN]; + + /* LINTED BAD_PTR_CAST_ALIGN */ + requestPtr = (regRequest *) messageHdr->pkt; + + if (code) { + goto reply; + } + + /* + * If we do not have a Mobile Node entry, let's see if + * we can create one. + */ + if (mnEntry == NULL) { + if (requestPtr->regLifetime == 0) { + /* + * A Mobile Node entry is needed for deregistration + * purposes. Let's silently discard this one. + */ + syslog(LOG_ERR, "Received a deregistration from an " + "unknown Mobile Node"); + return; + } + + /* + * Is the Mobile Node requesting an IP Address? + */ + if (defaultPool && requestPtr->homeAddr == INADDR_ANY) { + requestPtr->homeAddr = + GetAddressFromPool(defaultPool); + + if (requestPtr->homeAddr == INADDR_ANY) { + code = HA_INSUFFICIENT_RESOURCES; + syslog(LOG_ERR, "Unable to allocate address " + "from address pool %d", + defaultPool); + haCounters.haInsufficientResourceCnt++; + goto reply; + } + locallyAssignedAddress = _B_TRUE; + } + + /* + * 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)); + mnEntry = CreateMobileNodeEntry(_B_TRUE, + requestPtr->homeAddr, (char *)messageHdr->mnNAI, + messageHdr->mnNAILen, 0, mnSPI, NULL, + (locallyAssignedAddress == _B_TRUE) ? defaultPool : 0); + + if (mnEntry == NULL) { + /* + * We've got some bigger fish to fry... + */ + syslog(LOG_CRIT, "Unable to create dynamic MN Entry"); + haCounters.haInsufficientResourceCnt++; + code = HA_INSUFFICIENT_RESOURCES; + goto reply; + } + } else { + /* + * Is the Mobile Node requesting an IP Address? + */ + if (mnEntry->haPoolIdentifier && + requestPtr->homeAddr == INADDR_ANY) { + /* + * If we've already allocated an address, and + * the Mobile Node is still requesting one, let's + * free what we already have. + */ + if (mnEntry->haMnAddr) { + requestPtr->homeAddr = mnEntry->haMnAddr; + } else { + requestPtr->homeAddr = GetAddressFromPool( + mnEntry->haPoolIdentifier); + + if (requestPtr->homeAddr == INADDR_ANY) { + code = HA_INSUFFICIENT_RESOURCES; + syslog(LOG_ERR, "Unable to allocate " + "address from address " + "pool %d", + mnEntry->haPoolIdentifier); + haCounters. + haInsufficientResourceCnt++; + goto reply; + } + /* + * Save the allocated address + */ + mnEntry->haMnAddr = requestPtr->homeAddr; + locallyAssignedAddress = _B_TRUE; + } + } + } + + /* + * Was HA a broadcast address? + */ + if (requestPtr->haAddr != entry->maIfaceAddr) { + code = HA_UNKNOWN_HOME_AGENT; + haCounters.haUnknownHACnt++; + goto reply; + } + + /* + * Check if the number of active bindings exceeds the + * maximum allowed. + */ + if ((requestPtr->regFlags & REG_SIMULTANEOUS_BINDINGS) && + (mnEntry->haMnBindingCnt == MAX_SIMULTANEOUS_BINDINGS)) { + code = HA_TOO_MANY_SIMULTANEOUS; + haCounters.haTooManyBindingsCnt++; + 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. + */ + if ((mnsae = findSecAssocFromSPI(mnEntry->haMnSPI, + LOCK_READ)) == NULL) { + syslog(LOG_ERR, "Unable to find MN SPI for %s", + ntoa(requestPtr->homeAddr, addrstr1)); + code = HA_MN_AUTH_FAILURE; + goto reply; + } + + /* + * Check ID used for replay protection + */ + okID = HAisIDok(mnEntry->haMnRegIDHigh, mnEntry->haMnRegIDLow, + ntohl(requestPtr->IDHigh), ntohl(requestPtr->IDLow), + mnsae->mipSecReplayMethod); + + if (okID == _B_FALSE) { + code = HA_ID_MISMATCH; + haCounters.haIDMismatchCnt++; + goto reply; + } + + + if (requestPtr->regLifetime == 0) { + /* Do Radius Close Session */ +#ifdef RADIUS_ENABLED + if (radiusEnabled) + radiusCloseSession(mnEntry); +#endif /* RADIUS_ENABLED */ + haCounters.haDeRegReqRecvdCnt++; + delHABE(&mnEntry, requestPtr->homeAddr, requestPtr->COAddr, + &sessionLifeTime); + } else { + haCounters.haRegReqRecvdCnt++; + + /* + * 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! + */ + if (requestPtr->regFlags & REG_REVERSE_TUNNEL) { + /* MNs requesting, are we allowing? */ + if (!(entry->maReverseTunnelAllowed & RT_HA)) { + /* + * 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). + */ + code = HA_REVERSE_TUNNEL_UNAVAILABLE; + haCounters.haReverseTunnelUnavailableCnt++; + 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! + */ + if (entry->maReverseTunnelRequired & RT_HA) { + code = HA_REVERSE_TUNNEL_REQUIRED; + haCounters.haReverseTunnelRequiredCnt++; + } /* OK to proceed with the usual tunnel setup... */ + + } + + if (addHABE(mnEntry, messageHdr->src, messageHdr->srcPort, + messageHdr->ifEntry, requestPtr->regFlags, + requestPtr->homeAddr, requestPtr->COAddr, + requestPtr->haAddr, requestPtr->regLifetime, + &existingBindings, + &sessionLifeTime) < 0) { + code = HA_INSUFFICIENT_RESOURCES; + haCounters.haInsufficientResourceCnt++; + goto reply; + } + } + +#ifdef NO_SIMULTANEOUS + if (requestPtr->regFlags & REG_SIMULTANEOUS_BINDINGS) { + /* + * If simultaneous bindings was requested, set the appropriate + * acceptance code. + */ + code = MIP_SIMULTANEOUS_NOT_SUPPORTED; + } +#endif + +reply: + + HABuildRegReply(messageHdr, messageHdr->ifEntry, + code, mnEntry, faSPI, mnsae, okID, locallyAssignedAddress, + sessionLifeTime, existingBindings); +} + +static void +HABuildRegReply(MessageHdr *messageHdr, MaAdvConfigEntry *entry, + int code, HaMobileNodeEntry *mnEntry, uint32_t faSPI, + MipSecAssocEntry *mnsae, int okID, boolean_t locallyAssignedAddress, + uint32_t sessionLifeTime, boolean_t existingBindings) +{ + regReply *replyPtr; + regRequest *requestPtr; + unsigned char *challenge; + unsigned char challengeBuffer[ADV_MAX_CHALLENGE_LENGTH]; + size_t challengeLen = 0; + int index; + ipaddr_t COAddr; + ipaddr_t haAddr; + ipaddr_t homeAddr; + char NAIBuffer[ADV_MAX_NAI_LENGTH]; + uint32_t IDhi; + uint32_t IDlo; + time_t localTime; + int repLen; + MipSecAssocEntry *mipSecAssocEntry; + boolean_t ignoreTunnel; +#ifdef FIREWALL_SUPPORT + uint8_t tFlags; + boolean_t encapToFw; +#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 */ + requestPtr = (regRequest *) messageHdr->pkt; + + /* + * Retrieve the Challenge + */ + GET_EXT_DATA(messageHdr, index, REG_MF_CHALLENGE_EXT_TYPE, + challenge, challengeLen); + + /* + * Copy the challenge into a buffer so that we can manipulate it + * later... + */ + if (challengeLen > 0) { + if (challengeLen > ADV_MAX_CHALLENGE_LENGTH) { + syslog(LOG_ERR, "Challenge length exceeds maximum " + "supported length"); + code = HA_POORLY_FORMED_REQUEST; + haCounters.haPoorlyFormedRequestsCnt++; + } else { + (void) memcpy(challengeBuffer, challenge, challengeLen); + } + } + + /* + * For now, we'll create the new packet in place. But not before we + * save some of the fields that could get overwritten. + */ + COAddr = requestPtr->COAddr; /* this is the only one we risk losing */ + haAddr = requestPtr->haAddr; + homeAddr = requestPtr->homeAddr; +#ifdef FIREWALL_SUPPORT + tFlags = requestPtr->regFlags; +#endif + /* + * If we have an NAI, save it. + */ + if (messageHdr->mnNAILen) { + (void) memcpy(NAIBuffer, messageHdr->mnNAI, + messageHdr->mnNAILen); + } + + /* LINTED BAD_PTR_CAST_ALIGN */ + replyPtr = (regReply *) messageHdr->pkt; + replyPtr->type = REG_REPLY_TYPE; + replyPtr->code = (uint8_t)code; + if (ntohs(requestPtr->regLifetime) > entry->maAdvMaxRegLifetime) { + replyPtr->regLifetime = + htons(entry->maAdvMaxRegLifetime); + } else { + replyPtr->regLifetime = requestPtr->regLifetime; + } + replyPtr->homeAddr = homeAddr; + replyPtr->haAddr = entry->maIfaceAddr; + + HAnewID(&IDhi, &IDlo, ntohl(requestPtr->IDHigh), + ntohl(requestPtr->IDLow), + (mnsae == NULL) ? NONE : mnsae->mipSecReplayMethod, okID); + if (mnEntry != NULL && mnsae != NULL) { + HAstoreID(&(mnEntry->haMnRegIDHigh), &(mnEntry->haMnRegIDLow), + IDhi, IDlo, mnsae->mipSecReplayMethod, okID); + GET_TIME(localTime); + if (code) { + mnEntry->haServiceRequestsDeniedCnt++; + mnEntry->haRecentServiceDeniedCode = code; + mnEntry->haRecentServiceDeniedTime = localTime; + } else { + mnEntry->haServiceRequestsAcceptedCnt++; + mnEntry->haRecentServiceAcceptedTime = localTime; + } + } + replyPtr->IDHigh = htonl(IDhi); + replyPtr->IDLow = htonl(IDlo); + repLen = sizeof (regReply); + + /* + * 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. + */ + (void) rw_unlock(&mnsae->mipSecNodeLock); + } + + if (messageHdr->mnNAILen) { + repLen += appendExt((messageHdr->pkt + repLen), + REG_MN_NAI_EXT_TYPE, (unsigned char *) NAIBuffer, + messageHdr->mnNAILen); + } + + /* + * 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 + if ((messageHdr->pktSource == MIP_PKT_FROM_AAA && + messageHdr->mnHaKeyLen) || + messageHdr->kdcKeysPresent == _B_TRUE) { + 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. + */ + repLen += createMNKeyExt((messageHdr->pkt + repLen), + REG_GEN_MN_HA_KEY_EXT_TYPE, GEN_KEY_MN_HA, + messageHdr->mnHaKey, messageHdr->mnHaKeyLen, + messageHdr->mnHaSPI, messageHdr->mnAAASPI, + (uint8_t *)NAIBuffer, messageHdr->mnNAILen); + mnEntry->haMnSPI = messageHdr->mnHaSPI; + } else { +#else /* KEY_DISTRIBUTION */ + if (messageHdr->pktSource == MIP_PKT_FROM_AAA && + messageHdr->mnHaKeyLen && (aaaProtocol == DIAMETER)) { +#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. + */ + repLen += appendMierExt((messageHdr->pkt + repLen), + REG_GEN_MN_HA_KEY_EXT_TYPE, GEN_KEY_MN_HA, + messageHdr->mnHaKey, messageHdr->mnHaKeyLen); +#ifdef KEY_DISTRIBUTION + } +#endif /* KEY_DISTRIBUTION */ + } + +#ifdef KEY_DISTRIBUTION + if ((messageHdr->pktSource == MIP_PKT_FROM_AAA && + messageHdr->mnFaKeyLen) || + messageHdr->kdcKeysPresent == _B_TRUE) { + 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. + */ + repLen += createMNKeyExt((messageHdr->pkt + repLen), + REG_GEN_MN_FA_KEY_EXT_TYPE, GEN_KEY_MN_FA, + messageHdr->mnFaKey, messageHdr->mnFaKeyLen, + messageHdr->mnFaSPI, messageHdr->mnAAASPI, + (uint8_t *)NAIBuffer, messageHdr->mnNAILen); + } else { +#else /* KEY_DISTRIBUTION */ + if (messageHdr->pktSource == MIP_PKT_FROM_AAA && + messageHdr->mnFaKeyLen && aaaProtocol == DIAMETER) { +#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. + */ + repLen += appendMierExt((messageHdr->pkt + repLen), + REG_GEN_MN_FA_KEY_EXT_TYPE, GEN_KEY_MN_FA, + messageHdr->mnFaKey, messageHdr->mnFaKeyLen); +#ifdef KEY_DISTRIBUTION + } +#endif /* KEY_DISTRIBUTION */ + } + + /* + * The MN-HA MUST follow the MN-AAA Session Keys + */ + if ((mnsae = + findSecAssocFromSPI(mnEntry->haMnSPI, LOCK_READ)) != NULL) { + repLen += appendAuthExt(messageHdr->pkt, repLen, + REG_MH_AUTH_EXT_TYPE, mnsae); + + (void) rw_unlock(&mnsae->mipSecNodeLock); + } + } /* 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) { + repLen += appendExt((messageHdr->pkt + repLen), + REG_MF_CHALLENGE_EXT_TYPE, challengeBuffer, challengeLen); + } + +#ifdef KEY_DISTRIBUTION + if (messageHdr->mnFaKeyLen && + messageHdr->kdcKeysPresent == _B_TRUE) { + /* + * Support for the Generalized Key extension. + * + * We have some keying information to send to the Mobile + * Node from the AAA Server. + */ + repLen += + createFAKeyExt((char *)(messageHdr->pkt + repLen), + VENDOR_ID_SUN, REG_MN_FA_KEY_EXT, + (char *)&messageHdr->mnFaKey, messageHdr->mnFaKeyLen, + messageHdr->mnFaSPI); + + repLen += + createFAKeyExt((char *)(messageHdr->pkt + repLen), + VENDOR_ID_SUN, REG_FA_HA_KEY_EXT, + (char *)&messageHdr->faHaKey, messageHdr->faHaKeyLen, + messageHdr->faHaSPI); + faSPI = messageHdr->faHaSPI; + } +#endif /* KEY_DISTRIBUTION */ + + if (faSPI) { + /* + * Now we get the Foreign Agent's Security Association, + * which will be read locked upon return. + */ + if ((mipSecAssocEntry = + findSecAssocFromSPI(faSPI, LOCK_READ)) == NULL) { + syslog(LOG_ERR, "Unable to add FH Auth - SPI (%d) not" + "defined", faSPI); + replyPtr->code = HA_FA_AUTH_FAILURE; + + } else { + repLen += appendAuthExt(messageHdr->pkt, repLen, + REG_FH_AUTH_EXT_TYPE, mipSecAssocEntry); + + /* + * And now we must unlock the entry. + */ + (void) rw_unlock(&mipSecAssocEntry->mipSecNodeLock); + } + } else { + if (fhAuthRequired) { + replyPtr->code = HA_FA_AUTH_FAILURE; + haCounters.haFAAuthFailureCnt++; + syslog(LOG_ERR, "Cannot add FH Auth - No SA (%d)", + faSPI); + } + } + + /* + * First assume nothing special is needed to ensure that unsuccessful + * registrations reach the mobile node. + */ +#ifdef FIREWALL_SUPPORT + encapToFw = _B_FALSE; +#endif /* FIREWALL_SUPPORT */ + ignoreTunnel = _B_FALSE; + + /* Is this really the case? */ + if ((replyPtr->code != MIP_SUCCESSFUL_REGISTRATION) && + (replyPtr->code != MIP_SIMULTANEOUS_NOT_SUPPORTED)) { + /* + * For "deregister all" requests, ignore the tunnel to + * ensure unsuccessful registrations are sent on the + * local (home) network. + */ + if ((replyPtr->regLifetime == 0) && + (COAddr == homeAddr) && + mnEntry && (mnEntry->haMnBindingCnt)) { + ignoreTunnel = _B_TRUE; +#ifdef RADIUS_ENABLED + /* Do Radius Close Session */ + if (radiusEnabled) + radiusCloseSession(mnEntry); +#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. + */ + if ((isInsideProtectedDomain(COAddr) == FALSE) && + ((findHABE(&haMobileNodeHash, homeAddr, + COAddr) == _B_FALSE))) { + encapToFw = _B_TRUE; + } +#endif /* FIREWALL_SUPPORT */ + + /* + * Do we have an assigned Home Address that we need + * to free? + */ + if (mnEntry && locallyAssignedAddress == _B_TRUE) { + if (freeAddressFromPool(mnEntry->haPoolIdentifier, + mnEntry->haMnAddr) != _B_TRUE) { + syslog(LOG_ERR, "Unable to free address " + "from pool %d", + mnEntry->haPoolIdentifier); + } + mnEntry->haMnAddr = INADDR_ANY; + } + } + +#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 " + "firewall %s 0\n", ntoa(haAddr, addrstr1), + ntoa(COAddr, addrstr2), + ntoa(domainInfo.fwAddr[0], addrstr3))); + if ((val = encapadd(COAddr, haAddr, domainInfo.fwAddr[0], + tFlags & REG_REVERSE_TUNNEL)) < 0) { + syslog(LOG_ERR, "encapadd failed ... %s", + err2str(val)); + } + } +#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", + ntoa(replyPtr->homeAddr, addrstr1))); + if ((val = arpdel(replyPtr->homeAddr)) < 0) { + syslog(LOG_ERR, "arpdel failed ... %s", err2str(val)); + } + + mipverbose(("Temporarily suspending tunneling for %s\n", + ntoa(replyPtr->homeAddr, addrstr1))); + } + + /* If the packet was from AAA, send it back there. */ + if (messageHdr->pktSource == MIP_PKT_FROM_AAA) { + (void) fprintf(stderr, "AAA Message!\n"); + rc = aaaSendRegistrationReply(messageHdr, + repLen, haAddr, homeAddr); + } else { + /* + * AAA isn't in charge - use IPsec SA's we're configured with. + */ + MobilityAgentEntry *mae; + + if ((mae = findMaeFromIp(COAddr, LOCK_READ)) != NULL) { + /* + * Is there an IPSEC_REPLY_APPLY policy + * configured that isn't already? + */ + if (((mae->maIPsecFlags & IPSEC_REPLY_APPLY) == 0) && + (IPSEC_REPLY_ANY( + mae->maIPsecSAFlags[IPSEC_APPLY]))) { + /* pass it down */ + char peerAddr[IPv4_ADDR_LEN]; + + (void) ntoa(mae->maAddr, peerAddr); + + if (installIPsecPolicy( + mae->maIPsecReply[IPSEC_APPLY]) < 0) { + /* problems writing the policy */ + syslog(LOG_CRIT, "Could not install %s " + "for [Address %s]: %s", + IPSEC_POLICY_STRING( + IPSEC_REPLY_APPLY), peerAddr, + mae->maIPsecReply[IPSEC_APPLY]); + + /* unlock */ + (void) rw_unlock(&mae->maNodeLock); + + /* don't send a regreP in the clear! */ + return; + } + + /* set the flag */ + mae->maIPsecFlags |= IPSEC_REPLY_APPLY; + } + + /* + * 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). + */ + mae->maPeerFlags |= FA_PEER; + + /* unlock */ + (void) rw_unlock(&mae->maNodeLock); + } + + rc = sendUDPmessage(entry->maIfaceUnicastSock, + messageHdr->pkt, repLen, messageHdr->src, + messageHdr->srcPort); + } + if (rc == 0) { + + mipverbose(("\n---- %s (%s) ----\n", + sprintTime(currentTime, MAX_TIME_STRING_SIZE), + sprintRelativeTime(relativeTime, + MAX_TIME_STRING_SIZE))); + mipverbose(("HA sent reg reply to %s.%d (Code %d)\n", + ntoa(messageHdr->src, addrstr1), + messageHdr->srcPort, replyPtr->code)); + mipverbose(( + " " + "[Lifetime %d sec, ID %0#10x : %0#10x]\n", + (uint32_t)ntohs(replyPtr->regLifetime), + ntohl(replyPtr->IDHigh), + ntohl(replyPtr->IDLow))); + + if (logVerbosity > 2) { + mipverbose(("HA's reply is:\n")); + printBuffer((unsigned char *) messageHdr->pkt, + repLen); + mipverbose(("\n")); + } + + if (replyPtr->regLifetime != 0) + haCounters.haRegRepliesSentCnt++; + else + haCounters.haDeRegRepliesSentCnt++; + + } else { + syslog(LOG_ERR, "sendto failed at HA while replying."); + } + + /* + * Undo any temporary changes related to "deregistration all" + * messages. + * Proxy arp works only for non-PPP interfaces. + */ + if (((entry->maIfaceFlags & IFF_POINTOPOINT) == 0) && ignoreTunnel) { + /* restore prior state */ + mipverbose(("Re-enabling tunneling for %s\n", + ntoa(replyPtr->homeAddr, addrstr1))); + mipverbose(("Restoring proxy ARP for %s at %s\n", + ntoa(replyPtr->homeAddr, addrstr1), + hwAddrWrite(entry->maIfaceHWaddr, addrstr2))); + if ((val = arpadd(replyPtr->homeAddr, + entry->maIfaceHWaddr, ATF_PUBL)) < 0) { + syslog(LOG_ERR, "arpadd (proxy) failed ... %s", + err2str(val)); + } + } + + /* + * 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. + */ + if ((replyPtr->code == MIP_SUCCESSFUL_REGISTRATION) || + (replyPtr->code == MIP_SIMULTANEOUS_NOT_SUPPORTED)) { + /* + * A successful request, we must generate the + * appropriate accounting record. + */ + if (replyPtr->regLifetime == 0) { + if (((entry->maIfaceFlags & IFF_POINTOPOINT) == 0) && + (mnEntry != NULL) && + (mnEntry->haMnBindingCnt == 0)) { + if ((val = arprefresh(mnEntry, + replyPtr->homeAddr)) < 0) + syslog(LOG_ERR, + "arprefresh failed ... %s", + err2str(val)); + } + + if (aaaProtocol != AAA_NONE) { + /* + * An accounting stop record must be sent. + */ + result = sendAccountingRecord( + MOBILE_IP_ACCOUNTING_STOP_REQUEST, + (unsigned char *)NAIBuffer, + messageHdr->mnNAILen, + homeAddr, COAddr, haAddr, + sessionLifeTime, MN_DEREGISTERED); + + if (result) { + syslog(LOG_ERR, "Unable to " + "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 = + sendAccountingRecord( + MOBILE_IP_ACCOUNTING_INTERIM_REQUEST, + (unsigned char *) + NAIBuffer, + messageHdr->mnNAILen, + homeAddr, COAddr, + haAddr, + sessionLifeTime, 0); + + if (result) { + /* + * PRC: Here we must disconnect + * the mobile node since we can + * not account for services + * rendered. + */ + syslog(LOG_ERR, + "Unable to send " + "accounting interim " + "record"); + if (mnEntry) { + delHABE(&mnEntry, + homeAddr, + COAddr, + &sessionLifeTime); + } + } + } else { + /* + * An accounting start record must + * be sent. + */ + result = + sendAccountingRecord( + MOBILE_IP_ACCOUNTING_START_REQUEST, + (unsigned char *)NAIBuffer, + messageHdr->mnNAILen, + homeAddr, COAddr, haAddr, 0, 0); + + if (result) { + /* + * PRC: Here we must disconnect + * the mobile node since we can + * not account for services + * rendered. + */ + syslog(LOG_ERR, + "Unable to send " + "accounting start " + "record"); + if (mnEntry) { + delHABE(&mnEntry, + homeAddr, + COAddr, + &sessionLifeTime); + } + } + } + } + } + } else if (aaaProtocol != AAA_NONE) { + /* + * An accounting stop record must be sent to log the + * failed request. + */ + result = sendAccountingRecord( + MOBILE_IP_ACCOUNTING_STOP_REQUEST, + (unsigned char *)NAIBuffer, + messageHdr->mnNAILen, homeAddr, COAddr, haAddr, + sessionLifeTime, REG_EXPIRED); + + if (result) { + syslog(LOG_ERR, "Unable to send accounting stop record"); + } + } + + /* + * If we've made it this far, if we have a mobile node + * entry, we need to unlock it. + */ + if (mnEntry) { + (void) rw_unlock(&mnEntry->haMnNodeLock); + } + + 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 +acceptFAVEHashLookup(void *entry, uint32_t p1, uint32_t p2, uint32_t p3) +{ + FaVisitorEntry *faveEntry = entry; + + if ((faveEntry->faVisitorCOAddr == p1 || p1 == 0) && + ((uint32_t)faveEntry->faVisitorRegIsAccepted == p2) && + (p3 == 0 || faveEntry->faVisitorHomeAgentAddr == p3)) { + 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 +acceptFAVE(HashTable *htbl, regReply *replyPtr, FaVisitorEntry **favep) +{ + int val; + int in_Ifindex = 0; + int out_Ifindex = 0; + int tun_num; + FaVisitorEntry *entry; + char addrstr1[INET_ADDRSTRLEN]; + char addrstr2[INET_ADDRSTRLEN]; + char tun_name[LIFNAMSIZ]; + ipaddr_t mnAddr = replyPtr->homeAddr; + unsigned short lifetime = ntohs(replyPtr->regLifetime); + + /* + * 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. + */ + entry = findHashTableEntryUint(htbl, mnAddr, LOCK_WRITE, + acceptFAVEHashLookup, (*favep)->faVisitorCOAddr, + _B_TRUE, (*favep)->faVisitorHomeAgentAddr); + + 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). + */ + entry->faVisitorAddr = (*favep)->faVisitorAddr; + entry->faVisitorIfaceAddr = (*favep)->faVisitorIfaceAddr; + entry->faVisitorRegFlags = (*favep)->faVisitorRegFlags; + entry->faVisitorPort = (*favep)->faVisitorPort; + entry->faVisitorHomeAgentAddr = + (*favep)->faVisitorHomeAgentAddr; + GET_TIME(entry->faVisitorTimeGranted); + entry->faVisitorTimeExpires = + entry->faVisitorTimeGranted + lifetime; + mipverbose(("FA renewed visitor %s on iface %s (%d sec).\n", + ntoa(entry->faVisitorHomeAddr, addrstr1), + ntoa(entry->faVisitorIfaceAddr, addrstr2), + lifetime)); + entry->faVisitorRegIDHigh = (*favep)->faVisitorRegIDHigh; + entry->faVisitorRegIDLow = (*favep)->faVisitorRegIDLow; + entry->faVisitorInIfindex = (*favep)->faVisitorInIfindex; + entry->faVisitorIsSllaValid = (*favep)->faVisitorIsSllaValid; + (void) memcpy(&entry->faVisitorSlla, &(*favep)->faVisitorSlla, + sizeof (struct sockaddr_dl)); + + + entry->faVisitorChallengeAdvLen = + (*favep)->faVisitorChallengeAdvLen; + (void) memcpy(&entry->faVisitorChallengeAdv, + &(*favep)->faVisitorChallengeAdv, + entry->faVisitorChallengeAdvLen); + + /* + * Unlocking the entry here could cause deadlock. + * (void) rw_unlock(&entry->faVisitorNodeLock); + */ + + (void) rw_unlock(&(*favep)->faVisitorNodeLock); + + if (delHashTableEntryUint(htbl, *favep, mnAddr, LOCK_NONE)) { + /* + * Found a match, delete it + */ + delFAVEptr(*favep, _B_TRUE, 0); + (void) rw_unlock(&(*favep)->faVisitorNodeLock); + (void) rwlock_destroy(&(*favep)->faVisitorNodeLock); + free(*favep); + *favep = NULL; + } + /* + * Return the pointer to the old entry. + */ + *favep = 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. + */ + if ((*favep)->faVisitorMnNAI[0] != '\0' && + (*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. + */ + if (changeHashEntryStringToUint(htbl, *favep, + (*favep)->faVisitorMnNAI, (*favep)->faVisitorMnNAILen, + mnAddr) == _B_FALSE) { + 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. + */ + (*favep)->faVisitorHomeAddr = mnAddr; + mipverbose(("Moved pending visitor entry for %.*s to %s " \ + "at pos'n %p.\n", + (*favep)->faVisitorMnNAILen, (*favep)->faVisitorMnNAI, + ntoa(mnAddr, addrstr1), (void *)entry)); + } + + + /* + * We did not find an existing ACCEPTED entry. + */ + GET_TIME((*favep)->faVisitorTimeGranted); + (*favep)->faVisitorTimeExpires = + (*favep)->faVisitorTimeGranted + lifetime; + mipverbose(("FA accepted visitor %s on iface %s (expires %ld).\n", + ntoa((*favep)->faVisitorHomeAddr, addrstr1), + ntoa((*favep)->faVisitorIfaceAddr, addrstr2), + (*favep)->faVisitorTimeExpires)); + (*favep)->faVisitorRegIsAccepted = _B_TRUE; + + /* + * 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 + */ + if ((val = arpIfadd(mnAddr, (*favep)->faVisitorSlla.sdl_data, + (*favep)->faVisitorInIfindex)) < 0) { + syslog(LOG_ERR, "SIOCSXARP failed... %s", + err2str(val)); + } + } + + mipverbose(("Enabling decapsulation of inner pkts sent to %s\n", + ntoa((*favep)->faVisitorHomeAddr, addrstr1))); + + if ((val = decapadd((*favep)->faVisitorHomeAgentAddr, + (*favep)->faVisitorCOAddr)) < 0) { + syslog(LOG_ERR, "decapadd failed ... %s", err2str(val)); + /* + * The following reply code is a close approximation of why + * things might have failed. The main purpose is to let the + * MN know. + */ + replyPtr->code = FA_INSUFFICIENT_RESOURCES; + return; + } + + tun_num = gettunnelno((*favep)->faVisitorHomeAgentAddr, + (*favep)->faVisitorCOAddr); + if (tun_num < 0) { + syslog(LOG_ERR, "gettunnelno returns -1"); + /* + * The following reply code is a close approximation of why + * things might have failed. The main purpose is to let the MN + * know. + */ + replyPtr->code = FA_INSUFFICIENT_RESOURCES; + return; + } + (void) snprintf(tun_name, sizeof (tun_name), "ip.tun%d", tun_num); + in_Ifindex = if_nametoindex(tun_name); + if (in_Ifindex == 0) { + /* if_nametoindex fails... */ + syslog(LOG_ERR, "if_nametoindex fails for tunnel %s" + "with error %d", tun_name, errno); + /* + * The following reply code is a close approximation of why + * things might have failed. The main purpose is to let the MN + * know. + */ + replyPtr->code = FA_INSUFFICIENT_RESOURCES; + 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", + ntoa((*favep)->faVisitorHomeAddr, addrstr1), + ntoa((*favep)->faVisitorIfaceAddr, addrstr2))); + + if ((val = routeadd((*favep)->faVisitorHomeAddr, + (*favep)->faVisitorIfaceAddr, 0, in_Ifindex, + (*favep)->faVisitorInIfindex)) < 0) { + syslog(LOG_ERR, "routeadd failed ... :%s: " + "for visitor %s from interface index %d", + err2str(val), ntoa((*favep)->faVisitorHomeAddr, addrstr1), + in_Ifindex); + /* + * The following reply code is a close approximation of why + * things might have failed. The main purpose is to let the MN + * know. + */ + replyPtr->code = FA_INSUFFICIENT_RESOURCES; + 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. + */ + if ((*favep)->faVisitorRegFlags & REG_REVERSE_TUNNEL) { + + /* Do we apply an IPsec policy for the reverse tunnel? */ + MobilityAgentEntry *mae; + + if ((mae = findMaeFromIp(replyPtr->haAddr, LOCK_READ)) + != NULL) { + /* is there something we shoud set that isn't? */ + if (IPSEC_REVERSE_TUNNEL_ANY( + mae->maIPsecSAFlags[IPSEC_APPLY])) + /* + * 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 |= + IPSEC_REVERSE_TUNNEL_APPLY; + + /* unlock */ + (void) rw_unlock(&mae->maNodeLock); + } + + /* Add reverse tunnel route for MIPRTUN table */ + mipverbose(("Adding reverse tunnel route for visitor %s at" + "interface index %d to tunnel index %d\n", + ntoa((*favep)->faVisitorHomeAddr, addrstr1), + (*favep)->faVisitorInIfindex, in_Ifindex)); + + out_Ifindex = in_Ifindex; + if ((val = routeadd(0, 0, + (*favep)->faVisitorHomeAddr, + (*favep)->faVisitorInIfindex, + out_Ifindex)) < 0) { + syslog(LOG_ERR, "Reverse Tunnel route-add failed:%s:" + " for visitor %s from interface index %d to %d", + ntoa((*favep)->faVisitorHomeAddr, addrstr1), + (*favep)->faVisitorInIfindex, out_Ifindex, + err2str(val)); + /* + * The following reply code is a close approximation + * of why things might have failed. The main purpose + * is to let the MN know. + */ + replyPtr->code = FA_INSUFFICIENT_RESOURCES; + } + } +} + + +/* + * 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 +FAprocessRegReply(MessageHdr *messageHdr, MaAdvConfigEntry *entry) +{ + int code = MIP_SUCCESSFUL_REGISTRATION; + int val; + int index; + int result; + uint32_t challengeBuffer[4]; + /* LINTED E_FUNC_SET_NOT_USED */ + authExt *mnAuthExt; + int mnAuthExtLen; + uint32_t sessionLifeTime = 0; + ipaddr_t COAddr; + time_t localTime; + boolean_t visitor_entryExists; + regReply *replyPtr; + FaVisitorEntry *favePtr; + FaVisitorEntry *acceptedFAVE; + MipSecAssocEntry *mipSecAssocEntry = NULL; + HashTable *htbl = &faVisitorHash; + 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 */ + replyPtr = (regReply *) messageHdr->pkt; + + mipverbose(("\n---- %s (%s) ----\n", + sprintTime(currentTime, MAX_TIME_STRING_SIZE), + sprintRelativeTime(relativeTime, MAX_TIME_STRING_SIZE))); + mipverbose(("FA got reg reply [MN %s, HA %s, Code %d]\n", + ntoa(replyPtr->homeAddr, addrstr1), + ntoa(replyPtr->haAddr, addrstr2), + replyPtr->code)); + mipverbose((" [Lifetime %d sec, ID %0#10x : %0#10x]\n", + (uint32_t)ntohs(replyPtr->regLifetime), ntohl(replyPtr->IDHigh), + ntohl(replyPtr->IDLow))); + + mipverbose(("FAprocessRegReply called for pkt:\n")); + if (logVerbosity > 2) + printBuffer(messageHdr->pkt, messageHdr->pktLen); + mipverbose(("\n")); + + /* + * Support for new MIER-style extension header. + * + * Are extensions ok and in the right order? + */ + if (mkRegExtList(messageHdr, sizeof (regReply)) < 0) { + mipverbose(("FAprocessRegReply: poorly formed reply\n")); + code = FA_POORLY_FORMED_REQUEST; + faCounters.faPoorlyFormedRequestsCnt++; + /* + * 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? + */ + if ((code = IsPacketFromHaValid(messageHdr)) > 0) { + faCounters.faPoorlyFormedRequestsCnt++; + /* + * 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. + */ + favePtr = findPendingFAVE(&faVisitorHash, replyPtr->homeAddr, + messageHdr->mnNAI, messageHdr->mnNAILen, ntohl(replyPtr->IDLow)); + + if (favePtr == NULL) { + /* we wouldn't likewise find a matching ipsec SA anyway. */ + syslog(LOG_ERR, "Did not find matching pending request."); + 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) { + (void) memcpy(NAIBuffer, messageHdr->mnNAI, + messageHdr->mnNAILen); + } + + /* + * Check the message's authentication + */ + code = faCheckRegRepAuth(messageHdr, favePtr); + + if (code) { + goto reply; + } + + /* ... it is a good reply. No need to change the code in pkt. */ + faCounters.faRegRepliesRecvdCnt++; + + /* + * 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 */ + GET_AUTH_EXT(messageHdr, index, REG_MH_AUTH_EXT_TYPE, mnAuthExt, + mnAuthExtLen); + + if (mnAuthExtLen) { + /* + * If any extensions appear following the Mobile-Node + * Home Agent Extension, let's remove them. + */ + messageHdr->pktLen = (messageHdr->extIdx[index] - + messageHdr->pkt) + messageHdr->extHdrLength[index] + + mnAuthExtLen; + } + + /* + * As per the Challenge/Response Internet Draft, the + * 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(); + challengeBuffer[1] = getRandomValue(); + challengeBuffer[2] = getRandomValue(); + challengeBuffer[3] = getRandomValue(); + messageHdr->pktLen += appendExt((messageHdr->pkt + + messageHdr->pktLen), REG_MF_CHALLENGE_EXT_TYPE, + (unsigned char *)&challengeBuffer, ADV_CHALLENGE_LENGTH); + + (void) memcpy(favePtr->faVisitorChallengeAdv, + &challengeBuffer, ADV_CHALLENGE_LENGTH); + favePtr->faVisitorChallengeAdvLen = ADV_CHALLENGE_LENGTH; + } + + /* + * Get our visitor's Security Association, but keep in mind + * that the node will be locked upon return. + */ + if ((mipSecAssocEntry = + findSecAssocFromSPI(favePtr->faVisitorSPI, + LOCK_READ)) == NULL) { + /* + * TODO: Is this extension required? + */ + if (mfAuthRequired) { + syslog(LOG_ERR, + "Error: no SA in Visitor Entry"); + code = FA_MN_AUTH_FAILURE; + faCounters.faMNAuthFailureCnt++; + goto reply; + } + } else { + messageHdr->pktLen += appendAuthExt(messageHdr->pkt, + messageHdr->pktLen, REG_MF_AUTH_EXT_TYPE, + mipSecAssocEntry); + /* + * We need to unlock the node + */ + (void) rw_unlock(&mipSecAssocEntry->mipSecNodeLock); + } + + /* + * 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. + */ + if (messageHdr->pktSource == MIP_PKT_FROM_AAA || + messageHdr->pktSource == MIP_PKT_FROM_RADIUS && + aaaProtocol != AAA_NONE && + messageHdr->aaaResultCode != 0 && + replyPtr->code == 0 && code == 0) { + code = messageHdr->aaaResultCode; + } + + + /* Check for HA returning duplicate homeaddr */ + acceptedFAVE = findAcceptedFAVE(&faVisitorHash, + replyPtr->homeAddr, replyPtr->haAddr); + if ((acceptedFAVE != NULL) && + (acceptedFAVE->faVisitorMnNAI[0] != '\0')) { + /* + * Compare to see that homeaddr and NAI + * match and it's not due to some problem + * with misbehaving HA assigning duplicate addr + */ + if (strncmp((const char *)acceptedFAVE->faVisitorMnNAI, + (const char *)favePtr->faVisitorMnNAI, + (size_t)acceptedFAVE->faVisitorMnNAILen)) { + if (code == 0) { + /* Set to reason unspecified */ + code = FA_REASON_UNSPECIFIED; + faCounters.faReasonUnspecifiedCnt++; + } + } + } + if (acceptedFAVE != NULL) + (void) rw_unlock(&acceptedFAVE->faVisitorNodeLock); + + /* Check for assigned homeaddr validity */ + if (replyPtr->homeAddr == INADDR_ANY || + replyPtr->homeAddr == INADDR_LOOPBACK || + replyPtr->homeAddr == INADDR_BROADCAST) { + if (code == 0) { + /* Set to reason unspecified */ + code = FA_REASON_UNSPECIFIED; + faCounters.faReasonUnspecifiedCnt++; + } + } + +reply: + /* Do we need to overwrite the code field? */ + if (code) + replyPtr->code = (uint8_t)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 + */ + if (((replyPtr->code == MIP_SUCCESSFUL_REGISTRATION) || + (replyPtr->code == MIP_SIMULTANEOUS_NOT_SUPPORTED)) && + (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. + */ + acceptFAVE(&faVisitorHash, replyPtr, &favePtr); + } + /* + * TODO: Handle extensions properly. For now, we include no + * extensions in denials and therefore don't need to change + * newLen. + */ + + + visitor_entryExists = isAcceptedVisitor(&faVisitorHash, + replyPtr->homeAddr, favePtr->faVisitorIfaceAddr); + + + 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 && + (replyPtr->homeAddr != INADDR_ANY)) { + /* + * 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. + */ + if ((val = arpIfadd(replyPtr->homeAddr, + favePtr->faVisitorSlla.sdl_data, + favePtr->faVisitorInIfindex)) < 0) { + syslog(LOG_ERR, "SIOCSXARP failed... %s", + err2str(val)); + } + } + } + + /* + * 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) + */ + if ((replyPtr->homeAddr == INADDR_ANY) && + favePtr->faVisitorIsSllaValid) { + if (sendRawPkt(messageHdr, entry, messageHdr->pktLen) == 0) { + mipverbose(("\n---- %s (%s) ----\n", + sprintTime(currentTime, + MAX_TIME_STRING_SIZE), + sprintRelativeTime(relativeTime, + MAX_TIME_STRING_SIZE))); + (void) memcpy(ether.ether_addr_octet, + favePtr->faVisitorSlla.sdl_data, ETHERADDRL); + mipverbose(("FA relayed reg reply to " + "255.255.255.255.%d for MN 0.0.0.0 " + "[MAC: %s] (Code %d)\n", + favePtr->faVisitorPort, + ether_ntoa(ðer), + replyPtr->code)); + mipverbose(("FA relayed reply packet:\n")); + if (logVerbosity > 2) + printBuffer(messageHdr->pkt, + 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... + */ + val = favePtr->faVisitorInIfindex; + if (setsockopt(entry->maIfaceUnicastSock, IPPROTO_IP, IP_XMIT_IF, + &val, sizeof (val)) < 0) { + /* There's a problem... */ + syslog(LOG_ERR, "Can't set IP_XMIT_IF socket option for " + "registration reply to mobile node %s.", + ntoa(messageHdr->src, addrstr1)); + } + + if (sendUDPmessage(entry->maIfaceUnicastSock, messageHdr->pkt, + messageHdr->pktLen, favePtr->faVisitorHomeAddr, + favePtr->faVisitorPort) == 0) { + + mipverbose(("\n---- %s (%s) ----\n", + sprintTime(currentTime, MAX_TIME_STRING_SIZE), + sprintRelativeTime(relativeTime, MAX_TIME_STRING_SIZE))); + mipverbose(("FA relayed reg reply to %s.%d (Code %d)\n", + ntoa(favePtr->faVisitorHomeAddr, addrstr1), + favePtr->faVisitorPort, replyPtr->code)); + faCounters.faRegRepliesRelayedCnt++; + + mipverbose(("FA relayed reply packet:\n")); + if (logVerbosity > 2) + printBuffer(messageHdr->pkt, messageHdr->pktLen); + mipverbose(("\n")); + + } else { + syslog(LOG_ERR, "sendto failed at FA while relaying reply."); + } + + /* Reset IP_XMIT_IF option on socket */ + val = 0; + if (setsockopt(entry->maIfaceUnicastSock, IPPROTO_IP, IP_XMIT_IF, + &val, sizeof (val)) < 0) { + syslog(LOG_ERR, "Can't unset socket option IP_XMIT_IF" + "which was set for interface index %d", + favePtr->faVisitorInIfindex); + } + if (visitor_entryExists == _B_FALSE) { + + if (favePtr->faVisitorIsSllaValid) { + /* + * Delete the temporary ARP entry + */ + if ((val = arpIfdel(replyPtr->homeAddr, + favePtr->faVisitorSlla.sdl_data, + favePtr->faVisitorInIfindex)) < 0) { + /* + * If the deletion failed bcos there was no + * entry then we don't need to report it + */ + if (val != (-1)*ENXIO) { + syslog(LOG_ERR, + "SIOCDXARP failed... %s", + err2str(val)); + } + } + } + } + + if ((replyPtr->code == MIP_SUCCESSFUL_REGISTRATION) || + (replyPtr->code == MIP_SIMULTANEOUS_NOT_SUPPORTED)) { + if (replyPtr->regLifetime == 0) { + COAddr = favePtr->faVisitorCOAddr; + GET_TIME(localTime); + sessionLifeTime = localTime - + favePtr->faVisitorTimeGranted; + /* + * Deregistration ... delete visitor entries for + * this MN + */ + delFAVE(&faVisitorHash, &favePtr, replyPtr->homeAddr, + MN_DEREGISTERED); + + if (aaaProtocol != AAA_NONE) { + /* + * An accounting stop record must be sent. + */ + result = sendAccountingRecord( + MOBILE_IP_ACCOUNTING_STOP_REQUEST, + (unsigned char *)NAIBuffer, + messageHdr->mnNAILen, + replyPtr->homeAddr, COAddr, + replyPtr->haAddr, + sessionLifeTime, MN_DEREGISTERED); + + if (result) { + syslog(LOG_ERR, "Unable to send accounting " + "stop record"); + } + } + } else { + + if (visitor_entryExists == _B_FALSE && + aaaProtocol != AAA_NONE) { + /* + * An accounting start record must be sent. + */ + result = sendAccountingRecord( + MOBILE_IP_ACCOUNTING_START_REQUEST, + (unsigned char *)NAIBuffer, + messageHdr->mnNAILen, + replyPtr->homeAddr, + favePtr->faVisitorCOAddr, + replyPtr->haAddr, 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. + */ + syslog(LOG_ERR, + "Unable to send accounting " + "start record"); + } + } else if (aaaProtocol != AAA_NONE) { + /* + * An accounting start record must be sent. + */ + GET_TIME(localTime); + result = + sendAccountingRecord( + MOBILE_IP_ACCOUNTING_INTERIM_REQUEST, + (unsigned char *)NAIBuffer, + messageHdr->mnNAILen, + replyPtr->homeAddr, + (favePtr) ? + favePtr->faVisitorCOAddr : 0, + replyPtr->haAddr, + localTime - + ((favePtr) ? + favePtr->faVisitorTimeGranted: + 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. + */ + syslog(LOG_ERR, "Unable to send " + "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. + */ + if (replyPtr->code != HA_UNKNOWN_HOME_AGENT) { + COAddr = favePtr->faVisitorCOAddr; + if (delHashTableEntryUint(htbl, favePtr, + replyPtr->homeAddr, LOCK_NONE)) { + /* + * Found a match, delete it + */ + delFAVEptr(favePtr, _B_TRUE, 0); + (void) rw_unlock(&favePtr->faVisitorNodeLock); + (void) rwlock_destroy( + &favePtr->faVisitorNodeLock); + free(favePtr); + favePtr = NULL; + } + + if (aaaProtocol != AAA_NONE) { + /* + * An accounting stop record must be sent + * to log a failed request. + */ + result = sendAccountingRecord( + MOBILE_IP_ACCOUNTING_STOP_REQUEST, + (unsigned char *)NAIBuffer, + messageHdr->mnNAILen, + replyPtr->homeAddr, COAddr, + replyPtr->haAddr, 0, 0); + + if (result) { + syslog(LOG_ERR, "Unable to send accounting " + "stop record"); + } + } + } + } + + if (favePtr) { + (void) rw_unlock(&favePtr->faVisitorNodeLock); + } + + mipverbose(("\n\n")); +} + +#ifdef RADIUS_ENABLED +void +loadRadiusLibrary() +{ + void *handle; + int result; + /* + * Open the dynamic library + */ + handle = dlopen(radiusSharedLibrary, RTLD_LAZY|RTLD_GLOBAL); + if (handle == NULL) { + (void) fprintf(stderr, + "Unable to open dynamic library %s (%s)\n", + radiusSharedLibrary, dlerror()); + radiusEnabled = 0; + return; + } + + /* + * Setup our function pointers. + */ + radInitializeApi = (int (*)())dlsym(handle, "InitializeAPI"); + if (radInitializeApi == NULL) { + (void) fprintf(stderr, + "Unable to resolve initialization function %s (%s)\n", + radiusSharedLibrary, dlerror()); + radiusEnabled = 0; + dlclose(handle); + return; + } + radLookupData = (int (*)(char **, char *, RadData *)) dlsym(handle, + "LookupData"); + if (radLookupData == NULL) { + (void) fprintf(stderr, + "Unable to resolve lookup function %s (%s)\n", + radiusSharedLibrary, dlerror()); + radiusEnabled = 0; + dlclose(handle); + return; + } + radCloseSession = (int (*)(char *, char *, void *)) dlsym(handle, + "CloseSession"); + if (radLookupData == NULL) { + (void) fprintf(stderr, "Unable to resolve close function %s (%s)\n", + radiusSharedLibrary, dlerror()); + radiusEnabled = 0; + dlclose(handle); + return; + } + + /* + * Call the module's initialization function. + */ + result = radInitializeApi(); + if (result) { + (void) fprintf(stderr, "Error initializing dynamic library %s", + radiusSharedLibrary); + radiusEnabled = 0; + dlclose(handle); + return; + } + + dlclose(handle); +} /* 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 +formIPsecBits(int type, char *nodeID, char *ipsecPolicy_p, char *ipsecPolicy, + size_t ipsecPolicySize) +{ + /* a quick sanity check */ + if ((nodeID == NULL) || (ipsecPolicy_p == NULL) || + (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 */ + (void) snprintf(ipsecPolicy, ipsecPolicySize, + "{daddr %s ulp udp dport %d} %s\n", + nodeID, MIP_PORT, ipsecPolicy_p); + break; + + case IPSEC_REQUEST_PERMIT: + /* IPsec Policy - HA permit policy for receiving regreQ */ + (void) snprintf(ipsecPolicy, ipsecPolicySize, + "{saddr %s ulp udp dport %d} %s\n", + nodeID, MIP_PORT, ipsecPolicy_p); + break; + + case IPSEC_REPLY_APPLY: + /* IPsec Policy - HA apply policy for sending regreP */ + (void) snprintf(ipsecPolicy, ipsecPolicySize, + "{daddr %s ulp udp sport %d} %s\n", + nodeID, MIP_PORT, ipsecPolicy_p); + break; + + case IPSEC_REPLY_PERMIT: + /* IPsec Policy - FA permit policy for receiving regreQ */ + (void) snprintf(ipsecPolicy, ipsecPolicySize, + "{saddr %s ulp udp dport %d} %s\n", + nodeID, MIP_PORT, ipsecPolicy_p); + 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: + case IPSEC_REVERSE_TUNNEL_APPLY: + case IPSEC_REVERSE_TUNNEL_PERMIT: + /* syslog() in case we're actually trying to do this! */ + syslog(LOG_WARNING, + "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 */ + syslog(LOG_WARNING, + "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 + * only, '-' is stdin (I suppose I could use /dev/stdin for this, + * 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; + FILE *fp; + + if (policy == NULL) + return (-1); + + if ((fp = popen(IPSEC(ADD_POLICY), "w")) == NULL) { + syslog(LOG_CRIT, "Couldn't start ipsec install process."); + return (-1); + } + + /* send the policy to fp == stdin */ + (void) fprintf(fp, "%s", policy); + + /* pclose() will flush, and send the EOF */ + ret = pclose(fp); + + /* 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) { + FILE *fp; /* for file manipulation */ + int ret; + + if (policy == NULL) + /* caller's confused... */ + return (-1); + + /* pass to ipsec */ + if ((fp = popen(IPSEC(SUB_POLICY), "w")) == NULL) + return (-1); + + /* write policy to fp == stdin */ + (void) fprintf(fp, "%s", policy); + + /* only write one at a time */ + ret = fclose(fp); + + if (WEXITSTATUS(ret) != 0) { + syslog(LOG_CRIT, "Couldn't remove IPsec policy %s.", policy); + 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 +main(int argc, char *argv[]) +{ + sigset_t thread_signals; + int signal = 0; + int c; + int rc; + + (void) setlocale(LC_ALL, ""); +#if !defined(TEXT_DOMAIN) +#define TEXT_DOMAIN "SYS_TEST" +#endif + (void) textdomain(TEXT_DOMAIN); + + while ((c = getopt(argc, argv, "d")) != EOF) { + switch (c) { + case 'd': + /* private debugging argument */ + daemonize = _B_FALSE; + break; + default: + /* mipagent has no public arguments */ + (void) fprintf(stderr, "Usage: %s\n", *argv); + exit(-1); + } + } + + /* + * Read the config file name and create internal data + * structures. + */ + if (Initialize(CONF_FILE_NAME)) { + syslog(LOG_CRIT, "Error Initializing."); + exit(-1); + } + +#ifdef RADIUS_ENABLED + if (radiusEnabled) { + loadRadiusLibrary(); + } +#endif /* RADIUS_ENABLED */ + + (void) restoreAgentState(); + + /* + * We need to unblock the signals that we care about. + */ + (void) sigemptyset(&thread_signals); + (void) sigaddset(&thread_signals, SIGINT); + (void) sigaddset(&thread_signals, SIGTERM); + (void) sigaddset(&thread_signals, SIGUSR1); + + if (pthread_sigmask(SIG_BLOCK, &thread_signals, NULL)) { + syslog(LOG_ERR, "Unable to set thread signals"); + exit(-1); + } + + if (disableSNMP == _B_FALSE) { + /* + * Initialize the SNMP Thread. + */ + if (startSNMPTaskThread()) { + syslog(LOG_CRIT, "Error Initializing SNMP."); + exit(-1); + } + } + + /* + * Start the AAA thread. + */ + if (aaaProtocol != AAA_NONE) { + if ((rc = startAAATaskThread()) != 0) { + syslog(LOG_CRIT, + "Error: rc = %d when calling startAAATaskThread\n", + rc); + exit(-1); + } + } + + /* + * Start a thread which will handle all periodic tasks. + */ + if (startPeriodicTaskThread()) { + syslog(LOG_CRIT, "Unable to start periodic thread"); + exit(-1); + } + + /* + * Initialize the multi-thread message dispatcher. + */ + if (startDispatcherTaskThread()) { + syslog(LOG_CRIT, "Unable to initialize the message " + "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) { + syslog(LOG_ERR, + "Unable to create a list of interfaces: %m"); + exit(-1); + } + if (startDynamicInterfaceThread()) { + syslog(LOG_CRIT, + "Unable to start Dynamic Interface Thread"); + exit(-1); + } + } + + + /* + * Start stat door server. + */ + if (startStatServer()) { + syslog(LOG_ERR, "Unable to create stat server door"); + } + + /* + * Let's start the performance test thread + */ + if (performanceInterval) { + syslog(LOG_ERR, "Starting the performance checker"); + if (startPerfTestServer()) { + syslog(LOG_ERR, "Unable to create performance server"); + } + } + + /* + * We need to unblock the signals that we care about. + */ + (void) sigemptyset(&thread_signals); + (void) sigaddset(&thread_signals, SIGINT); + (void) sigaddset(&thread_signals, SIGTERM); + (void) sigaddset(&thread_signals, SIGUSR1); + + if (pthread_sigmask(SIG_UNBLOCK, &thread_signals, NULL)) { + syslog(LOG_ERR, "Unable to set thread signals"); + exit(-1); + } + + (void) sigwait(&thread_signals, &signal); + + Finalize(signal); + + return (0); +} +#endif + + +static void +perf_thread() +{ + time_t startTime; + time_t stopTime; + struct timeval tv; + char buffer[PERF_MSG_SIZE]; + + while (faCounters.faRegReqRecvdCnt == 0 && + haCounters.haRegReqRecvdCnt == 0) { + (void) sleep(1); + } + + GET_TIME(startTime); + /* CONSTCOND */ + while (_B_TRUE) { + tv.tv_sec = performanceInterval; + tv.tv_usec = 0; + (void) select(FD_SETSIZE, NULL, NULL, NULL, &tv); + GET_TIME(stopTime); + + if (haCounters.haRegReqRecvdCnt) { + (void) sprintf(buffer, "HA Packets per second %ld\n", + haCounters.haRegReqRecvdCnt / + (stopTime - startTime)); + syslog(LOG_ERR, "%s", buffer); + } + + if (faCounters.faRegReqRecvdCnt) { + (void) sprintf(buffer, "FA Packets per second %ld\n", + faCounters.faRegReqRecvdCnt / + (stopTime - startTime)); + syslog(LOG_ERR, "%s", buffer); + } + } +} + + +static int +startPerfTestServer() +{ + pthread_t threadId = 0; + pthread_attr_t pthreadAttribute; + int result; + + result = pthread_attr_init(&pthreadAttribute); + + if (result) { + syslog(LOG_CRIT, "Error Initializing pthread."); + return (-1); + } + + /* + * We now create a thread to deal with all periodic task. + */ + result = pthread_create(&threadId, &pthreadAttribute, + (void *(*)()) perf_thread, + (void *)NULL); + + if (result) { + syslog(LOG_CRIT, "pthread_create() failed."); + 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. + */ + result = pthread_detach(threadId); + + if (result) { + syslog(LOG_CRIT, "pthread_detach() failed."); + 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 */ +boolean_t +ConfigEntryHashLookup(void *entry, uint32_t p1, uint32_t p2, uint32_t p3) +{ + MaAdvConfigEntry *maAdvEntry = entry; + + if (maAdvEntry->maIfindex == p1) + return (_B_TRUE); + else + return (_B_FALSE); +} diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agent.h b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agent.h new file mode 100644 index 0000000000..cf8e5ee672 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agent.h @@ -0,0 +1,774 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 1999-2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _AGENT_H +#define _AGENT_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * This file contains definitions for structures used by + * Mobility Agents (either Home Agents or Foreign Agents) + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <synch.h> +#include <pthread.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/if_ether.h> +#include <netinet/in.h> +#include "mip.h" +#include "hash.h" +#include "aaa.h" + +/* Hash types */ +#define HASH_IT 0 +#define MD5_HASH 1 + +#define MAX_FN_LEN 256 + +#define VERSION_MAJOR 1 +#define VERSION_MINOR 0 + + +/* + * We do not current support simultaneous bindings + * due to the new tunnel driver architecture. This + * is something that we may wish to change in the + * future. + */ + +#define MAX_SIMULTANEOUS_BINDINGS 7 +#define DEFAULT_MAX_REG_TIME 300 +#define DEFAULT_MAX_ADV_TIME 300 +#define DEFAULT_MAX_INTERVAL 10 +#define DEFAULT_MIN_INTERVAL 1 + +#define ADV_INIT_COUNT_DEFAULT 1 +#define ADV_INIT_COUNT_MIN 0 +#define DEFAULT_FRESHNESS_SLACK 300 + +#define DEFAULT_ADVERTISEMENT_INTERVAL 5 + +#define MIP_PORT 434 + +/* + * These are for the IPsec flags in the MobilityAgentEntry. + */ +#define IPSEC_REQUEST 0x01 +#define IPSEC_REPLY 0x02 +#define IPSEC_TUNNEL 0x04 +#define IPSEC_REVERSE_TUNNEL 0x08 + +#define APPLY(x) (x) +#define PERMIT(x) ((x) << 4) + +/* + * We define the other way so we can have indexes into validIPsecAction[], + * and the maIPsec*'s in the MobilityAgentEntry struct, too. + */ +#define FIRST_IPSEC_ACTION 0 +#define IPSEC_APPLY 0 +#define IPSEC_PERMIT 1 +#define LAST_IPSEC_ACTION 2 + +#define REQUEST(a) (1 << (((int)(a)) * 4)) +#define REPLY(a) (1 << ((((int)(a)) * 4) + 1)) +#define TUNNEL(a) (1 << ((((int)(a)) * 4) + 2)) +#define REVERSE_TUNNEL(a) (1 << ((((int)(a)) * 4) + 3)) + +/* + * The above pair of 6 macros yield the following: + * + * bit 1 -> APPLY(IPSEC_REQUEST) = IPSEC_REQUEST_APPLY + * bit 2 -> APPLY(IPSEC_REPLY) = IPSEC_REPLY_APPLY + * bit 3 -> APPLY(IPSEC_TUNNEL) = IPSEC_TUNNEL_APPLY + * bit 4 -> APPLY(IPSEC_REVERSE_TUNNEL) = IPSEC_REVERSE_TUNNEL_APPLY + * bit 5 -> PERMIT(IPESC_REQUEST) = IPSEC_REQUEST_PERMIT + * bit 6 -> PERMIT(IPSEC_REPLY) = IPSEC_REPLY_PERMIT + * bit 7 -> PERMIT(IPSEC_TUNNEL) = IPSEC_TUNNEL_PERMIT + * bit 8 -> PERMIT(IPSEC_REVERSE_TUNNEL) = IPSEC_REVERSE_TUNNEL_PERMIT + */ +#define IPSEC_REQUEST_APPLY 0x01 +#define IPSEC_REPLY_APPLY 0x02 +#define IPSEC_TUNNEL_APPLY 0x04 +#define IPSEC_REVERSE_TUNNEL_APPLY 0x08 +#define IPSEC_REQUEST_PERMIT 0x10 +#define IPSEC_REPLY_PERMIT 0x20 +#define IPSEC_TUNNEL_PERMIT 0x40 +#define IPSEC_REVERSE_TUNNEL_PERMIT 0x80 + +/* + * Bitmasks for the maIPsecSAFlags[] members of the MobilityAgentEntry struct + * that we pass to mipagentstat. As the HA_PEER we use request-permit, + * reply-apply, tunnel-apply, and reverse-tunnel permit. This means we have to + * mask-in reply and tunnel from maIPsecSAFlags[IPSEC_APPLY], and request and + * reverse tunnel from maIPsecSAFlags[IPSEC_PERMIT]. As an FA_PEER we use + * request-apply, reply-permit, tunnel-permit, and reverse-tunnel-apply. This + * means we have to mask-in request and reverse-tunnel from + * maIPsecSAFlags[IPSEC_APPLY], and reply and tunnel from + * maIsecSAFlags[IPSEC_PERMIT]. + */ + /* type: RQRPFTRT */ + /* SA : AEAEAEAE */ +#define HA_PEER_APPLY_MASK (IPSEC_REPLY_BOTH | IPSEC_TUNNEL_BOTH) + /* 0x3c, 00111100b */ +#define FA_PEER_APPLY_MASK (IPSEC_REQUEST_BOTH | IPSEC_REVERSE_TUNNEL_BOTH) + /* 0xc3, 11000011b */ +#define HA_PEER_PERMIT_MASK (IPSEC_REQUEST_BOTH | IPSEC_REVERSE_TUNNEL_BOTH) + /* 0xc3, 11000011b */ +#define FA_PEER_PERMIT_MASK (IPSEC_REPLY_BOTH | IPSEC_TUNNEL_BOTH) + /* 0x3c, 00111100b */ + +#define IPSEC_ORDER 2 /* Arrays are 2-by: apply and permit */ +#define MAX_IPSEC_GET_SIZE 1024 /* read()/write() via PF_KEY socket */ +#define FINE_STRUCT_CONST 137 /* Our initial ipsec sequence number */ +#define MAX_IPSEC_POLICY_SIZE 1024 /* Same as MAXLEN in ipsecconf.h */ + +/* Commands for ipsecconf are "/usr/sbin/ipsecconf -(a|r) /dev/stdin -q" */ +#define IPSEC_CONF_COMMAND_SIZE 37 + +#define IPv4_ADDR_LEN 16 /* in dotted-decimal */ +#define CONF_FILE_NAME "/etc/inet/mipagent.conf" + +/* easy flag to index algorithm (warning: use on flags only!) */ +#define IPSEC_POLICY_STRING(x) ipsec_policy_string[ffs(x) - 1] + +/* developer-friendly add/remove policy strings */ +#define ADD_POLICY 0 +#define SUB_POLICY 1 +#define IPSEC(x) ipsec_policy_action[x] + + +/* + * Maximum number of visitor entries (accepted + pending) maintained + * at a Foreign Agent. A foreign agent sets the busy bit 'B' in its + * advertisements when number of visitors reaches DEFAULT_HIGH_VISITORS + * and does not reset it till it drops below DEFAULT_LOW_VISITORS. + * A pending entry is kept in the visitor table for at most + * DEFAULT_VISITOR_EXPIRY seconds. + * + * The new solaris Mobile-IP does not have any such restrictions, + * therefore we will set the visitor entry threshold to some ungodly + * large number, which can be overriden by the administrator. + */ +#define DEFAULT_HIGH_VISITORS -1 +#define DEFAULT_LOW_VISITORS -5 +#define DEFAULT_VISITOR_EXPIRY 30 + +#ifdef FIREWALL_SUPPORT +/* Max number of address intervals for specifying protected domain */ +#define MAX_ADDR_INTERVALS 6 + +/* Max. number of firewalls */ +#define MAX_FIREWALLS 3 +#endif /* FIREWALL_SUPPORT */ + +#define MAX_IFNAME_LEN 8 +#define MAX_HWADDR_LEN sizeof (struct ether_addr) + +#define MAX_TIME_STRING_SIZE 32 + +/* + * The following bits are set depending on the value of 'ReverseTunnelAllowed + * and ReverseTunnelRequired' parameter in the mipagent.conf file. By default + * the value for each is RT_NONE. It's a policy set by the configuration file + * to check if Reverse Tunnel bit must be present or NOT in the registration + * request. For example a FA may only accept registration packet with 'T' bit + * on while the HA accepts regReq with or without T bit on. These are for + * reverse tunnel settings. We advertise the T-bit on a per-interface level, + * so discern only on a per-interface, and not a per-agent-per-interface level + * (e.g. advertise the 'T' bit, but only enforce reverse-tunnel-required on + * the HA). These will allow us to do that. + */ +#define RT_NONE 0x0 +#define RT_HA 0x1 +#define RT_FA 0x2 +#define RT_BOTH 0x3 + +/* + * The following are the minimum and maximum values + * that one can configure for garbage collection. Note + * that this feature is largely undocumented, and can be + * used to alter the frequency that the agent attempts to + * clean up expired data structures. + */ +#define MIN_GARBAGE_COLLECTION_INTERVAL 5 +#define MAX_GARBAGE_COLLECTION_INTERVAL 120 +#define DEFAULT_GARBAGE_COLLECTION_INTERVAL 15 + +#define UNSOLICITED_ADV 1 +#define SOLICITED_ADV 2 + + +/* One such entry for each mobility-supporting interface */ +typedef struct { + /* + * The nodeLock field MUST be the first field present in + * this structure, and is required by the hashing mobule. + */ + rwlock_t maIfaceNodeLock; + ipaddr_t maIfaceAddr; + uint32_t maIfaceNetmask; + uint8_t maIfaceHWaddr[MAX_HWADDR_LEN]; /* used in proxy-ARPs */ + int8_t maIfaceName[LIFNAMSIZ]; + uint64_t maIfaceFlags; /* interface flags */ + int maIfaceIcmpSock; /* ICMP socket bound to ifaceAddr */ + int maIfaceUnicastSock; /* UDP socket bound to IfaceAddr */ + int maIfaceBcastSock; /* ... bound to subnet bcastAddr */ + int maIfaceDirBcastSock; /* ... to directed bcast Addr */ + int maIfaceAdvMulticastSock; /* ... bound to mcastAddr */ + int maIfaceRegMulticastSock; /* ... bound to mcastAddr */ + uint32_t maAdvMaxRegLifetime; + uint32_t maAdvAddr; + uint32_t maAdvMaxInterval; + uint32_t maAdvMinInterval; + uint32_t maAdvMaxAdvLifetime; + /* boolean maAdvResponseSolicitationOnly; */ + unsigned short maAdvSeqNum; + uint8_t maAdvServiceFlags; /* RBHFM[GV]T flags */ + boolean_t maAdvPrefixLenInclusion; + uint8_t maReverseTunnelAllowed; + uint8_t maReverseTunnelRequired; + /* dynamic interface support */ + boolean_t maAdvDynamicInterface; /* Used in lookup */ + boolean_t maAdvLimitUnsolicited; + uint8_t maAdvInitCount; /* Initial Count when */ + /* maAdvLimitUnsolicited is true */ + uint32_t maAdvInterval; + time_t maNextAdvTime; + uint32_t maIfindex; /* Interface index */ +} MaAdvConfigEntry; + +/* + * Mobile tunnel specific data + */ +typedef struct { + rwlock_t TunlNodeLock; + uint32_t tunnelno; + uint32_t refcnt; + ipaddr_t tunnelsrc; /* Tunnel source end-point */ + uint32_t mux_fd; /* fd associated with tun */ +} MipTunlEntry; + +/* One entry for each visiting mobile node at a foreign agent. */ +typedef struct { + /* + * The nodeLock field MUST be the first field present in + * this structure, and is required by the hashing mobule. + */ + rwlock_t faVisitorNodeLock; + ipaddr_t faVisitorAddr; + ipaddr_t faVisitorIfaceAddr; /* interface addr through */ + /* which visitor is reachable */ + boolean_t faVisitorRegIsAccepted; + int8_t faVisitorRegFlags; + in_port_t faVisitorPort; + ipaddr_t faVisitorHomeAddr; + ipaddr_t faVisitorHomeAgentAddr; + ipaddr_t faVisitorCOAddr; /* COaddr field in request */ + time_t faVisitorTimeGranted; /* only valid if IsAccepted */ + time_t faVisitorTimeExpires; /* only valid if IsAccepted */ + uint32_t faVisitorSPI; + uint32_t faVisitorRegIDHigh; + uint32_t faVisitorRegIDLow; + uint8_t faVisitorMnNAI[MAX_NAI_LENGTH]; /* Mobile Node's NAI */ + uint32_t faVisitorMnNAILen; + uint8_t faVisitorChallengeToHA[ADV_CHALLENGE_LENGTH]; + uint32_t faVisitorChallengeToHALen; + uint8_t faVisitorChallengeAdv[ADV_CHALLENGE_LENGTH]; + uint32_t faVisitorChallengeAdvLen; + uint32_t faVisitorInIfindex; /* interface index on which */ + /* reg. request is recvd */ + boolean_t faVisitorIsSllaValid; /* if the MN's SLLA is legit */ + struct sockaddr_dl faVisitorSlla; /* MN's link layer address */ +} FaVisitorEntry; + + +/* + * The Home Agent maintains one such entry for each mobility binding. + * A single mobile node may have multiple bindings. + */ +typedef struct habindingentry { + ipaddr_t haBindingMN; /* Mobile node's home address */ + ipaddr_t haBindingCOA; /* Mobile node's care-of address */ + ipaddr_t haBindingSrcAddr; + ipaddr_t haBindingHaAddr; /* Home Agent address */ + time_t haBindingTimeGranted; + time_t haBindingTimeExpires; + in_port_t haBindingSrcPort; + int8_t haBindingRegFlags; /* 8 bit - comes from the wire */ + struct habindingentry *next; /* Next structure */ +} HaBindingEntry; + +/* + * The Home Agent maintains one mobile node entry for each supported Mobile + * Node. In addition, the Home Agent keeps a MipSecAssocEntry for + * for every other node with which it shares a mobility security + * association. By using the interface information, the home agent + * can filter out broadcast packets that it picks up from subnets + * other than the mobile node's home subnet. + */ +typedef struct { + /* + * The nodeLock field MUST be the first field present in + * this structure, and is required by the hashing mobule. + */ + rwlock_t haMnNodeLock; + boolean_t haMnIsEntryDynamic; + ipaddr_t haMnAddr; /* Mobile Node's IP address */ + uint8_t haMnNAI[MAX_NAI_LENGTH]; /* Mobile Node NAI */ + uint8_t haMnNAILen; /* Mobile Node NAI Len */ + ipaddr_t haBindingIfaceAddr; /* interface on the mobile */ + /* node's home subnet */ + uint32_t haMnRegIDHigh; /* Stored ID used in replay */ + /* protection */ + uint32_t haMnRegIDLow; + uint32_t haMnSPI; + int haMnBindingCnt; /* Number of current bindings */ +#ifdef RADIUS_ENABLED + char *haRadiusState; /* maintains radius state info */ + time_t haRadiusLastLookupTime; +#endif /* RADIUS_ENABLED */ + uint32_t haServiceRequestsAcceptedCnt; /* The number of */ + /* successful registrations */ + uint32_t haServiceRequestsDeniedCnt; /* The number of */ + /* failed registrations */ + time_t haOverallServiceTime; /* The total amount of */ + /* service time */ + time_t haRecentServiceAcceptedTime; /* The last time */ + /* service was provided */ + time_t haRecentServiceDeniedTime; /* The last time */ + /* service was denied */ + uint32_t haRecentServiceDeniedCode; /* The last failure */ + /* code */ + uint32_t haPoolIdentifier; + HaBindingEntry *bindingEntries; +} HaMobileNodeEntry; + + +/* + * Mobility Agent Authentication Information. + */ +typedef struct { + /* + * The nodeLock field MUST be the first field present in + * this structure, and is required by the hashing mobule. + */ + rwlock_t maNodeLock; + boolean_t maIsEntryDynamic; + ipaddr_t maAddr; + uint32_t maSPI; + /* + * The following value is used during garbage collection to check + * if this Mobility Agent has expired. + */ + time_t maExpiration; + + /* + * How is IPsec securing traffic to this agent-peer? Ultimately, all + * we should need are the ipsec_req_t structs here, but that wont + * happen until either ipsec has an API, or they support multiple + * policies per socket. Until then, we need the char strings to pass + * to ipsecconf(1M). We do use the ipsec_req_t structs for our tunnel + * setup, but not at this time for the registration traffic. Still, + * this is setup at init time, so why not parse everything in + * anticipation of ipsec support. Note, also, until ipsec supports + * multiple policies per socket, we can only support symmetric tunnel + * polices (forward tunnel policy = reverse tunnel policy). IPSEC_ORDER + * here refers to the 'depth' of ipsec protection, that is how many + * different actions do we support. This is done this way for + * expandability. + */ + ipsec_req_t maIPsecRequestIPSR[IPSEC_ORDER]; + ipsec_req_t maIPsecReplyIPSR[IPSEC_ORDER]; + ipsec_req_t maIPsecTunnelIPSR[IPSEC_ORDER]; + ipsec_req_t maIPsecReverseTunnelIPSR[IPSEC_ORDER]; + uint8_t maIPsecFlags; /* what's currently invoked */ + uint8_t maPeerFlags; /* 2 for IPsec: ha and fa. Rest TBD */ + + /* + * The SA flags are arranged like this: + * + * Request Reply Tunnel RTunnel + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | + * AH ESP AH ESP AH ESP AH ESP + * + * So bits 0, 1 say whether AH or ESP are protecting requests, but + * 2, 3 say whether AH or ESP are protecting replies, etc. + * We need one of these SA flag fields for each of our actions. + * This way we know which are specific for APPLY = outbound, PERMIT = + * inbound, (etc, should there be more someday). + */ + uint8_t maIPsecSAFlags[IPSEC_ORDER]; + + /* these are the chars mentioned above that should go away */ + char maIPsecRequest[IPSEC_ORDER][MAX_IPSEC_POLICY_SIZE]; + char maIPsecReply[IPSEC_ORDER][MAX_IPSEC_POLICY_SIZE]; +} MobilityAgentEntry; + +#ifdef FIREWALL_SUPPORT +/* Data structure to store the information regarding protected domain */ +typedef struct { + ipaddr_t addr[MAX_ADDR_INTERVALS]; + uint32_t netmask[MAX_ADDR_INTERVALS]; + uint32_t addrIntervalCnt; + uint32_t fwAddr[MAX_FIREWALLS]; + uint32_t firewallCnt; +} DomainInfo; +#endif /* FIREWALL_SUPPORT */ + +/* + * Counters common to all Mobility Agents + * + * Note: We will not be locking this structure before modifying it, + * even though we know that we are multi-threaded. The worst case + * scenario is that we will return incorrect statistics to the snmp + * requestor. The cost of locking and unlocking this structure is + * simply not worth it. + */ +typedef struct { + uint32_t maAdvSentCnt; + uint32_t maAdvSentForSolicitationsCnt; + uint32_t maSolicitationsRecvdCnt; +} CommonCounters; + +/* + * Counters maintained by Foreign Agents + * + * Note: We will not be locking this structure before modifying it, + * even though we know that we are multi-threaded. The worst case + * scenario is that we will return incorrect statistics to the snmp + * requestor. The cost of locking and unlocking this structure is + * simply not worth it. + */ +typedef struct { + uint32_t faRegReqRecvdCnt; /* total valid reg requests received */ + uint32_t faRegReqRelayedCnt; /* total valid reg reqs relayed to HA */ + uint32_t faReasonUnspecifiedCnt; /* rejected with code 64 */ + uint32_t faAdmProhibitedCnt; /* rejected with code 65 */ + uint32_t faInsufficientResourceCnt; /* rejected with code 66 */ + uint32_t faMNAuthFailureCnt; /* rejected with code 67 */ + uint32_t faHAAuthFailureCnt; /* rejected with code 68 */ + uint32_t faRegLifetimeTooLongCnt; /* rejected with code 69 */ + uint32_t faPoorlyFormedRequestsCnt; /* rejected with code 70 */ + uint32_t faPoorlyFormedRepliesCnt; /* rejected with code 71 */ + uint32_t faEncapUnavailableCnt; /* rejected with code 72 */ + uint32_t faVJCompUnavailableCnt; /* rejected with code 73 */ + uint32_t faReverseTunnelUnavailableCnt; /* rejected with code 74 */ + uint32_t faReverseTunnelRequiredCnt; /* rejected with code 75 */ + uint32_t faMNTooDistantCnt; /* rejected with code 76 */ + uint32_t faInvalidCareOfAddrCnt; /* rejected with code 77 */ + uint32_t faRTEncapUnavailableCnt; /* rejected with code 79 */ + uint32_t faHAUnreachableCnt; /* rejected with codes 80-95 */ + uint32_t faRegRepliesRecvdCnt; /* well-formed reg replies received */ + uint32_t faRegRepliesRelayedCnt; /* well-formed regrep relayd */ + uint32_t faRegRepliesICMPUnreachCnt; /* replies for ICMP_UNREACH */ + uint32_t faRegRepliesICMPTimxceedCnt; /* replies for ICMP_TIMXCEED */ + uint32_t faIsBusyCnt; /* number of times we were too busy */ +} ForeignAgentCounters; + +/* + * Counters maintained by Home Agents + * + * Note: We will not be locking this structure before modifying it, + * even though we know that we are multi-threaded. The worst case + * scenario is that we will return incorrect statistics to the snmp + * requestor. The cost of locking and unlocking this structure is + * simply not worth it. + */ +typedef struct { + uint32_t haRegAccepted0Cnt; /* reg requests accepted with code 0 */ + uint32_t haRegAccepted1Cnt; /* reg requests accepted with code 1 */ + uint32_t haReasonUnspecifiedCnt; /* denied with code 128 */ + uint32_t haAdmProhibitedCnt; /* denied with code 129 */ + uint32_t haInsufficientResourceCnt; /* denied with code 130 */ + uint32_t haMNAuthFailureCnt; /* denied with code 131 */ + uint32_t haFAAuthFailureCnt; /* denied with code 132 */ + uint32_t haIDMismatchCnt; /* denied with code 133 */ + uint32_t haPoorlyFormedRequestsCnt; /* denied with code 134 */ + uint32_t haTooManyBindingsCnt; /* denied with code 135 */ + uint32_t haUnknownHACnt; /* denied with code 136 */ + uint32_t haReverseTunnelUnavailableCnt; + /* denied with code 137 */ + uint32_t haReverseTunnelRequiredCnt; /* denied with code 138 */ + uint32_t haEncapUnavailableCnt; /* denied with code 139 */ + uint32_t haGratuitousARPsSentCnt; + uint32_t haProxyARPsSentCnt; + uint32_t haRegReqRecvdCnt; + uint32_t haDeRegReqRecvdCnt; + uint32_t haRegRepliesSentCnt; + uint32_t haDeRegRepliesSentCnt; +} HomeAgentCounters; + +/* + * Mobile-IP is a simple protocol, with limited extensions. Today + * the number of extensions in a single message cannot exceed 10. + */ +#define MAX_EXPECTED_EXTENSIONS 16 + +/* + * Mobile IP Packets are relatively small, and cannot really + * exceed 2k in size. + */ +#define MAX_PKT_SIZE 2048 +/* Maximum control/data buffer size (in long's) for getmsg() */ +#define MAXDLBUF 8192 + +typedef struct messagehdr { + enum { + MIP_PKT_FROM_FA = 1, + MIP_PKT_FROM_AAA, + MIP_PKT_FROM_RADIUS + } pktSource; + enum { + PKT_UDP = 1, + PKT_ICMP + } pktType; + unsigned char pkt[MAX_PKT_SIZE]; + uint32_t pktLen; + ipaddr_t src; + in_port_t srcPort; + uint8_t *mnNAI; + unsigned int mnNAILen; + size_t extCnt; + uint8_t extType[MAX_EXPECTED_EXTENSIONS]; + uint16_t extSubType[MAX_EXPECTED_EXTENSIONS]; + uint8_t *extIdx[MAX_EXPECTED_EXTENSIONS]; + uint8_t *extData[MAX_EXPECTED_EXTENSIONS]; + size_t extHdrLength[MAX_EXPECTED_EXTENSIONS]; + size_t extLength[MAX_EXPECTED_EXTENSIONS]; + uint32_t extVendorId[MAX_EXPECTED_EXTENSIONS]; + MaAdvConfigEntry *ifEntry; + enum { + ON_UNICAST_SOCK, + ON_BCAST_SOCK, + ON_MCAST_SOCK + } ifType; + boolean_t dontDeleteNow; + + /* + * The following is some AAA Stuff, and can ONLY be set + * if the packet source is AAA. + */ + uint32_t messageHandle; + unsigned char *faNAI; + size_t faNAILen; + uint32_t mnAAASPI; + uint16_t algorithm; + uint32_t mnHaSPI; + uint8_t mnHaKey[MAX_KEY_LEN]; + size_t mnHaKeyLen; + uint32_t mnFaSPI; + uint8_t mnFaKey[MAX_KEY_LEN]; + size_t mnFaKeyLen; + uint32_t faHaSPI; + uint8_t faHaKey[MAX_KEY_LEN]; + size_t faHaKeyLen; + uint32_t aaaSessionTimeout; + uint32_t aaaResultCode; +#ifdef KEY_DISTRIBUTION + /* + * KEY_DISTRIBUTION MUST ONLY BE COMPILED FOR TESTING!!! + * + * This version of mipagent supports a AAA/DIAMETER + * 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. + * + * Since DIAMETER/AAA is not currently a product, and key + * 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. + */ + boolean_t kdcKeysPresent; +#endif /* KEY_DISTRIBUTION */ + + /* + * Ancillary data gleaned from the registration request + */ + boolean_t isSllaValid; /* is SLLA valid/legitimate ? */ + struct sockaddr_dl slla; /* source link layer address */ + uint32_t inIfindex; /* Inbound interface index */ + uint8_t ttl; /* IP TTL of inbound pkt */ + + struct messagehdr *next; +} MessageHdr; + + +/* + * This entry holds the dynamic interface type and the common + * information that will be applied to all dynamic interfaces + * of the same type. For example, for an entry of interfacename + * ppp*, there will be one such entry. + */ +typedef struct dynamicIfacetype { + struct dynamicIfacetype *next; + int RegLifetime; + int AdvLifetime; + uint32_t AdvInterval; + int32_t AdvServiceflag; + boolean_t AdvLimitUnsolicited; + boolean_t AdvPrefixflag; + boolean_t advertiseOnBcast; + uint8_t AdvInitCount; + uint8_t RevtunReqd; + uint8_t RevtunAllowed; + char dynamicIfcetype[LIFNAMSIZ]; +} DynamicIfaceTypeEntry; + +/* DynamicInterface, dynamicIfaceHead variables are set in agentInit.c */ +boolean_t DynamicInterface; +DynamicIfaceTypeEntry *dynamicIfaceHead; + +/* + * This data structure keeps track of existing interfaces + * at the time of mipagent startup + */ +typedef struct staticIface { + char ifacename[LIFNAMSIZ]; + struct staticIface *next; +} StaticIfaceEntry; + +#define GET_EXT_DATA(messageHdr, counter, extId, ptr, len) \ + for (counter = 0, len = 0, ptr = NULL; \ + counter < messageHdr->extCnt; counter++) { \ + if (messageHdr->extType[counter] == extId) { \ + /* \ + * Support for non-traditional \ + * extension header formats \ + * \ + * Get a pointer to the data and its length \ + */ \ + ptr = messageHdr->extData[counter]; \ + len = messageHdr->extLength[counter]; \ + break; \ + } \ + } \ + +#define GET_AUTH_EXT(messageHdr, counter, extId, ptr, len) \ + for (counter = 0, len = 0, ptr = NULL; \ + counter < messageHdr->extCnt; counter++) { \ + if (messageHdr->extType[counter] == extId) { \ + /* \ + * Support for non-traditional \ + * extension header formats \ + * \ + * Get a pointer to the data and its length \ + */ \ + ptr = (authExt *)messageHdr->extIdx[counter]; \ + len = messageHdr->extLength[counter]; \ + break; \ + } \ + } \ + +/* + * Support for the latest Challenge/Response I-D + */ +#define GET_GEN_AUTH_EXT(messageHdr, counter, extId, ptr, len) \ + for (counter = 0, len = 0, ptr = NULL; \ + counter < messageHdr->extCnt; counter++) { \ + if ((messageHdr->extType[counter] == \ + REG_GEN_AUTH_EXT_TYPE) && \ + (messageHdr->extSubType[counter] == extId)) { \ + /* \ + * Get a pointer to the data and its length \ + */ \ + ptr = (genAuthExt *)messageHdr->extIdx[counter]; \ + len = messageHdr->extLength[counter]; \ + break; \ + } \ + } \ + +/* + * Support for vendor specific extensions. + */ +#define GET_VEND_KEY_EXT(messageHdr, counter, vendId, extId, ptr, len) \ + for (counter = 0, len = 0, ptr = NULL; \ + counter < messageHdr->extCnt; counter++) { \ + if ((messageHdr->extVendorId[counter] == vendId) && \ + (messageHdr->extSubType[counter] == extId)) { \ + /* \ + * Get a pointer to the data and its length \ + */ \ + ptr = (keyDataExt *)messageHdr->extData[counter]; \ + len = messageHdr->extLength[counter]; \ + break; \ + } \ + } \ + +#define GET_TIME(currentTime) \ + { \ + struct timeval timer; \ + if (gettimeofday(&timer, NULL) == -1) { \ + currentTime = 0; \ + } else { \ + currentTime = timer.tv_sec; \ + } \ + } + +#define GENERATE_NET_BROADCAST_ADDR(entry) \ + (entry->maIfaceAddr & entry->maIfaceNetmask) | \ + ~entry->maIfaceNetmask + +/* Common agent functions used by multiple files */ +extern boolean_t ConfigEntryHashLookup(void *, uint32_t, uint32_t, uint32_t); +extern int CreateListOfExistingIntfce(void); +extern int startDynamicInterfaceThread(void); +extern int killDynamicInterfaceThread(void); +extern int InitSockets(MaAdvConfigEntry *); +extern void docleanup(void); +extern void disableService(struct hash_table *); +extern int aaaCreateKey(int, unsigned char *, size_t, uint32_t); +extern int haCheckRegReqAuthContinue(MessageHdr *, HaMobileNodeEntry **, + uint32_t *, uint32_t *); +extern int addHABE(HaMobileNodeEntry *, ipaddr_t, in_port_t, + MaAdvConfigEntry *, uint8_t, ipaddr_t, ipaddr_t, ipaddr_t, uint32_t, + boolean_t *, uint32_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* _AGENT_H */ diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agentID.c b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agentID.c new file mode 100644 index 0000000000..e69aadc53b --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agentID.c @@ -0,0 +1,216 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999-2000 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * file: agentID.c + * + * This files contains all of the routines necessary to + * manage the Mobile-IP Replay protection mechanisms. + */ + +#include "mip.h" +#include "agent.h" + +/* + * IDfreshnessSlack contains the number of seconds that + * we allow as a difference between our clock and the + * mobile node's clock when timestamp-based replay + * protection is used. + */ +extern int IDfreshnessSlack; +extern uint32_t getRandomValue(); +extern uint32_t CurrentTimeNTPSec(); + + +/* + * Function: HAinitID + * + * Arguments: IDHigh - High order 32 bit ID + * IDLow - Low order 32 bit ID + * ReplayStyle - Replay type. + * + * Description: This function is called by the Home Agent + * to initialize a Mobile Node's replay + * identifier. + * + * Returns: + */ +void +HAinitID(uint32_t *IDHigh, uint32_t *IDLow, int ReplayStyle) +{ + if (ReplayStyle == TIMESTAMPS) { + *IDHigh = CurrentTimeNTPSec() - IDfreshnessSlack; + *IDLow = getRandomValue(); + } else { + *IDHigh = 0; + *IDLow = 0; + } +} + + +/* + * Function: isIDgreater + * + * Arguments: StoredIDHigh - Locally stored high order 32 bit replay ID + * StoredIDLow - Locally stored low order 32 bit replay ID + * IDHigh - High order 32 bit replay ID + * IDLow - Low order 32 bit replay ID + * + * Description: This function will return TRUE if the ID received + * by the Mobile Node is higher than the value stored + * locally. + * + * Returns: boolean_t, TRUE if value is greater than stored value. + */ +static boolean_t +isIDgreater(uint32_t StoredIDHigh, uint32_t StoredIDLow, + uint32_t IDHigh, uint32_t IDLow) +{ + if ((IDHigh > StoredIDHigh) || + ((IDHigh == StoredIDHigh) && (IDLow > StoredIDLow))) + return (_B_TRUE); + else + return (_B_FALSE); +} + + +/* + * Function: isIDfresh + * + * Arguments: IDHigh - High order 32 bit replay ID + * IDLow - Low order 32 bit replay ID + * + * Description: This value will compare the ID received + * with the local NTP time. Specifically, we + * will check if the time sent by the Mobile Node + * is within the current time +/- our configured + * clock skew. + * + * Returns: boolean_t, TRUE if the time is within our window. + */ +/* ARGSUSED */ +static boolean_t +isIDfresh(uint32_t IDHigh, uint32_t IDLow) +{ + long diff; + + diff = (long)(IDHigh - CurrentTimeNTPSec()); + + if (diff < 0) + diff = (0 - diff); + + return ((diff < IDfreshnessSlack) ? _B_TRUE : _B_FALSE); +} + + +/* + * Function: HAisIDok + * + * Arguments: StoredIDHigh - Locally stored high order 32 bit replay ID + * StoredIDLow - Locally stored low order 32 bit replay ID + * IDHigh - High order 32 bit replay ID + * IDLow - Low order 32 bit replay ID + * ReplayStyle - Replay type. + * + * Description: This routine will validate the Mobile Node's ID + * using the replay style configured within the Security + * Assocation. + * + * Returns: boolean_t, TRUE if the ID is valid + */ +boolean_t +HAisIDok(uint32_t StoredIDHigh, uint32_t StoredIDLow, + uint32_t IDHigh, uint32_t IDLow, int ReplayStyle) +{ + if (ReplayStyle == TIMESTAMPS) { + if (isIDgreater(StoredIDHigh, StoredIDLow, IDHigh, IDLow) && + isIDfresh(IDHigh, IDLow)) + return (_B_TRUE); + else + return (_B_FALSE); + } else if (ReplayStyle == NONE) { + return (_B_TRUE); + } else { + return (_B_FALSE); + } +} + + +/* + * Function: HAnewID + * + * Arguments: newIDHigh - Locally stored high order 32 bit replay ID + * newIDLow - Locally stored low order 32 bit replay ID + * IDHigh - High order 32 bit replay ID + * IDLow - Low order 32 bit replay ID + * ReplayStyle - Replay type. + * IDmatched - specifies whether the ID provided + * should be used. + * + * Description: This function will update the locally stored ID + * + * Returns: + */ +void +HAnewID(uint32_t *newIDHigh, uint32_t *newIDLow, uint32_t IDHigh, + uint32_t IDLow, int ReplayStyle, boolean_t IDmatched) +{ + if (ReplayStyle == TIMESTAMPS) { + *newIDHigh = IDmatched ? IDHigh : CurrentTimeNTPSec(); + } else { + *newIDHigh = 0; + } + + *newIDLow = IDLow; +} + + +/* + * Function: HAstoreID + * + * Arguments: newIDHigh - Locally stored high order 32 bit replay ID + * newIDLow - Locally stored low order 32 bit replay ID + * IDHigh - High order 32 bit replay ID + * IDLow - Low order 32 bit replay ID + * ReplayStyle - Replay type. + * IDmatched - specifies whether the ID provided + * should be used. + * + * Description: This function will store the IDs locally + * + * Returns: + */ +void +HAstoreID(uint32_t *StoredIDHigh, uint32_t *StoredIDLow, uint32_t IDHigh, + uint32_t IDLow, int ReplayStyle, boolean_t IDmatched) +{ + if (((ReplayStyle == TIMESTAMPS) && IDmatched)) { + *StoredIDHigh = IDHigh; + *StoredIDLow = IDLow; + } +} diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agentInit.c b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agentInit.c new file mode 100644 index 0000000000..55193eb46e --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agentInit.c @@ -0,0 +1,2798 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * file: agentInit.c + * + * This file contains the functions necessary to read + * and parse the /etc/inet/mipagent.conf configuration + * file. + */ + +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <signal.h> +#include <errno.h> +#include <alloca.h> +#include <syslog.h> +#include <unistd.h> +#include <sys/resource.h> +#include <net/pfkeyv2.h> /* ipsec */ +#include <net/if.h> /* ipsec */ + +#include <sys/utsname.h> + +#include "mip.h" +#include "agent.h" +#include "conflib.h" +#include "pool.h" +#include "setup.h" +#include "mipagentstat_door.h" + +/* Common to all mobility agents */ +extern struct hash_table maAdvConfigHash; +extern char maNai[MAX_NAI_LENGTH]; + +/* Foreign Agent specific data structures. */ +extern struct hash_table faVisitorHash; + +/* Home Agent specific data structures. */ +extern struct hash_table haMobileNodeHash; + +/* This table stores all of the Security Violations */ +extern struct hash_table mipSecViolationHash; + + +/* Home Agent specific data structures. */ +#ifdef FIREWALL_SUPPORT +extern DomainInfo domainInfo; +#endif /* FIREWALL_SUPPORT */ + +extern uint32_t subagent_addr; + +/* + * This table stores all of the Security Assocations + */ +extern HashTable mipSecAssocHash; + +/* + * This table has one entry for each known Mobility Agent + */ +extern HashTable mipAgentHash; + +/* + * This table has one entry for each pool defined in the config file + */ +extern HashTable mipPoolHash; + +/* + * This table has one entry for each active tunnel number + */ +extern HashTable mipTunlHash; + +/* Other external declarations */ +extern int logVerbosity; +#ifdef RADIUS_ENABLED +extern int radiusEnabled; +extern char radiusSharedLibrary[]; +#endif /* RADIUS_ENABLED */ +extern int visitorEntryHighWaterMark; +extern int visitorEntryLowWaterMark; +extern int IDfreshnessSlack; + +extern int advLifetime; +extern int periodicInterval; + +extern boolean_t faNAIadv; +extern boolean_t faChallengeAdv; +extern boolean_t mfAuthRequired; +extern boolean_t fhAuthRequired; +extern boolean_t shutdown_flag; +extern boolean_t daemonize; +extern int performanceInterval; +extern boolean_t disableSNMP; + +boolean_t ipsec_loaded = _B_FALSE; /* presume we're not secure */ +boolean_t ipsec_ah_loaded = _B_FALSE; +boolean_t ipsec_esp_loaded = _B_FALSE; + +extern char *ipsec_policy_string[]; +extern char *validIPsecAction[]; + +/* AAA Globals */ +extern unsigned short gbl_aaaPort; +extern char gbl_aaaHost[]; +extern AAA_Protocol_Code aaaProtocol; + +/* + * Default Values... + */ +extern uint32_t defaultPool; +extern uint32_t defaultNodeSPI; + +extern char *ntoa(uint32_t, char *); +extern char *sprintTime(char *, int); +extern char *sprintRelativeTime(char *, int); +extern void HAinitID(uint32_t *, uint32_t *, int); +extern int hexConvert(char *, int, char *); +#ifdef FIREWALL_SUPPORT +extern void printProtectedDomainInfo(DomainInfo); +#endif /* FIREWALL_SUPPORT */ + +/* OS-specific initialization for Mobile IP */ +extern void OScleanup(); + +/* Called when SIGUSR1 is received to save state. */ +extern int saveAgentState(void); + +extern void delFAVEptr(FaVisitorEntry *, boolean_t, uint32_t); +extern void delHABEent(HaMobileNodeEntry *, HaBindingEntry *); + +extern int killDispatcherTaskThread(); +extern int killPeriodicTaskThread(); +extern int killSNMPTaskThread(); +extern int killAAATaskThread(); +extern int killStatServer(); +extern void printMaAdvConfigHash(struct hash_table *); + +extern void randomInit(); +extern int InitNet(); +extern void printHaMobileNodeHash(struct hash_table *); + +extern int getdomainname(char *, int); + +extern int installIPsecPolicy(char *); +extern int removeIPsecPolicy(char *); +extern int formIPsecBits(int, char *, char *, char *, size_t); + +typedef struct { + char *string; + uint32_t value; +} Str2Int; + +/* YES(x) simply checks to see if the string begins with a y. */ +#define YES(x) ((tolower(x) == 'y') ? 1 : 0) + +/* + * FA(x) needs to check if the FA is included in the setting. This happens + * if the setting is "yes", "both" or "fa" [and NOT when the setting is + * "no", "none", or "ha"). + */ +#define FA(x) (((tolower(x) == 'y') || \ + (tolower(x) == 'b') || \ + (tolower(x) == 'f')) ? 1 : 0) + +/* + * Macros to produce a quoted string containing the value of a + * preprocessor macro. For example, if SIZE is defined to be 256, + * VAL2STR(SIZE) is "256". This is used to construct format + * strings for scanf-family functions below. + */ +#define QUOTE(x) #x +#define VAL2STR(x) QUOTE(x) + +/* The analogous HA(x) is not needed [yet] */ + +#define MAX_BUFFER_SIZE 1024 +#define MAX_KEY_STRING_LEN 256 +#define MAX_TAG_SIZE 30 + + +/* + * Function: daemonInit + * + * Arguments: + * + * Description: This function will deamonize the agent + * + * Returns: int, -1 if the deamon could not be started. + */ +static int +daemonInit() +{ + switch (fork()) { + case -1: + perror("mipagent: can not fork"); + return (-1); + case 0: + break; + default: + exit(0); + } + + /* + * Close existing file descriptors, open "/dev/null" as + * standard input, output, and error, and detach from + * controlling terminal. + */ + closefrom(0); + (void) open("/dev/null", O_RDONLY); + (void) open("/dev/null", O_WRONLY); + (void) dup(1); + (void) setsid(); + + (void) chdir("/"); /* change working directory */ + (void) umask(0); /* clear file mode creation mask */ + return (0); +} + + + +/* + * Function: get_ipsec_support + * + * Parameters: s the PF_KEY socket + * struct sadb_msg *msg pointer to message buffer + * uint8_t satype which SA type (ah, or esp) + * int seq The sequence number to increment/use. + * + * Description: Builds, and writes an sadb_message to s, then reads until it + * gets the appropriate message, and returns the length so the caller + * knows how many bytes to parse. + * + * Returns: -1 on error. + * The length of what was put in msg on success. + */ +int +get_ipsec_support(int s, struct sadb_msg *msg, uint8_t satype, int seq) +{ + /* Note: parsing the <base, supported> msg requires an ipsec_req_t */ + int len; /* what we'll return */ + uint32_t mypid = getpid(); + + msg->sadb_msg_version = PF_KEY_V2; + msg->sadb_msg_type = SADB_REGISTER; + msg->sadb_msg_satype = satype; + msg->sadb_msg_len = SADB_8TO64(sizeof (*msg)); + msg->sadb_msg_reserved = msg->sadb_msg_errno = 0; + msg->sadb_msg_seq = seq++; + msg->sadb_msg_pid = mypid; + + if ((len = write(s, (void *)msg, sizeof (*msg))) < 0) { + syslog(LOG_WARNING, "Can't determine state of ipsec support."); + return (-1); + } + + /* don't let stale data in msg confuse our read! */ + bzero(msg, sizeof (*msg)); + + /* send a <base> message to the kernel, get back <base, supported> */ + do { + len = read(s, msg, MAX_IPSEC_GET_SIZE); + } while (msg->sadb_msg_type != SADB_REGISTER && + msg->sadb_msg_pid != mypid && + msg->sadb_msg_seq != seq); + + return (msg->sadb_msg_errno != 0 ? -1 : len); +} + +/* + * Function: IsIPsecLoaded() + * + * Description: uses a PF_KEY socket to determine if AH and/or ESP are loaded. + * the globals ipsec_ah_loaded, and ipsec_esp_loaded are set directly for + * reference during init. + */ +boolean_t +IsIPsecLoaded() +{ + uint64_t msg_buffer[MAX_IPSEC_GET_SIZE] = { 0 }; + struct sadb_msg *msg = (struct sadb_msg *)msg_buffer; + int s; + uint32_t seq = FINE_STRUCT_CONST; + + if ((s = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) { + /* Curious. We're root, or mipagent would've stopped by now */ + return (_B_FALSE); + } + + /* AH support? */ + if (get_ipsec_support(s, (void *)msg, SADB_SATYPE_AH, seq) > 0) + /* we got something back, so ah is supported */ + ipsec_ah_loaded = _B_TRUE; + + /* ESP support? */ + if (get_ipsec_support(s, (void *)msg, SADB_SATYPE_ESP, seq) > 0) + /* we got something back, so esp is supported */ + ipsec_esp_loaded = _B_TRUE; + + (void) close(s); + return (_B_TRUE); +} + + + +/* + * Funcition: setIPsecSAFlags + * + * Arguments: ipsr_p - pointer to an ipsec_req_t containing the ipsec policy. + * type - the type of service this policy is for (request, ...). + * + * Description: setIPsecSAFlags looks at the details of the ipsec policy, and + * returns a bit-field of what the policy is requiring in terms of + * AH and ESP support. + * + * Returns: The bit field indicating what of AH and ESP type is requiring. + */ +uint8_t +setIPsecSAFlags(ipsec_req_t *ipsr_p, int type) +{ + uint8_t bitfield = 0; + + /* type defines how we set our bits. For now use low-order bits */ + if (ipsr_p->ipsr_auth_alg) + bitfield |= IPSEC_REQUEST_AH; + + if ((ipsr_p->ipsr_esp_alg) || (ipsr_p->ipsr_esp_auth_alg)) + bitfield |= IPSEC_REQUEST_ESP; + + /* Shift depending on the actual type */ + switch (type) { + case IPSEC_REQUEST: + return (bitfield); + + case IPSEC_REPLY: + return (bitfield << 2); + + case IPSEC_TUNNEL: + return (bitfield << 4); + + case IPSEC_REVERSE_TUNNEL: + return (bitfield << 6); + + default: + syslog(LOG_WARNING, "setIPsecSAFlags: unknown IPsec " + "configuration type %d\n", type); + break; + } + + return (0); +} + +/* + * ParseAgentIPsecPolicy + * + * Arguments: mae - A pointer to a MobilityAgentEntry struct containing + * information about an agent-peer with which we may have + * to add IPsec security associations. + * ipsType - Identifies the type of IPsec Policy we're parsing. + * ipsp - The string that may contain one or two IPsec Policies. + * Keywords to look for are 'apply' and 'permit', and if + * both appear, the policies MUST be separated by a ':'. + * + * Description: We need to sanity check the policies pointed to by ipsp, and + * put them into the correct placeholder in the MobilityAgentEntry + * structure. We return the relevant bits in mpIPsecFlags so the + * caller knows which policies were found. + * + * Note: there can never be more than two bits set at once, one + * for the permit, and one for the apply of this ipsType, + * so a return of -1 is quite revealing! + */ +int +ParseAgentIPsecPolicy(MobilityAgentEntry *mae, int ipsType, char *ipsp) +{ + uint8_t ipsFlags = 0; /* (will become) what we'll return */ + int i; + char *p, *freeP, *lasts; + char *ipsPolicy[IPSEC_ORDER] = {NULL, NULL}; + int policies_found = 0; + + /* Oh, sanity... */ + if ((mae == NULL) || (ipsp == NULL)) + return (-1); + + if ((p = strdup(ipsp)) == NULL) + return (-1); + + freeP = p; /* strtok_r() is destructive! */ + + /* lets just deal with lower case */ + for (i = 0; i < strlen(ipsp); i++) + ipsp[i] = tolower(ipsp[i]); + + /* + * ipsec policies can only be passed one-at-a-time, so thunk if needed. + * + * Note: we don't know which order the user's put his actions in, + * so we have to always start at the begining of validIPsecAction[]s. + */ + while (strtok_r(p, IPSP_SEPARATOR, &lasts) != NULL) { + + if (++policies_found > IPSEC_ORDER) { + char peerAddr[IPv4_ADDR_LEN]; + (void) ntoa(mae->maAddr, peerAddr); + + /* Tell the user they have too many */ + syslog(LOG_CRIT, "[Address %s] %s: too many actions.", + peerAddr, IPSEC_POLICY_STRING(ipsType)); + (void) free(freeP); + return (-1); + } + + for (i = 0; validIPsecAction[i] != NULL; i++) { + /* + * Fill a corresponding empty array with a policy + * containing this validIPsecAction[]. + */ + if ((ipsPolicy[i] == NULL) && + ((ipsPolicy[i] = strstr(p, validIPsecAction[i])) + != NULL)) { + /* something new to parse */ + char peerAddr[IPv4_ADDR_LEN]; + + (void) ntoa(mae->maAddr, peerAddr); + + switch (ipsType) { + case IPSEC_REQUEST: + if (isIPsecPolicyValid(ipsPolicy[i], + &(mae->maIPsecRequestIPSR[i])) + != _B_TRUE) { + (void) free(freeP); + return (-1); + } + + /* policy is OK (and parsed)! */ + if (formIPsecBits(REQUEST(i), + peerAddr, ipsPolicy[i], + &mae->maIPsecRequest[i][0], + sizeof (mae->maIPsecRequest[i])) + < 0) { + (void) free(freeP); + return (-1); + } + + /* set SA flags */ + mae->maIPsecSAFlags[i] |= + setIPsecSAFlags( + &mae->maIPsecRequestIPSR[i], + ipsType); + + /* Remember we did this */ + ipsFlags |= REQUEST(i); + break; + + case IPSEC_REPLY: + if (isIPsecPolicyValid(ipsPolicy[i], + &(mae->maIPsecReplyIPSR[i])) + != _B_TRUE) { + (void) free(freeP); + return (-1); + } + /* policy is OK (and parsed)! */ + if (formIPsecBits(REPLY(i), + peerAddr, ipsPolicy[i], + &mae->maIPsecReply[i][0], + sizeof (mae->maIPsecReply[i])) + < 0) { + (void) free(freeP); + return (-1); + } + + /* set SA flags */ + mae->maIPsecSAFlags[i] |= + setIPsecSAFlags( + &mae->maIPsecReplyIPSR[i], + ipsType); + + /* Remember we did this */ + ipsFlags |= REPLY(i); + break; + + /* + * For the tunnel policies, we pass the + * IPSR bits into the ioctl(), so we + * don't need to form the ASCII policy. + */ + case IPSEC_TUNNEL: + if (isIPsecPolicyValid(ipsPolicy[i], + &(mae->maIPsecTunnelIPSR[i])) + != _B_TRUE) { + (void) free(freeP); + return (-1); + } + /* policy is OK (and parsed)! */ + + /* set SA flags */ + mae->maIPsecSAFlags[i] |= + setIPsecSAFlags( + &mae->maIPsecTunnelIPSR[i], + ipsType); + + /* Remember we did this */ + ipsFlags |= TUNNEL(i); + break; + + case IPSEC_REVERSE_TUNNEL: + if (isIPsecPolicyValid(ipsPolicy[i], + &(mae->maIPsecReverseTunnelIPSR[i])) + != _B_TRUE) { + (void) free(freeP); + return (-1); + } + /* policy is OK (and parsed)! */ + + /* set SA flags */ + mae->maIPsecSAFlags[i] |= + setIPsecSAFlags( + &mae->maIPsecReverseTunnelIPSR[i], + ipsType); + + /* Remember we did this */ + ipsFlags |= REVERSE_TUNNEL(i); + break; + + } + } + } + + /* setup for the next policy */ + p = NULL; + } + + /* we're out of policies */ + (void) free(freeP); + + /* reveal what we found */ + return (ipsFlags); + +} + + +/* + * Function: setupSPI + * + * Arguments: configFile - Pointer to config file + * SPIstr - Pointer to the section + * + * Description: This function will process an [SPI x] section. + * If the section is valid, we will create the + * static security assocation entry. + * + * Returns: int - 0 if successful. + */ +static int +setupSPI(char *configFile, char *SPIstr) +{ + int rc; + int i; + char buffer[MAX_BUFFER_SIZE+1]; + /* Agent Node */ + char Key[MAX_KEY_STRING_LEN]; + int32_t SPI, replayMethod = NONE; + char mipSecKey[MAX_KEY_LEN]; + MipSecAssocEntry *entry; + Str2Int replayMethods[] = { + { "none", NONE }, + { "timestamps", TIMESTAMPS }, + { NULL, NULL }}; + + /* SPI Definition */ + rc = sscanf(SPIstr, "%" VAL2STR(MAX_BUFFER_SIZE) "s %d", buffer, &SPI); + if (rc != 2) { + syslog(LOG_CRIT, "Error: Invalid SPI Section [%s]", SPIstr); + return (-1); + } + rc = GetPrivateProfileString(SPIstr, "ReplayMethod", + "", buffer, MAX_KEY_STRING_LEN, configFile); + /* + * GetPrivateProfileString() returns "-2" for all + * configuration file loading and parsing errors. + * Hence, to catch those errors, there is a check + * for rc == -2 here. + */ + if (rc == -2) { + syslog(LOG_ERR, " Unable to read %s tags :%s", SPIstr, + ErrorString); + return (-1); + } + if (*buffer == '\0') { + syslog(LOG_CRIT, "Problem reading SPI <%d>. No ReplayMethod", SPI); + return (-1); + } + + /* Check the replay method */ + for (i = 0; replayMethods[i].string; i++) { + if (!strcasecmp(buffer, replayMethods[i].string)) { + replayMethod = replayMethods[i].value; + break; + } + } + if (replayMethods[i].string == NULL) { + syslog(LOG_CRIT, "Error: Invalid replay method in section [%s]." + "Possible values are (none or timestamps)", SPIstr); + return (-1); + } + + rc = GetPrivateProfileString(SPIstr, "Key", "", Key, + MAX_KEY_STRING_LEN, configFile); + if (rc == -2) { + syslog(LOG_ERR, " Unable to read %s tags :%s", SPIstr, + ErrorString); + return (-1); + } + + if (Key[0] == 0) { + syslog(LOG_CRIT, "Problem reading SPI <%d>. No Key", SPI); + return (-1); + } + + if (hexConvert((char *)mipSecKey, + strlen(Key)/2, Key) < 0) { + syslog(LOG_CRIT, "Problem Converting key <%s>", Key); + return (-2); + } + + /* + * Now we create the Security Assocation + */ + entry = CreateSecAssocEntry(_B_FALSE, SPI, replayMethod, MD5, + PREFIXSUFFIX, strlen(Key)/2, mipSecKey, 0); + + if (entry == NULL) { + syslog(LOG_CRIT, "Unable to create SPI %d", SPI); + return (-2); + } + + /* + * The Create function ends up locking the node, so + * we need to free it. + */ + (void) rw_unlock(&entry->mipSecNodeLock); + + return (0); + +} /* setupSPI */ + +/* + * Function: setupAddress + * + * Arguments: configFile - Pointer to config file + * Address - Pointer to the section + * + * Description: This function will process an [Address x] section. + * If the section is valid, we will create the + * static Mobile Node or Mobility Agent entry. + * + * This function supports three different types + * of addresses: + * x.x.x.x - Normal IP Address format + * xxx@yyy - Network Access Identifier (up to 256 characters) + * Default-Node - Default Mobile Node Config + * + * Returns: int - 0 if successful. + */ +static int +setupAddress(char *configFile, char *Address) +{ + int32_t rc; + char buffer[MAX_BUFFER_SIZE+1]; + char nodeID[MAX_NAI_LENGTH+1]; + int32_t SPI, Pool; + char *NAI = NULL; + + /* Check what we were passed!!! */ + if ((configFile == NULL) || (Address == NULL)) { + syslog(LOG_CRIT, + "Error: Invalid Address passed to setupAddress."); + return (-1); + } + + /* + * Mobile Node Definition - + */ + rc = sscanf(Address, + "%" VAL2STR(MAX_BUFFER_SIZE) "s " + "%" VAL2STR(MAX_NAI_LENGTH) "s", + buffer, nodeID); + if (rc != 2) { + syslog(LOG_CRIT, "Error: Invalid Address Section <%s>.", Address); + return (-1); + } + + if (strlen(nodeID) >= MAX_NAI_LENGTH) { + syslog(LOG_CRIT, + "Error: NAI too long in [%s...] section of config file.\n", + Address); + return (-1); + } + + rc = GetPrivateProfileString(Address, "Type", "", buffer, + MAX_TAG_SIZE, configFile); + if (rc == -2) { + syslog(LOG_ERR, " Unable to read %s tags: %s", Address, + ErrorString); + return (-1); + } + if (!*buffer) { + syslog(LOG_CRIT, "Error: Must specify \"Type\" in addresses." + "Error in section [%s]", Address); + return (-1); + } + + /* Figure out what type of address this is */ + if (!strncasecmp(nodeID, "Node-Default", 12)) { + /* + * This is a default entry.... Fun and Joy!! + */ + SPI = GetPrivateProfileInt(Address, "SPI", -1, configFile); + if (SPI == -1) { + syslog(LOG_CRIT, + "Problem reading MobileNode <%s>. No SPI", Address); + return (-1); + } + Pool = GetPrivateProfileInt(Address, "Pool", -1, + configFile); + + /* + * The default SPI MUST be present, however the Pool is + * optional. + */ + defaultNodeSPI = SPI; + if (Pool != -1) { + defaultPool = Pool; + } + /* Figure out what type of address this is */ + } else if (!strncasecmp(buffer, "Node", 4)) { + HaMobileNodeEntry *entry; + + SPI = GetPrivateProfileInt(Address, "SPI", -1, configFile); + if (SPI == -1) { + syslog(LOG_CRIT, + "Problem reading MobileNode <%s>. No SPI", + Address); + return (-1); + } + + NAI = strchr(nodeID, '@'); + Pool = GetPrivateProfileInt(Address, "Pool", -1, configFile); + + /* + * We don't need a pool every time we have an NAI (FA-only + * config, for example; NAIs are used for more than obtaining + * an address these days). If we end up being this node's HA + * and it needs an address, but there's none to give it (that + * is, we have a broken config, read: user error), then we'll + * reply with 130 "insufficient resources", and (hopefully) + * log the appropriate error in the user-feedback nicities. + */ + if (Pool != -1) { + /* + * If the MN will need a pool, it implies we'll need + * an NAI for identification! + */ + if (NAI == NULL) { + syslog(LOG_CRIT, + "Problem reading MobileNode <%s>. " + "Pool invalid for non-NAI addresses", Address); + return (-1); + } + } else { + Pool = 0; /* don't pass -1 into Create...(). */ + } + + /* + * And we create the Mobile Node + */ + if (NAI != NULL) { + entry = CreateMobileNodeEntry(_B_FALSE, INADDR_ANY, + nodeID, strlen(nodeID), 0, SPI, NULL, Pool); + } else { + entry = CreateMobileNodeEntry(_B_FALSE, + inet_addr(nodeID), NULL, 0, 0, SPI, NULL, Pool); + } + + if (entry == NULL) { + syslog(LOG_CRIT, + "Unable to create MN-HA for %s", nodeID); + return (-2); + } + + /* + * A successful Create...() function ends up locking the node, + * so we need to unlock it. + */ + (void) rw_unlock(&entry->haMnNodeLock); + + } else if (strncasecmp(buffer, "Agent", 5) == 0) { + /* Agent Node */ + int32_t SPI; + char IPSPolicy[MAX_IPSEC_POLICY_SIZE] = ""; + MobilityAgentEntry *maEntry; + + NAI = strchr(nodeID, '@'); + if (NAI) { + syslog(LOG_CRIT, + "Error: NAIs invalid for Agent Addresses"); + return (-1); + } + + /* + * The assumption, then, is nodeID is a dotted-decimal + * address. Even if not, we can use it to identify to + * the user which [Address *] section we're flagging. + * + * The SPI is for identifying the usual MD5 agent-agent + * SA/authentication, and has nothing to do with the SPI + * used by ipsec! + */ + SPI = GetPrivateProfileInt(Address, "SPI", -1, configFile); + if (SPI == -1) { + syslog(LOG_CRIT, + "Problem reading FA-HA-auth Node <%s>. No SPI", + nodeID); + return (-1); + } + + maEntry = CreateMobilityAgentEntry(_B_FALSE, + (ipaddr_t)inet_addr(nodeID), SPI, 0); + + if (maEntry == NULL) { + syslog(LOG_CRIT, + "Unable to create HA-FA for %s", nodeID); + return (-2); + } + + /* Check to see if there are any IPsec policies to apply */ + if (GetPrivateProfileString(Address, "IPsecRequest", + "", IPSPolicy, MAX_IPSEC_POLICY_SIZE, configFile) == -2) { + syslog(LOG_CRIT, + "Catastrophic failure while trying to get " + "IPsecRequest configuration in the %s section " + "of %s. Please verify file integrity.", + Address, configFile); + return (-1); + } + + if (*IPSPolicy) { + /* + * The first time we could have found an IPSec policy + * as restoring our state is done after we init. Note: + * we don't support NAIs, or MA-MA authenticators. + */ + if (ParseAgentIPsecPolicy(maEntry, IPSEC_REQUEST, + IPSPolicy) < 0) { + /* syslog the error, and fail */ + syslog(LOG_CRIT, "Problem parsing " + "IPsecRequest in [%s] section of %s.", + Address, configFile); + + /* mipagent fails in these cases. */ + return (-1); + } + } + + if (GetPrivateProfileString(Address, "IPsecReply", + "", IPSPolicy, MAX_IPSEC_POLICY_SIZE, configFile) == -2) { + syslog(LOG_CRIT, + "Catastrophic failure while trying to get " + "IPsecReply configuration in the %s section " + "of %s. Please verify file integrity.", + Address, configFile); + return (-1); + } + + if (*IPSPolicy) { + /* parse it into it's individual properties */ + if (ParseAgentIPsecPolicy(maEntry, IPSEC_REPLY, + IPSPolicy) < 0) { + /* syslog the error, and fail. */ + syslog(LOG_CRIT, "Problem parsing IPsecReply" + " policy in [%s] section of %s", + Address, configFile); + + /* mipagent fails in these cases. */ + return (-1); + } + } + + if (GetPrivateProfileString(Address, "IPsecTunnel", + "", IPSPolicy, MAX_IPSEC_POLICY_SIZE, configFile) == -2) { + syslog(LOG_CRIT, + "Catastrophic failure while trying to get " + "IPsecTunnel configuration in the %s section of %s." + " Please verify file integrity.", + Address, configFile); + return (-1); + } + + + if (*IPSPolicy) { + /* parse it into it's individual properties */ + if (ParseAgentIPsecPolicy(maEntry, IPSEC_TUNNEL, + IPSPolicy) < 0) { + /* syslog the error, and fail. */ + syslog(LOG_CRIT, "Problem parsing IPsecTunnel" + " policy in [%s] section of %s", + Address, configFile); + + /* mipagent fails in these cases. */ + return (-1); + } + } + + /* + * ipsec only supports symmetric tunnel policies, so we can't + * support asymmetric tunnel policies yet. When ipsec supports + * multiple per-socket policies, that will (likely) change. + * Note that if this GetPrivateProfileString() returns -2, we + * don't care. + */ + (void) GetPrivateProfileString(Address, "IPsecReverseTunnel", + "", IPSPolicy, MAX_IPSEC_POLICY_SIZE, configFile); + + if (*IPSPolicy) + /* + * If the user tried the obvious tag, then at least + * warn them asymmetric tunnel policies are not + * supported at this time. + */ + syslog(LOG_WARNING, "Found [%s] setting for " + "IPSecReverseTunnel. Asymmetric IPsec tunnel " + "policies are not supported at this time. Setting" + " reverse tunnel policies to conform to forward" + " tunnel settings.", Address); + + /* Make the tunnel policies symmetric (for mipagentstat) */ + if (maEntry->maIPsecSAFlags[IPSEC_APPLY] & IPSEC_TUNNEL_AH) + /* tunnel apply = HA, so we set reverse tunnel permit */ + maEntry->maIPsecSAFlags[IPSEC_PERMIT] |= + IPSEC_REVERSE_TUNNEL_AH; + + if (maEntry->maIPsecSAFlags[IPSEC_APPLY] & IPSEC_TUNNEL_ESP) + /* tunnel apply = HA, so we set reverse tunnel permit */ + maEntry->maIPsecSAFlags[IPSEC_PERMIT] |= + IPSEC_REVERSE_TUNNEL_ESP; + + if (maEntry->maIPsecSAFlags[IPSEC_PERMIT] & IPSEC_TUNNEL_AH) + /* tunnel permit = FA, so we set reverse tunnel apply */ + maEntry->maIPsecSAFlags[IPSEC_APPLY] |= + IPSEC_REVERSE_TUNNEL_AH; + + if (maEntry->maIPsecSAFlags[IPSEC_PERMIT] & IPSEC_TUNNEL_ESP) + /* tunnel permit = FA, so we set reverse tunnel apply */ + maEntry->maIPsecSAFlags[IPSEC_APPLY] |= + IPSEC_REVERSE_TUNNEL_ESP; + + /* if the user wants to use ipsec, see if we can */ + if ((ipsec_loaded == _B_FALSE) && + (maEntry->maIPsecSAFlags[IPSEC_APPLY] || + maEntry->maIPsecSAFlags[IPSEC_PERMIT])) { + /* load, if not loaded */ + if (IsIPsecLoaded() == _B_FALSE) + syslog(LOG_WARNING, + "Can't determine ipsec state. Configured " + "[%s] IPsec policies may fail to install!", + Address); + else + ipsec_loaded = _B_TRUE; + } + + /* Is AH or ESP protection requested, but not offered? */ + if ((!ipsec_ah_loaded) && + IPSEC_ANY_AH(maEntry->maIPsecSAFlags[IPSEC_APPLY] | + maEntry->maIPsecSAFlags[IPSEC_PERMIT])) + /* --><-- user wants, not available (now) */ + syslog(LOG_WARNING, "[%s] is configured to use " + "IPsec AH protections, but AH is not " + "provided/loaded at this time.", Address); + + if ((!ipsec_esp_loaded) && + IPSEC_ANY_ESP(maEntry->maIPsecSAFlags[IPSEC_APPLY] | + maEntry->maIPsecSAFlags[IPSEC_PERMIT])) + /* --><-- user wants, not available (now) */ + syslog(LOG_WARNING, "[%s] is configured to use " + "IPsec ESP protection, but ESP is not" + "provided/loaded at this time.", Address); + + /* + * "IPsecRequest permit {properties}" are for HAs receiving + * registration requests from FAs, and so we need to be + * ready to receive these (they'll be unannounced). + * Pass down any of these policies now. Note: we don't check + * to see if it's been installed because we just read the + * policy, and we haven't called AgentRestoreState() yet! + */ + if (IPSEC_REQUEST_ANY(maEntry->maIPsecSAFlags[IPSEC_PERMIT])) { + /* + * We found an IPsecRequest permit. Do whatever + * we do to install the ipsec policy. + */ + if (installIPsecPolicy( + maEntry->maIPsecRequest[IPSEC_PERMIT]) < 0) { + syslog(LOG_CRIT, + "Could not install %s for [Address %s]: %s", + IPSEC_POLICY_STRING(IPSEC_REQUEST_PERMIT), + nodeID, + maEntry->maIPsecRequest[IPSEC_PERMIT]); + + /* we're exiting, but unlock anyway */ + (void) rw_unlock(&maEntry->maNodeLock); + + /* mipagent fails to load at these times */ + return (-1); + } else + /* + * success, set the flag. Note: this is NOT + * technically an agent-peer until we have + * a mobile node registered with it! + */ + maEntry->maIPsecFlags |= IPSEC_REQUEST_PERMIT; + } + + /* done processing type = agent, UNLOCK! */ + (void) rw_unlock(&maEntry->maNodeLock); + + return (0); + } else { + syslog(LOG_CRIT, + "Error: invalid type in section [%s]", Address); + return (-1); + } + + return (0); + +} /* setupAddress */ + + +/* + * Function: setupInterface + * + * Arguments: configFile - Pointer to config file + * Interface - Pointer to the interface section + * + * Description: This function will process an [Interface x] section. + * If the section is valid, we will create the + * static Interface entry. + * + * Returns: int - 0 if successful. + */ +static int +setupInterface(char *configFile, char *Interface) +{ + int32_t rc; + char buffer[MAX_BUFFER_SIZE]; + /* Interface definition */ + char dev[LIFNAMSIZ+1]; + char devAddr[INET_ADDRSTRLEN+1]; + int32_t ServicesFlags = ADV_IS_HOME_AGENT | ADV_IS_FOREIGN_AGENT; + uint8_t reverseTunnelAllowed = RT_NONE; + uint8_t reverseTunnelRequired = RT_NONE; + boolean_t PrefixFlags = _B_TRUE; + boolean_t advertiseOnBcast = _B_FALSE; + int advInitCount = 1; + int advInterval; + boolean_t advLimitUnsolicited = _B_FALSE; + int i; + /* + * We need a local regLifetime variable + */ + int regLifetime; + + Str2Int flagTable[] = { + { "homeAgent", ADV_IS_HOME_AGENT}, + { "foreignAgent", ADV_IS_FOREIGN_AGENT}, + { "registrationRequired", ADV_REGISTRATION_REQUIRED}, +#ifdef ENABLE_ALL_FLAGS + { "minEncap", ADV_MIN_ENCAP}, + { "greEncap", ADV_GRE_ENCAP}, + { "vjCompression", ADV_VJ_COMPRESSION}, +#endif + { "reverseTunnel", ADV_REVERSE_TUNNEL}, + { NULL, 0 }}; + + + + /* Search the file for Advertisements tags */ + for (i = 0; flagTable[i].string; i++) { + rc = GetPrivateProfileString(Interface, flagTable[i].string, + "", buffer, MAX_FN_LEN, configFile); + if (rc == -2) { + syslog(LOG_ERR, "Unable to read advertisement tags :%s", + ErrorString); + return (-1); + } + + if (*buffer) { + /* + * If we're talking "reverseTunnel", then we only + * advertise what the setting for the FA is. This is + * because the only MNs that care about what's in these + * becons are those that are visiting this subnet, so + * if the setting for HA is no, but the setting for FA + * is yes, advertise them. + */ + if (strcmp(flagTable[i].string, "reverseTunnel") == 0) { + if (FA(*buffer)) { + ServicesFlags |= flagTable[i].value; + } else { + ServicesFlags &= ~flagTable[i].value; + } + continue; + } + + /* every other setting is simply yes/no... */ + if (YES(*buffer)) { + ServicesFlags |= flagTable[i].value; + } else { + ServicesFlags &= ~flagTable[i].value; + } + } + } + + /* regLifetime */ + rc = GetPrivateProfileInt(Interface, "regLifetime", -1, configFile); + if (rc != -1) + regLifetime = rc; + + /* advLifetime */ + rc = GetPrivateProfileInt(Interface, "advLifetime", -1, configFile); + if (rc != -1) + advLifetime = rc; + + /* periodicInterval */ + rc = GetPrivateProfileInt(Interface, "advFrequency", + DEFAULT_ADVERTISEMENT_INTERVAL, configFile); + + advInterval = rc; + + if (advInterval < DEFAULT_MIN_INTERVAL) + advInterval = DEFAULT_ADVERTISEMENT_INTERVAL; + else if (advInterval > (int)(advLifetime/3)) { + syslog(LOG_WARNING, + "advFrequency value exceeds recommended value: " + "less than or equal to %d", + (int)(advLifetime/3)); + } + /* AdvInitCount */ + advInitCount = GetPrivateProfileInt(Interface, + "advInitCount", 1, configFile); + if (advInitCount < (uint8_t)ADV_INIT_COUNT_MIN) + advInitCount = ADV_INIT_COUNT_DEFAULT; + + /* AdvLimitUnsolicited */ + rc = GetPrivateProfileString(Interface, "advLimitUnsolicited", + "no", buffer, MAX_BUFFER_SIZE, configFile); + if (rc == -2) { + syslog(LOG_ERR, "Unable to read advertisement tags: %s", + ErrorString); + return (-1); + } + + if (strcasecmp(buffer, "yes") == 0) { + advLimitUnsolicited = _B_TRUE; + } + if (advLimitUnsolicited == _B_FALSE) + advInitCount = 1; + + /* Is Reverse Tunneling allowed on this interface? */ + rc = GetPrivateProfileString(Interface, "reverseTunnel", + "no", buffer, MAX_FN_LEN, configFile); + if (rc == -2) { + syslog(LOG_ERR, "Unable to read advertisement tags: %s", + ErrorString); + return (-1); + } + + /* We support differenct HA and FA reverseTunnelAllowed settings. */ + if (!strcasecmp(buffer, "no")) { + reverseTunnelAllowed = RT_NONE; + } + + if (!strcasecmp(buffer, "none")) { + reverseTunnelAllowed = RT_NONE; + } + + if (!strcasecmp(buffer, "ha")) { + reverseTunnelAllowed = RT_HA; + } + + if (!strcasecmp(buffer, "fa")) { + reverseTunnelAllowed = RT_FA; + } + + if (!strcasecmp(buffer, "yes")) { + reverseTunnelAllowed = RT_BOTH; + } + if (!strcasecmp(buffer, "both")) { + reverseTunnelAllowed = RT_BOTH; + } + + /* Is Reverse Tunneling required on this interface? */ + rc = GetPrivateProfileString(Interface, "reverseTunnelRequired", + "no", buffer, MAX_FN_LEN, configFile); + if (rc == -2) { + syslog(LOG_ERR, "Unable to read advertisement tags: %s", + ErrorString); + return (-1); + } + + /* We support differenct HA and FA reverseTunnelRequired settings */ + if (!strcasecmp(buffer, "no")) { + reverseTunnelRequired = RT_NONE; + } + + if (!strcasecmp(buffer, "none")) { + reverseTunnelRequired = RT_NONE; + } + + if (!strcasecmp(buffer, "ha")) { + reverseTunnelRequired = RT_HA; + } + + if (!strcasecmp(buffer, "fa")) { + reverseTunnelRequired = RT_FA; + } + + if (!strcasecmp(buffer, "yes")) { + reverseTunnelRequired = RT_BOTH; + } + if (!strcasecmp(buffer, "both")) { + reverseTunnelRequired = RT_BOTH; + } + + rc = sscanf(Interface, + "%" VAL2STR(LIFNAMSIZ) "s " + "%" VAL2STR(INET_ADDRSTRLEN) "s", + devAddr, dev); + if (rc != 2) { + syslog(LOG_CRIT, "Error: Invalid Advertisement Section <%s>", + Interface); + return (-1); + } + + rc = GetPrivateProfileString(Interface, "prefixLengthExt", + "", buffer, MAX_FN_LEN, configFile); + if (rc == -2) { + syslog(LOG_ERR, "Unable to read advertisement tags: %s", + ErrorString); + return (-1); + } + if (*buffer) { + if (YES(*buffer)) { + PrefixFlags = _B_TRUE; + } else { + PrefixFlags = _B_FALSE; + } + } + + + /* advertiseOnBcast */ + rc = GetPrivateProfileString(Interface, "advertiseOnBcast", + "", buffer, MAX_FN_LEN, configFile); + if (rc == -2) { + syslog(LOG_ERR, "Unable to read advertisement tags: %s", + ErrorString); + return (-1); + } + if (*buffer) { + if (YES(*buffer)) { + advertiseOnBcast = _B_TRUE; + } else { + advertiseOnBcast = _B_FALSE; + } + } + + /* + * Note that the CreateInterfaceEntry does NOT lock the node + * and simply returns an int. Last argument is B_FALSE for static + * entries + */ + if (CreateInterfaceEntry(dev, regLifetime, advertiseOnBcast, + DEFAULT_MIN_INTERVAL, DEFAULT_MAX_INTERVAL, advLifetime, + 0, ServicesFlags, PrefixFlags, reverseTunnelAllowed, + reverseTunnelRequired, advLimitUnsolicited, advInitCount, + advInterval, _B_FALSE)) { + syslog(LOG_CRIT, "Unable to create Interface"); + return (-2); + } + + return (0); + +} /* setupInterface */ + +/* + * Function: setupPool + * + * Arguments: configFile - Pointer to config file + * Poolstr - Pointer to the section + * + * Description: This function will process an [Pool x] section. + * If the section is valid, we will create the + * static Pool entry. + * + * Returns: int - 0 if successful. + */ +static int +setupPool(char *configFile, char *Poolstr) +{ + Pool *entry; + int32_t rc; + char buffer[MAX_BUFFER_SIZE+1]; + uint32_t poolId; + uint32_t poolBaseAddr; + int32_t poolSize; + + /* SPI Definition */ + rc = sscanf(Poolstr, "%" VAL2STR(MAX_BUFFER_SIZE) "s %u", + buffer, &poolId); + if (rc != 2) { + syslog(LOG_CRIT, "Error: Invalid Pool Section [%s]", Poolstr); + return (-1); + } + + rc = GetPrivateProfileString(Poolstr, "BaseAddress", + "", buffer, MAX_KEY_STRING_LEN, configFile); + if (rc == -2) { + syslog(LOG_ERR, "Unable to read %s tags: %s", Poolstr, + ErrorString); + return (-1); + } + if (*buffer == '\0') { + syslog(LOG_CRIT, + "Problem reading Pool <%d>. No BaseAddress", poolId); + return (-1); + } + poolBaseAddr = inet_addr(buffer); + + poolSize = GetPrivateProfileInt(Poolstr, "Size", -1, configFile); + if (poolSize == -1) { + syslog(LOG_CRIT, "Problem reading Pool <%d>. No Pool Size", poolId); + return (-1); + } + + /* + * Now we create the Security Assocation + */ + if ((entry = CreateAddressPool(poolId, poolBaseAddr, + poolSize)) == NULL) { + syslog(LOG_CRIT, "Unable to create Pool %d", poolId); + return (-2); + } + + /* + * The Create function ends up locking the node, so + * we need to free it. + */ + (void) rw_unlock(&entry->poolNodeLock); + + return (0); + +} /* setupPool */ + +/* + * Function: readGSPs + * + * Arguments: configFile - Pointer to config file + * + * Description: This function will parse the + * [GlobalSecurityParameters] section in the + * config file. + * + * Returns: void + */ +static void +readGSPs(char *configFile) +{ + int32_t rc; + char buffer[MAX_BUFFER_SIZE]; + char *GSP = "GlobalSecurityParameters"; + int32_t strlenmax; + + /* IDfreshnessSlack */ + rc = GetPrivateProfileInt(GSP, "maxClockSkew", -1, configFile); + if (rc != -1) + IDfreshnessSlack = rc; + + /* + * Is inter-Mobility-Agent Authentication Required? + */ + rc = GetPrivateProfileString(GSP, "HA-FAauth", + "", buffer, MAX_FN_LEN, configFile); + if (rc == -2) { + syslog(LOG_ERR, "Unable to read %s tags: %s", GSP, + ErrorString); + exit(1); + } + if (*buffer) { + if (YES(*buffer)) + fhAuthRequired = _B_TRUE; + else + fhAuthRequired = _B_FALSE; + } + + /* + * Is Authentication between the Mobile Node and the Foreign + * agent required? + */ + rc = GetPrivateProfileString(GSP, "MN-FAauth", + "", buffer, MAX_FN_LEN, configFile); + if (rc == -2) { + syslog(LOG_ERR, "Unable to read %s tags: %s", GSP, + ErrorString); + exit(1); + } + if (*buffer) { + if (YES(*buffer)) + mfAuthRequired = _B_TRUE; + else + mfAuthRequired = _B_FALSE; + } + + /* + * Should we be advertising the challenge? + */ + rc = GetPrivateProfileString(GSP, "Challenge", + "", buffer, MAX_FN_LEN, configFile); + if (rc == -2) { + syslog(LOG_ERR, "Unable to read %s tags: %s", GSP, + ErrorString); + exit(1); + } + if (*buffer) { + if (YES(*buffer)) + faChallengeAdv = _B_TRUE; + else + faChallengeAdv = _B_FALSE; + } + + /* + * What is our key distribution strategy? + */ + rc = GetPrivateProfileString(GSP, "KeyDistribution", + "", buffer, MAX_FN_LEN, configFile); + if (rc == -2) { + syslog(LOG_ERR, "Unable to read %s tags: %s", GSP, + ErrorString); + exit(1); + } + strlenmax = MAX_FN_LEN - 1; + if (!strncasecmp(buffer, "diameter", strlenmax)) { + aaaProtocol = DIAMETER; + } else if (!strncasecmp(buffer, "radius", strlenmax)) { + aaaProtocol = RADIUS; + } + +#ifdef RADIUS_ENABLED + /* Radius Library */ + rc = GetPrivateProfileString(GSP, "RadiusSharedLibrary", + "", radiusSharedLibrary, MAX_FN_LEN, configFile); + if (rc == -2) { + syslog(LOG_ERR, "Unable to read %s tags: %s", GSP, + ErrorString); + return (-1); + } + if (*radiusSharedLibrary) { + syslog(LOG_CRIT, "ERROR!!! --- RADIUS SUPPORT BROKEN!"); + radiusEnabled = 0; + } +#endif /* RADIUS_ENABLED */ + return; + +} /* readGSPs */ + +/* + * Function: readAAASettings + * + * Arguments: configFile - Pointer to config file + * + * Description: This function will parse the + * [AAASettings] section in the config file. + * + * Returns: void + */ + +/* ARGSUSED */ +static void +readAAASettings(char *configFile) +{ +#ifdef TEST_DIAMETER + char buffer[MAX_BUFFER_SIZE]; + char *AAASettings = "AAASettings"; + int rc; +#endif + + /* First, set the defaults */ + gbl_aaaPort = AAA_PORT; + (void) strcpy(gbl_aaaHost, LOOPBACK); + + /* + * The only time we would ever want these configurable is during + * testing. So, only enable them when TEST_DIAMETER is defined. + */ + +#ifdef TEST_DIAMETER + + /* Server */ + (void) GetPrivateProfileString(AAASettings, "Server", + "", buffer, MAX_FN_LEN, configFile); + if (rc == -2) { + syslog(LOG_ERR, "Unable to read AAASettings tags :%s", + ErrorString); + return (-1); + } + if (*buffer) { + (void) strncpy(gbl_aaaHost, buffer, + MIN(MAX_SERVER_NAME_LEN, + MAX_BUFFER_SIZE)); + gbl_aaaHost[MAX_SERVER_NAME_LEN - 1] = 0; + } + + /* Port */ + rc = GetPrivateProfileInt(AAASettings, "Port", -1, + configFile); + if (rc != -1) + gbl_aaaPort = (short)rc; + + mipverbose(("WARNING: Changing DIAMETER host/port to" + " %s:%d for testing!\n", + gbl_aaaHost, gbl_aaaPort)); +#endif + return; + +} /* readGSPs */ + +/* + * Function: readGeneral + * + * Arguments: configFile - Pointer to config file + * + * Description: This function will parse the + * [General] section in the config file. + * + * Returns: int - 0 if successful. + */ +static int +readGeneral(char *configFile) +{ + int32_t rc; + char buffer[MAX_BUFFER_SIZE]; + char *General = "General"; + int i; + Str2Int debugLevels[] = { + { "quiet", 0 }, + { "low", 1 }, + { "norm", 2 }, + { "all", 3 }, + { NULL, NULL }}; + + /* Debug Level */ + rc = GetPrivateProfileString(General, "logVerbosity", "", buffer, + MAX_TAG_SIZE, configFile); + if (rc == -2) { + syslog(LOG_ERR, "Unable to read General tags :%s", + ErrorString); + return (-1); + } + if (*buffer) { + for (i = 0; debugLevels[i].string; i++) { + if (!strcasecmp(buffer, debugLevels[i].string)) { + logVerbosity = debugLevels[i].value; + break; + } + } + if (!debugLevels[i].string) { + /* Broke out of loop! */ + syslog(LOG_CRIT, "Bad logVerbosity level. Should be" + " one of (quiet, low, norm, or all)"); + return (-1); + } + } + + /* + * Should we be advertising our NAI? + */ + rc = GetPrivateProfileString(General, "AdvertiseNAI", "", buffer, + MAX_FN_LEN, configFile); + if (rc == -2) { + syslog(LOG_ERR, "Unable to read General tags :%s", + ErrorString); + return (-1); + } + if (*buffer) { + if (YES(*buffer)) + faNAIadv = _B_TRUE; + else + faNAIadv = _B_FALSE; + } + + /* Visitor Entry High Water Mark */ + rc = GetPrivateProfileInt(General, "visitorHighWaterMark", -1, + configFile); + if (rc != -1) + visitorEntryHighWaterMark = rc; + + /* Visitor Entry Low Water Mark */ + rc = GetPrivateProfileInt(General, "visitorLowWaterMark", -1, + configFile); + if (rc != -1) + visitorEntryLowWaterMark = rc; + + /* periodicInterval - This one is undocumented. */ + rc = GetPrivateProfileInt(General, "GarbageCollectionFrequency", + -1, configFile); + if (rc != -1) { + /* + * Magic numbers. Given that this is a faily dangerous + * feature, we need to restrict the values one can + * configure. + */ + if (rc < MIN_GARBAGE_COLLECTION_INTERVAL) { + rc = MIN_GARBAGE_COLLECTION_INTERVAL; + } else if (rc > MAX_GARBAGE_COLLECTION_INTERVAL) { + rc = MAX_GARBAGE_COLLECTION_INTERVAL; + } + periodicInterval = rc; + } + + /* performance checking interval - This one is undocumented. */ + rc = GetPrivateProfileInt(General, "PerformanceCheckInterval", + -1, configFile); + if (rc != -1) { + performanceInterval = rc; + } + + + /* + * Should we be advertising our NAI? + */ + rc = GetPrivateProfileString(General, "Daemonize", "", buffer, + MAX_FN_LEN, configFile); + if (rc == -2) { + syslog(LOG_ERR, "Unable to read General tags :%s", + ErrorString); + return (-1); + } + if (*buffer) { + if (YES(*buffer)) + daemonize = _B_TRUE; + else + daemonize = _B_FALSE; + } + + /* + * Should SNMP be disabled? + */ + rc = GetPrivateProfileString(General, "DisableSNMP", "", buffer, + MAX_FN_LEN, configFile); + if (rc == -2) { + syslog(LOG_ERR, "Unable to read General tags :%s", + ErrorString); + return (-1); + } + if (*buffer) { + if (YES(*buffer)) + disableSNMP = _B_TRUE; + else + disableSNMP = _B_FALSE; + } + + return (0); +} /* readGeneral */ + + +/* + * Function: memswp + * + * Arguments: A - Pointer to buffer + * B - Pointer to buffer + * length - length + * + * Description: This function will swap the contents + * of A and B. + * + * Returns: int - 0 if successful. + */ +static void +memswp(char *A, char *B, int length) +{ + char *temp; + temp = alloca(length); + if (!temp) { + syslog(LOG_CRIT, "Unable to allocate from the heap"); + return; + } + + (void) memcpy(temp, A, length); + (void) memcpy(A, B, length); + (void) memcpy(B, temp, length); +} + + +/* + * Function: sortSections + * + * Arguments: Sections - Pointer to sections + * numSections - Number of sections + * sectionSize - Size of section + * + * Description: Since we have to have the Pools and SPIs defined + * before we add an address, move all of the addresses to the end + * of the sections. Use a single pass, starting at the end, and + * doing a direct swap. + * + * Returns: + */ +static void +sortSections(char *Sections, int numSections, int sectionSize) +{ + int i; + int j = -1; + + for (i = numSections-1; i >= 0; i--) { + if (strncasecmp(&Sections[i*sectionSize], "Address", 7)) { + /* Ok, we're stuck at a non-address, find one */ + /* to exchange with us */ + if (j < 0) + j = i-1; + + for (; j >= 0; j--) { + if (!strncasecmp(&Sections[j*sectionSize], + "Address", 7)) { + /* Found one! Swap it */ + memswp(&Sections[i*sectionSize], + &Sections[j*sectionSize], + sectionSize); + /* break out of inner for loop */ + break; + } + } + /* Check to see if we're finished */ + if (j < 0) + return; + } + } +} /* sortSections */ + +/* + * Function: readConfigInfo + * + * Arguments: configFile - Pointer to filename + * + * Description: Read configuration information for the mobility + * agent from file + * + * Returns: int - 0 if successful + */ +static int +readConfigInfo(char *configFile) +{ + char *Sections; + int numSections, sectionSize; + +#ifdef FIREWALL_SUPPORT + domainInfo.addrIntervalCnt = 0; + domainInfo.firewallCnt = 0; +#endif /* FIREWALL_SUPPORT */ + + if (readGeneral(configFile)) { + return (-1); + } + + readGSPs(configFile); + + readAAASettings(configFile); + + /* + * Ok, now is when it gets a little complex. Read in all the + * section names, then add Interfaces and Mobile nodes as they + * come up. + */ + Sections = IniListSections(configFile, &numSections, §ionSize); + + /* + * We need to check for NULL return from iniListSections, + * otherwise we would be accessing a NULL pointer. + */ + if (Sections != NULL) { + int i; + + sortSections(Sections, numSections, sectionSize); + + for (i = 0; i < numSections; i++) { + if (!strncasecmp(&Sections[i*sectionSize], + "Advertisements", 14)) { + if (setupInterface(configFile, + &Sections[i*sectionSize])) + return (-1); + } else if (!strncasecmp(&Sections[i*sectionSize], + "Address", 7)) { + if (setupAddress(configFile, + &Sections[i*sectionSize])) + return (-1); + } else if (!strncasecmp(&Sections[i*sectionSize], + "SPI", 3)) { + if (setupSPI(configFile, + &Sections[i*sectionSize])) + return (-1); + } else if (!strncasecmp(&Sections[i*sectionSize], + "Pool", 4)) { + if (setupPool(configFile, + &Sections[i*sectionSize])) + return (-1); + } +#ifdef FIREWALL_SUPPORT + /* + * XXX: Does this section need some enhancement ?. + */ + else if (!strncasecmp(&Sections[i*sectionSize], + "Firewall", 8)) { + char Firewall[INET_ADDRSTRLEN+1]; + sscanf(&Sections[i*sectionSize], + "%*s %" VAL2STR(INET_ADDRSTRLEN) "s", + Firewall); + + domainInfo.fwAddr[domainInfo.firewallCnt++] = + inet_addr(Firewall); + } /* end If */ +#endif /* FIREWALL_SUPPORT */ + + } /* End for() each section */ + } + + if (Sections != NULL) { + free(Sections); + } + + return (0); + +} /* readConfigInfo */ + + +/* + * Function: InitSockets + * + * Arguments: pointer to MaAdvConfigEntry + * + * Description: This function will open the ICMP, BCAST and + * the multicast socket, and will bind on all + * interfaces configured. A specific Join must + * be done for multicast on each interface. + * + * Returns: int, 0 if successful + */ +int +InitSockets(MaAdvConfigEntry *entry) +{ + int sid; + int enable = 1; + unsigned int ifceno; + char addrstr1[40]; + struct sockaddr_in sa; + struct ip_mreq imr; + struct in_addr ifaddr; + + mipverbose(("Creating ICMP socket.\n")); + + + /* + * First off, let's get the interface number. + */ + ifceno = if_nametoindex(entry->maIfaceName); + + if (ifceno == 0) { + syslog(LOG_ERR, + "Unable to get interface number for %s", + entry->maIfaceName); + return (-1); + } + + /* Get a socket to receive ICMPs on. */ + if ((sid = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) { + syslog(LOG_CRIT, + "socket()Error: Couldn't create ICMP socket " \ + "in InitSockets."); + return (-1); + } + + /* + * Just in case we advertise on 255.255.255.255, enable + * bcast + */ + enable = 1; + if (setsockopt(sid, SOL_SOCKET, SO_BROADCAST, + (char *)&enable, sizeof (int)) < 0) { + syslog(LOG_CRIT, "SO_BROADCAST on ICMPsock failed"); + return (-1); + + } + + if (setsockopt(sid, IPPROTO_IP, IP_BOUND_IF, (char *)&ifceno, + sizeof (char *))) { + syslog(LOG_ERR, + "Unable to bind socket to interface %d", ifceno); + return (-1); + } + + /* + * Enable IP_XMIT_IF here so that we don't need to + * turn it on sendICMPmessage everytime we send + * multicast adv. IP_XMIT_IF will have to be set + * for all PPP interfaces, because there may be + * cases when PPP local and remote end both have + * non-unique addresses ( ex: private address) + */ + if (entry->maIfaceFlags & IFF_POINTOPOINT) { + /* + * set IP_XMIT_IF + */ + if (setsockopt(sid, IPPROTO_IP, IP_XMIT_IF, + &ifceno, sizeof (ifceno)) < 0) { + syslog(LOG_ERR, + "setsockopt() couldn't set IP_XMIT_IF" + "on Adv socket for interface id %d", + ifceno); + return (-1); + } + } else { + /* + * For non-pointtopoint interfaces we are still + * setting IP_MULTICAST_IF, as we expect to have + * unique ifaddr in this case. + * We can take advantage of cached routing entry + * too. + */ + ifaddr.s_addr = entry->maIfaceAddr; + if (setsockopt(sid, IPPROTO_IP, IP_MULTICAST_IF, + (char *)&ifaddr, sizeof (ifaddr)) == -1) { + syslog(LOG_ERR, + "setsockopt() Couldn't set multicast" + "on socket"); + return (-1); + } + } + entry->maIfaceIcmpSock = sid; + + + /* + * Create and bind the socket to monitor the + * unicast interface addr + */ + + if ((sid = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + syslog(LOG_CRIT, + "socket()Error: Couldn't create unicast UDP " \ + "socket - to monitor unicast interface addr"); + return (-1); + } + + if (setsockopt(sid, SOL_SOCKET, SO_REUSEADDR, + (char *)&enable, sizeof (int)) < 0) { + syslog(LOG_NOTICE, "setsockopt() failed." \ + "socket - to monitor unicast interface addr"); + } + + sa.sin_family = AF_INET; + sa.sin_port = htons(MIP_PORT); + sa.sin_addr.s_addr = entry->maIfaceAddr; + + mipverbose(("Binding UDP socket to %s port %d.\n", + ntoa(sa.sin_addr.s_addr, addrstr1), ntohs(sa.sin_port))); + if (bind(sid, (struct sockaddr *)&sa, sizeof (sa)) < 0) { + syslog(LOG_CRIT, + "bind() Error: Could not bind unicast socket." \ + "(maIfaceaddr): %m"); + return (-1); + } + /* + * ToDO: Verify whether IP_RECV[IF|SLLA|TTL] socket + * options to be set here. This socket is used for + * broadcasting advertisements. + */ + + if (setsockopt(sid, IPPROTO_IP, IP_RECVIF, &enable, + sizeof (int)) < 0) { + syslog(LOG_ERR, "setsockopt IP_RECVIF " + "(maIfaceAddr):%m"); + return (-1); + } + + + if (setsockopt(sid, IPPROTO_IP, IP_RECVSLLA, &enable, + sizeof (int)) < 0) { + syslog(LOG_ERR, "setsockopt IP_RECVSLLA " \ + "(maIfaceAddr): %m"); + return (-1); + } + + if (setsockopt(sid, IPPROTO_IP, IP_RECVTTL, &enable, + sizeof (int)) < 0) { + syslog(LOG_ERR, "setsockopt IP_RECVTTL " \ + "(maIfaceAddr): %m"); + return (-1); + } + if (setsockopt(sid, IPPROTO_IP, IP_BOUND_IF, (char *)&ifceno, + sizeof (char *))) { + syslog(LOG_ERR, + "Unable to bind socket to interface %d", ifceno); + return (-1); + } + + entry->maIfaceUnicastSock = sid; + + /* + * PPP interfaces would not receive any broadcast packets. + * Therefore we don't need to bind to broadcast addresses. + */ + if ((entry->maIfaceFlags & IFF_POINTOPOINT) == 0) { + /* + * Create and bind the socket to monitor + * the bcast interface addr + */ + if ((sid = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + syslog(LOG_CRIT, + "socket()Error:Couldn't create broadcast " + "UDP socket"); + return (-1); + } + + if (setsockopt(sid, SOL_SOCKET, SO_REUSEADDR, + (char *)&enable, sizeof (int)) < 0) { + syslog(LOG_NOTICE, "setsockopt() failed " \ + "on the broadcast UDP socket"); + } + + sa.sin_family = AF_INET; + sa.sin_port = htons(MIP_PORT); + sa.sin_addr.s_addr = inet_addr(LINK_BCAST_ADDR); + + mipverbose(("Binding UDP socket to %s port %d.\n", + ntoa(sa.sin_addr.s_addr, addrstr1), + ntohs(sa.sin_port))); + if (bind(sid, (struct sockaddr *)&sa, + sizeof (sa)) < 0) { + syslog(LOG_CRIT, + "bind Error: Could not bind broadcast " + "socket - to monitor the bcast interface " + "addr"); + return (-1); + } + + /* + * TODO: Verify whether IP_RECV* sockets are useful + * in this socket which binds itself to link_broadcast + * address. + */ + + if (setsockopt(sid, IPPROTO_IP, IP_RECVIF, &enable, + sizeof (int)) < 0) { + syslog(LOG_ERR, "setsockopt IP_RECVIF failed " \ + "(LINK_BCAST_ADDR): %m"); + return (-1); + } + + if (setsockopt(sid, IPPROTO_IP, IP_RECVSLLA, &enable, + sizeof (int)) < 0) { + syslog(LOG_ERR, + "setsockopt IP_RECVSLLA failed " + "(LINK_BCAST_ADDR): %m"); + return (-1); + } + + if (setsockopt(sid, IPPROTO_IP, IP_RECVTTL, &enable, + sizeof (int)) < 0) { + syslog(LOG_ERR, + "setsockopt IP_RECVTTL failed " + "(LINK_BCAST_ADDR): %m"); + return (-1); + } + + if (setsockopt(sid, IPPROTO_IP, IP_BOUND_IF, + (char *)&ifceno, sizeof (char *))) { + (void) fprintf(stderr, + "Unable to bind socket to interface %d", + ifceno); + return (-1); + } + + entry->maIfaceBcastSock = sid; + + /* + * Create and bind the socket to monitor + * the directed bcast interface addr + */ + if ((sid = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + syslog(LOG_CRIT, + "socket()Error:Couldn't create broadcast UDP " + "socket"); + return (-1); + } + + if (setsockopt(sid, SOL_SOCKET, SO_REUSEADDR, + (char *)&enable, sizeof (int)) < 0) { + syslog(LOG_NOTICE, "setsockopt() failed " \ + "on broadcast UDP socket"); + } + + sa.sin_family = AF_INET; + sa.sin_port = htons(MIP_PORT); + sa.sin_addr.s_addr = GENERATE_NET_BROADCAST_ADDR(entry); + + mipverbose(("Binding UDP socket to %s port %d.\n", + ntoa(sa.sin_addr.s_addr, addrstr1), + ntohs(sa.sin_port))); + if (bind(sid, (struct sockaddr *)&sa, + sizeof (sa)) < 0) { + syslog(LOG_CRIT, + "bind Error: Could not bind broadcast " + "socket."); + return (-1); + } + + /* + * Setting option on socket bound to NET_BROADCAST_ADDR + */ + if (setsockopt(sid, IPPROTO_IP, IP_RECVIF, &enable, + sizeof (int)) < 0) { + syslog(LOG_ERR, "setsockopt IP_RECVIF " + "(NET_BROADCAST_ADDR): %m"); + return (-1); + } + + + if (setsockopt(sid, IPPROTO_IP, IP_RECVSLLA, &enable, + sizeof (int)) < 0) { + syslog(LOG_ERR, "setsockopt IP_RECVSLLA ", + "(NET_BROADCAST_ADDR): %m"); + return (-1); + } + + + if (setsockopt(sid, IPPROTO_IP, IP_RECVTTL, &enable, + sizeof (int)) < 0) { + syslog(LOG_ERR, "setsockopt IP_RECVTTL " + "(NET_BROADCAST_ADDR): %m"); + return (-1); + } + + if (setsockopt(sid, IPPROTO_IP, IP_BOUND_IF, + (char *)&ifceno, sizeof (char *))) { + syslog(LOG_ERR, + "Unable to bind socket to interface %d", + ifceno); + return (-1); + } + + enable = 1; + if (setsockopt(sid, SOL_SOCKET, SO_REUSEADDR, + (char *)&enable, sizeof (int)) < 0) { + syslog(LOG_NOTICE, "setsockopt() " \ + "(NET_BROADCAST_ADDR): %m"); + } + + entry->maIfaceDirBcastSock = sid; + } else { + /* Set fd to -1 */ + entry->maIfaceBcastSock = -1; + entry->maIfaceDirBcastSock = -1; + } + + /* + * Create and bind the socket to monitor + * the multicast advertisement traffic (224.0.0.1 + * and 224.0.0.2) + */ + + if ((sid = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) { + syslog(LOG_CRIT, + "socket() Error: Couldn't create ICMP socket " \ + "in InitSockets to monitor mcast advertisement."); + return (-1); + } + + if (setsockopt(sid, IPPROTO_IP, IP_RECVIF, &enable, + sizeof (int)) < 0) { + syslog(LOG_ERR, "setsockopt IP_RECVIF failed...%s", + strerror(errno)); + return (-1); + } + + if (setsockopt(sid, IPPROTO_IP, IP_BOUND_IF, (char *)&ifceno, + sizeof (char *))) { + syslog(LOG_ERR, + "Unable to bind socket to interface %d", ifceno); + return (-1); + } + + /* + * Join multicast groups so we can receive ICMP messages + * on this interface sent to 224.0.0.1 + */ + imr.imr_multiaddr.s_addr = inet_addr(LINK_MCAST_ADV_ADDR); + imr.imr_interface.s_addr = entry->maIfaceAddr; + + if (setsockopt(sid, IPPROTO_IP, IP_ADD_MEMBERSHIP, + (char *)&imr, sizeof (struct ip_mreq)) < 0) { + syslog(LOG_NOTICE, + "Could not join multicast group 224.0.0.1"); + } else { + mipverbose(("Joined %s on interface %s.\n", + LINK_MCAST_ADV_ADDR, + ntoa(entry->maIfaceAddr, addrstr1))); + } + + /* + * Join multicast groups so we can receive ICMP messages + * on this interface sent to 224.0.0.2. + */ + imr.imr_multiaddr.s_addr = inet_addr(LINK_MCAST_ADV_ADDR2); + imr.imr_interface.s_addr = entry->maIfaceAddr; + if (setsockopt(sid, IPPROTO_IP, IP_ADD_MEMBERSHIP, + (char *)&imr, sizeof (struct ip_mreq)) < 0) { + syslog(LOG_NOTICE, + "Could not join multicast group 224.0.0.2"); + } else { + mipverbose(("Joined %s on interface %s.\n", + LINK_MCAST_ADV_ADDR2, + ntoa(entry->maIfaceAddr, addrstr1))); + } + + + entry->maIfaceAdvMulticastSock = sid; + + /* + * Create and bind the socket to monitor + * the multicast registration traffic (224.0.0.11) + */ + if ((sid = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + syslog(LOG_CRIT, + "socket()Error:Couldn't create broadcast UDP socket " \ + "to monitor multicast registration traffic."); + return (-1); + } + + if (setsockopt(sid, SOL_SOCKET, SO_REUSEADDR, + (char *)&enable, sizeof (int)) < 0) { + syslog(LOG_NOTICE, "setsockopt() failed for broadcast " \ + "UDP socket to monitor mcast registration traffic."); + } + + sa.sin_family = AF_INET; + sa.sin_port = htons(MIP_PORT); + sa.sin_addr.s_addr = inet_addr(LINK_MCAST_REG_ADDR); + + mipverbose(("Binding UDP socket to %s port %d.\n", + ntoa(sa.sin_addr.s_addr, addrstr1), ntohs(sa.sin_port))); + if (bind(sid, (struct sockaddr *)&sa, sizeof (sa)) < 0) { + syslog(LOG_CRIT, + "bind Error: Could not bind broadcast socket."); + return (-1); + } + /* Set socket option for socket bound to 224.0.0.11 */ + + if (setsockopt(sid, IPPROTO_IP, IP_RECVIF, &enable, + sizeof (int)) < 0) { + syslog(LOG_ERR, "setsockopt IP_RECVIF " \ + "(LINK_MCAST_REG_ADDR): %m"); + return (-1); + } + + + if (setsockopt(sid, IPPROTO_IP, IP_RECVSLLA, &enable, + sizeof (int)) < 0) { + syslog(LOG_ERR, "setsockopt IP_RECVSLLA " \ + "(LINK_MCAST_REG_ADDR): %m"); + return (-1); + } + + if (setsockopt(sid, IPPROTO_IP, IP_RECVTTL, &enable, + sizeof (int)) < 0) { + syslog(LOG_ERR, "setsockopt IP_RECVTTL " \ + "(LINK_MCAST_REG_ADDR): %m"); + return (-1); + } + if (setsockopt(sid, IPPROTO_IP, IP_BOUND_IF, (char *)&ifceno, + sizeof (char *))) { + syslog(LOG_ERR, + "Unable to bind socket to interface %d", ifceno); + return (-1); + } + + + /* + * Join 224.0.0.11 so we can receive Registration Requests + * from the multicast address. + */ + imr.imr_multiaddr.s_addr = inet_addr(LINK_MCAST_REG_ADDR); + imr.imr_interface.s_addr = entry->maIfaceAddr; + if (setsockopt(sid, IPPROTO_IP, IP_ADD_MEMBERSHIP, + (char *)&imr, sizeof (struct ip_mreq)) < 0) { + syslog(LOG_NOTICE, + "Could not join multicast group 224.0.0.11"); + } else { + mipverbose(("Joined %s on interface %s.\n", + LINK_MCAST_REG_ADDR, + ntoa(entry->maIfaceAddr, addrstr1))); + + } + + entry->maIfaceRegMulticastSock = sid; + + + return (0); +} + + +/* + * Function: deleteMobileNodeEntryHashHelper + * + * 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 Finalize() when we need to delete all + * mobile node entries, and will be called by + * getAllHashTableEntries(). + * + * Returns: _B_TRUE if the entry matches the desired criteria, + * otherwise _B_FALSE. + */ +/* ARGSUSED */ +static boolean_t +deleteMobileNodeEntryHashHelper(void *entry, uint32_t p1) +{ + HaMobileNodeEntry *hentry = entry; + HaBindingEntry *bindingEntry; + HaBindingEntry *next_entry; + + bindingEntry = hentry->bindingEntries; + while (bindingEntry) { + next_entry = bindingEntry->next; + delHABEent(hentry, bindingEntry); + free(bindingEntry); + bindingEntry = next_entry; + } + + + return (_B_FALSE); +} + +/* + * Function: deleteVisitorEntryHashHelper + * + * 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 Finalize() when we need to delete all + * visitor entries, and will be called by + * getAllHashTableEntries(). + * + * Returns: _B_TRUE if the entry matches the desired criteria, + * otherwise _B_FALSE. + */ +/* ARGSUSED */ +static boolean_t +deleteVisitorEntryHashHelper(void *entry, uint32_t p1) +{ + FaVisitorEntry *faEntry = entry; + + delFAVEptr(faEntry, _B_TRUE, REASON_UNKNOWN); + free(faEntry); + return (_B_FALSE); +} + +/* + * This funciton cleans up whatever registration policy is + * flagged as remaining. We don't clean up tunnels policy + * because that is done when the tunnel in encaprem() or + * decaprem(). We return _B_FALSE since we want the entry + * to be freed. + */ +/* ARGSUSED */ +static boolean_t +deleteIPsecSAHashHelper(void *entry, uint32_t p1) +{ + MobilityAgentEntry *mae = entry; + int i; + + for (i = FIRST_IPSEC_ACTION; i < LAST_IPSEC_ACTION; i++) { + if (mae->maIPsecFlags & REQUEST(i)) + (void) removeIPsecPolicy(mae->maIPsecRequest[i]); + + if (mae->maIPsecFlags & REPLY(i)) + (void) removeIPsecPolicy(mae->maIPsecReply[i]); + } + + return (_B_FALSE); +} + + +/* + * Function: Finalize + * + * Arguments: signo - signal + * + * Description: This function is the signal handler and is + * called when the agent is terminating. This + * function will destroy all of the threads, + * and free all of the binding and visitor entries + * which will clean up the Tunnel interfaces and the + * routing entries. + * + * Returns: + */ +/* ARGSUSED */ +void +Finalize(int signo) +{ + char relativeTime[MAX_TIME_STRING_SIZE]; + char currentTime[MAX_TIME_STRING_SIZE]; + + syslog(LOG_INFO, "---- %s (%s) ----", + sprintTime(currentTime, MAX_TIME_STRING_SIZE), + sprintRelativeTime(relativeTime, MAX_TIME_STRING_SIZE)); + + shutdown_flag = _B_TRUE; + + /* + * First we need to kill all of the threads to ensure that no one + * will try to step on our toes. This will ensure that no other + * threads try to access any of the HashTables that we will need + * next. + */ + syslog(LOG_INFO, "<<< Shutting down threads >>>"); + + mipverbose(("<<< Shutting down threads >>>\n")); + if (DynamicInterface) + (void) killDynamicInterfaceThread(); + (void) killDispatcherTaskThread(); + (void) killPeriodicTaskThread(); + (void) killSNMPTaskThread(); + (void) killAAATaskThread(); + (void) killStatServer(); + + /* + * Save the state of the entire agent (mobile node entries, + * (dynamic) security associations, IPsec SAs, and binding + * entries. This allows subsequent restoration of the state. + */ + (void) saveAgentState(); + + /* + * Let's delete all of the Mobile Node binding entries + * so we end up cleaning up our tunnel interfaces. Note that + * since we are coming down, we will not request any locks, + * since that could get the signal handler in a deadlock + * situation. + */ + syslog(LOG_INFO, "<<< Cleaning up mobility bindings >>>"); + getAllHashTableEntries(&haMobileNodeHash, + deleteMobileNodeEntryHashHelper, LOCK_NONE, 0, _B_TRUE); + + + /* + * Let's delete all of the Mobile Node binding entries + * so we end up cleaning up our routes. Note that + * since we are coming down, we will not request any locks, + * since that could get the signal handler in a deadlock + * situation. + */ + syslog(LOG_INFO, "<<< Cleaning up accepted visitor entries >>>"); + getAllHashTableEntries(&faVisitorHash, + deleteVisitorEntryHashHelper, LOCK_NONE, 0, _B_TRUE); + + /* + * Finally clean up any IPsec policies we have installed! We don't + * do this above, because cleaning out the FA removed those + * specific to the FA, now we'll clean up the rest. + */ + syslog(LOG_INFO, "<<< Cleaning up all remaining IPsec policies >>>"); + getAllHashTableEntries(&mipAgentHash, deleteIPsecSAHashHelper, + LOCK_NONE, 0, _B_TRUE); + + OScleanup(); + + syslog(LOG_INFO, "Terminated by signal (SIGTERM or SIGINT)"); + + exit(1); +} + +/* + * Function: docleanup + * + * Arguments: + * + * Description: This function is called when the AAA connection + * to mipagent is down. The function will + * free all of the binding and visitor entries + * which will clean up the Tunnel interfaces and the + * routing entries. + * Returns: + */ +void +docleanup(void) +{ + char relativeTime[MAX_TIME_STRING_SIZE]; + char currentTime[MAX_TIME_STRING_SIZE]; + + syslog(LOG_INFO, "---- %s (%s) ----", + sprintTime(currentTime, MAX_TIME_STRING_SIZE), + sprintRelativeTime(relativeTime, MAX_TIME_STRING_SIZE)); + mipverbose(("mipagent-AAA connection is down\n")); + + /* + * Let's delete all of the Mobile Node binding entries + * so we end up cleaning up our tunnel interfaces. + */ + syslog(LOG_INFO, "<<< Cleaning up mobility bindings >>>"); + getAllHashTableEntries(&haMobileNodeHash, + deleteMobileNodeEntryHashHelper, LOCK_NONE, 0, _B_TRUE); + + /* + * Let's delete all of the Mobile Node binding entries + * so we end up cleaning up our routes. + */ + syslog(LOG_INFO, "<<< Cleaning up accepted visitor entries >>>"); + getAllHashTableEntries(&faVisitorHash, + deleteVisitorEntryHashHelper, LOCK_NONE, 0, _B_TRUE); +} + + +/* + * Function: SetSigHandlers + * + * Arguments: Set up handlers for various signals + * + * Description: + * + * Returns: + */ +static void +SetSigHandlers() +{ + if (signal(SIGINT, Finalize) == SIG_ERR) { + syslog(LOG_CRIT, + "signal() Error: failed to set handler for SIGINT."); + } + + if (signal(SIGTERM, Finalize) == SIG_ERR) { + syslog(LOG_CRIT, + "signal() Error: failed to set handler for SIGTERM."); + } +} + + +/* + * Function: showConfigInfo + * + * Arguments: + * + * Description: This function will print out the current + * configuration of the agent. + * + * Returns: + */ +static void +showConfigInfo() +{ + + mipverbose(("LogLevel : %d\n", logVerbosity)); +#ifdef RADIUS_ENABLED + mipverbose(("RadiusEnabled : %d\n", radiusEnabled)); + if (radiusEnabled) + mipverbose((" RadiusSharedLibrary : %s\n", + radiusSharedLibrary)); +#endif /* RADIUS_ENABLED */ + mipverbose(("PeriodicInterval : %d\n", periodicInterval)); +/* + * No longer used + * mipverbose(("AdvLifetime : %d\n", advLifetime)); + * mipverbose(("RegLifetime : %d\n", regLifetime)); + */ + mipverbose(("IDfreshnessSlack : %d\n", IDfreshnessSlack)); + mipverbose(("\n")); + printMaAdvConfigHash(&maAdvConfigHash); + mipverbose(("\n")); + printHaMobileNodeHash(&haMobileNodeHash); + mipverbose(("\n")); +#ifdef FIREWALL_SUPPORT + printProtectedDomainInfo(domainInfo); +#endif /* FIREWALL_SUPPORT */ + mipverbose(("\n")); +} + + +/* + * Function: Initialize + * + * Arguments: configFile - Pointer to the config file name + * + * Description: This is the main initialization function. This + * function will initialize the hash tables, retrieve + * our NAI, read the config file and initialize the + * network interfaces. + * + * Returns: int, 0 if successful + */ +int +Initialize(char *configFile) +{ + struct utsname name; + char domainname[MAX_NAI_LENGTH]; + char currentTime[MAX_TIME_STRING_SIZE]; + char relativeTime[MAX_TIME_STRING_SIZE]; + struct hash_table *htbl; + struct hash_entry *pentry; + int i; + + /* Make sure we are running as root. */ + if (getuid()) { + (void) fprintf(stderr, + "mipagent: Error: must be run by root\n"); + return (-1); + } + + openlog("mipagent", LOG_CONS, LOG_DAEMON); + + syslog(LOG_INFO, "Mobile IP agent started ..."); + syslog(LOG_INFO, "---- %s (%s) ----", + sprintTime(currentTime, MAX_TIME_STRING_SIZE), + sprintRelativeTime(relativeTime, MAX_TIME_STRING_SIZE)); + + /* Initiate global DynamicInterface variables here */ + DynamicInterface = _B_FALSE; + dynamicIfaceHead = NULL; + + /* Can we find, and read our config file? */ + if (access(configFile, R_OK) < 0) { + /* + * config file non existent, or can't be read... + * keel over verbosely (is there an other way?) + */ + syslog(LOG_CRIT, "Config file non-existent, or not readable."); + syslog(LOG_CRIT, "Cannot load initialization settings, " + "access() error %m."); + syslog(LOG_CRIT, "-> See mipagent(1M)."); + + /* Spit a critical startup error to the user, too */ + (void) fprintf(stderr, "Error: config file non-existent, " + "or not readable, cannot initialize.\n"); + (void) fprintf(stderr, "-> See mipagent(1M) for more info.\n"); + + /* tell the calling function it can keel over now. */ + return (-1); + } + + /* Initialize random number generator */ + randomInit(); + + /* Get the hosts' Network Access Identifier */ + if (uname(&name) < 0) { + syslog(LOG_CRIT, "Error 1: Unable to get our own identity."); + return (-1); + } + + errno = 0; + (void) getdomainname(domainname, sizeof (domainname)); + if (errno != 0) { + syslog(LOG_CRIT, "Error 2: Unable to get our own identity."); + return (-1); + } + + (void) strcpy(maNai, name.nodename); + (void) strcat(maNai, "@"); + (void) strcat(maNai, domainname); + + syslog(LOG_INFO, "Our NAI is %s", maNai); + + /* + * Initialize the hash tables + */ + if (InitHash(&faVisitorHash)) { + syslog(LOG_CRIT, "Unable to initialize visitor hash table"); + return (-1); + } + + if (InitHash(&maAdvConfigHash)) { + syslog(LOG_CRIT, "Unable to initialize interface hash table"); + return (-1); + } + + if (InitHash(&haMobileNodeHash)) { + syslog(LOG_CRIT, "Unable to initialize mobile node hash table"); + return (-1); + } + + if (InitHash(&mipSecAssocHash)) { + syslog(LOG_CRIT, + "Unable to initialize security associations hash table"); + return (-1); + } + + if (InitHash(&mipAgentHash)) { + syslog(LOG_CRIT, "Unable to initialize agents hash table"); + return (-1); + } + + if (InitHash(&mipSecViolationHash)) { + syslog(LOG_CRIT, + "Unable to initialize security violation hash table"); + return (-1); + } + + if (InitHash(&mipPoolHash)) { + syslog(LOG_CRIT, "Unable to initialize pool hash table"); + return (-1); + } + + if (InitHash(&mipTunlHash)) { + syslog(LOG_CRIT, "Unable to initialize tunnel hash table"); + return (-1); + } + + /* Initialize maAdvConfigTable and haMobileNodeTable from file */ + if (readConfigInfo(configFile) < 0) { + syslog(LOG_CRIT, "Error: Start up configuration unsuccessful."); + return (-1); + } + + + /* + * Initialize itself as a daemon + */ + if (daemonize == _B_TRUE) { + if (daemonInit() == -1) + exit(1); + } + + showConfigInfo(); + + /* OS-specific initialization of tunneling module etc */ + if (InitNet() == -1) { + syslog(LOG_CRIT, "InitNet failed"); + return (-1); + } + + /* OS-neutral, socket initialization */ + htbl = &maAdvConfigHash; + for (i = 0; i < HASH_TBL_SIZE && htbl->size; i++) { + pentry = htbl->buckets[i]; + while (pentry != NULL) { + if (InitSockets((MaAdvConfigEntry *)pentry->data) < 0) { + syslog(LOG_CRIT, "InitSockets failed."); + return (-1); + } + pentry = pentry->next; + } + } + + /* Set up periodic house keeping and other chores */ + SetSigHandlers(); + + return (0); +} diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agentKernelIntfce.c b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agentKernelIntfce.c new file mode 100644 index 0000000000..8fe88b5d4b --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agentKernelIntfce.c @@ -0,0 +1,2726 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Routines in this program implement OS-specific portions of + * a Mobile-IP agent (RFC 2002). + * + */ + +#ifndef _REENTRANT +#error "Error! Reentrant must be defined!" +#endif + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <fcntl.h> +#include <netdb.h> +#include <errno.h> +#include <assert.h> +#include <synch.h> +#include <syslog.h> +#include <stropts.h> +#include <sys/dlpi.h> +#include <sys/types.h> +#include <sys/stream.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/errno.h> +#include <sys/param.h> +#include <sys/conf.h> +#include <sys/stropts.h> +#include <sys/stropts.h> +#include <sys/types.h> + +#include <inet/common.h> +#include <inet/ip.h> + +#include <net/if.h> +#include <net/route.h> +#include <net/if_dl.h> +#include <net/pfkeyv2.h> /* ipsec alg values, etc. */ + +#include <netinet/in.h> +#include <netinet/if_ether.h> + +#include <arpa/inet.h> + +#include "agent.h" +#include "mip.h" +#include "agentKernelIntfce.h" +#include "conflib.h" + +/* Check for bad os version, and compile anyway xxx WORK -- remove this */ +#ifndef IFF_NORTEXCH +#define IFF_NORTEXCH 0 +#define IFF_MIPRUNNING 1 +#define RTF_PRIVATE 2 +#endif + +/* + * Routing socket message len for creating route for + * reverse tunnel + */ + +#define MIP_RTUN_RTM_MSGLEN sizeof (struct rt_msghdr) + \ + sizeof (struct sockaddr_in) + \ + sizeof (struct sockaddr_in) + \ + sizeof (struct sockaddr_in) + \ + sizeof (struct sockaddr_dl) + \ + sizeof (struct sockaddr_in) + \ + sizeof (struct sockaddr_dl) + +/* + * Routing socket message len for normal route + * created to send reg reply to MN + */ +#define MIP_RTM_MSGLEN sizeof (struct rt_msghdr) + \ + sizeof (struct sockaddr_in) + \ + sizeof (struct sockaddr_in) + \ + sizeof (struct sockaddr_in) + +/* Common to all mobility agents */ +extern struct hash_table haMobileNodeHash; +extern struct hash_table maAdvConfigHash; +extern struct hash_table mipTunlHash; +extern int logVerbosity; + +struct dynamicIfacetype *dynamicIfaceHead; + +static int ioctl_sockid; +static int rtsock; +static rwlock_t gbl_tunnelLock; +static int first_tun_to_check = 0; +static struct staticIface *StaticIntfaceHead = NULL; + +char *err2str(int); + +#define DEVICEDIR "/dev/" +#ifndef ETH_ALEN +#define ETH_ALEN sizeof (struct ether_addr) +#endif + +/* Definitions needed for refresh_mn_arp() module */ +#define BITSPERBYTE 8 +#define IPADDRL sizeof (struct in_addr) +#define DEVICEDIR "/dev/" +#define BCAST_HW_ADDR "ff:ff:ff:ff:ff:ff" + +#define MAX_ERR 2048 +#define INVALID_PPA (MAX_ERR + 1) +#define INVALID_STRING (MAX_ERR + 2) +#define DLOKACK_SHORT_RESPONSE (MAX_ERR + 3) +#define DLOKACK_NOT_M_PCPROTO (MAX_ERR + 4) +#define ERR_MORECTL (MAX_ERR + 5) +#define ERR_MOREDATA (MAX_ERR + 6) +#define ERR_MORECTLDATA (MAX_ERR + 7) +#define DL_PRIMITIVE_ERROR (MAX_ERR + 8) +#define SHORT_CONTROL_PORTION (MAX_ERR + 9) +#define INVALID_ADDR (MAX_ERR + 10) +#define MN_ENTRY_ABSENT (MAX_ERR + 11) +#define NO_MAPPING (MAX_ERR + 12) + +/* Tunnel related definitions */ +#define MAX_TUNNEL_SUPPORTED 256 +#define NO_FREE_TUNNEL (MAX_ERR + 1) +#define TUNNEL_NOT_FOUND (MAX_ERR + 2) +#define DEV_NAME_NOT_FOUND ENXIO +#define INVALID_IP_ADDR ENXIO +#define MN_ENTRY_ABSENT (MAX_ERR + 11) +#define NO_MAPPING (MAX_ERR + 12) + + +/* Table for mapping tunnelno with mobile-node address */ +/* + * WORK -- this will be removed once the tunneling interface returns us + * a unique tunnel id. + */ +static struct { + rwlock_t tunlLock; + ipaddr_t mnaddr; + ipaddr_t tunnelsrc; /* only used on FA side */ + uint32_t refcnt; +} mnaddr_tunl[MAX_TUNNEL_SUPPORTED + 1]; + + +#define MAXWAIT 15 +/* Maximum address buffer length */ +#define MAXDLADDR 1024 +/* Handy macro. */ +#define OFFADDR(s, n) (unsigned char *)((char *)(s) + (int)(n)) + + +/* Internal Prototypes */ +static int settaddr(int tnum, ipaddr_t ifaddr1, ipaddr_t ifaddr2, + ipaddr_t saddr, ipaddr_t daddr, ipsec_req_t *); +static int garp(char *, uint32_t, unsigned char *); +static int plumb_one_tun(int tnum); +static int unplumb_one_tun(int muxfd); +static int setifflags(int tnum, int value); +static int strgetmsg(int fd, struct strbuf *ctlp, struct strbuf *datap, + int *flagsp); +static int expecting(int prim, union DL_primitives *dlp); +static int arpgetHWaddr(ipaddr_t, unsigned char *); +int gettunnelno(ipaddr_t, ipaddr_t); + +int arpIfadd(ipaddr_t, char *, uint32_t); +int arpIfdel(ipaddr_t, char *, uint32_t); + +/* External Prototypes */ +extern MipTunlEntry *CreateTunlEntry(int tnum, ipaddr_t target, ipaddr_t tsrc, + int muxfd); +extern char *ntoa(uint32_t addr_long, char *addr_string); +extern MobilityAgentEntry *findMaeFromIp(ipaddr_t, int); + +/* + * Function: InitTunnelModule + * + * Arguments: none + * + * Description: Initialize our globals. Currently, initalize the global + * tunnel lock. + * + * Returns: int (zero on success) + */ +static int +InitTunnelModule() +{ + int result; + + result = rwlock_init(&gbl_tunnelLock, USYNC_THREAD, NULL); + + return (result); +} /* InitTunnelModule */ + +/* + * Function: newtunnel + * + * Arguments: ipaddr_t addr + * ipaddr_t tsrc_addr + * int *tunnels_scanned + * + * Description: This function returns the available tunnel number in the + * range 0 through MAX_TUNNEL_SUPPORTED. If none are available + * it returns NO_FREE_TUNNEL. tunnels_scanned is used by the caller + * to figure out if all the tunnel numbers are scanned before + * concluding that there's no free tunnel left. + * + * Returns: int (tunnel number, or -1 on error) + */ +static int +newtunnel(ipaddr_t addr, ipaddr_t tsrc_addr, int *tunnels_scanned) +{ + int i; + boolean_t found = _B_FALSE; + int tun_num; + + /* WARNING: check this xxx WORK */ + (void) rw_wrlock(&gbl_tunnelLock); + *tunnels_scanned = 0; + + for (i = 0; i < MAX_TUNNEL_SUPPORTED; i++) { + /* start scanning tunnel numbers where we were left last time */ + tun_num = (i + first_tun_to_check) % MAX_TUNNEL_SUPPORTED; + + /* is this an available tunnel? */ + if (mnaddr_tunl[tun_num].mnaddr == 0) { + mnaddr_tunl[tun_num].mnaddr = addr; + mnaddr_tunl[tun_num].tunnelsrc = tsrc_addr; + found = _B_TRUE; + break; + } + } + + /* + * Send back the number of tunnels scanned, so that caller can + * give up after scanning MAX_TUNNEL_SUPPORTED many tunnels. + * Also save where we were left, so that next time we start scanning + * from that point on. + */ + if (found) { + *tunnels_scanned = i + 1; + first_tun_to_check = (tun_num + 1) % MAX_TUNNEL_SUPPORTED; + } else { + *tunnels_scanned = MAX_TUNNEL_SUPPORTED; + /* + * First_tun_to_check stays same. We did a one full round of + * scanning tunnel numbers and couldn't find any available. + * Next time we come here to find another available, we'll + * start from the same tunnel number. + */ + } + + (void) rw_unlock(&gbl_tunnelLock); + + + if (found) { + return (tun_num); + } else { + return (-1); + } +} /* newtunnel */ + + +/* + * Function: freetunnel + * + * Arguments: int tnum + * + * Description: This function will free the current tunnel resource. This + * function will disappear with the new kernel tunnel interface. + * + * Returns: void + */ +static void +freetunnel(int tnum) +{ + + (void) rw_wrlock(&gbl_tunnelLock); + + assert(mnaddr_tunl[tnum].refcnt == 0); + + mnaddr_tunl[tnum].mnaddr = 0; + mipverbose(("Freeing tunnel module number %d\n", tnum)); + + (void) rw_unlock(&gbl_tunnelLock); +} /* freetunnel */ + + +/* + * Gets the tunnel number corresponding to given + * mobile node address . + * If the corresponding tunnel number exist then it return s the tunnel no. + * else return s -(TUNNEL_NOT_FOUND) + */ +/* + * Function: gettunnelno + * + * Arguments: ipaddr_t mnaddr + * ipaddr_t tsrc_addr + * + * Description: Returns the tunnel number corresponding to a given mobile + * node address. If the corresponding tunnel number exists, then + * it returns the tunnel number. Otherwise it returns (-1) + * When called from HA mnaddr=mnaddr. + * when called from FA mnaddr=haaddr + * Tunnel source end-point addr=tsrc_addr + * + * Returns: int (Tunnel Number, -1 on failure) + */ +int +gettunnelno(ipaddr_t mnaddr, ipaddr_t tsrc_addr) +{ + int i; + int found = _B_FALSE; + + (void) rw_rdlock(&gbl_tunnelLock); + + for (i = 0; i < MAX_TUNNEL_SUPPORTED; i++) { + if (mnaddr_tunl[i].mnaddr == mnaddr && + mnaddr_tunl[i].tunnelsrc == tsrc_addr) { + found = _B_TRUE; + break; + } + } + + (void) rw_unlock(&gbl_tunnelLock); + + if (found == _B_TRUE) { + return (i); + } else { + return (-1); + } +} /* gettunnelno */ + +#if 0 +/* + * Function: printtunnels + * + * Arguments: none + * + * Description: This function prints out all the tunnels. It is used for + * debugging. + * + * Returns: void + */ +void +printtunnels() +{ + int i; + char mnaddr[INET_ADDRSTRLEN]; + + (void) rw_rdlock(&gbl_tunnelLock); + + for (i = 0; i < MAX_TUNNEL_SUPPORTED; i++) { + if (mnaddr_tunl[i].mnaddr != 0) { + mipverbose(("Tunnel %d is for %s with refcnt %d\n", + i, ntoa(mnaddr_tunl[i].mnaddr, mnaddr), + mnaddr_tunl[i].refcnt)); + } + } + + (void) rw_unlock(&gbl_tunnelLock); +} /* printtunnels */ +#endif + + +/* Convert a negative error value into a human readable error message */ +/* + * Function: err2str + * + * Arguments: int errval + * + * Description: This function tries to return an error message based on + * an error code, or errno. It first checks for special errors, + * then checks the strerror string. + * WARNING: If the error is not found, then it returns a + * pointer to a static string. This function is NOT thread safe. + * + * Returns: char * (error string) + */ +char * +err2str(int errval) +{ + int err = (-1 * errval); + static char tmp[30]; + + switch (err) { + case INVALID_PPA: + return ("Invalid PPA"); + + case INVALID_STRING: + return ("Invalid input string"); + + case DLOKACK_SHORT_RESPONSE: + return ("Short DLOKACK response"); + + case DLOKACK_NOT_M_PCPROTO: + return ("DLOKACK is not M_PCPROTO"); + + case ERR_MORECTL: + return ("MORECTL"); + + case ERR_MOREDATA: + return ("MOREDATA"); + + case ERR_MORECTLDATA: + return ("MORECTL or MOREDATA"); + + case SHORT_CONTROL_PORTION: + return ("Control portion is short"); + + case DL_PRIMITIVE_ERROR: + return ("DL primitive error"); + + case INVALID_ADDR: + return ("Invalid Address"); + + case MN_ENTRY_ABSENT: + return ("Missing Mobile node entry"); + + case NO_MAPPING: + return ("Bad ARP mapping for mobile node"); + + default: + { + /* Check for errno error */ + char *reason; + + reason = strerror(err); + + if (reason != NULL) { + return (reason); + } else { + (void) sprintf(tmp, "Reason unclear : %d", + err); + return (tmp); + } + } + } /* switch */ +} /* err2str */ + + +/* + * Function: ifname2devppa + * + * Arguments: char *ifname, char *devname, int *ppa + * + * Description: Parse the interface name(e.g. "le0" or "hme1") and place the + * corresponding device name(e.g. "/dev/le", "/dev/hme") in + * devname and the ppa(e.g. 0 or 1 for the examples above) in ppa. + * It expects that the caller will pass adequate buffer in + * 'devname' such that it can hold the full devicename. + * + * Returns: void + */ +void +ifname2devppa(char *ifname, char *devname, int *ppa) +{ + char *p; + int i, j, val; + + val = 0; + j = strlen(DEVICEDIR); + (void) strncpy(devname, DEVICEDIR, j); + for (i = 0, p = ifname; i < strlen(ifname); i++, p++) { + if (*p >= '0' && *p <= '9') + val = 10*val + (*p - '0'); + else + devname[j++] = *p; + } + devname[j] = '\0'; + *ppa = val; +} /* ifname2devppa */ + + +/* + * Function: mkpt2pt + * + * Arguments: char *ifname, ipaddr_t srcaddr, ipaddr_t dstaddr + * + * Description: Configure the point-to-point interface named ifname with the + * given address. The source address being 'srcaddr' and + * destination address being 'dstaddr' + * + * Returns: int + */ +static int +mkpt2pt(char *ifname, ipaddr_t srcaddr, ipaddr_t dstaddr) +{ + struct lifreq lifr; + struct sockaddr_in *sin; + + /* set the interface address */ + (void) memset((char *)&lifr, 0, sizeof (lifr)); + (void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); + sin = (struct sockaddr_in *)&lifr.lifr_addr; + (void) memset(sin, 0, sizeof (*sin)); + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = srcaddr; + + if (ioctl(ioctl_sockid, SIOCSLIFADDR, (caddr_t)&lifr) < 0) { + syslog(LOG_ERR, "SIOCSLIFADDR failed"); + return (-1); + } + + /* set the remote/peer address */ + (void) memset((char *)&lifr, 0, sizeof (lifr)); + (void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); + sin = (struct sockaddr_in *)&lifr.lifr_addr; + (void) memset(sin, 0, sizeof (*sin)); + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = dstaddr; + + if (dstaddr && (ioctl(ioctl_sockid, SIOCSLIFDSTADDR, + (caddr_t)&lifr) < 0)) { + syslog(LOG_ERR, "SIOCSIFDSTADDR failed"); + return (-1); + } + + return (0); +} /* mkpt2pt */ + +/* + * Function: InitNet + * + * Arguments: none + * + * Description: Network-related initialization, e.g. loading tunneling module + * etc. Information about each mobility supporting interface is + * available in maAdvConfigHash + * + * Returns: int (zero on success) + */ +int +InitNet() +{ + /* + * Enable forwarding, disable ICMP redirects in kernel, e.g. FA + * should not redirect visiting mobile nodes to another router). + */ + (void) system( + "/usr/sbin/ndd -set /dev/ip " + "ip_forwarding 1 > /dev/null 2>&1\n"); + (void) system( + "/usr/sbin/ndd -set /dev/ip " + "ip_send_redirects 0 > /dev/null 2>&1\n"); + + mipverbose(("IP forwarding on, ICMP redirects off.\n")); + + /* Initialize the tunnel management module */ + if (InitTunnelModule() < 0) { + syslog(LOG_ERR, "InitTunnelModule failed."); + return (-1); + } + + /* Make a socket for the various SIOCxxxx ioctl commands */ + if ((ioctl_sockid = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + syslog(LOG_ERR, + "Error: could not create socket for SIOCxxxx commands."); + return (-1); + } + + /* Open a routing socket for passing route commands */ + if ((rtsock = socket(AF_ROUTE, SOCK_RAW, AF_INET)) < 0) { + syslog(LOG_ERR, + "Error: could not create socket for Route commands."); + return (-1); + } + return (0); +} /* InitNet */ + +/* + * Function: encapadd + * + * Arguments: ipaddr_t target, ipaddr_t tsrc, uint32_t tdst, uint8_t tflags + * + * Description: Enables encapsulation of pkts meant for target addr to the + * tunnel's destination addr (tdst) with the source address + * being that of the specified agent (tsrc). To configure an + * IP-in-IP tunnel, first get an unused tunnel number and + * then plumb it. Next, invoke any ipsec policies to ensure outbound + * tunnel packets to, and incomming tunnel packets from the agent-peer are + * protected (or we, or they will discard)! We do NOT set the peer-flag + * here as it's unnecessary, and should have been done anyway when we got + * the registration request (peer status isn't, after all, just about + * having a security association). Next set up a point-to-point + * interface between the target addr (target) - this is + * usually the mobile node address and address of the specified + * agent (tsrc) - this is usually the home agent address; + * the routine also sets up the tunnel with the source address + * of the tunnel being the specified agent address (tsrc) + * and the destination address of the tunnel being the + * address (tdst) - this usually is the foreign agent address. + * Next a number of interface specific flags are set and + * the tunnel is enabled. The tunnel specific entry data is + * next added to the hash table, keying on target address. + * + * If a tunnel entry already exists for the target addr + * increase the entry reference count. + * + * For now, tflags only identify if we're to protect a reverse tunnel, + * but in the future it can be used to identify when a tunnel other than + * an IP in IP tunnel should be set up. + * + * Returns: int + */ +int +encapadd(ipaddr_t target, ipaddr_t tsrc, uint32_t tdst, uint8_t tflags) +{ + int tnum, muxfd; + MipTunlEntry *entry; + int tunnels_scanned; /* no. of tunnels scanned in a */ + /* single newtunnel() call. */ + int total_tunnels_scanned; /* total no. of tunnels scanned */ + /* in this encapadd() call. */ + MobilityAgentEntry *mae; /* for IPsec Tunnel SA */ + ipsec_req_t *ipsr_p = NULL; /* for ipsec tunnel policy */ + + /* + * We don't need a MipTunlEntryLookup here to match + * with destination endpoint address as we know that + * the target(mnaddr) is unique per HA + */ + if ((entry = (MipTunlEntry *)findHashTableEntryUint( + &mipTunlHash, target, LOCK_WRITE, NULL, 0, 0, + 0)) != NULL) { + entry->refcnt++; + (void) rw_unlock(&entry->TunlNodeLock); + return (0); + } + + total_tunnels_scanned = 0; + muxfd = -1; + + while ((total_tunnels_scanned < MAX_TUNNEL_SUPPORTED) && + (muxfd == -1)) { + if ((tnum = newtunnel(target, tsrc, &tunnels_scanned)) < 0) { + syslog(LOG_ERR, "encapadd: couldnot find free tnum"); + return (-1); + } + total_tunnels_scanned += tunnels_scanned; + + if ((muxfd = plumb_one_tun(tnum)) == -1) + freetunnel(tnum); + } + if (muxfd == -1) { + syslog(LOG_ERR, "encapadd: couldnot find free tnum"); + return (-1); + } + + /* + * Before we can call settaddr, we need to see if we should pass down + * any IPSEC SAs so treqs can be set. + */ + if ((mae = findMaeFromIp(tdst, LOCK_READ)) != NULL) { + /* for encapadd, we're an HA using "ipSecTunnel apply ..." */ + + if (IPSEC_TUNNEL_ANY(mae->maIPsecSAFlags[IPSEC_APPLY])) { + /* pass down what we've parsed */ + ipsr_p = &(mae->maIPsecTunnelIPSR[IPSEC_APPLY]); + mae->maIPsecFlags |= IPSEC_TUNNEL_APPLY; + + /* Symetric tunnels: should we set the reverse bit? */ + if (tflags & REG_REVERSE_TUNNEL) + mae->maIPsecFlags |= + IPSEC_REVERSE_TUNNEL_PERMIT; + } + + /* unlock */ + (void) rw_unlock(&mae->maNodeLock); + } + + + if (settaddr(tnum, tsrc, target, tsrc, tdst, ipsr_p) == -1) { + syslog(LOG_ERR, "encapadd: settaddr failed"); + (void) unplumb_one_tun(muxfd); + mipverbose(("unplumb tunnel with number %d\n", tnum)); + freetunnel(tnum); + return (-1); + } + + if (setifflags(tnum, IFF_UP | IFF_NORTEXCH | IFF_MIPRUNNING | + IFF_PRIVATE) == -1) { + syslog(LOG_ERR, "encapadd: setifflags failed"); + mipverbose(("unplumb tunnel with number %d\n", tnum)); + (void) unplumb_one_tun(muxfd); + freetunnel(tnum); + return (-1); + } + + if ((entry = CreateTunlEntry(tnum, target, tsrc, muxfd)) == NULL) { + syslog(LOG_ERR, "encapadd: CreateTunlEntry failed"); + mipverbose(("unplumb tunnel with number %d\n", tnum)); + (void) unplumb_one_tun(muxfd); + freetunnel(tnum); + return (-1); + } + + entry->refcnt++; + + (void) rw_unlock(&entry->TunlNodeLock); + + return (0); +} /* encapadd */ + +/* + * Function: encaprem + * + * Arguments: ipaddr_t target + * + * Description: Terminates encapulation service for target addr. + * First find the tunnel entry in the hash table. + * If this is the last reference count to the tunnel entry + * then unplumb the tunnel and break the tunnel association + * between the foreign agent and home agent for + * encapsulation of packets destined for the target address. + * Next free the tunnel and the tunnel entry from hash table. + * + * Returns: int -1 on failure, the tunnel reference count on success. + */ +int +encaprem(ipaddr_t target) +{ + int tnum, muxfd; + MipTunlEntry *entry; + + /* + * NOTE: We do not need to call MipTunlEntryLookup here + * because we assume MN home address(target) is unique per HA. + */ + if ((entry = (MipTunlEntry *)findHashTableEntryUint( + &mipTunlHash, target, LOCK_WRITE, NULL, 0, 0, 0)) == NULL) { + syslog(LOG_ERR, "encaprem: Target entry %x missing", target); + return (-1); + } + + tnum = entry->tunnelno; + muxfd = entry->mux_fd; + + if (entry->refcnt == 1) { + (void) setifflags(entry->tunnelno, + -IFF_UP | -IFF_NORTEXCH | -IFF_MIPRUNNING); + mipverbose(("unplumb tunnel with number %d\n", tnum)); + if (unplumb_one_tun(muxfd) == -1) { + (void) rw_unlock(&entry->TunlNodeLock); + syslog(LOG_ERR, + "encaprem: unplumb of tunnel %d failed", tnum); + return (-1); + } + } + + /* if refcnt is 0, this encapsulation point just went away */ + if (--entry->refcnt == 0) { + /* WORK:Todo: This should call delHashTableEntry */ + int index = HASHIT(target); + HashTable *htbl = &mipTunlHash; + HashEntry *p, *q; + + freetunnel(tnum); + + (void) rw_wrlock(&htbl->bucketLock[index]); + p = htbl->buckets[index]; + + while (p) { + if (p->key == target) + break; + q = p; + p = p->next; + } + + if (p == htbl->buckets[index]) + htbl->buckets[index] = p->next; + else + q->next = p->next; + + (void) rw_unlock(&entry->TunlNodeLock); + (void) rwlock_destroy(&entry->TunlNodeLock); + + free(entry); + free(p); + + (void) rw_wrlock(&htbl->hashLock); + htbl->size--; + (void) rw_unlock(&htbl->hashLock); + + (void) rw_unlock(&htbl->bucketLock[index]); + } else { + /* Release the lock held in findHashTableEntryUint */ + (void) rw_unlock(&entry->TunlNodeLock); + } + + return (entry->refcnt); +} /* encaprem */ + + +/* + * Function: decapadd + * + * Arguments: ipaddr_t ipipsrc, ipaddr_t ipipdst + * + * Description: Enable decapsulation service for target addr. To configure + * an IP-in-IP tunnel, first get an unused tunnel number and + * then plumb it. Next set up a point-to-point interface + * between the ipipdst addr - this is usually the foreign agent + * address and a dummy address ("0.0.0.0"); the routine + * also sets up the tunnel with the source address + * of the tunnel being ipipdst - usually foreign agent address + * and the destination address of the tunnel being the address + * ipipsrc - this usually is the home agent address. Next a + * number of interface specific flags are set and the tunnel is + * enabled. The tunnel specific entry data is next added to + * the hash table, keying on ipipsrc address. + * + * If a tunnel entry already exists for the ipipsrc addr + * increase the entry reference count. + * This function is called at the foreign agent end of tunnel. + * + * Returns: int (zero on success) + */ +int +decapadd(ipaddr_t ipipsrc, ipaddr_t ipipdst) +{ + int tnum, muxfd; + MipTunlEntry *entry; + int tunnels_scanned; /* no. of tunnels scanned in a */ + /* single newtunnel() call. */ + int total_tunnels_scanned; /* total no. of tunnels scanned */ + /* in this decapadd() call. */ + MobilityAgentEntry *mae; /* to check for IPsec policy */ + ipsec_req_t *ipsr_p = NULL; /* for ipsec tunnel policy */ + + if ((entry = (MipTunlEntry *)findHashTableEntryUint( + &mipTunlHash, ipipsrc, LOCK_WRITE, MipTunlEntryLookup, + (uint32_t)ipipdst, 0, 0)) != NULL) { + entry->refcnt++; + (void) rw_unlock(&entry->TunlNodeLock); + return (0); + } + + total_tunnels_scanned = 0; + muxfd = -1; + + while ((total_tunnels_scanned < MAX_TUNNEL_SUPPORTED) && + (muxfd == -1)) { + if ((tnum = newtunnel(ipipsrc, ipipdst, + &tunnels_scanned)) < 0) { + syslog(LOG_ERR, "decapadd: couldnot find free tnum"); + return (-1); + } + total_tunnels_scanned += tunnels_scanned; + + if ((muxfd = plumb_one_tun(tnum)) == -1) + freetunnel(tnum); + } + if (muxfd == -1) { + syslog(LOG_ERR, "decapadd: couldnot find free tnum"); + return (-1); + } + + /* + * Before tunnel is plumbed, and the interface is created, see if we + * have an IPsecPolicy. If so, point at it for settaddr(). + */ + if ((mae = findMaeFromIp(ipipsrc, LOCK_READ)) != NULL) { + /* + * for decapadd, we're an FA using "IPsecTunnel permit ..." + * Note that we set the IPSEC_REVERSE_TUNNEL_PERMIT flag when + * processing for a reverse-tunnel request. + * Note that we don't check to see if the IPSEC_TUNNEL_PERMIT + * flag is set because we always want to make sure the tunnel's + * protected correctly. + */ + if (IPSEC_TUNNEL_ANY(mae->maIPsecSAFlags[IPSEC_PERMIT])) { + /* pass down what we've parsed */ + ipsr_p = &(mae->maIPsecTunnelIPSR[IPSEC_PERMIT]); + + /* set the invoked bit in case we have to restore */ + mae->maIPsecFlags |= IPSEC_TUNNEL_PERMIT; + } + + /* unlock */ + (void) rw_unlock(&mae->maNodeLock); + } + + /* + * Tunnels in Solaris are bi-directional, with the obvious caveat that + * the dst address must be set. For security reasons, we only do this + * if the MN is requesting a reverse tunnel. If so, ipipsrc should be + * the MN's home agent address. ipsr contains our ipsec values. + * From FA end the parameters are : tsrc=COA, tdst=HAA, dstaddr=0.0.0.0 + * srcaddr=COA + */ + if (settaddr(tnum, ipipdst, inet_addr("0.0.0.0"), ipipdst, + ipipsrc, ipsr_p) == -1) { + syslog(LOG_ERR, "decapadd: settaddr failed"); + mipverbose(("unplumb tunnel with number %d\n", tnum)); + (void) unplumb_one_tun(muxfd); + freetunnel(tnum); + return (-1); + } + + if (setifflags(tnum, IFF_UP | IFF_NORTEXCH | IFF_MIPRUNNING) == -1) { + syslog(LOG_ERR, "decapadd: setifflags failed"); + mipverbose(("unplumb tunnel with number %d\n", tnum)); + (void) unplumb_one_tun(muxfd); + freetunnel(tnum); + return (-1); + } + + /* Entry will be locked after CreateTunlEntry */ + if ((entry = CreateTunlEntry(tnum, ipipsrc, ipipdst, muxfd)) == NULL) { + syslog(LOG_ERR, "decapadd: CreateTunlEntry failed"); + mipverbose(("unplumb tunnel with number %d\n", tnum)); + (void) unplumb_one_tun(muxfd); + freetunnel(tnum); + return (-1); + } + + entry->refcnt++; + (void) rw_unlock(&entry->TunlNodeLock); + + return (0); +} /* decapadd */ + +/* + * Function: decaprem + * + * Arguments: ipaddr_t target : Tunnel outer destination IP address at FA + * ipaddr_t tsrc : Tunnel outer source IP address at FA + * + * Description: Terminates decapulation service for target address. + * First find the tunnel entry in the hash table. + * If this is the last reference count to the tunnel entry + * then unplumb the tunnel and break the tunnel association + * between the foreign agent and home agent for + * decapsulation of packets. Next free the tunnel and the + * tunnel entry from hash table. + * + * Returns: int (zero on success) + */ +int +decaprem(ipaddr_t target, ipaddr_t tsrc) +{ + int tnum, muxfd; + MipTunlEntry *entry; + + if ((entry = (MipTunlEntry *)findHashTableEntryUint( + &mipTunlHash, target, LOCK_WRITE, MipTunlEntryLookup, + (uint32_t)tsrc, 0, 0)) == NULL) { + syslog(LOG_ERR, "encaprem: Target entry %x missing", target); + return (-1); + } + + tnum = entry->tunnelno; + muxfd = entry->mux_fd; + + if (entry->refcnt == 1) { + (void) setifflags(entry->tunnelno, + -IFF_UP | -IFF_NORTEXCH | -IFF_MIPRUNNING); + mipverbose(("unplumb tunnel with number %d\n", tnum)); + if (unplumb_one_tun(muxfd) == -1) { + (void) rw_unlock(&entry->TunlNodeLock); + syslog(LOG_ERR, + "decaprem: unplumb of tunnel %d failed", tnum); + return (-1); + } + } + + + if (--entry->refcnt == 0) { + int index = HASHIT(target); + HashTable *htbl = &mipTunlHash; + HashEntry *p, *q; + MipTunlEntry *Tunentry; + + freetunnel(tnum); + + (void) rw_wrlock(&htbl->bucketLock[index]); + p = htbl->buckets[index]; + + while (p) { + Tunentry = (MipTunlEntry *)p->data; + if (p->key == target && Tunentry->tunnelsrc == tsrc) + break; + q = p; + p = p->next; + } + + if (p == htbl->buckets[index]) + htbl->buckets[index] = p->next; + else + q->next = p->next; + + (void) rw_unlock(&entry->TunlNodeLock); + (void) rwlock_destroy(&entry->TunlNodeLock); + + free(entry); + free(p); + + (void) rw_wrlock(&htbl->hashLock); + htbl->size--; + (void) rw_unlock(&htbl->hashLock); + + (void) rw_unlock(&htbl->bucketLock[index]); + } else { + /* + * Release the lock. Other mobile node(s) may be + * using this tunnel. + */ + (void) rw_unlock(&entry->TunlNodeLock); + } + + return (entry->refcnt); +} + + +/* + * Function: MipTunlEntryLookup + * Arguments: entry - Pointer to MipTunl entry + * p1- First parameter to match (Tunnel src-endpoint IPaddr) + * p2- Second Parameter to match (unused) + * p3- Second Parameter to match (unused) + * Description: + * This function is used to lookup a tunnel entry which is hashed + * by the tunnel destination endpoint address and matched with + * it's source end point address. This matching is necessary + * to support multihomed foreign agent with more than one COAs + */ +/* ARGSUSED */ +boolean_t +MipTunlEntryLookup(void *entry, uint32_t p1, uint32_t p2, uint32_t p3) +{ + MipTunlEntry *Tunentry = entry; + + if (Tunentry->tunnelsrc == (ipaddr_t)p1) + return (_B_TRUE); + return (_B_FALSE); +} + +/* + * Function: arpadd + * + * Arguments: ipaddr_t host, unsigned char *eaddr, char *flag + * + * Description: Adds an arp entry with ip address set to host and hardware + * address set to eaddr with approriate flags specified by flag + * argument, e.g. arpadd(inet_addr("129.146.122.121"), + * "08:20:AB:FE:33:11", "pub") creates a proxy ARP entry for + * 129.146.122.121. + * + * Returns: int + */ +int +arpadd(ipaddr_t host, unsigned char *eaddr, unsigned int flags) +{ + struct arpreq ar; + struct sockaddr_in *sin; + + bzero((caddr_t)&ar, sizeof (ar)); + /* LINTED E_BAD_PTR_CAST_ALIGN */ + sin = (struct sockaddr_in *)&ar.arp_pa; + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = (host); + + (void) memcpy(ar.arp_ha.sa_data, eaddr, ETH_ALEN); + + ar.arp_flags = ATF_PERM | flags; +#if 0 + if (strncmp(flag, "temp", 4) == 0) + ar.arp_flags &= ~ATF_PERM; + if (strncmp(flag, "pub", 3) == 0) + ar.arp_flags |= ATF_PUBL; + if (strncmp(flag, "trail", 5) == 0) + ar.arp_flags |= ATF_USETRAILERS; +#endif + + if (ioctl(ioctl_sockid, SIOCSARP, (caddr_t)&ar) < 0) { + if (errno != EEXIST) + return ((-1) * errno); + } + + return (0); +} /* arpadd */ + + +/* + * Function: arpdel + * + * Arguments: ipaddr_t host + * + * Description: Deletes an arp entry for ip address set to host + * + * Returns: int (zero on success) + */ +int +arpdel(ipaddr_t host) +{ + struct arpreq ar; + struct sockaddr_in *sin; + + bzero((caddr_t)&ar, sizeof (ar)); + ar.arp_pa.sa_family = AF_INET; + /* LINTED E_BAD_PTR_CAST_ALIGN */ + sin = (struct sockaddr_in *)&ar.arp_pa; + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = (host); + + if (ioctl(ioctl_sockid, SIOCDARP, (caddr_t)&ar) < 0) { + if (errno != ENXIO) + return ((-1) * errno); + } + return (0); +} /* arpdel */ + + +/* + * Function: arpgetHWaddr + * + * Arguments: ipaddr_t mnaddr, unsigned char *mnetheraddr + * + * Description: Get the hardware address corresponding to mnaddr from + * the arp table. + * + * Returns: int (zero on success) + */ +static int +arpgetHWaddr(ipaddr_t mnaddr, unsigned char *mnetheraddr) +{ + struct arpreq ar; + struct sockaddr_in *sin; + + bzero((caddr_t)&ar, sizeof (ar)); + ar.arp_pa.sa_family = AF_INET; + /* LINTED E_BAD_PTR_CAST_ALIGN */ + sin = (struct sockaddr_in *)&ar.arp_pa; + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = mnaddr; + + if (ioctl(ioctl_sockid, SIOCGARP, (caddr_t)&ar) < 0) + return (-1 * (errno)); + else { + (void) memcpy(mnetheraddr, ar.arp_ha.sa_data, ETH_ALEN); + return (0); + } +} /* arpgetHWaddr */ + + +/* + * Function: arprefresh + * + * Arguments: HaMobileNodeEntry *hentry, ipaddr_t mnaddr + * + * Description: Sends gratuitous arp for the mnaddr using the hardware address + * found for mnaddr in its own ARP cache (making sure that the + * hardware address is not HA's own). The home agent calls + * arprefresh when a mobile node returns home and successfully + * deregisters itself. + * + * Returns: int (zero on success) + */ +int +arprefresh(HaMobileNodeEntry *hentry, ipaddr_t mnaddr) +{ + int ret; + ipaddr_t ifaceaddr; + char devname[LIFNAMSIZ + 1]; + unsigned char hainterfaceaddr[ETH_ALEN + 1]; + unsigned char mnetheraddr[ETH_ALEN + 1]; + unsigned char zero_addr[ETH_ALEN + 1] = {0x00, 0x00, 0x00, + 0x00, 0x00, 0x00}; + MaAdvConfigEntry *mentry; + + mipverbose(("Arp refresh called for %d.%d.%d.%d\n", + (unsigned char) ((ntohl(mnaddr) >> 24) & 0xff), + (unsigned char) ((ntohl(mnaddr) >> 16) & 0xff), + (unsigned char) ((ntohl(mnaddr) >> 8) & 0xff), + (unsigned char) (ntohl(mnaddr) & 0xff))); + + ifaceaddr = hentry->haBindingIfaceAddr; + + /* Get the matching maIfaceAddr from mnAdvConfigTable */ + if ((mentry = (MaAdvConfigEntry *)findHashTableEntryUint( + &maAdvConfigHash, ifaceaddr, LOCK_NONE, NULL, 0, 0, 0)) == NULL) { + syslog(LOG_ERR, "Unable to find interface in hash table"); + return (-1 * MN_ENTRY_ABSENT); /* Unlikely to occur */ + } + + (void) strcpy(devname, mentry->maIfaceName); + (void) memcpy(hainterfaceaddr, mentry->maIfaceHWaddr, ETH_ALEN); + + if ((ret = arpgetHWaddr(mnaddr, mnetheraddr)) < 0) + return (ret); + + if ((memcmp(hainterfaceaddr, mnetheraddr, ETH_ALEN) == 0) || + (memcmp(zero_addr, mnetheraddr, ETH_ALEN) == 0)) + return (-1 * NO_MAPPING); + else + return (garp(devname, mnaddr, mnetheraddr)); +} /* arprefresh */ + +/* + * Function: routemodify + * + * Arguments: ipaddr_t dst, ipaddr_t gw, + * ipaddr_t insrc, int in_if, int out_if, + * unsigned int cmd + * + * Description: Add or Delete route depending on 'cmd' argument. + * 'cmd' argument can be either ADDRT or DELRT. + * For adding/deleting route from registration + * process and reply functions, only dst,gw args + * are required. Thus that is defined as simple route. + * NOTE: simple route is not used by mipagent registration + * reply process as it uses IP_XMIT_IF socket option + * instead of simple route. Simple route can not distinguish + * between two different mobile nodes with same private + * addresses. But the code still contains simple route + * section, in case it's needed in future for any purpose. + * After the visitor is accepted at FA, the + * forward route created from FA to MN to relay the + * packet from tunnel from home agent is defined + * as 'ftun_route'. This route must have in_if and out_if + * index arguments. For reverse tunnel route, this + * function expects a valid in_if and a valid out_if + * value and a non-zero source address(insrc). For ftun_route + * insrc must be zero. + * + * To set up forward route to reach MN: + * dst= MN's home addr, gw= COA, in_if=tun's if_index + * out_if = FA's interface index on which MN is attached. + * insrc = 0.0.0.0 + * + * To set up reverse tunnel route: + * dst = 0.0.0.0 gw = 0.0.0.0 in_if = FA's interface index on + * which MN is attached, out_if = tunnel's interface index. + * insrc = MN's homeaddr + * + * Returns: int (zero on success) + */ +int +routemodify(ipaddr_t dst, ipaddr_t gw, ipaddr_t insrc, int in_if, + int out_if, unsigned int cmd) +{ + struct rt_msghdr *rt_msg; + struct sockaddr_in *dstaddr; + struct sockaddr_in *gwaddr; + struct sockaddr_in *insrcaddr; + struct sockaddr_dl *rta_ifp; + struct sockaddr_dl *rta_srcifp; + char *cp; + static int rtmseq; + int rlen; + int flags = RTF_STATIC | RTF_UP; + boolean_t rtun_route = _B_FALSE; /* when insrc!=0, in_if, out_if !=0 */ + boolean_t ftun_route = _B_FALSE; /* when insrc==0, in_if!=0 */ + + if (insrc == INADDR_ANY && in_if == 0 && out_if == 0) { + /* Simple route case dst<->gw: not used by mipagent */ + flags = RTF_HOST | RTF_PRIVATE; + rlen = MIP_RTM_MSGLEN; + } else if (insrc == INADDR_ANY && in_if != 0 && out_if != 0) { + /* Forward route to MN from tunnel */ + ftun_route = _B_TRUE; + flags = RTF_HOST | RTF_PRIVATE; + rlen = MIP_RTM_MSGLEN + 2 * (sizeof (struct sockaddr_dl)); + } else if (insrc != INADDR_ANY && in_if != 0 && out_if != 0) { + /* Reverse tunnel route: insrc != 0 */ + rtun_route = _B_TRUE; + flags = RTF_GATEWAY | RTF_PRIVATE; + rlen = MIP_RTUN_RTM_MSGLEN; + } else { + /* Invalid Call */ + return (-1 * EINVAL); + } + + rt_msg = (struct rt_msghdr *)malloc(rlen); + if (rt_msg == NULL) { + syslog(LOG_ERR, "route_modify: Cannot allocate memory"); + return (-1 * (errno)); + } + + bzero(rt_msg, rlen); + rt_msg->rtm_msglen = rlen; + rt_msg->rtm_version = RTM_VERSION; + rt_msg->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; + rt_msg->rtm_pid = getpid(); + if (cmd == ADDRT) + rt_msg->rtm_type = RTM_ADD; + else + rt_msg->rtm_type = RTM_DELETE; + + rt_msg->rtm_seq = ++rtmseq; + rt_msg->rtm_flags = flags; + + cp = (char *)rt_msg + sizeof (struct rt_msghdr); + + /* DST */ + /* LINTED E_BAD_PTR_CAST_ALIGN */ + dstaddr = (struct sockaddr_in *)cp; + dstaddr->sin_family = AF_INET; + if (!rtun_route) + dstaddr->sin_addr.s_addr = dst; + else + dstaddr->sin_addr.s_addr = INADDR_ANY; + + /* GATEWAY */ + cp += sizeof (struct sockaddr_in); + /* LINTED E_BAD_PTR_CAST_ALIGN */ + gwaddr = (struct sockaddr_in *)cp; + gwaddr->sin_family = AF_INET; + gwaddr->sin_addr.s_addr = gw; + + /* NETMASK */ + cp += sizeof (struct sockaddr_in); + /* LINTED E_BAD_PTR_CAST_ALIGN */ + dstaddr = (struct sockaddr_in *)cp; + dstaddr->sin_family = AF_INET; + + if (!rtun_route) { + dstaddr->sin_addr.s_addr = IP_HOST_MASK; + } else { + dstaddr->sin_addr.s_addr = INADDR_ANY; + } + + /* Check if ftun_route or rtun_route is set, else it's simple_route */ + + if (ftun_route) { + /* + * We need to set both RTA_IFP and RTA_SRCIFP + * in order to support Lucent PPP interfaces to + * mobile nodes. Since there may not be an interface + * route for the dynamically plumbed PPP interfaces + * which are used in 3Gwireless technology to connect + * to the mobile node from the PDSN (Packet Data Service + * Network, IS-835, TIA document), thus the foreign agent + * (PDSN) end of PPP interface may have non-unique address + * (for example, all these special PPP interfaces may have + * same address, COA in the PDSN end). So it is not + * possible to derive interface index from the supplied + * gateway address. Hence the caller of this function + * must provide both outgoing and incoming interface + * index when creating the forward tunnel. + */ + rt_msg->rtm_addrs |= RTA_IFP | RTA_SRCIFP; + + /* IFP */ + cp += sizeof (struct sockaddr_in); + /* LINTED E_BAD_PTR_CAST_ALIGN */ + rta_ifp = (struct sockaddr_dl *)cp; + rta_ifp->sdl_family = AF_LINK; + rta_ifp->sdl_index = out_if; + + /* SRCIFP */ + cp += sizeof (struct sockaddr_dl); + /* LINTED E_BAD_PTR_CAST_ALIGN */ + rta_srcifp = (struct sockaddr_dl *)cp; + rta_srcifp->sdl_family = AF_LINK; + rta_srcifp->sdl_index = in_if; + + } else if (rtun_route) { + + /* it's a reverse tunnel route */ + + rt_msg->rtm_addrs |= (RTA_IFP | RTA_SRC | RTA_SRCIFP); + + /* IFP */ + cp += sizeof (struct sockaddr_in); + /* LINTED E_BAD_PTR_CAST_ALIGN */ + rta_ifp = (struct sockaddr_dl *)cp; + rta_ifp->sdl_family = AF_LINK; + rta_ifp->sdl_index = out_if; + + /* SRC */ + cp += sizeof (struct sockaddr_dl); + /* LINTED E_BAD_PTR_CAST_ALIGN */ + insrcaddr = (struct sockaddr_in *)cp; + insrcaddr->sin_family = AF_INET; + insrcaddr->sin_addr.s_addr = insrc; + + /* SRCIFP */ + cp += sizeof (struct sockaddr_in); + /* LINTED E_BAD_PTR_CAST_ALIGN */ + rta_srcifp = (struct sockaddr_dl *)cp; + rta_srcifp->sdl_family = AF_LINK; + rta_srcifp->sdl_index = in_if; + } + + /* Send the routing message */ + rlen = write(rtsock, rt_msg, rt_msg->rtm_msglen); + if (rlen > 0) { + if (cmd == ADDRT) + mipverbose(("Added route\n")); + else + mipverbose(("Deleted route\n")); + } + /* Free rt_msg now */ + free((void *)rt_msg); + + if (rlen < 0) + return ((-1) * (errno)); + + return (0); +} /* routemodify */ + +/* Routines for refresh_mn_arp() */ +/* -------- Start of dlcommon routines */ +/* + * Common (shared) DLPI test routines. + * Mostly pretty boring boilerplate sorta stuff. + * These can be split into individual library routines later + * but it's just convenient to keep them in a single file + * while they're being developed. + * + * Not supported: + * Connection Oriented stuff + * QOS stuff + */ + + +/* + * Function: dlinforeq + * + * Arguments: fd + * + * Description: + * + * Returns: int + */ +static int +dlinforeq(int fd) +{ + dl_info_req_t info_req; + struct strbuf ctl; + + info_req.dl_primitive = DL_INFO_REQ; + + ctl.maxlen = 0; + ctl.len = sizeof (info_req); + ctl.buf = (char *)&info_req; + + if (putmsg(fd, &ctl, (struct strbuf *)NULL, RS_HIPRI) < 0) { + return (-1 * errno); + } + return (0); +} /* dlinforeq */ + + +/* + * Function: dlinfoack + * + * Arguments: fd, bufp + * + * Description: + * + * Returns: int + */ +static int +dlinfoack(int fd, char *bufp) +{ + union DL_primitives *dlp; + struct strbuf ctl; + int flags; + int ret; + + ctl.maxlen = MAXDLBUF; + ctl.len = 0; + ctl.buf = bufp; + + (void) strgetmsg(fd, &ctl, (struct strbuf *)NULL, &flags); + + /* LINTED E_BAD_PTR_CAST_ALIGN */ + dlp = (union DL_primitives *)ctl.buf; + + if ((ret = expecting(DL_INFO_ACK, dlp)) < 0) { + (void) close(fd); + return (ret); + } + + if (ctl.len < sizeof (dl_info_ack_t)) { + return (-1 * DLOKACK_SHORT_RESPONSE); + } + + if (flags != RS_HIPRI) { + return (-1 * DLOKACK_NOT_M_PCPROTO); + } + + if (ctl.len < sizeof (dl_info_ack_t)) { + return (-1 * DLOKACK_SHORT_RESPONSE); + } + + return (0); +} /* dlinfoack */ + + +/* + * Function: dlattachreq + * + * Arguments: fd, ppa + * + * Description: + * + * Returns: int + */ +int +dlattachreq(int fd, int ppa) +{ + dl_attach_req_t attach_req; + struct strbuf ctl; + + attach_req.dl_primitive = DL_ATTACH_REQ; + attach_req.dl_ppa = ppa; + + ctl.maxlen = 0; + ctl.len = sizeof (attach_req); + ctl.buf = (char *)&attach_req; + + if (putmsg(fd, &ctl, (struct strbuf *)NULL, 0) < 0) + return (-1 * errno); + + return (0); +} /* dlattachreq */ + + +/* + * Function: dlbindreq + * + * Arguments: fd, sap, max_conind, service_mode, conn_mgmt, xidtest + * + * Description: + * + * Returns: int + */ +int +dlbindreq(int fd, uint32_t sap, uint32_t max_conind, uint32_t service_mode, + uint32_t conn_mgmt, uint32_t xidtest) +{ + dl_bind_req_t bind_req; + struct strbuf ctl; + + bind_req.dl_primitive = DL_BIND_REQ; + bind_req.dl_sap = sap; + bind_req.dl_max_conind = max_conind; + bind_req.dl_service_mode = service_mode; + bind_req.dl_conn_mgmt = conn_mgmt; + bind_req.dl_xidtest_flg = xidtest; + + ctl.maxlen = 0; + ctl.len = sizeof (bind_req); + ctl.buf = (char *)&bind_req; + + if (putmsg(fd, &ctl, (struct strbuf *)NULL, 0) < 0) + return (-1 * errno); + + return (0); +} /* dlbindreq */ + +/* + * Function: dlunitdatareq + * + * Arguments: int fd, unsigned char *addrp, int addrlen, ulong_t minpri + * ulong_t maxpri, unsigned char *datap, int datalen) + * + * Description: + * + * Returns: int + */ +static int +dlunitdatareq(int fd, unsigned char *addrp, int addrlen, ulong_t minpri, + ulong_t maxpri, unsigned char *datap, int datalen) +{ + long buf[MAXDLBUF]; + union DL_primitives *dlp; + struct strbuf data, ctl; + + dlp = (union DL_primitives *)buf; + + dlp->unitdata_req.dl_primitive = DL_UNITDATA_REQ; + dlp->unitdata_req.dl_dest_addr_length = addrlen; + dlp->unitdata_req.dl_dest_addr_offset = sizeof (dl_unitdata_req_t); + dlp->unitdata_req.dl_priority.dl_min = minpri; + dlp->unitdata_req.dl_priority.dl_max = maxpri; + + (void) memcpy(OFFADDR(dlp, sizeof (dl_unitdata_req_t)), addrp, + addrlen); + + ctl.maxlen = 0; + ctl.len = sizeof (dl_unitdata_req_t) + addrlen; + ctl.buf = (char *)buf; + + data.maxlen = 0; + data.len = datalen; + data.buf = (char *)datap; + + if (putmsg(fd, &ctl, &data, 0) < 0) + return (-1 * errno); + + return (0); +} /* dlunitdatareq */ + + +/* + * Function: dlokack + * + * Arguments: int fd, char *bufp + * + * Description: + * + * Returns: int + */ +int +dlokack(int fd, char *bufp) +{ + union DL_primitives *dlp; + struct strbuf ctl; + int flags; + int ret; + + ctl.maxlen = MAXDLBUF; + ctl.len = 0; + ctl.buf = bufp; + + (void) strgetmsg(fd, &ctl, (struct strbuf *)NULL, &flags); + + /* LINTED E_BAD_PTR_CAST_ALIGN */ + dlp = (union DL_primitives *)ctl.buf; + + if ((ret = expecting(DL_OK_ACK, dlp)) < 0) + return (ret); + + if (ctl.len < sizeof (dl_ok_ack_t)) + return (-1 * DLOKACK_SHORT_RESPONSE); + + if (flags != RS_HIPRI) + return (-1 * DLOKACK_NOT_M_PCPROTO); + + if (ctl.len < sizeof (dl_ok_ack_t)) + return (-1 * DLOKACK_SHORT_RESPONSE); + + return (0); +} /* dlokack */ + + +/* + * Function: dlbindack + * + * Arguments: int fd, char *bufp + * + * Description: + * + * Returns: int + */ +int +dlbindack(int fd, char *bufp) +{ + union DL_primitives *dlp; + struct strbuf ctl; + int flags; + int ret; + + ctl.maxlen = MAXDLBUF; + ctl.len = 0; + ctl.buf = bufp; + + (void) strgetmsg(fd, &ctl, (struct strbuf *)NULL, &flags); + + /* LINTED E_BAD_PTR_CAST_ALIGN */ + dlp = (union DL_primitives *)ctl.buf; + + if ((ret = expecting(DL_BIND_ACK, dlp)) < 0) + return (ret); + + if (flags != RS_HIPRI) + return (-1 * DLOKACK_NOT_M_PCPROTO); + + if (ctl.len < sizeof (dl_bind_ack_t)) + return (-1 * DLOKACK_SHORT_RESPONSE); + + return (0); +} /* dlbindack */ + + +/* + * Function: strgetmsg + * + * Arguments: int fd, struct strbuf *ctlp, struct strbuf *datap, int *flagsp, + * char *caller + * + * Description: + * + * Returns: int + */ +static int +strgetmsg(int fd, struct strbuf *ctlp, struct strbuf *datap, int *flagsp) +{ + int rc; + + /* + * Set flags argument and issue getmsg(). + */ + *flagsp = 0; + if ((rc = getmsg(fd, ctlp, datap, flagsp)) < 0) { + return (-1 * errno); + } + + /* + * Check for MOREDATA and/or MORECTL. + */ + if ((rc & (MORECTL | MOREDATA)) == (MORECTL | MOREDATA)) + return (-1 * ERR_MORECTLDATA); + + if (rc & MORECTL) + return (-1 * ERR_MORECTL); + + if (rc & MOREDATA) + return (-1 * ERR_MOREDATA); + + /* + * Check for at least sizeof (long) control data portion. + */ + if (ctlp->len < sizeof (long)) + return (-1 * SHORT_CONTROL_PORTION); + + return (0); +} /* strgetmsg */ + + +/* + * Function: expecting + * + * Arguments: int prim, union DL_primitives *dlp + * + * Description: + * + * Returns: int (zero on success) + */ +static int +expecting(int prim, union DL_primitives *dlp) +{ + if (dlp->dl_primitive != (ulong_t)prim) + return (-1 * DL_PRIMITIVE_ERROR); + + return (0); +} /* expecting */ + + +/* + * Function: MAaddrtostring + * + * Arguments: unsigned char *addr, ulong_t length, unsigned char *s + * + * Description: return hardware address as string. + * + * Returns: void + */ +static void +MAaddrtostring(unsigned char *addr, ulong_t length, unsigned char *s) +{ + int i; + + for (i = 0; i < length; i++) { + (void) sprintf((char *)s, "%x:", addr[i] & 0xff); + s = s + strlen((char *)s); + } + if (length) + *(--s) = '\0'; +} /* MAaddrtostring */ + +#if 0 +/* + * Function: stringtoaddr + * + * Arguments: char *sp, char *addr + * + * Description: This function converts the string to an address. + * + * Returns: int (length of address) + */ +int +stringtoaddr(char *sp, char *addr) +{ + int n = 0; + char *p; + unsigned int val; + + p = sp; + while (p = strtok(p, ":")) { + if (sscanf(p, "%x", &val) != 1) + return (-1 * INVALID_STRING); + if (val > 0xff) + return (-1 * INVALID_STRING); + *addr++ = val; + n++; + p = NULL; + } + + return (n); +} /* stringtoaddr */ + +#endif +/* -------- End of dlcommon routines */ + +/* + * The parms are as follows: + * device String definition of the device (e.g. "/dev/le"). + * ppa Int for the instance of the device (e.g. 3, for "le3"). + * phys Byte String for the dst MAC address of this packet. + * This is just the bcast address("ff:ff:ff:ff:ff:ff") + * physlen Length (int) of the mac address (not the string). E.g: + * 6 for enet. + * ipaddr long for the ip address of the host we are advertising + * our mac address for. + * ether_addr Ether address we want to set for the ipaddress we are + * impersonating + * NOTE: The mac addr of this system is not passed in, it is obtained + * directly from the dlpi info ack structure. + * Steps executed :- + * ----------------- + * Open datalink provider. + * Attach to PPA. + * Bind to sap + * Send arp request as DL_UNITDATA_REQ msg + * + */ +static int send_gratuitous_arp(char *device, int ppa, unsigned char *phys, + int physlen, ipaddr_t ipaddr, unsigned char *ether_addr) +{ + int saplen; + int size = sizeof (struct ether_arp); + int sapval = ETHERTYPE_ARP; + int localsap = ETHERTYPE_ARP; + int fd; + char buf[MAXDLBUF]; + unsigned char sap[MAXDLADDR]; + unsigned char addr[MAXDLADDR]; + int addrlen; + struct ether_arp req; + union DL_primitives *dlp; + int i, ret; + ipaddr_t target_ipaddr = ipaddr; + + + /* initialize buf[] */ + for (i = 0; i < MAXDLBUF; i++) + buf[i] = (unsigned char) i & 0xff; + + /* Open the device. */ + if ((fd = open(device, 2)) < 0) + return (-1 * errno); + + /* Attach. */ + if ((ret = dlattachreq(fd, ppa)) < 0) { + (void) close(fd); + return (ret); + } + + if ((ret = dlokack(fd, buf)) < 0) { + (void) close(fd); + return (ret); + } + + /* Bind. */ + if ((ret = dlbindreq(fd, localsap, 0, DL_CLDLS, 0, 0)) < 0) { + (void) close(fd); + return (ret); + } + + if ((ret = dlbindack(fd, buf)) < 0) { + (void) close(fd); + return (ret); + } + + /* Get info */ + if ((ret = dlinforeq(fd)) < 0) { + (void) close(fd); + return (ret); + } + + if ((ret = dlinfoack(fd, buf)) < 0) { + (void) close(fd); + return (ret); + } + + /* + * Verify sap and phys address lengths. + */ + + /* LINTED E_BAD_PTR_CAST_ALIGN */ + dlp = (union DL_primitives *)buf; + + MAaddrtostring(OFFADDR(dlp, dlp->info_ack.dl_addr_offset), + dlp->info_ack.dl_addr_length, addr); + + saplen = ABS(dlp->info_ack.dl_sap_length); + + /* + * Convert destination address string to address. + */ + for (i = 0; i < saplen; ++i) { + int rev_index = saplen - 1 -i; + sap[i] = (sapval >> (rev_index * BITSPERBYTE)) & 0xff; + } + + /* + * printdlprim(dlp); + */ + if (physlen != (dlp->info_ack.dl_addr_length - saplen)) { + (void) close(fd); + return (-1 * INVALID_ADDR); + } + + addrlen = saplen + physlen; + + /* + * Construct destination address. + */ + if (dlp->info_ack.dl_sap_length > 0) { /* order is sap+phys */ + (void) memcpy(addr, sap, saplen); + (void) memcpy(addr + saplen, phys, physlen); + + /* obtain our MAC address */ + /* + * (void) memcpy((char *)my_etheraddr, + * (char *)OFFADDR(dlp, + * dlp->info_ack.dl_addr_offset + saplen), + * physlen); + */ + } else { /* order is phys+sap */ + (void) memcpy(addr, phys, physlen); + (void) memcpy(addr + physlen, sap, saplen); + + /* Obtain our MAC address */ + /* + * (void) memcpy((char *)my_etheraddr, + * (char *)OFFADDR(dlp, dlp->info_ack.dl_addr_offset), physlen); + */ + } + + /* create arp request */ + (void) memset(&req, 0, sizeof (req)); + req.arp_hrd = htons(ARPHRD_ETHER); + req.arp_pro = htons(ETHERTYPE_IP); + req.arp_hln = ETHERADDRL; + req.arp_pln = IPADDRL; + req.arp_op = htons(ARPOP_REQUEST); + (void) memcpy(&req.arp_sha, ether_addr, ETHERADDRL); + (void) memcpy(&req.arp_spa, &ipaddr, IPADDRL); + (void) memcpy(&req.arp_tpa, &target_ipaddr, IPADDRL); + + /* Transmit it. */ + + if ((ret = + dlunitdatareq(fd, addr, addrlen, 0, 0, (unsigned char *)&req, + size)) < 0) { + (void) close(fd); + return (ret); + } + + (void) close(fd); + return (0); +} /* send_gratuitous_arp() */ + + +/* + * SYNOPSIS: + * garp interface ipaddr ether_addr + * + * RETURN VALUE : + * Returns 0 on success else -(error code) + * "interface" is the interface to send the grarp out on. + * "interface" is expressed in ifname convention(e.g. "le0", "bf2"), + * and it will be converted by ifname2device_ppa() into the dlpi convention + * (e.g. "/dev/le" + "0" and "/dev/bf" + "2"). + * "ipaddr" is the ipaddr of the system we're "impersonating" + * ether_addr is the ethernet address to which we want to be impersonated. + * Sends a gratuitous arp to hw addr ff:ff:ff:ff:ff:ff. + * + * The arp packet fields are filled in as follows: + * (To be in conformance gratuitous arp described in RFC2002) + * In the gratuitous arp packet for Mobile - IP : + * Ethernet header : + * Source address : Its own hardware address + * Destination address : ff:ff:ff:ff:ff:ff(Broadcast address) + * Frame Type : 0x0806 Arp Request/Reply + * + * Arp Packet : + * Format of hardware address : ARPHRD_ETHER 1 + * Format of protocol address : 0x0800 + * Length of hardware address : ETH_ALEN 6 + * Length of protocol address : 4 + * ARP opcode : ARPOP_REQUEST 1 + * Sender hardware address : Ethernet address to which to be updated. + * Destination harware address : XXXX Don't Care + * Sender IP address : IP Address(Cache entry to be updated) + * Target IP address : Sender IP Address. + * For an ARP Request Packet : + * + * Note : For ARP Reply packet target IP address should be set same + * as source IP address + * + * Modified from gabriels's arp module which was + * blatantly stolen from dlunitdatareq.c by Neal Nuckolls. Just added + * stuff to compose an arp packet. + */ +int +garp(char *dev, ipaddr_t mnaddr, unsigned char *mnetheraddr) +{ + int ppa; + unsigned char phys[MAXDLADDR]; + char device[MAX_INPUT]; + + ifname2devppa(dev, device, &ppa); + (void) memset(phys, 0xff, ETH_ALEN); + + /* Validate arguments. */ + if (ppa < 0) + return (-1 * INVALID_PPA); + + return (send_gratuitous_arp(device, ppa, phys, ETH_ALEN, + mnaddr, mnetheraddr)); +} /* garp */ + + +/* + * Function: OScleanup + * + * Arguments: none + * + * Description: Close filedescriptors for shutdown. + * Also cleans up the dynamic interface and static + * interface list entries. + * + * Returns: void + */ +void +OScleanup() +{ + (void) close(ioctl_sockid); + /* Cleanup static existing interface table */ + if (dynamicIfaceHead != NULL) { + struct dynamicIfacetype *dp; + struct dynamicIfacetype *savep; + + dp = dynamicIfaceHead; + while (dp != NULL) { + savep = dp->next; + dp->next = NULL; + free(dp); + dp = savep; + } + } + if (StaticIntfaceHead != NULL) { + struct staticIface *sp; + struct staticIface *save_sp; + + sp = StaticIntfaceHead; + while (sp != NULL) { + save_sp = sp->next; + sp->next = NULL; + free(sp); + sp = save_sp; + } + } + dynamicIfaceHead = NULL; + StaticIntfaceHead = NULL; + ioctl_sockid = -1; +} /* OScleanup */ + +/* + * Function: plumb_one_tun + * + * Arguments: int tnum + * + * Description: Plumb the tunnel interface by opening the + * associated devices and pushing the required modules eg. + * 'tunl' module and others and then create persistent links. + * + * Returns: -1 on error and mux_fd is returned upon success. + * mux_fd will be used by unplumb_one_tun to destroy + * the tunnel. + */ +static int +plumb_one_tun(int tnum) +{ + struct lifreq lifr; + int ip_fd, mux_fd, ip_muxid; + char name[LIFNAMSIZ]; + + mipverbose(("plumb_one_tun: tunnel number %d\n", tnum)); + + if ((ip_fd = open("/dev/ip", O_RDWR)) < 0) { + syslog(LOG_ERR, "open of /dev/ip failed"); + return (-1); + } + + if (ioctl(ip_fd, I_PUSH, "tun") < 0) { + syslog(LOG_ERR, "I_PUSH of tun failed"); + (void) close(ip_fd); + return (-1); + } + + if ((mux_fd = open("/dev/udp", O_RDWR)) < 0) { + syslog(LOG_ERR, "open of /dev/ip failed"); + (void) close(ip_fd); + return (-1); + } + + if (ioctl(ip_fd, I_PUSH, "ip") == -1) { + syslog(LOG_ERR, "I_PUSH of ip failed"); + (void) close(ip_fd); + (void) close(mux_fd); + return (-1); + } + + /* Get the existing flags for this stream */ + (void) memset(&lifr, 0, sizeof (lifr)); + lifr.lifr_name[0] = '\0'; + if (ioctl(ip_fd, SIOCGLIFFLAGS, (char *)&lifr) == -1) { + syslog(LOG_ERR, "plumb_one_tun: SIOCGLIFFLAGS"); + (void) close(ip_fd); + (void) close(mux_fd); + return (-1); + } + + lifr.lifr_ppa = tnum; + (void) sprintf(name, "ip.tun%d", tnum); + (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); + if (ioctl(ip_fd, SIOCSLIFNAME, (char *)&lifr) == -1) { + (void) close(ip_fd); + (void) close(mux_fd); + return (-1); + } + + if ((ip_muxid = ioctl(mux_fd, I_LINK, ip_fd)) == -1) { + syslog(LOG_ERR, "I_LINK for ip failed"); + (void) close(ip_fd); + (void) close(mux_fd); + return (-1); + } + + lifr.lifr_ip_muxid = ip_muxid; + + /* + * Tell IP the muxids of the LINKed interface + * streams so that they can be closed down at a later + * time by an unplumb operation. + */ + if (ioctl(mux_fd, SIOCSLIFMUXID, (caddr_t)&lifr) < 0) { + syslog(LOG_ERR, "plumb_one_tun: SIOCSLIFMUXID failed"); + (void) close(ip_fd); + (void) close(mux_fd); + return (-1); + } + + (void) close(ip_fd); + + return (mux_fd); +} /* plumb_one_tun */ + + +/* + * Function: unplumb_one_tun + * + * Arguments: int mux_fd + * + * Description: Unplumb the tunnel interface. Destroy all streams + * associated with this tunnel and close it. + * + * Returns: int + */ +static int +unplumb_one_tun(int mux_fd) +{ + int retval; + + retval = close(mux_fd); + return (retval); +} + + +/* + * Function: setifflags + * + * Arguments: int tnum, int value + * + * Description: Set the interface specific flags indicated in + * the argument 'value' for the given tunnel interface whose + * tunnel number is the argument 'tnum'. + * + * Returns: int + */ +static int +setifflags(int tnum, int value) +{ + + + struct lifreq lifr; + char name[LIFNAMSIZ]; + + (void) sprintf(name, "ip.tun%d", tnum); + mipverbose(("setifflags %s\n", name)); + + (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); + if (ioctl(ioctl_sockid, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { + syslog(LOG_ERR, "setifflags: SIOCGLIFFLAGS failed"); + return (-1); + } + if (value < 0) { + value = -value; + lifr.lifr_flags &= ~value; + } else + lifr.lifr_flags |= value; + + (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); + if (ioctl(ioctl_sockid, SIOCSLIFFLAGS, (caddr_t)&lifr) < 0) { + syslog(LOG_ERR, "setifflags: SIOCSLIFFLAGS failed"); + return (-1); + } + return (0); +} + + +/* + * Function: settaddr + * + * Arguments: int tnum, ipaddr_t ifaddr1, ipaddr_t ifaddr2, + * ipaddr_t saddr, ipaddr_t daddr, struct ipsec_req_t *ipsr + * + * Description: First forms a point-to-point interface between + * ifaddr1 and ifaddr2 addresses. Next the source address of + * the tunnel is set to address 'saddr'. This is the source + * address of an outer encapsulating IP header and it must be + * the address of an interface that has already been configured. + * The destination address of the tunnel is set to 'daddr'. + * + * Returns: static int + */ +static int +settaddr(int tnum, ipaddr_t ifaddr1, ipaddr_t ifaddr2, + ipaddr_t saddr, ipaddr_t daddr, ipsec_req_t *ipsr_p) +{ + + struct sockaddr_storage laddr1, laddr2; + struct iftun_req treq; + char name[LIFNAMSIZ]; + struct sockaddr_in *sin; + + (void) sprintf(name, "ip.tun%d", tnum); + mipverbose(("settaddr %s\n", name)); + + + if (mkpt2pt(name, ifaddr1, ifaddr2) < 0) { + syslog(LOG_ERR, "settaddr: mkpt2pt failed"); + return (-1); + } + + bzero(&treq, sizeof (struct iftun_req)); + treq.ifta_vers = IFTUN_VERSION; + (void) strncpy(treq.ifta_lifr_name, name, + sizeof (treq.ifta_lifr_name)); + if (ioctl(ioctl_sockid, SIOCGTUNPARAM, (caddr_t)&treq) < 0) { + syslog(LOG_ERR, "Not a tunnel"); + return (-1); + } + + if (treq.ifta_lower != IFTAP_IPV4) { + syslog(LOG_ERR, "Unknown lower tunnel"); + return (-1); + } + + sin = (struct sockaddr_in *)&laddr1; + (void) memset(&laddr1, 0, sizeof (laddr1)); + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = saddr; + + sin = (struct sockaddr_in *)&laddr2; + (void) memset(&laddr2, 0, sizeof (laddr2)); + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = daddr; + + treq.ifta_saddr = laddr1; + treq.ifta_daddr = laddr2; + treq.ifta_flags = IFTUN_SRC|IFTUN_DST; + (void) strncpy(treq.ifta_lifr_name, name, + sizeof (treq.ifta_lifr_name)); + treq.ifta_vers = IFTUN_VERSION; + + /* non-null means there's tunnel protection to be added! */ + if (ipsr_p != NULL) { + /* finally set the ipsec protection bits! */ + (void) memcpy(&treq.ifta_secinfo, ipsr_p, sizeof (ipsec_req_t)); + + /* set the flag so the kernel sets up the security! */ + treq.ifta_flags |= IFTUN_SECURITY; + } + + if (ioctl(ioctl_sockid, SIOCSTUNPARAM, (caddr_t)&treq) < 0) { + syslog(LOG_ERR, "set tunnel addr failed"); + return (-1); + } + + return (0); +} /* settaddr */ + +/* + * Function: getEthernetAddr + * + * Arguments: char *ename, unsigned char *eaddr + * + * Description: Get the hardware address for specified interface name. + * + * Returns: int + */ +int +getEthernetAddr(char *ename, unsigned char *eaddr) +{ + int saplen; + int localsap = ETHERTYPE_ARP; + int fd; + char buf[MAXDLBUF]; + unsigned char addr[MAXDLADDR]; + union DL_primitives *dlp; + int i, ret; + int physlen = ETHERADDRL; + int ppa; + char device[LIFNAMSIZ + 5]; + char *lasts; + + /* + * If this is a virtual interface, remove the ':' character (and + * everything following that character. We do not really care + * about it since the MAC address is the same as the physical + * interface. + */ + ename = strtok_r(ename, ":", &lasts); + if (ename == NULL) { + return (-1); + } + + ifname2devppa(ename, device, &ppa); + + /* initialize buf[] */ + for (i = 0; i < MAXDLBUF; i++) + buf[i] = (unsigned char) i & 0xff; + + /* Open the device. */ + if ((fd = open(device, (O_RDWR | O_NDELAY))) < 0) + return (-1 * errno); + + /* Attach. */ + if ((ret = dlattachreq(fd, ppa)) < 0) { + (void) close(fd); + return (ret); + } + + if ((ret = dlokack(fd, buf)) < 0) { + (void) close(fd); + return (ret); + } + + /* Bind. */ + if ((ret = dlbindreq(fd, localsap, 0, DL_CLDLS, 0, 0)) < 0) { + (void) close(fd); + return (ret); + } + + if ((ret = dlbindack(fd, buf)) < 0) { + (void) close(fd); + return (ret); + } + + /* Get info */ + if ((ret = dlinforeq(fd)) < 0) { + (void) close(fd); + return (ret); + } + + /* WORK -- check this error message, and send to mohanp@eng */ + (void) sleep(1); + + if ((ret = dlinfoack(fd, buf)) < 0) { + (void) close(fd); + return (ret); + } + + /* Verify sap and phys address lengths */ + /* LINTED E_BAD_PTR_CAST_ALIGN */ + dlp = (union DL_primitives *)buf; + + MAaddrtostring(OFFADDR(dlp, dlp->info_ack.dl_addr_offset), + dlp->info_ack.dl_addr_length, addr); + + saplen = ABS(dlp->info_ack.dl_sap_length); + + /* Construct destination address. */ + if (dlp->info_ack.dl_sap_length > 0) { /* order is sap+phys */ + /* obtain our MAC address */ + (void) memcpy(eaddr, OFFADDR(dlp, + dlp->info_ack.dl_addr_offset + saplen), + physlen); + } else { /* order is phys+sap */ + /* Obtain our MAC address */ + (void) memcpy(eaddr, OFFADDR(dlp, + dlp->info_ack.dl_addr_offset), + physlen); + } + + (void) close(fd); + return (0); +} /* getEthernetAddr */ + + +/* + * Function: getIfaceInfo + * + * Arguments: char *ifaceName, ipaddr_t *addr, ipaddr_t *mask, uint64_t *flags + * uint32_t *ifindex + * + * Description: Gets the interface information given the name. + * + * Returns: int + */ +int +getIfaceInfo(char *ifaceName, ipaddr_t *addr, ipaddr_t *mask, + uint64_t *flags, uint32_t *ifindex) +{ + struct lifreq lifr; + struct sockaddr_in *sin; + int ioc_sockid; + + bzero((char *)&lifr, sizeof (lifr)); + (void) strncpy(lifr.lifr_name, ifaceName, sizeof (lifr.lifr_name)); + + ioc_sockid = socket(AF_INET, SOCK_DGRAM, 0); + if (ioc_sockid < 0) { + syslog(LOG_ERR, + "Could not open socket for ioctls in getIfaceInfo()"); + return (-1); + } + + if (ioctl(ioc_sockid, SIOCGLIFADDR, (caddr_t)&lifr) < 0) { + syslog(LOG_ERR, "Could not read IP address for %s", ifaceName); + (void) close(ioc_sockid); + return (-1); + } + + sin = (struct sockaddr_in *)&lifr.lifr_addr; + *addr = sin->sin_addr.s_addr; + + if (ioctl(ioc_sockid, SIOCGLIFNETMASK, (caddr_t)&lifr) < 0) { + syslog(LOG_ERR, "Could not read netmask for %s", ifaceName); + (void) close(ioc_sockid); + return (-1); + } + + sin = (struct sockaddr_in *)&lifr.lifr_addr; + *mask = sin->sin_addr.s_addr; + + (void) strncpy(lifr.lifr_name, ifaceName, sizeof (lifr.lifr_name)); + if (ioctl(ioc_sockid, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { + syslog(LOG_ERR, "Could not read flags for %s", ifaceName); + (void) close(ioc_sockid); + return (-1); + } + + *flags = lifr.lifr_flags; + + if (ioctl(ioc_sockid, SIOCGLIFINDEX, (char *)&lifr) < 0) { + syslog(LOG_ERR, "Can't read IFINDEX %s", ifaceName); + (void) close(ioc_sockid); + return (-1); + } + *ifindex = lifr.lifr_index; + + (void) close(ioc_sockid); + + return (0); +} /* getIfaceInfo */ + + +/* + * Function: arpIfadd + * + * Arguments: vaddr - visitor MN's IP address + * inIfindex - inbound interface index + * slla - MN's source link layer addr + * + * Description: Add an ARP entry given the interface index. Invokes + * SIOCSXARP with sdl_data array filled with interface + * name (without null terminator) followed by address. + * This code assumes it is being invoked on Ethernet. + * + * Returns: 0 - sucesss; errno - failure + */ +int +arpIfadd(ipaddr_t vaddr, char *slla, uint32_t inIfindex) +{ + struct xarpreq ar; + char *etheraddr; + int val; + char addrstr1[INET_ADDRSTRLEN]; + struct ether_addr ether; + + (void) memset(&ar, 0, sizeof (struct xarpreq)); + if (if_indextoname(inIfindex, ar.xarp_ha.sdl_data) == NULL) { + syslog(LOG_ERR, "if_indextoname returned NULL\n"); + return ((-1) * errno); + } + + /* + * Mark this entry permanent to prevent ARP from blowing this + * away. + */ + ar.xarp_flags = ATF_PERM; + ((struct sockaddr_in *)&ar.xarp_pa)->sin_addr.s_addr = vaddr; + ((struct sockaddr_in *)&ar.xarp_pa)->sin_family = AF_INET; + + (void) memcpy(ether.ether_addr_octet, slla, ETHERADDRL); + etheraddr = ether_ntoa(ðer); + mipverbose(("Adding temporary ARP entry for visitor %s," + " hardware address %s on interface %s [index %d]\n", + ntoa(vaddr, addrstr1), etheraddr, ar.xarp_ha.sdl_data, inIfindex)); + ar.xarp_ha.sdl_nlen = strlen(ar.xarp_ha.sdl_data); + ar.xarp_ha.sdl_alen = ETHERADDRL; + ar.xarp_ha.sdl_family = AF_LINK; + (void) memcpy(LLADDR(&ar.xarp_ha), slla, ar.xarp_ha.sdl_alen); + + val = ioctl(ioctl_sockid, SIOCSXARP, (caddr_t)&ar); + + if (val < 0) + return ((-1) * errno); + else + return (val); +} + +/* + * Function: arpIfdel + * + * Arguments: vaddr - visitor MN's IP address + * slla - MN's source link layer addr (used here for mipverbose) + * inIfindex - inbound interface index + * + * Description: Delete an ARP entry based on the interface index. Invokes + * SIOCDXARP with sdl_data array filled with interface + * name. This code assumes it is being invoked on Ethernet. + * + * Returns: 0 - sucesss; errno - failure + */ +int +arpIfdel(ipaddr_t vaddr, char *slla, uint32_t inIfindex) +{ + struct xarpreq ar; + int val; + char *etheraddr; + char addrstr1[INET_ADDRSTRLEN]; + struct ether_addr ether; + + (void) memset(&ar, 0, sizeof (struct xarpreq)); + if (if_indextoname(inIfindex, ar.xarp_ha.sdl_data) == NULL) { + syslog(LOG_ERR, "if_indextoname returned NULL\n"); + return ((-1) * errno); + } + + ar.xarp_flags = ATF_PERM; + ((struct sockaddr_in *)&ar.xarp_pa)->sin_addr.s_addr = vaddr; + ((struct sockaddr_in *)&ar.xarp_pa)->sin_family = AF_INET; + + (void) memcpy(ether.ether_addr_octet, slla, ETHERADDRL); + etheraddr = ether_ntoa(ðer); + mipverbose(("Deleting temporary ARP entry for visitor %s," + " hardware address %s on interface %s [index %d]\n", + ntoa(vaddr, addrstr1), etheraddr, ar.xarp_ha.sdl_data, inIfindex)); + ar.xarp_ha.sdl_nlen = strlen(ar.xarp_ha.sdl_data); + ar.xarp_ha.sdl_family = AF_LINK; + + /* + * Delete an ARP entry in the ARP cache + */ + val = ioctl(ioctl_sockid, SIOCDXARP, (caddr_t)&ar); + + if (val < 0) + return ((-1) * errno); + else + return (0); +} + +/* + * Function: CreateListOfExistingIntfce + * This function stores a list of existing interfaces into a + * static interface entry table when the mipagent is started. + * The existing interface list does not include any IPv6, + * loopback and logical interfaces. + * Return value : 0 on success, -1 on failure + */ +int +CreateListOfExistingIntfce(void) { + struct lifnum lifn; + struct lifconf lifc; + struct lifreq lifr; + struct lifreq *lifrp; + int numifs; + int bufsize; + int iocsock; + int n; + char *buf; + StaticIfaceEntry *ifce_ptr; + StaticIfaceEntry *saveptr = NULL; + + iocsock = socket(AF_INET, SOCK_DGRAM, 0); + if (iocsock < 0) { + syslog(LOG_ERR, "Can't open IOCTL socket: %m"); + return (-1); + } + + lifn.lifn_family = AF_INET; + lifn.lifn_flags = 0; + if (ioctl(iocsock, SIOCGLIFNUM, (char *)&lifn) < 0) { + syslog(LOG_ERR, "SIOCGLIFNUM failed: %m"); + return (-1); + } + numifs = lifn.lifn_count; + bufsize = numifs * sizeof (struct lifreq); + buf = malloc(bufsize); + if (buf == NULL) { + syslog(LOG_ERR, + "Can't create existing interface list: Out of memory: %m"); + return (-1); + } + + lifc.lifc_family = AF_INET; + lifc.lifc_flags = 0; + lifc.lifc_len = bufsize; + lifc.lifc_buf = buf; + if (ioctl(iocsock, SIOCGLIFCONF, (char *)&lifc) < 0) { + syslog(LOG_ERR, + "Can't get existing system interface configuration: %m"); + free(buf); + return (-1); + } + + + StaticIntfaceHead = NULL; + lifrp = lifc.lifc_req; + for (n = lifc.lifc_len / sizeof (struct lifreq); n > 0; n--, lifrp++) { + (void) strncpy(lifr.lifr_name, lifrp->lifr_name, + sizeof (lifr.lifr_name)); + if (strchr(lifr.lifr_name, ':') != NULL) + continue; + if (ioctl(iocsock, SIOCGLIFFLAGS, (char *)&lifr) < 0) { + syslog(LOG_ERR, + "Can't get flag information for %s: %m", + lifr.lifr_name); + continue; + } + if (lifr.lifr_flags & IFF_LOOPBACK) + continue; + /* Create or add interface list */ + ifce_ptr = (struct staticIface *) + malloc(sizeof (struct staticIface)); + if (ifce_ptr == NULL) { + syslog(LOG_ERR, + "malloc: Can't create existing interface list: %m"); + free(buf); + return (-1); + } + (void) strncpy(ifce_ptr->ifacename, lifr.lifr_name, + sizeof (lifr.lifr_name)); + if (StaticIntfaceHead == NULL) + StaticIntfaceHead = ifce_ptr; + if (saveptr != NULL) { + saveptr->next = ifce_ptr; + } + ifce_ptr->next = NULL; + saveptr = ifce_ptr; + } + (void) close(iocsock); + free(buf); + return (0); +} + +/* + * This function returns true or false based on matching entries + * from StaticIfaceEntry list + */ +boolean_t +existingStaticInterface(const char *ifname) { + struct staticIface *Sptr; + + Sptr = StaticIntfaceHead; + while (Sptr != NULL) { + if (strcmp(Sptr->ifacename, ifname) == 0) { + mipverbose(("existingStaticInterface:" + "Found a static existing entry\n")); + return (_B_TRUE); + } + Sptr = Sptr->next; + } + return (_B_FALSE); +} diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agentKernelIntfce.h b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agentKernelIntfce.h new file mode 100644 index 0000000000..a8637098e1 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agentKernelIntfce.h @@ -0,0 +1,73 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999-2001 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ifndef _AGENTKERNELINTERFACE_H +#define _AGENTKERNELINTERFACE_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Prototypes for routines that interface with routing + * engine and tunnel driver. + */ + +#include <sys/sockio.h> +#include <net/if_arp.h> +#include <net/if_dl.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define ETHER_STR_LEN 18 + +#define ADDRT 1 +#define DELRT 0 + + +#define routeadd(dst, gw, insrc, in_if, out_if) \ + routemodify(dst, gw, insrc, in_if, out_if, ADDRT) +#define routedel(dst, gw, insrc, in_if, out_if) \ + routemodify(dst, gw, insrc, in_if, out_if, DELRT) + +int encapadd(ipaddr_t, ipaddr_t, uint32_t, uint8_t); +int encaprem(ipaddr_t); +int decapadd(ipaddr_t, ipaddr_t); +int decaprem(ipaddr_t, ipaddr_t); +int arpadd(ipaddr_t, unsigned char *, unsigned int); +int arpdel(ipaddr_t); +int arprefresh(HaMobileNodeEntry *, ipaddr_t); +int routemodify(ipaddr_t, ipaddr_t, ipaddr_t, int, int, unsigned int); +int getEthernetAddr(char *, unsigned char *); +int getIfaceInfo(char *, ipaddr_t *, ipaddr_t *, uint64_t *, uint32_t *); +boolean_t MipTunlEntryLookup(void *, uint32_t, uint32_t, uint32_t); +boolean_t existingStaticInterface(const char *); + +#ifdef __cplusplus +} +#endif + +#endif /* _AGENTKERNELINTERFACE_H */ diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agentNet.c b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agentNet.c new file mode 100644 index 0000000000..defae18ba6 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agentNet.c @@ -0,0 +1,2035 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 1999-2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * file: agentNet.c + * + * This file contains all routines used to interact with the + * network, such as reading and writing. + * + * This file also contains the event dispatcher, which submits + * packets for processing to a pool of threads. + */ + +#include <stdio.h> +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> +#include <sys/socket.h> +#include <sys/fcntl.h> +#include <sys/poll.h> +#include <sys/sockio.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_icmp.h> +#include <netinet/udp.h> +#include <arpa/inet.h> +#include <net/route.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <syslog.h> +#include <assert.h> +#include <ctype.h> +#include <fcntl.h> + +#include "mip.h" +#include "agent.h" +#include "thq.h" +#include "setup.h" +#include "agentKernelIntfce.h" + +#define MIN_IP_HDR_LEN 20 +#define INFTIM -1 + +/* + * The following is the max number of Message Headers we will + * allocate in a single chunk. The bigger the value, the more + * memory we allocate, the smaller, the more often we malloc(). + */ +#define MAX_MSG_HDR_NUM 512 + +#define MIP_MAX_THREADS 64 +#define MIP_MIN_THREADS 4 + + +static char *ifTypeName[] = { + "Unicast", + "Broadcast", + "Multicast" +}; + +static tqTp messageQueue = NULL; +static rwlock_t msgQueueLock; +static MessageHdr *msgHdrQueue = NULL; +static int allocatedMsgHdr = 0; +static pthread_t dispatchThreadId = 0; +static pthread_t DynamicThreadId = 0; +static fd_set saved_fdvec; +static struct rt_msghdr *rt_msg; +static struct if_msghdr *ifm; +static int ioc_sock; + +/* Counters common to all Mobility Agents */ +extern CommonCounters commonCounters; + +/* Foreign Agent specific data structures. */ +extern struct hash_table faVisitorHash; +extern ForeignAgentCounters faCounters; + +extern int logVerbosity; +extern struct hash_table maAdvConfigHash; +extern boolean_t faBusy; +extern int visitorEntryHighWaterMark; +extern int visitorEntryLowWaterMark; + +static int lookup_existing_entries(ushort_t, ipaddr_t); +static void *processMsgHdr(); +static void *getAndDispatchNetworkPacket(void); +static void *doDynamicInterfaceProcess(void *); +static void process_rtsock_msg(int); +static void processIncomingMessage(HashTable *, fd_set *); +static void *find_ancillary(struct msghdr *msg, int cmsg_type); +static void delmaAdvConfigEntry(uint32_t); +static DynamicIfaceTypeEntry *match_dynamic_table(char *); + +extern char *ntoa(uint32_t, char *); +extern void maSendAdvertisement(MaAdvConfigEntry *entry, ipaddr_t dst, + int advType, boolean_t faBusy); +extern void FAprocessRegRequest(MessageHdr *, MaAdvConfigEntry *, ipaddr_t *); +extern void HAprocessRegRequest(MessageHdr *, MaAdvConfigEntry *, ipaddr_t *); +extern void FAprocessRegReply(MessageHdr *, MaAdvConfigEntry *); + +extern void rejectFromICMPToMN(MessageHdr *, ipaddr_t, int); + +extern void HAdispatchRadius(MessageHdr *messageHdr, MaAdvConfigEntry *entry, + ipaddr_t *inAddr); + +/* + * Function: AllocateMessageHdrBlock + * + * Arguments: + * + * Description: This function will pre-allocate a block of + * MAX_MSG_HDR_NUM Message Control Blocks. + * + * Returns: int - 0 if successful. + */ +static boolean_t +AllocateMessageHdrBlock() +{ + MessageHdr *messageHdr; + int i; + + /* + * Now we create the message control blocks... + */ +#if 0 + msgHdrQueue = (MessageHdr *)calloc(1, sizeof (MessageHdr) * + MAX_MSG_HDR_NUM); +#else + msgHdrQueue = (MessageHdr *)calloc(MAX_MSG_HDR_NUM, + sizeof (MessageHdr)); +#endif + + if (msgHdrQueue == NULL) { + syslog(LOG_CRIT, "Unable to allocate message header queue"); + return (_B_TRUE); + } + + for (i = 0, messageHdr = msgHdrQueue; i < MAX_MSG_HDR_NUM; i++) { + messageHdr->next = messageHdr + 1; + } + messageHdr->next = NULL; + + return (_B_FALSE); +} + +/* + * Function: AllocateMessageHdr + * + * Arguments: + * + * Description: This function will return one of the Message + * Control Blocks from the queue. If none are + * available, we will attempt to allocate another + * chunk of control blocks. + * + * Returns: Pointer to Messge Control Block. NULL if failed. + */ +MessageHdr * +AllocateMessageHdr() +{ + MessageHdr *messageHdr = NULL; + + /* + * Lock the queue + */ + (void) rw_wrlock(&msgQueueLock); + + /* + * If there are no items on the queue, we will try to allocate + * another chunk. + */ + if (msgHdrQueue == NULL) { + if (AllocateMessageHdrBlock()) { + syslog(LOG_CRIT, "Unable to allocate more message queues"); + return (NULL); + } + } + + /* + * Now get the message header to return + */ + messageHdr = msgHdrQueue; + msgHdrQueue = msgHdrQueue->next; + allocatedMsgHdr++; + + /* + * Unlock the queue + */ + (void) rw_unlock(&msgQueueLock); + + /* + * Initialize the NAI stuff in the message header. + */ + messageHdr->mnNAILen = 0; + messageHdr->mnNAI = NULL; + + messageHdr->faNAILen = 0; + messageHdr->faNAI = NULL; + + messageHdr->dontDeleteNow = _B_FALSE; + +#ifdef KEY_DISTRIBUTION + /* + * KEY_DISTRIBUTION MUST ONLY BE COMPILED FOR TESTING!!! + * + * This version of mipagent supports a AAA/DIAMETER + * 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. + * + * Since DIAMETER/AAA is not currently a product, and key + * 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. + */ + messageHdr->mnHaKeyLen = 0; + messageHdr->mnFaKeyLen = 0; + messageHdr->faHaKeyLen = 0; + messageHdr->kdcKeysPresent = _B_FALSE; +#endif /* KEY_DISTRIBUTION */ + return (messageHdr); +} + +/* + * Function: FreeMessageHdr + * + * Arguments: messageHdr - Pointer to a pointer to a + * Message Control Block + * + * Description: Puts a Message Control Block back on the + * free list. + * + * Returns: + */ +void +FreeMessageHdr(MessageHdr *messageHdr) +{ + /* + * When FA uses Radius to authenticate the RegReq, it sends a reg + * to Radius server and waits for the reply. Meanwhile, we want to + * preserve the messageHdr, because FA is going to need it. So, + * let's prevent messageHdr from being deleted, until FA is done and + * it explicitely calls FreeMessageHdr() with dontDeleteNow == FALSE + */ + if (messageHdr->dontDeleteNow) + return; + + /* Free up faNAI space malloc-ed in aaa.c */ + if (messageHdr->faNAI != NULL) + free(messageHdr->faNAI); + /* + * Lock and put the item back on the queue + */ + (void) rw_wrlock(&msgQueueLock); + messageHdr->next = msgHdrQueue; + msgHdrQueue = messageHdr; + allocatedMsgHdr--; + (void) rw_unlock(&msgQueueLock); +} + +/* + * Function: startDispatcherTaskThread + * + * Arguments: + * + * Description: This function will allocate the thread queue, + * which is used to dispatch objects to be processed + * by threads created by the thread management module + * (thq.c). The function will also allocate the initial + * chunk of MAX_MSG_HDR_NUM Message Control Blocks and + * start the dispatching thread. + * + * Returns: int - 0 if successful. + */ +int +startDispatcherTaskThread(void) +{ + pthread_attr_t pthreadAttribute; + int result; + + messageQueue = tq_alloc(processMsgHdr, NULL, + (void *) NULL, NULL, MIP_MAX_THREADS, MIP_MIN_THREADS, FALSE); + + if (!messageQueue) { + syslog(LOG_CRIT, "Unable to create thread queue"); + return (-1); + } + + (void) rw_wrlock(&msgQueueLock); + + if (AllocateMessageHdrBlock()) { + (void) rw_unlock(&msgQueueLock); + syslog(LOG_CRIT, "Unable to allocate message Queues"); + tq_shutdown(messageQueue, 1); + return (-1); + } + + (void) rw_unlock(&msgQueueLock); + + result = pthread_attr_init(&pthreadAttribute); + + if (result) { + syslog(LOG_CRIT, "Error Initializing pthread."); + tq_shutdown(messageQueue, 1); + return (-1); + } + + /* + * We now create a thread to deal with all periodic task. + */ + result = pthread_create(&dispatchThreadId, &pthreadAttribute, + (void *(*)()) getAndDispatchNetworkPacket, + (void *)NULL); + + if (result) { + syslog(LOG_CRIT, "pthread_create() failed."); + tq_shutdown(messageQueue, 1); + return (-1); + } + + /* + * In order for system resources to be properly cleaned up, + * we need to detach the thread. Otherwise, we need to wait for + * a pthread_join(), which we do not want. + */ + result = pthread_detach(dispatchThreadId); + + if (result) { + syslog(LOG_CRIT, "pthread_detach() failed."); + (void) pthread_cancel(dispatchThreadId); + tq_shutdown(messageQueue, 1); + return (-1); + } + + return (0); +} + +/* + * Function: killDispatcherTaskThread + * + * Arguments: + * + * Description: This function is used to kill the dispatch thread, + * the threads that are created by the thread queue + * management sub-system as well as the thread queue. + * + * Returns: int - 0 if sucessful. + */ +int +killDispatcherTaskThread() +{ + int result; + + if (dispatchThreadId) { + /* + * Next we need to kill the dispatching thread. + */ + result = pthread_cancel(dispatchThreadId); + + if (result) { + /* + * Well, there's not much we can do here.. + */ + syslog(LOG_CRIT, "Unable to kill dispatching thread"); + } + } + + if (messageQueue) { + /* + * First we kill all of the message handling threads. + */ + tq_shutdown(messageQueue, 1); + } + + return (0); +} + +/* + * Function: startDynamicInterfaceThread + * Arguments: None + * Description: + * This function is called only when + * the configuration file indicates dynamic interface + * and DynamicInterface variable is true. + * + * Returns 0 on success. + */ +int +startDynamicInterfaceThread(void) +{ + pthread_attr_t pthreadAttribute; + int result; + + result = pthread_attr_init(&pthreadAttribute); + + if (result != 0) { + syslog(LOG_CRIT, "Error Initializing pthread: %m"); + return (-1); + } + + /* + * We now create a thread to deal with processing new interfaces + */ + result = pthread_create(&DynamicThreadId, &pthreadAttribute, + doDynamicInterfaceProcess, NULL); + + if (result != 0) { + syslog(LOG_CRIT, "pthread_create() failed: %m"); + 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. + */ + result = pthread_detach(DynamicThreadId); + + if (result != 0) { + syslog(LOG_CRIT, "pthread_detach() failed: %m"); + return (-1); + } + + return (0); +} + + + +/* + * Function: killDynamicInterfaceThread + * Arguments: + * Description: This function is used for thread cleanup + * Returns 0 on success + */ +int +killDynamicInterfaceThread(void) +{ + int result; + + if (DynamicThreadId) { + /* + * Next we need to kill the dispatching thread. + */ + result = pthread_cancel(DynamicThreadId); + + if (result != 0) { + /* + * Well, there's not much we can do here.. + */ + syslog(LOG_CRIT, "Unable to kill Dynamic thread: %m"); + return (-1); + } + DynamicThreadId = 0; + } + return (0); +} + +/* + * Function: dispatchMsgToThread + * + * Arguments: messageHdr - Pointer to a pointer to a + * Message Control Block + * + * Description: This function will submit a Message Control + * Block for processing to a child thread using + * the thread management sub-system. + * + * Returns: int - 0 if successfully dispatched to thread. + */ +int +dispatchMsgToThread(MessageHdr **messageHdr) +{ + + if (*messageHdr == NULL) { + return (-1); + } + + if (tq_queue(messageQueue, *messageHdr)) { + syslog(LOG_CRIT, "Unable to dispatch message to thread"); + return (-1); + } + + /* + * Since we've queued the packet for a thread, we will + * NULL out the pointer so that it does not get re-used. + */ + *messageHdr = NULL; + + return (0); +} + + +/* + * Function: sendUDPmessage + * + * Arguments: sock - Socket + * pkt - Packet to send + * pktLen - packet Length + * dst - Destination IP Address + * dstPort - Destination IP Port + * + * Description: Send a UDP message from sock, to dst address and port + * dstPort. The pkt is contained in pkt and is of length + * pktLen. dst is already in network byte order. + * + * Returns: + */ +int +sendUDPmessage(int sock, unsigned char *pkt, int pktLen, + ipaddr_t dst, in_port_t dstPort) +{ + struct sockaddr_in sa; + + sa.sin_family = AF_INET; + sa.sin_port = htons(dstPort); + sa.sin_addr.s_addr = dst; + + /* send the message */ + if (sendto(sock, (char *)pkt, pktLen, 0, (struct sockaddr *)&sa, + sizeof (struct sockaddr_in)) < 0) { + syslog(LOG_ERR, "sendto() Sendto failed in sendUDPmessage."); + return (-1); + } + + return (0); +} + +/* + * Function: sendICMPmessage + * + * Arguments: s - socket + * dst - Destination Address + * data - Data to send + * len - length of data to send + * + * Description: Send an ICMP message contained in data to dst + * from src + * + * Returns: + */ +void +sendICMPmessage(int s, ipaddr_t dst, + unsigned char data[], int len) +{ + struct sockaddr_in sa; + + sa.sin_family = AF_INET; + sa.sin_port = 0; + sa.sin_addr.s_addr = dst; + + /* send the message */ + if (sendto(s, (char *)data, len, 0, (struct sockaddr *)&sa, + sizeof (struct sockaddr_in)) < 0) { + syslog(LOG_ERR, "sendto() Sendto failed in sendICMPmessage."); + } +} + + +/* + * Function: screenICMPpkt + * + * Arguments: messageHdr - Pointer to a Message Control Block + * + * Description: Pkt contains a complete IP datagram(including IP + * header) received on a socket monitoring ICMP packets. + * + * Returns: + */ +static void +screenICMPpkt(MessageHdr *messageHdr) +{ + icmph *icmpPtr; + struct ip *ipPtr, *inneripPtr; /* ICMPs outer and inner IP headers */ + struct udphdr *innerudpPtr; /* perchance the innerIP is UDP */ + char addrstr1[INET_ADDRSTRLEN]; + char addrstr2[INET_ADDRSTRLEN]; + uint16_t ipHdrLen, iError; + ipaddr_t *ipDst; + + if (messageHdr->pktLen < sizeof (struct ip) + sizeof (icmph)) { + syslog(LOG_ERR, "ICMP Packet received too small"); + return; + } + + /* LINTED E_BAD_PTR_CAST_ALIGN */ + ipPtr = (struct ip *)&messageHdr->pkt; + + ipHdrLen = (uint16_t)(ipPtr->ip_hl << 2); + + if (messageHdr->pktLen < ipHdrLen + sizeof (icmph)) { + syslog(LOG_ERR, "Packet received is smaller than reported"); + return; + } + + /* LINTED E_BAD_PTR_CAST_ALIGN */ + icmpPtr = (icmph *)((char *)messageHdr->pkt + ipHdrLen); + + ipDst = (ipaddr_t *)&ipPtr->ip_dst; + + /* + * Note: we don't have to check the ICMP size, and/or the ICMP + * checksum because the kernel takes care of this. As far as dst + * addr goes, the understanding is traffic is checked for forwarding + * before the kernel's parser mechanism gets it for passing up. + */ + + if (icmpPtr->type == ICMP_ROUTERSOLICIT) { + mipverbose(( + "Got ICMP solicitation <type %d, code %d> from %s to %s.\n", + icmpPtr->type, icmpPtr->code, + ntoa(messageHdr->src, addrstr1), + ntoa(*ipDst, addrstr2))); + + if (icmpPtr->code == 0) { + /* Currently, the only code for type 10 solicits. */ + commonCounters.maSolicitationsRecvdCnt++; + + /* + * Restrict advertisement to the particular interface + * on which the solicitation was received. + */ + if (((messageHdr->ifEntry->maIfaceFlags & + IFF_POINTOPOINT) == 0) || + (messageHdr->src == INADDR_ANY)) { + /* + * Since we don't have ARP information at this + * point, advertise on Bcast or Mcast addr. + */ + maSendAdvertisement(messageHdr->ifEntry, + messageHdr->ifEntry->maAdvAddr, + SOLICITED_ADV, faBusy); + } else { + /* + * Solicitation from PPP interface with a + * non-zero source address. + */ + maSendAdvertisement(messageHdr->ifEntry, + messageHdr->src, SOLICITED_ADV, faBusy); + } + + /* + * should actually be manipulated inside + * maSendAdvertisement() + */ + commonCounters.maAdvSentForSolicitationsCnt++; + } + + /* There can be only one reason we're in here, so we're done. */ + return; + } + + /* + * If this ICMP is in response to a forwarded registration request, + * the IP dst addr should be ours... + */ + if (ipPtr->ip_dst.s_addr != messageHdr->ifEntry->maIfaceAddr) { + /* not for us */ + return; + } + + /* + * A response to a packet we sent, check if it's a undelivered regreQ. + * We'd better have gotten enough for a returned UDP header. + */ + if (messageHdr->pktLen < sizeof (struct ip) + sizeof (icmph) + + sizeof (struct udphdr)) { + /* if we can't get to the udp port info, we can't continue */ + syslog(LOG_ERR, + "Recieved ICMP error allegedly for a packet we sent," + " but it's too small to do anything with!\n"); + return; + } + + /* + * Note: the belief is before the kernel sends up the ICMP, it's + * checked things like length, checksum, etc. + */ + + /* It's time to look at the returned IP packet. */ + inneripPtr = (struct ip *)(icmpPtr+1); + + /* We should be the sender of the inner packet */ + if (inneripPtr->ip_src.s_addr != messageHdr->ifEntry->maIfaceAddr) { + /* We're not responsible for sending that packet */ + return; + } + + /* UDP? */ + if (inneripPtr->ip_p != IPPROTO_UDP) { + /* protocol in returned IP header isn't UDP - <zap> */ + return; + } + + /* OK, the encased IP packet allegedly carries UDP info - go there */ + ipHdrLen = (uint16_t)(inneripPtr->ip_hl << 2); + /* LINTED E_BAD_PTR_CAST_ALIGN */ + innerudpPtr = (struct udphdr *)((char *)inneripPtr + ipHdrLen); + + /* + * Swapping madness for the port value because this piece is RAW off + * the network. Note: htons() is a no-op on SPARC. + */ + if (htons(innerudpPtr->uh_dport) != MIP_PORT) { + /* dst port of returned UDP packet isn't MIP_PORT <zzzt>. */ + return; + } + + + /* + * Looks like we were returned a UDP packet to port 434, so lets + * find out why delivery failed, then let the mobile node know. + * + * There are two reasons we could be geting an ICMP unreachable. The + * most obvious comes from bad addresses, but another possibility is + * the simple timeout. + */ + if (icmpPtr->type == ICMP_UNREACH) { + + /* All that info implies it was for something we sent out */ + mipverbose(( + "Received ICMP error in response to regreQ from MN: ")); + mipverbose(("Type: UNREACH, ICMPcode: %d.", icmpPtr->code)); + + /* The error to the MN is based on the ICMP code... */ + switch (icmpPtr->code) { + case ICMP_UNREACH_NET: + case ICMP_UNREACH_NET_UNKNOWN: + case ICMP_UNREACH_NET_PROHIB: + /* return error 80 home network unreachable */ + mipverbose(("Home Network Unreachable.\n")); + iError = FA_HA_NET_UNREACHABLE; + break; + + case ICMP_UNREACH_HOST: + case ICMP_UNREACH_HOST_UNKNOWN: + case ICMP_UNREACH_HOST_PROHIB: + /* return error 81 home agent host unreachable */ + mipverbose(("Home Agent IP Unreachable.\n")); + iError = FA_HA_HOST_UNREACHABLE; + break; + + case ICMP_UNREACH_PORT: + /* return error 82 home agent port unreachable */ + mipverbose(("Home Agent Port Unreachable.\n")); + iError = FA_HA_PORT_UNREACHABLE; + break; + + case ICMP_UNREACH_ISOLATED: + case ICMP_SOURCEQUENCH: + /* + * Notes for the case of sourceQuench - the packet + * was lost somewhere (what else can we assume?) + * Two choices: send an unreachable error to the + * MN, or resend the registration request, but it's + * NOT contained in the ICMP error message. If it + * cares, the MN will regenerate, perhaps to a + * fallback HA. + * + * Return error 88 home agent unreachable. + */ + mipverbose(("Home Agent Unreachable.\n")); + iError = FA_HA_UNREACHABLE; + break; + + default: + /* + * E.g. ICMP_UNREACH_PROTOCOL, ICMP_UNREACH_NEEDFRAG, + * ICMP_UNREACH_SRCFAIL - catch them here (OK, the last + * two are a bit of a reach). Also, anything "new" to + * ICMP will have to return something generic for now. + * + * Return error 88 home agent unreachable. + */ + mipverbose(("Unreachable default:" + " Home Agent Unreachable.\n")); + iError = FA_HA_UNREACHABLE; + break; + + } /* switch(icmpPtr->code) */ + + /* bump our counters */ + faCounters.faRegRepliesICMPUnreachCnt++; + + /* only one ICMP type, so... */ + (void) rejectFromICMPToMN(messageHdr, + inneripPtr->ip_dst.s_addr, iError); + + /* There can be only one reason, we're done */ + return; + } + + /* Don't forget timeouts */ + if (icmpPtr->type == ICMP_TIMXCEED) { + mipverbose(( + "Received ICMP error in response to regreQ from MN: ")); + + mipverbose(("Type: TIMEOUT, ICMPcode: %d.", icmpPtr->code)); + + /* The error is based on the ICMP message... */ + switch (icmpPtr->code) { + case ICMP_TIMXCEED_INTRANS: + case ICMP_TIMXCEED_REASS: + mipverbose(("timeout-88: Home Agent Unreachable.\n")); + iError = FA_HA_UNREACHABLE; + break; + + default: + /* Not the format of an ICMP_TIMXCEED, but still... */ + mipverbose(("timeout: default" + "88: Home Agent Unreachable.\n")); + iError = FA_HA_UNREACHABLE; + break; + } + + /* bump our counters */ + faCounters.faRegRepliesICMPTimxceedCnt++; + + /* only one reason to reject... */ + (void) rejectFromICMPToMN(messageHdr, + inneripPtr->ip_dst.s_addr, iError); + } + + /* + * Think: ICMP_REDIRECT{NET,HOST,TOSNET,TOSHOST} should be handled + * in-stack before we see it. ^^^^^^ ^^^^^^^ + */ + + /* If we made it here, we don't care about this ICMP type; done... */ + return; + +} /* screenICMPpkt() */ + + +/* + * Function: screenUDPpkt + * + * Arguments: messageHdr - Pointer to a Message Control Block + * + * Description: Pkt contains a complete UDP datagram received on + * a socket monitoring UDP packets. + * + * Returns: + */ +static void +screenUDPpkt(MessageHdr *messageHdr) +{ + regRequest *regReqPtr; + unsigned char *cp; + char addrstr1[INET_ADDRSTRLEN]; + char addrstr2[INET_ADDRSTRLEN]; + ipaddr_t inAddr; + boolean_t ha_match, fa_match; + boolean_t is_ha, is_fa; + + switch (messageHdr->ifType) { + case ON_UNICAST_SOCK: + inAddr = messageHdr->ifEntry->maIfaceAddr; + break; + + case ON_MCAST_SOCK: + inAddr = inet_addr(LINK_MCAST_REG_ADDR); + break; + + case ON_BCAST_SOCK: + inAddr = GENERATE_NET_BROADCAST_ADDR(messageHdr->ifEntry); + break; + default: + syslog(LOG_ERR, "screenUDPpkt: Unknown socket type \n"); + break; + + } + + cp = messageHdr->pkt; + + switch (*cp) { + + case REG_REQUEST_TYPE: + + if (messageHdr->pktLen < sizeof (regRequest)) { + syslog(LOG_ERR, "Received registration request is " \ + "too short."); + return; + } + /* LINTED E_BAD_PTR_CAST_ALIGN */ + regReqPtr = (regRequest *) messageHdr->pkt; + + /* + * Here is what we need to do. If the Home Agent Address + * matches our interface address, or the packet is a broadcast, + * then we process it as a Home Agent. However, if the packet's + * care of address matches our address, or if it is a + * multicast, then we process the packet as a Foreign Agent. + */ + is_ha = (messageHdr->ifEntry->maAdvServiceFlags & + ADV_IS_HOME_AGENT); + ha_match = (is_ha && ((regReqPtr->haAddr == inAddr) || + (messageHdr->ifType == ON_BCAST_SOCK))); + + is_fa = (messageHdr->ifEntry->maAdvServiceFlags & + ADV_IS_FOREIGN_AGENT); + fa_match = (is_fa && ((regReqPtr->COAddr == inAddr) || + (messageHdr->ifType == ON_MCAST_SOCK))); + + mipverbose(("req.haddr=0x%08x, inAddr=0x%08x, coAddr=0x%08x, ", + regReqPtr->haAddr, inAddr, regReqPtr->COAddr)); + mipverbose(("HAFlag = %d, FAFlag = %d, ", is_ha ? 1 : 0, + is_fa ? 1 : 0)); + if (ha_match) + mipverbose((" we are *the* HA\n")); + if (fa_match) + mipverbose((" we are *the* FA\n")); + + /* + * Check out the matching criterias to determine if we are + * acting as the HA or FA for this request. If we match the + * request as the HA, process it as HA. If we match the request + * as the FA, process it as FA. In case we are acting as HA but + * the request doesn't match neither our HA nor FA, let's go + * ahead and process this request as an HA and deny it. + * Similarly, in case we are acting as FA but the request + * doesn't match neither our FA nor HA, let's go ahead and + * process this request as an FA and deny it. + */ + if (messageHdr->pktSource == MIP_PKT_FROM_RADIUS) { + /* + * This occurs when the HA address in the registration + * request is invalid, which occurs when AAA is used + * and the Home Agent's address is set to either zero + * or 0xffffffff in the registration Request. In this + * case, we need to update the Home Agent's address + * in the Registration Reply. + * + * MIP_PKT_FROM_RADIUS is Radius specific. In this + * case a call is made to HAprocessRegRequestRadius. + */ + regReqPtr->haAddr = messageHdr->ifEntry->maIfaceAddr; + (void) HAdispatchRadius(messageHdr, + messageHdr->ifEntry, &inAddr); + } else if (fa_match || (is_fa && !ha_match)) { + /* process as FA */ + FAprocessRegRequest(messageHdr, messageHdr->ifEntry, + &inAddr); + } else if (ha_match || (is_ha && !fa_match)) { + /* process as HA */ + HAprocessRegRequest(messageHdr, messageHdr->ifEntry, + &inAddr); + } else if (messageHdr->pktSource == MIP_PKT_FROM_AAA) { + /* + * MIP_PKT_FROM_AAA - for all other aaa protocols. + * This also occurs when the HA address in the reg + * request is invalid, which occurs when AAA is used + * and the Home Agent's address is set to either zero + * or 0xffffffff in the registration Request. In this + * case, we need to update the Home Agent's address + * in the Registration Reply. + */ + regReqPtr->haAddr = messageHdr->ifEntry->maIfaceAddr; + HAprocessRegRequest(messageHdr, messageHdr->ifEntry, + &inAddr); + } else { + syslog(LOG_ERR, + "Not configured to handle this reg req on addr " \ + "%s from %s.", + ntoa(inAddr, addrstr1), ntoa(messageHdr->src, + addrstr2)); + } + break; + + case REG_REPLY_TYPE: + if (messageHdr->pktLen < sizeof (regReply)) { + syslog(LOG_ERR, "Received registration reply is too " \ + "short."); + return; + } + FAprocessRegReply(messageHdr, messageHdr->ifEntry); + break; + + default: + syslog(LOG_ERR, + "Unknown UDP message (first byte 0x%x) from %s.", + *cp, ntoa(messageHdr->src, addrstr1)); + } +} + +/* + * Function: processMsgHdr + * + * Description: This is the child thread that is called by + * the thread management sub-system to handle + * a specific Message Control Block. This function + * will remain in a while loop waiting for messages + * to handle. + * + * This function never returns, but can be killed by + * another thread calling tq_shutdown(). + * + * Returns: void pointer of NULL. Note this is not really necessary, + * but makes thq.c/h prototypes happy. + */ +static void * +processMsgHdr() +{ + MessageHdr *messageHdr; + + /* + * Main while loop... should never exit + */ + /* CONSTCOND */ + while (_B_TRUE) { + messageHdr = (MessageHdr *) tq_dequeue(messageQueue, 0); + + if (messageHdr == NULL) + continue; + + switch (messageHdr->pktType) { + case PKT_UDP: + screenUDPpkt(messageHdr); + break; + case PKT_ICMP: + screenICMPpkt(messageHdr); + break; + default: + syslog(LOG_ERR, "processMsgHdr: Unknown Pkt type\n"); + break; + } + + FreeMessageHdr(messageHdr); + } + + return (NULL); +} + + +/* + * Function: getAndDispatchNetworkPacket + * + * Arguments: + * + * Description: This is the main dispatch thread. This + * function has two main functions. First it will + * use select to determine if any data has been + * received on our sockets. Second, the select + * function is called with a timeout, which is + * used to determine when we need to send router + * advertisements. + * + * This function never returns, but will be killed + * if killDispatcherTaskThread() is called. + * + * Returns: + */ +static void * +getAndDispatchNetworkPacket() +{ + int i, nentry; + int result; + static fd_set fdvec; + static struct timeval tv; + time_t nextAdvTime = 0; + time_t currentTime; + time_t lowestNextAdvTime = 0; + struct hash_table *htbl; + MaAdvConfigEntry *entry; + struct hash_entry *p; + + htbl = &maAdvConfigHash; + + /* + * Setup the initial advertisement time. + */ + GET_TIME(currentTime); + nextAdvTime = currentTime; + + /* + * We will save the file descriptor vector for future use. + * This saves us the trouble of having to skip through the + * while interface entry each time. + * + * NOTE: Since this block of code is called during initial static + * interface configuration, we do not need to lock the config + * entries here as the sequence at startup is startDispatcherTaskThread + * followed by startDynamicInterfaceThread. + */ + for (i = 0, nentry = 0; + i < HASH_TBL_SIZE && (nentry < htbl->size); i++) { + p = htbl->buckets[i]; + while (p != NULL) { + nentry++; + entry = (MaAdvConfigEntry *)p->data; + FD_SET(entry->maIfaceUnicastSock, &saved_fdvec); + if ((entry->maIfaceFlags & IFF_POINTOPOINT) == 0) { + FD_SET(entry->maIfaceDirBcastSock, + &saved_fdvec); + FD_SET(entry->maIfaceBcastSock, + &saved_fdvec); + } + FD_SET(entry->maIfaceAdvMulticastSock, &saved_fdvec); + FD_SET(entry->maIfaceRegMulticastSock, &saved_fdvec); + FD_SET(entry->maIfaceIcmpSock, &saved_fdvec); + /* Update maNextAdvtime to advertise now */ + entry->maNextAdvTime = currentTime; + p = p->next; + } + } + + for (;;) { + /* + * Take a snapshot of the file descriptors. + */ + fdvec = saved_fdvec; + + /* + * What time is it? + */ + GET_TIME(currentTime); + + /* + * Wait on select for next adv or input or when + * there is no static interface entry in the config file + */ + if ((currentTime < nextAdvTime) || (nentry == 0)) { + tv.tv_sec = nextAdvTime - currentTime; + tv.tv_usec = 0; + + /* + * Caveat: Currently, if one static/dynamic interface + * adv n sec later, then advertisement for new + * interface waits until select times out. So, in + * some cases, the first adv does not happen instantly. + * Recommended AdvFrequency is 2-3 sec for dynamic + * interfaces. + */ + result = select(FD_SETSIZE, + &fdvec, NULL, NULL, &tv); + + if (result < 0) { + if ((errno != EINTR) && (errno != ERESTART) && + (errno != EBADF)) { + /* + * EBADF can be often set + * from select in situations when + * the socket fd's corresponding + * to the dynamic interface is gone + * while select was in sleep. + * This situation can happen often + * as the connection comes and goes. + * Assuming the mipagent sets + * FD_SET correctly, at this point + * it is best not to print syslog + * error for the EBADF case to avoid + * plenty of such messages in the + * console. + */ + syslog(LOG_ERR, + "select failed with error: %m"); + } + continue; + } + + /* + * Now that we've slept, let's get our current time. + */ + GET_TIME(currentTime); + } else { + /* + * It looks like it's time to advertise, so we set + * result to zero. This will ensure that we will not + * attempt to receive a network packet. + */ + result = 0; + } + + /* + * Let's check if it is time to start advertising + */ + if (currentTime >= nextAdvTime) { + /* + * Check each entry to see if it's time for at least + * one entry to advertise. lowestNextAdvTime keeps + * track of lowest NextAdvTime value of the traversed + * entries. During eachtime we check the entries to + * advertise, lowestNextAdvTime is updated to a + * lower value if the current entry's nextAdvTime is + * lower than the nextAdvTime local variable. + */ + lowestNextAdvTime = 0; + for (i = 0, nentry = 0; + i < HASH_TBL_SIZE && (nentry < htbl->size); i++) { + p = htbl->buckets[i]; + while (p) { + nentry++; + entry = (MaAdvConfigEntry *)p->data; + (void) rw_rdlock( + &entry->maIfaceNodeLock); + if (currentTime >= + entry->maNextAdvTime) { + /* Advertise now */ + if (faVisitorHash.size <= + visitorEntryLowWaterMark) { + faBusy = _B_FALSE; + } else if (faVisitorHash.size >= + visitorEntryHighWaterMark) { + faBusy = _B_TRUE; + } + if (entry->maAdvInitCount > 0) { + maSendAdvertisement( + entry, + entry->maAdvAddr, + UNSOLICITED_ADV, + faBusy); + } + entry->maNextAdvTime = + currentTime + + entry->maAdvInterval; + } + /* + * Set next timeout equal to the minimum + * time left for next advertisement for + * an entry. The following comparison is + * true when nextAdvTime is updated by + * interval and there is another entry + * in the list which needs to advertise + * before nextAdvTime. + */ + if (entry->maAdvInitCount > 0) { + nextAdvTime = + entry->maNextAdvTime; + + if (lowestNextAdvTime == 0) { + /* First pass */ + lowestNextAdvTime = + nextAdvTime; + } + if (nextAdvTime > + lowestNextAdvTime) { + nextAdvTime = + lowestNextAdvTime; + } else { + lowestNextAdvTime = + nextAdvTime; + } + } + p = p->next; + (void) rw_unlock( + &entry->maIfaceNodeLock); + } + } + /* + * If for some reason there is no entry in the + * Confighash table and nextAdvTime was not + * updated at all, then set the nextAdvTime to + * to default value to avoid looping. This block + * can also be exercized if there is no periodic + * advertisment is done as we may have set + * AdvLimitUnsolicited to all advertising interfaces. + */ + if (currentTime >= nextAdvTime) { + nextAdvTime = currentTime + + DEFAULT_MIN_INTERVAL; + } + } else if (result > 0) { + processIncomingMessage(htbl, &fdvec); + } + } + /* LINTED E_STMT_NOT_REACHED */ + return (NULL); +} + +/* + * Function: find_ancillary + * Arguments: msg - contains the ancillary information + * cmsg_type - type of ancillary data + * Description: Return a pointer to the specified option buffer. + * If not found return NULL. + */ +static void * +find_ancillary(struct msghdr *msg, int cmsg_type) +{ + struct cmsghdr *cmsg; + + for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; + cmsg = CMSG_NXTHDR(msg, cmsg)) { + if (cmsg->cmsg_level == IPPROTO_IP && + cmsg->cmsg_type == cmsg_type) { + return (CMSG_DATA(cmsg)); + } + } + return (NULL); +} + +/* + * Function: recvNetworkPacket + * + * Arguments: socket - Socket on which data is pending + * entry - Interface on which the data is pending + * ifType - Whether the interface if UNICAST, BCAST or MCAST + * packetType - Wether the packet is UDP or ICMP + * + * Description: This function is called if data is pending + * on one of our sockets. This function will + * allocate a Messge Control Block, receive + * the data and call the function that dispatches + * the control block to a thread. + * + * Returns: + */ +static void +recvNetworkPacket(int socket, MaAdvConfigEntry *entry, uint32_t ifType, + uint32_t packetType) +{ + MessageHdr *messageHdr; + struct sockaddr_in from; + static uint64_t in_packet[(MAX_PKT_SIZE + 1)/8]; + static uint64_t ancillary_data[(MAX_PKT_SIZE + 1)/8]; + struct msghdr msg; + struct iovec iov; + uchar_t *opt; + + iov.iov_base = (char *)in_packet; + iov.iov_len = sizeof (in_packet); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_name = (struct sockaddr *)&from; + msg.msg_namelen = sizeof (from); + msg.msg_control = ancillary_data; + msg.msg_controllen = sizeof (ancillary_data); + + /* + * Allocate a Message Header. + */ + if ((messageHdr = AllocateMessageHdr()) == NULL) { + syslog(LOG_CRIT, + "Unable to allocate a message header"); + return; + } + + if ((messageHdr->pktLen = recvmsg(socket, &msg, 0)) + == (unsigned int) (-1)) { + FreeMessageHdr(messageHdr); + syslog(LOG_ERR, + "recvmsg failed for UDP on " + "%s socket...%s", ifTypeName[ifType], strerror(errno)); + } else { + unsigned char *cp; + + (void) memcpy(messageHdr->pkt, in_packet, MAX_PKT_SIZE); + + cp = messageHdr->pkt; + /* + * If it's a registration request then we need to get the + * ancillary information. + * TODO: 1. Fix this section of code to IP_RECVIF + * for ICMP packets too. + * 2. Add kernel support for IP_RECVSLLA for ICMP + * packets. This is required for response to + * unicast address for agent solicitation + */ + if ((packetType == PKT_UDP) && (*cp == REG_REQUEST_TYPE)) { + + /* + * If this is an PPP interface, don't attempt to + * get the slla. + */ + if (entry->maIfaceFlags & IFF_POINTOPOINT) { + messageHdr->isSllaValid = _B_FALSE; + } else { + /* try to extract slla from the packet */ + opt = find_ancillary(&msg, IP_RECVSLLA); + if (opt == NULL) { + syslog(LOG_ERR, + "receving IP_RECVSLLA ancillary" + "failed...%s", strerror(errno)); + /* + * IP_RECVSLLA could fail for various + * reasons: + * a> the interface is no-resolver type + * (eg PPP) + * b> kernel ran out of memory + * c> the information the driver passed + * to IP is bogus + * we could return from here but this + * info (i.e SLLA) is non-critical, so + * we don't. Instead we mark the entry + * as invalid so it's not used in the + * code. Currently the entry is used to + * prevent the FA from broadcast ARPing + */ + messageHdr->isSllaValid = _B_FALSE; + } else { + messageHdr->isSllaValid = _B_TRUE; + bcopy(opt, &messageHdr->slla, + sizeof (struct sockaddr_dl)); + } + } + + opt = find_ancillary(&msg, IP_RECVIF); + if (opt == NULL) { + syslog(LOG_ERR, "receving IP_RECVIF ancillary" + "failed"); + FreeMessageHdr(messageHdr); + return; + } + + /* LINTED BAD_PTR_CAST_ALIGN */ + messageHdr->inIfindex = *(uint_t *)opt; + + opt = find_ancillary(&msg, IP_RECVTTL); + if (opt == NULL) { + syslog(LOG_ERR, "receving IP_RECVTTL ancillary" + "failed"); + FreeMessageHdr(messageHdr); + return; + } + + messageHdr->ttl = *(uint8_t *)opt; + } else { + + /* + * Make sure they are initialized, just in case + */ + messageHdr->inIfindex = 0; + messageHdr->isSllaValid = _B_FALSE; + } + + messageHdr->src = + from.sin_addr.s_addr; + messageHdr->srcPort = + ntohs(from.sin_port); + messageHdr->ifEntry = entry; + messageHdr->ifType = ifType; + messageHdr->pktType = packetType; + messageHdr->pktSource = MIP_PKT_FROM_FA; + assert(!messageHdr->mnNAILen); + (void) dispatchMsgToThread(&messageHdr); + } +} + +/* + * Function: getFirstInterface + * + * Arguments: none + * + * Description: This function will return the first interface in the hash + * table. Todo: Pick the closest interface + * + * Returns: MaAdvConfigEntry * + */ +MaAdvConfigEntry * +getFirstInterface() +{ + HashTable *htbl; + MaAdvConfigEntry *entry; + HashEntry *p; + int i, nentry; + + /* + * for each mobility supporting interface ... + */ + htbl = &maAdvConfigHash; + + for (i = 0, nentry = 0; + i < HASH_TBL_SIZE && (nentry < htbl->size); i++) { + p = htbl->buckets[i]; + if (p) { + nentry++; + entry = (MaAdvConfigEntry *)p->data; + return (entry); + } + } + return (NULL); +} /* getFirstInterface */ + + +/* + * Function: getClosestInterfaceAddr + * + * Arguments: ipaddr_t dest + * + * Description: This routine will return the nerest interface for reaching + * the dest. (For now, it will simply lookup the ip address + * of our first mobility interface.) Todo! + * + * Returns: ipaddr_t (0 on error) + */ +ipaddr_t +/* LINTED E_FUNC_ARG_UNUSED */ +getClosestInterfaceAddr(ipaddr_t dest) +{ + MaAdvConfigEntry *entry; + + /* + * for each mobility supporting interface ... + */ + + entry = getFirstInterface(); + if (entry) + return (entry->maIfaceAddr); + else + return (0); +} /* getClosestInterfaceAddr */ + +/* + * Function: processIncomingMessage + * + * Arguments: htbl - Pointer to the Hash Table + * fdvec - Pointer to file descriptor + * + * Description: This function is called if data is pending + * on one of our sockets. This function loop + * through the interfaces looking for the socket + * on which data is pending. + * + * Returns: + */ +static void +processIncomingMessage(HashTable *htbl, fd_set *fdvec) +{ + MaAdvConfigEntry *entry; + HashEntry *p; + int i, nentry; + + /* + * for each mobility supporting interface ... + */ + htbl = &maAdvConfigHash; + + for (i = 0, nentry = 0; + i < HASH_TBL_SIZE && (nentry < htbl->size); i++) { + p = htbl->buckets[i]; + while (p) { + nentry++; + entry = (MaAdvConfigEntry *)p->data; + + /* + * process data received on ICMP socket + */ + if (FD_ISSET(entry->maIfaceIcmpSock, fdvec)) { + recvNetworkPacket(entry->maIfaceIcmpSock, + entry, ON_BCAST_SOCK, PKT_ICMP); + } + + if (FD_ISSET(entry->maIfaceAdvMulticastSock, fdvec)) { + recvNetworkPacket( + entry->maIfaceAdvMulticastSock, + entry, ON_MCAST_SOCK, PKT_ICMP); + } + + /* + * ... process data on UDP socket bound to + * unicast address + */ + if (FD_ISSET(entry->maIfaceUnicastSock, fdvec)) { + recvNetworkPacket(entry->maIfaceUnicastSock, + entry, ON_UNICAST_SOCK, PKT_UDP); + } + + /* + * mipagent doesn't listen to broadcast sockets if + * this is a PPP interface. + */ + if ((entry->maIfaceFlags & IFF_POINTOPOINT) == 0) { + /* + * ... process data on UDP socket bound to + * directed broadcast address + */ + if (FD_ISSET(entry->maIfaceDirBcastSock, + fdvec)) { + recvNetworkPacket( + entry->maIfaceDirBcastSock, + entry, ON_BCAST_SOCK, PKT_UDP); + } + + /* + * ... process data on UDP socket bound to + * broadcast address + */ + if (FD_ISSET(entry->maIfaceBcastSock, fdvec)) { + recvNetworkPacket( + entry->maIfaceBcastSock, + entry, ON_BCAST_SOCK, PKT_UDP); + } + } + + /* + * ... process data on UDP socket bound to + * multicast address + */ + if (FD_ISSET(entry->maIfaceRegMulticastSock, fdvec)) { + recvNetworkPacket( + entry->maIfaceRegMulticastSock, + entry, ON_MCAST_SOCK, PKT_UDP); + } + p = p->next; + } + } +} + + +/* + * Function: doDynamicInterfaceProcess + * Argument: + * Description: + * This process is launched by dynamic interface thread. It's purpose + * is to hang around and poll to check if any new interface comes up. + * It calls process_rtsock_msg() for any valid RTM_INFO. + * + * Returns : NULL + */ + +/* ARGSUSED */ +static void * +doDynamicInterfaceProcess(void * arg) +{ + int s; /* Routing socket id */ + int ret; + struct pollfd pollfds[1]; + + /* Open a socket to send ICOTL cmd down by rtsock_process_msg */ + ioc_sock = socket(AF_INET, SOCK_DGRAM, 0); + if (ioc_sock < 0) { + syslog(LOG_CRIT, "Can't open IOC socket: %m"); + return (NULL); + } + s = socket(PF_ROUTE, SOCK_RAW, AF_INET); + if (s == -1) { + syslog(LOG_CRIT, + "unable to open Routing socket for dynamic interface: %m"); + (void) close(ioc_sock); + return (NULL); + } + ret = fcntl(s, F_SETFL, O_NDELAY|O_NONBLOCK); + if (ret < 0) { + syslog(LOG_CRIT, + "fcntl failed on routing socket: %m"); + (void) close(ioc_sock); + (void) close(s); + return (NULL); + } + + pollfds->fd = s; + pollfds->events = POLLIN; + + for (;;) { + if (poll(pollfds, 1, INFTIM) < 0 || + (pollfds->revents & POLLERR)) { + if (errno == EINTR) + continue; + syslog(LOG_CRIT, + "Poll failed: %m"); + (void) close(s); + (void) close(ioc_sock); + return (NULL); + } + if (!pollfds->revents & POLLIN) + continue; + if (pollfds->fd == s) { + mipverbose(("doDynamicInterfaceProcess: " + "received message on RTsocket\n")); + process_rtsock_msg(s); + } + } + /* LINTED E_STMT_NOT_REACHED */ + return (NULL); /* Never reached */ +} + + +/* + * Function: process_rtsock_msg + * Argument : int + * Description : + * process_rtsock_msg processes the RTM_INFO messages. It checks + * if the flag is IFF_UP for the specified interface index. It also + * checks that this is IPV4, non-loopback, non-logical interface. It + * makes all other necessary checks before establishing the new + * interface as mobility interface. When an interface is plumbed it + * receives two RTM_IFINFO messages per interface. + */ + +static void +process_rtsock_msg(int rtsock) +{ + +#define RTSOCK_MAX_MSG 2048 + + int64_t msg[RTSOCK_MAX_MSG / sizeof (int64_t)]; + int num; + struct lifreq lifr; + ipaddr_t addr; + struct sockaddr_in *sin; + DynamicIfaceTypeEntry *d_entry; + MaAdvConfigEntry *ifentry; + uint64_t ifflags; + time_t currentTime; + + num = (int)read(rtsock, msg, sizeof (msg)); + if (num <= 0) { + /* No messages */ + return; + } + rt_msg = (struct rt_msghdr *)msg; + if (rt_msg->rtm_version != RTM_VERSION) { + syslog(LOG_CRIT, "Bad RTM version: %d", rt_msg->rtm_version); + return; + } + + if (rt_msg->rtm_type != RTM_IFINFO) + return; + + /* Now process the RTM_INFO message */ + ifm = (struct if_msghdr *)rt_msg; + mipverbose(("process_rtsock_msg: RTM_IFINFO for if_index %d\n", + ifm->ifm_index)); + + (void) memset(&lifr, 0, sizeof (struct lifreq)); + if (if_indextoname(ifm->ifm_index, lifr.lifr_name) == NULL) { + /* + * Interface unplumbed ? + * Make sure we delete any unused entry. + */ + (void) delmaAdvConfigEntry(ifm->ifm_index); + return; + } + /* Found the ifname, check if it's new */ + + if (strchr(lifr.lifr_name, ':') != NULL) { + /* We don't support logical interfaces */ + mipverbose(("process_rtsock_msg: logical interface %s\n", + lifr.lifr_name)); + return; + } + + /* + * Check if this entry belongs to any existing interfaces + * that were already configured at the time of mipagent + * startup. If any of those interfaces ifconfiged down and then + * ifconfig'ed up, we don't consider them as dynamic interface. + */ + if (existingStaticInterface(lifr.lifr_name)) + return; + + /* Check for IPv4 and multicast flag */ + if ((int)ioctl(ioc_sock, SIOCGLIFFLAGS, (char *)&lifr) < 0) { + /* Interface disappeared ? */ + mipverbose(("process_rtsock_msg: SIOCGLIFFLAGS failed\n")); + return; + } + if (!(lifr.lifr_flags & IFF_IPV4) || + !(lifr.lifr_flags & IFF_MULTICAST)) { + mipverbose(("process_rtsock_msg: flag not IPV4 MULTICAST\n")); + return; + } + + ifflags = lifr.lifr_flags; + + if (ioctl(ioc_sock, SIOCGLIFADDR, (caddr_t)&lifr) < 0) { + syslog(LOG_ERR, "Could not read IP address for" + "%s: %m", lifr.lifr_name); + return; + } + sin = (struct sockaddr_in *)&lifr.lifr_addr; + addr = sin->sin_addr.s_addr; + + /* Now lookup for existing dynamic interface entries */ + num = lookup_existing_entries(ifm->ifm_index, addr); + /* + * num = 1 means this entry is a static one. + * num = 0 means this entry is a dynamic existing entry + * We only care about dynamic entries here. + */ + if (num == 1) { + mipverbose(("process_rtsock_msg: Uninteresting " + "static entry\n")); + return; + } else if (num == 0) { + if (!(ifflags & IFF_UP)) { + /* The entry is down ? Is it unplumbed ? */ + (void) delmaAdvConfigEntry(ifm->ifm_index); + } + return; + } + if (!(ifflags & IFF_UP)) { + mipverbose(("process_rtsock_msg: Interface is down?\n")); + return; + } + + if ((d_entry = match_dynamic_table(lifr.lifr_name)) != NULL) { + /* + * Create the dynamic interface entry into the + * ConfigHash table + */ + + if (CreateInterfaceEntry(lifr.lifr_name, + d_entry->RegLifetime, d_entry->advertiseOnBcast, + DEFAULT_MIN_INTERVAL, DEFAULT_MAX_INTERVAL, + d_entry->AdvLifetime, 0, d_entry->AdvServiceflag, + d_entry->AdvPrefixflag, d_entry->RevtunAllowed, + d_entry->RevtunReqd, d_entry->AdvLimitUnsolicited, + d_entry->AdvInitCount, d_entry->AdvInterval, + _B_TRUE) != 0) { + syslog(LOG_ERR, + "Unable to create dynamic Interface: %m"); + return; + } + /* Find my entry */ + + if ((ifentry = (MaAdvConfigEntry *)findHashTableEntryUint( + &maAdvConfigHash, addr, LOCK_WRITE, + ConfigEntryHashLookup, (uint32_t)ifm->ifm_index, 0, + 0)) == NULL) { + syslog(LOG_CRIT, + "Can't find dynamic entry in Hash table"); + mipverbose(("process_rtsock_msg: Can't find dynamic " + "entry in Hash table\n")); + return; + } + if (InitSockets(ifentry) != 0) { + syslog(LOG_CRIT, "InitSockets failed for dynamic" + " Interface %s", ifentry->maIfaceName); + (void) rw_unlock(&ifentry->maIfaceNodeLock); + return; + } + /* Now set the FDs for advertisements */ + GET_TIME(currentTime); + ifentry->maNextAdvTime = currentTime; + FD_SET(ifentry->maIfaceUnicastSock, &saved_fdvec); + if (!(ifflags & IFF_POINTOPOINT)) { + FD_SET(ifentry->maIfaceDirBcastSock, &saved_fdvec); + FD_SET(ifentry->maIfaceBcastSock, &saved_fdvec); + } + FD_SET(ifentry->maIfaceAdvMulticastSock, &saved_fdvec); + FD_SET(ifentry->maIfaceRegMulticastSock, &saved_fdvec); + FD_SET(ifentry->maIfaceIcmpSock, &saved_fdvec); + (void) rw_unlock(&ifentry->maIfaceNodeLock); + return; + } + mipverbose(("process_rtsock_msg: entry %s not found\n", + lifr.lifr_name)); +} + + +/* + * Function: Lookup_existing_entries + * Description: Looks for any existing entry in config table. + * returns : 1 if finds a static entry + * 0 if finds a dynamic entry + * -1 if none found + */ + +static int +lookup_existing_entries(ushort_t index, ipaddr_t ifaddr) +{ + MaAdvConfigEntry * ifentry; + + ifentry = (MaAdvConfigEntry *)findHashTableEntryUint( + &maAdvConfigHash, ifaddr, LOCK_READ, ConfigEntryHashLookup, + (uint32_t)index, 0, 0); + + if (ifentry == NULL) { + mipverbose(("lookup_existing_entries: " + "Can't find entry in Hash table for index %d\n", + index)); + return (-1); + } + /* found an existing entry */ + if (ifentry->maAdvDynamicInterface == _B_TRUE) { + (void) rw_unlock(&ifentry->maIfaceNodeLock); + return (0); + } else { + (void) rw_unlock(&ifentry->maIfaceNodeLock); + return (1); + } +} + + +/* + * Function: match_dynamic_table + * Argument : interface name + * + * Description: + * Match the dynamic interface table to see if this interface + * is valid to become a dynamic mobility interface. + * dynamicIface list is handled by a single thread, thus + * we are not locking here. + * returns : DynamicIfceTypeEntry pointer + */ + +static DynamicIfaceTypeEntry * +match_dynamic_table(char *ifname) +{ + DynamicIfaceTypeEntry *dynentry; + int typelen; + + + dynentry = dynamicIfaceHead; + while (dynentry != NULL) { + typelen = strlen(dynentry->dynamicIfcetype); + if ((strncmp(ifname, dynentry->dynamicIfcetype, + (size_t)typelen) == 0) && + ((int)isdigit(ifname[typelen]) != 0)) { + /* Matches devicename with dynamicIfacetype */ + mipverbose(("match_dynamic_table: matched entry\n")); + return (dynentry); + } + dynentry = dynentry->next; + } + + return (NULL); +} + + +/* + * Function: delmaAdvConfigEntry + * Argument: Interface index + * Description: It can only take index, as there may be situation when + * it's too late to find name/addr info because the interface + * is gone (ENXIO error). So, in those cases we have no other + * info in hand and thus we have to go through the whole + * table and delete the entry. + */ +static void +delmaAdvConfigEntry(uint32_t index) +{ + + MaAdvConfigEntry *ifentry; + struct hash_entry *hash_entry; + struct hash_table *conf_htbl; + int count; + boolean_t found = _B_FALSE; + ipaddr_t addr; + + + conf_htbl = &maAdvConfigHash; + + /* + * The following search does not provide high performance + * result. The confighash table needs to be hashed with key + * <interface-index>. Currently all hashtables are hashed by + * address. But when delmaAdvConfigEntry() is called from + * process_rtsock_msg() routine, interface might be unplumbed + * already and thus the addr cannot be known. So we have to do + * a long search to compare the interface index for each entry. + * There could be two solutions in future to address this: + * 1. hash configHash table with interface index + * 2. Or modify routing socket to return addr and flag etc with + * the routing socket message. + */ + + for (count = 0; count < HASH_TBL_SIZE && !found; count++) { + hash_entry = conf_htbl->buckets[count]; + while (hash_entry != NULL) { + if (ConfigEntryHashLookup(hash_entry->data, + index, 0, 0)) { + (void) rw_wrlock((rwlock_t *)hash_entry->data); + found = _B_TRUE; + break; + } + hash_entry = hash_entry->next; + } + } + if (found) { + ifentry = hash_entry->data; + addr = ifentry->maIfaceAddr; + } else { + mipverbose(("delmaAdvConfigEntry: " + "Can't find dynamic entry in Hash table\n")); + return; + } + /* close all sockets */ + FD_CLR(ifentry->maIfaceUnicastSock, &saved_fdvec); + FD_CLR(ifentry->maIfaceAdvMulticastSock, &saved_fdvec); + FD_CLR(ifentry->maIfaceRegMulticastSock, &saved_fdvec); + FD_CLR(ifentry->maIfaceIcmpSock, &saved_fdvec); + (void) close(ifentry->maIfaceUnicastSock); + if (ifentry->maIfaceDirBcastSock > -1) { + FD_CLR(ifentry->maIfaceDirBcastSock, &saved_fdvec); + (void) close(ifentry->maIfaceDirBcastSock); + } + if (ifentry->maIfaceBcastSock > -1) { + FD_CLR(ifentry->maIfaceBcastSock, &saved_fdvec); + (void) close(ifentry->maIfaceBcastSock); + } + (void) close(ifentry->maIfaceAdvMulticastSock); + (void) close(ifentry->maIfaceRegMulticastSock); + (void) close(ifentry->maIfaceIcmpSock); + + if (delHashTableEntryUint(&maAdvConfigHash, ifentry, addr, + LOCK_NONE)) { + /* Success: Entry has been taken out of the table */ + (void) rw_unlock(&(ifentry->maIfaceNodeLock)); + (void) rwlock_destroy(&(ifentry->maIfaceNodeLock)); + free(ifentry); + mipverbose(("delmaAdvConfigEntry: deleted config entry\n")); + } +} diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agentPeriodic.c b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agentPeriodic.c new file mode 100644 index 0000000000..7efe4421b0 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agentPeriodic.c @@ -0,0 +1,1190 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_icmp.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 */ +boolean_t faBusy = _B_FALSE; +/* + * 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. + */ +boolean_t advBusy = _B_FALSE; + +extern boolean_t faNAIadv; /* Determines whether we advertise */ + /* our NAI */ +extern boolean_t faChallengeAdv; /* Determines whether we advertise */ + /* 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 */ +extern char faLastChallengeIssued[2][ADV_CHALLENGE_LENGTH]; + +/* 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 char *ntoa(uint32_t, char *); +extern void sendICMPmessage(int, ipaddr_t, unsigned char *, int); +extern char *err2str(int); +#ifdef FIREWALL_SUPPORT +extern boolean_t isOutsideProtectedDomain(uint32_t); +#endif /* FIREWALL_SUPPORT */ +extern uint32_t getRandomValue(); +extern int prefixLen(uint32_t); +extern int arpIfdel(ipaddr_t, char *, uint32_t); +extern int gettunnelno(ipaddr_t, ipaddr_t); +extern MobilityAgentEntry *findMaeFromIp(ipaddr_t, int); +extern int removeIPsecPolicy(char *); + +#define LOWEST_ROUTER_PRIORITY 0x80000000 + +static void doPeriodicTask(); +void maSendAdvertisement(MaAdvConfigEntry *, ipaddr_t, int, boolean_t faBusy); + +/* + * 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 +disableService(struct hash_table *htbl) +{ + int index, nentry; + MaAdvConfigEntry *entry; + struct hash_entry *p; + + advBusy = _B_TRUE; + for (index = 0, nentry = 0; + index < HASH_TBL_SIZE && (nentry < htbl->size); index++) { + p = htbl->buckets[index]; + while (p) { + nentry++; + entry = (MaAdvConfigEntry *)p->data; + 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 +enableService() +{ + advBusy = _B_FALSE; +} + +/* + * 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 +maSendAdvertisement(MaAdvConfigEntry *entry, ipaddr_t dst, int advType, + boolean_t faBusy) +{ + int j; + static unsigned char advPkt[512]; + int naiLength; + uint32_t randomValue; + unsigned char *randomValuePtr; + int len; + icmph *icmpPtr; + ipaddr_t *addrPtr; + advExt *advExtPtr; + unsigned char *cp; + + + /* We don't do unsolicited adv if AdvInitCount = 0 */ + if (entry->maAdvInitCount == 0 && advType == UNSOLICITED_ADV) { + mipverbose(("maSendAdvertisement: zero InitCount\n")); + return; + } + + + /* Fill out the ICMP header for a router advertisement */ + + /* LINTED BAD_PTR_CAST_ALIGN */ + icmpPtr = (icmph *) advPkt; + icmpPtr->type = ICMP_ROUTERADVERT; + icmpPtr->code = 16; + icmpPtr->icmpAdvNumAddr = 0; + icmpPtr->icmpAdvAddrEntrySize = 2; + icmpPtr->icmpAdvLifetime = htons((uint16_t)advLifetime); + + /* create advertisement ... */ + len = sizeof (icmph); + /* LINTED BAD_PTR_CAST_ALIGN */ + addrPtr = (uint32_t *)(advPkt + sizeof (icmph)); + + /* + * ... fill (optional) addresses in the RFC 1256 portion + * we only fill out one address. + */ + icmpPtr->icmpAdvNumAddr = 1; + icmpPtr->icmpAdvAddrEntrySize = 2; + *addrPtr++ = htonl(entry->maIfaceAddr); + len += sizeof (uint32_t); + *addrPtr++ = htonl(LOWEST_ROUTER_PRIORITY); + len += sizeof (uint32_t); + + /* + * ... fill out the mobility agent advertisement extension + * we only advertise one address + */ + /* LINTED BAD_PTR_CAST_ALIGN */ + advExtPtr = (advExt *) (advPkt + len); + advExtPtr->type = ADV_EXT_TYPE; + advExtPtr->length = 10; + advExtPtr->seqNum = htons(entry->maAdvSeqNum); + + /* + * 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) + entry->maAdvSeqNum = 256; + advExtPtr->regLifetime = htons(entry->maAdvMaxRegLifetime); + advExtPtr->advFlags = entry->maAdvServiceFlags; + + /* set the busy bit, if appropriate */ + if ((advBusy) || (faBusy && (advExtPtr->advFlags & + ADV_IS_FOREIGN_AGENT))) { + faCounters.faIsBusyCnt++; + advExtPtr->advFlags |= ADV_IS_BUSY; + } + + advExtPtr->reserved = 0; + len += sizeof (advExt); + + /* fill out the advertised care-of address */ + /* LINTED BAD_PTR_CAST_ALIGN */ + addrPtr = (uint32_t *)(advPkt + len); + *addrPtr++ = htonl(entry->maIfaceAddr); + len += sizeof (uint32_t); + + /* + * We only advertise our NAI if we were + * configured to do so. + */ + if (faNAIadv == _B_TRUE) { + /* Add the Mobility Agent NAI */ + naiLength = strlen(maNai); + cp = advPkt + len; + *cp++ = ADV_AGENT_NAI_EXT_TYPE; + *cp++ = (uchar_t)naiLength; + len += 2; + (void) strncpy((char *)cp, maNai, naiLength); + len += naiLength; + } + + /* + * 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 = advPkt + len; + *cp++ = ADV_CHALLENGE_EXT_TYPE; + *cp++ = ADV_CHALLENGE_LENGTH; + len += 2; + + /* + * Save the last Challenge issued + */ + (void) memcpy(faLastChallengeIssued[1], + faLastChallengeIssued[0], + ADV_CHALLENGE_LENGTH); + + randomValuePtr = cp; + + /* We want a 16 octet (128 bit) challenge */ + for (j = 0; j < ADV_CHALLENGE_LENGTH; j += 4) { + randomValue = getRandomValue(); + (void) strncpy((char *)cp, (char *)&randomValue, + sizeof (randomValue)); + len += sizeof (randomValue); + cp += sizeof (randomValue); + } + + /* We want a 16 octet (128 bit) challenge */ + /* + * Save the New Challenge issued + */ + (void) memcpy(faLastChallengeIssued[0], randomValuePtr, + ADV_CHALLENGE_LENGTH); + } else if (advType == SOLICITED_ADV) { + + /* Add the Foreign Agent Challenge Value */ + cp = advPkt + len; + *cp++ = ADV_CHALLENGE_EXT_TYPE; + *cp++ = ADV_CHALLENGE_LENGTH; + len += 2; + /* We use the last advertised challenge */ + (void) memcpy(cp, faLastChallengeIssued[0], + ADV_CHALLENGE_LENGTH); + len += ADV_CHALLENGE_LENGTH; + cp += ADV_CHALLENGE_LENGTH; + } + } + + /* fill out prefix length extension, if required */ + if ((entry->maAdvPrefixLenInclusion == _B_TRUE) && + icmpPtr->icmpAdvNumAddr) { + cp = advPkt + len; + *cp++ = ADV_PREFIX_EXT_TYPE; + *cp++ = icmpPtr->icmpAdvNumAddr; + len += 2; + /* fill out prefix len for each addr in RFC1256 portion */ + for (j = 0; j < icmpPtr->icmpAdvNumAddr; j++) { + *cp++ = prefixLen(entry->maIfaceNetmask); + len++; + } + } + + /* pad ICMP message to even length, if required */ + if (len % 2) { + *cp++ = ADV_PADDING_EXT_TYPE; + len++; + } + + /* fill out ICMP checksum */ + icmpPtr->checksum = 0; + icmpPtr->checksum = inChecksum((unsigned short *) icmpPtr, len); + + /* ship it! */ + commonCounters.maAdvSentCnt++; + + /* + * IP_XMIT_IF or IP_MULTICAST_IF are set on this socket + * during initiation time in InitSockets(). + */ + sendICMPmessage(entry->maIfaceIcmpSock, dst, advPkt, len); + + + /* + * 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. + */ + if (entry->maAdvLimitUnsolicited && entry->maAdvInitCount > 0) { + /* update maAdvInitCount */ + entry->maAdvInitCount--; + mipverbose(("maSendAdvertisement: updating maAdvInitCount " + " to %d\n", entry->maAdvInitCount)); + } + + /* + * Note that the mipverbose format is different here. + * We want to just print the interface index with each + * advertisement. + */ + mipverbose(("+[%d]", entry->maIfindex)); +} + + +/* + * 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 +delHABEent(HaMobileNodeEntry *mnePtr, HaBindingEntry *entry) +{ + ipaddr_t mnAddr, coAddr; + char addrstr1[INET_ADDRSTRLEN]; + char addrstr2[INET_ADDRSTRLEN]; + int val; + time_t localTime; + time_t sessionLifeTime; + int result; + + mnAddr = entry->haBindingMN; + coAddr = entry->haBindingCOA; + + /* + * 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", + ntoa(coAddr, addrstr1), + ntoa(domainInfo.fwAddr[0], addrstr2))); + if ((val = encaprem(coAddr)) < 0) { + syslog(LOG_ERR, "encaprem failed ... %s", err2str(val)); + } + } +#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", + ntoa(mnAddr, addrstr1), ntoa(coAddr, addrstr2))); + + if ((val = encaprem(mnAddr)) < 0) { + syslog(LOG_ERR, "encaprem failed ... %s", err2str(val)); + } + + /* 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 */ + MobilityAgentEntry *mae; + + /* note: this should work for colocated MNs too! */ + if ((mae = findMaeFromIp(coAddr, LOCK_READ)) != NULL) { + /* + * 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() + */ + if (mae->maIPsecFlags & IPSEC_REPLY_APPLY) { + /* off it */ + if (removeIPsecPolicy( + mae->maIPsecReply[IPSEC_APPLY]) < 0) { + /* whine about it */ + char peerAddr[IPv4_ADDR_LEN]; + + (void) ntoa(coAddr, peerAddr); + syslog(LOG_CRIT, "Could not remove %s" + "ipsec regisration reply apply.", + peerAddr); + } else + /* it's gone, unset the flag bit */ + mae->maIPsecFlags &= + ~IPSEC_REPLY_APPLY; + } + + /* The tunnels are down, so just unset those bits */ + mae->maIPsecFlags &= ~IPSEC_TUNNEL_APPLY; + mae->maIPsecFlags &= ~IPSEC_REVERSE_TUNNEL_PERMIT; + + /* more importantly, this is no longer an agent peer */ + mae->maPeerFlags &= ~FA_PEER; + + /* unlock */ + (void) rw_unlock(&mae->maNodeLock); + } + } + + if (--mnePtr->haMnBindingCnt == 0) { + + /* + * Notify AAA server that the MN is going away. + */ + if ((aaaProtocol == RADIUS || aaaProtocol == DIAMETER)) { + GET_TIME(localTime); + sessionLifeTime = localTime - + entry->haBindingTimeGranted; + result = sendAccountingRecord( + MOBILE_IP_ACCOUNTING_STOP_REQUEST, + (unsigned char *)mnePtr->haMnNAI, + mnePtr->haMnNAILen, mnAddr, coAddr, + entry->haBindingHaAddr, + sessionLifeTime, MN_DEREGISTERED); + if (result) { + syslog(LOG_ERR, "Unable to send accounting " + "stop record"); + } + } + + mipverbose(("Terminating arp service for %s\n", + ntoa(mnAddr, addrstr1))); + + /* + * 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", + ntoa(mnAddr, addrstr1))); + if ((val = arpdel(mnAddr)) < 0) { + syslog(LOG_ERR, "arpdel failed ... %s", err2str(val)); + } + + /* + * Do we have an assigned Home Address that we need + * to free? + */ + if (mnePtr->haPoolIdentifier && mnePtr->haMnAddr) { + if (freeAddressFromPool(mnePtr->haPoolIdentifier, + mnePtr->haMnAddr) != _B_TRUE) { + syslog(LOG_ERR, + "Unable to free address from pool %d", + mnePtr->haPoolIdentifier); + } + mnePtr->haMnAddr = 0; + } + } + + mipverbose(( + "HA binding removed for %s@%s at entry %p (Binding Cnt %d).\n", + ntoa(mnAddr, addrstr1), ntoa(coAddr, addrstr2), (void *)entry, + 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 +delFAVEptr(FaVisitorEntry *entry, boolean_t sendASR, uint32_t releaseindicator) +{ + int val; + int tun_num; + int in_index; + char tun_name[LIFNAMSIZ]; + char addrstr1[INET_ADDRSTRLEN]; + char addrstr2[INET_ADDRSTRLEN]; + int result; + time_t localTime; + time_t sessionLifeTime; + + +#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... + */ + if (rw_trywrlock(&entry->nodeLock) == 0) { + assert(0); + } + +#endif + + mipverbose(("FA expired %s visitor entry for %s\n", + (entry->faVisitorRegIsAccepted ? + "accepted" : "pending"), + ntoa(entry->faVisitorHomeAddr, addrstr1))); + + /* For accepted requests, kill route and disable decapsulation. */ + + if (entry->faVisitorRegIsAccepted == _B_TRUE) { + + tun_num = gettunnelno(entry->faVisitorHomeAgentAddr, + entry->faVisitorIfaceAddr); + if (tun_num < 0) { + syslog(LOG_ERR, "gettunnelno returns -1"); + return; + } + (void) snprintf(tun_name, sizeof (tun_name), "ip.tun%d", + tun_num); + in_index = if_nametoindex(tun_name); + if (in_index == 0) { + /* if_nametoindex fails... */ + syslog(LOG_ERR, "if_nametoindex failed for tunnel %s", + tun_name); + } + mipverbose(( + "Removing direct, local route for visitor %s thru %s\n", + ntoa(entry->faVisitorHomeAddr, addrstr1), + ntoa(entry->faVisitorIfaceAddr, addrstr2))); + + if ((val = routedel(entry->faVisitorHomeAddr, + entry->faVisitorIfaceAddr, 0, in_index, + entry->faVisitorInIfindex)) < 0) { + syslog(LOG_ERR, + "routedel failed ...for visitor %s: %s\n", + ntoa(entry->faVisitorHomeAddr, addrstr1), + err2str(val)); + } + + if (entry->faVisitorRegFlags & REG_REVERSE_TUNNEL) { + + /* delete Reverse Tunnel route */ + mipverbose(( + "Removing Reverse tunnel route for visitor %s at" + " interface index %d\n", + ntoa(entry->faVisitorHomeAddr, addrstr2), + entry->faVisitorInIfindex)); + + if ((val = routedel(0, 0, + entry->faVisitorHomeAddr, + entry->faVisitorInIfindex, + in_index)) < 0) { + syslog(LOG_ERR, + "Reverse Tunnel route delete failed: %s:" + " for visitor %s at interface index %d", + err2str(val), + ntoa(entry->faVisitorHomeAddr, addrstr1), + entry->faVisitorInIfindex); + } + } + /* + * 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. + */ + if ((aaaProtocol == RADIUS || aaaProtocol == DIAMETER) && + (sendASR == _B_TRUE)) { + GET_TIME(localTime); + sessionLifeTime = localTime - + entry->faVisitorTimeGranted; + result = sendAccountingRecord( + MOBILE_IP_ACCOUNTING_STOP_REQUEST, + (unsigned char *)entry->faVisitorMnNAI, + entry->faVisitorMnNAILen, + entry->faVisitorHomeAddr, + entry->faVisitorCOAddr, + entry->faVisitorHomeAgentAddr, + sessionLifeTime, releaseindicator); + if (result) { + syslog(LOG_ERR, "Unable to send accounting " + "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. + */ + mipverbose(( + "Disabling decapsulation of inner pkts sent to %s\n", + ntoa(entry->faVisitorHomeAddr, addrstr1))); + if ((val = decaprem(entry->faVisitorHomeAgentAddr, + entry->faVisitorIfaceAddr)) < 0) { + syslog(LOG_ERR, "decaprem failed: %s", err2str(val)); + } + + /* if decaprem() returns 0 there are no MNs using the tunnel */ + if (val == 0) { + /* kill any tunnel ipsec SAs we have with this peer */ + MobilityAgentEntry *mae; + + if ((mae = + findMaeFromIp(entry->faVisitorHomeAgentAddr, + LOCK_READ)) != NULL) { + /* + * We're the FA, so we look for + * IPSEC_REPLY_PERMIT, and + * IPSEC_REQUEST_APPLY policies. + */ + if (mae->maIPsecFlags & IPSEC_REPLY_PERMIT) { + /* off it */ + if (removeIPsecPolicy( + mae->maIPsecReply[IPSEC_PERMIT]) + < 0) { + /* whine about it */ + char peerAddr[IPv4_ADDR_LEN]; + (void) ntoa(entry-> + faVisitorHomeAgentAddr, + peerAddr); + syslog(LOG_CRIT, + "Could not remove %s's " + "ipsec reply permit.", + peerAddr); + } else + /* unset the flag bit */ + mae->maIPsecFlags &= + ~IPSEC_REPLY_PERMIT; + } + + /* + * 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 &= ~IPSEC_TUNNEL_PERMIT; + mae->maIPsecFlags &= + ~IPSEC_REVERSE_TUNNEL_APPLY; + + /* this is no longer an agent peer */ + mae->maPeerFlags &= ~HA_PEER; + + /* unlock */ + (void) rw_unlock(&mae->maNodeLock); + } + } + + /* + * 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 && + ((val = arpIfdel(entry->faVisitorHomeAddr, + entry->faVisitorSlla.sdl_data, + entry->faVisitorInIfindex)) < 0)) { + /* + * If deletion failed bcos there was'nt an entry + * mipagent need not report it + */ + if (val != (-1)*ENXIO) + syslog(LOG_ERR, "arpIfdel failed ...%s\n", + err2str(val)); + } + } +} + + +/* + * 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 +haAgeBindingsHashHelper(void *entry, uint32_t p1) +{ + HaMobileNodeEntry *hentry = entry; + HaBindingEntry *bindingEntry; + HaBindingEntry *prev_entry = NULL; + HaBindingEntry *next_entry; + + bindingEntry = hentry->bindingEntries; + while (bindingEntry) { + next_entry = bindingEntry->next; + if (bindingEntry->haBindingTimeExpires > p1) { + /* + * We want to keep this one, so setup the pointer. + */ + prev_entry = bindingEntry; + } else { + if (prev_entry) { + prev_entry->next = bindingEntry->next; + } else { + hentry->bindingEntries = bindingEntry->next; + } + delHABEent(hentry, bindingEntry); + free(bindingEntry); + } + bindingEntry = next_entry; + } + + /* + * We need to delete the Mobile Node Entry if the + * entry was dynamic and has no more bindings. + */ + if (hentry->haMnBindingCnt == 0 && + hentry->haMnIsEntryDynamic == TRUE) { + (void) rw_unlock(&hentry->haMnNodeLock); + (void) rwlock_destroy(&hentry->haMnNodeLock); + free(hentry); + + /* + * 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 +haAgeBindings(struct hash_table *htbl, time_t currentTime) +{ + getAllHashTableEntries(htbl, haAgeBindingsHashHelper, LOCK_WRITE, + currentTime, _B_FALSE); +} + + +/* + * 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 +faAgeVisitorsHashHelper(void *entry, uint32_t p1) +{ + FaVisitorEntry *faEntry = entry; + + if (faEntry->faVisitorTimeExpires <= p1) { + (void) fprintf(stderr, "Deleting visitor entry!!\n"); + /* Expired */ + delFAVEptr(faEntry, _B_TRUE, REG_EXPIRED); + (void) rw_unlock(&faEntry->faVisitorNodeLock); + (void) rwlock_destroy(&faEntry->faVisitorNodeLock); + free(faEntry); + 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 +faAgeVisitors(struct hash_table *htbl, time_t currentTime) +{ + getAllHashTableEntries(htbl, faAgeVisitorsHashHelper, LOCK_WRITE, + currentTime, _B_FALSE); +} + + +/* + * 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 +mipAgeSecAssocHashHelper(void *entry, uint32_t p1) +{ + MipSecAssocEntry *saEntry = entry; + + if (saEntry->mipSecIsEntryDynamic == TRUE && + saEntry->mipSecKeyLifetime <= p1) { + (void) fprintf(stderr, + "Deleting Security Assocation entry!!\n"); + /* Expired */ + (void) rw_unlock(&saEntry->mipSecNodeLock); + (void) rwlock_destroy(&saEntry->mipSecNodeLock); + free(saEntry); + 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 +mipAgeSecAssoc(struct hash_table *htbl, time_t currentTime) +{ + getAllHashTableEntries(htbl, mipAgeSecAssocHashHelper, + LOCK_WRITE, currentTime, _B_FALSE); +} + +/* + * 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 +mipAgeMobilityAgentsHashHelper(void *entry, uint32_t p1) +{ + MobilityAgentEntry *maEntry = entry; + + if (maEntry->maIsEntryDynamic == TRUE && + maEntry->maExpiration <= p1) { + (void) fprintf(stderr, "Deleting Mobility Agent entry!!\n"); + /* Expired */ + (void) rw_unlock(&maEntry->maNodeLock); + (void) rwlock_destroy(&maEntry->maNodeLock); + free(maEntry); + 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 +mipAgeMobilityAgents(struct hash_table *htbl, time_t currentTime) +{ + getAllHashTableEntries(htbl, mipAgeMobilityAgentsHashHelper, + LOCK_WRITE, currentTime, _B_FALSE); +} + +/* + * Function: startPeriodicTaskThread + * + * Arguments: + * + * Description: This function is called to start the + * periodic task handling thread. + * + * Returns: int, 0 if successful. + */ +int +startPeriodicTaskThread(void) +{ + pthread_attr_t pthreadAttribute; + int result; + + result = pthread_attr_init(&pthreadAttribute); + + if (result) { + syslog(LOG_CRIT, "Error Initializing pthread."); + return (-1); + } + + /* + * We now create a thread to deal with all periodic task. + */ + result = pthread_create(&periodicThreadId, &pthreadAttribute, + (void *(*)()) doPeriodicTask, + (void *)NULL); + + if (result) { + syslog(LOG_CRIT, "pthread_create() failed."); + 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. + */ + result = pthread_detach(periodicThreadId); + + if (result) { + syslog(LOG_CRIT, "pthread_detach() failed."); + 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 +killPeriodicTaskThread() +{ + int result; + + if (periodicThreadId) { + /* + * Next we need to kill the dispatching thread. + */ + result = pthread_cancel(periodicThreadId); + + if (result) { + /* + * Well, there's not much we can do here.. + */ + syslog(LOG_CRIT, "Unable to kill periodic thread"); + 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) +{ + struct timeval tv; + time_t nextPeriodicTime = 0; + time_t currentTime; + + /* CONSTCOND */ + while (_B_TRUE) { + GET_TIME(currentTime); + + if (currentTime < nextPeriodicTime) { + tv.tv_sec = nextPeriodicTime - currentTime; + tv.tv_usec = 0; + (void) select(FD_SETSIZE, NULL, NULL, NULL, &tv); + GET_TIME(currentTime); + } + + if (currentTime >= nextPeriodicTime) { + haAgeBindings(&haMobileNodeHash, currentTime); + faAgeVisitors(&faVisitorHash, currentTime); + (void) mipAgeSecAssoc(&mipSecAssocHash, currentTime); + mipAgeMobilityAgents(&mipAgentHash, currentTime); + nextPeriodicTime = currentTime + periodicInterval; + mipverbose(("*")); + (void) fflush(stdout); + } + } +} diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agentSaveState.c b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agentSaveState.c new file mode 100644 index 0000000000..2580ab2150 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/agentSaveState.c @@ -0,0 +1,1079 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999-2001 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Functions used to save and read the binding table for persistence across + * mipagent reboots. + * Saving should be invoked by sending mipagent the proper signal. + * After the signal is trapped, the functions here are invoked and save + * the state into the binary file: + * "/var/inet/mipagent_state" + * The file + * "/var/inet/mipagent_state.lock" + * is used as a mutex. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <thread.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <netinet/in.h> + +#include "impl.h" + +#include "agent.h" +#include "setup.h" +#include "hash.h" +#include "conflib.h" + +#define MAXLINELENGTH 200 +/* file to save all mobility bindings to capture state across reboots */ +#define SAVE_BINDINGS_FILE "/var/inet/mipagent_state" +#ifdef LOCKFILE +#define SAVE_BINDINGS_LOCK_FILE "/var/inet/mipagent_state.lock" +#endif /* LOCKFILE */ +#define ENVVAR "MIPAGENT_SAVE_STATE" + +/* Controls verbosity of debug messages when compiled w/ "-D MIP_DEBUG" */ +extern int logVerbosity; + +/* + * Counters maintained by Home Agents + */ +extern HomeAgentCounters haCounters; + +/* Home Agent specific data structures. */ +extern HashTable haMobileNodeHash; +extern HashTable mipSecAssocHash; +extern HashTable mipAgentHash; + +extern int installIPsecPolicy(char *); +extern MobilityAgentEntry *findMaeFromIp(ipaddr_t, int); + +static FILE *agentStateFile; /* file ptr for the state file */ +#ifdef LOCKFILE +static int lockFile; /* lock file file descriptor */ +#endif /* LOCKFILE */ + +static int preFileAccess(boolean_t forReading); +static int postFileAccess(void); +static void removeStateFile(void); +static size_t saveOneEntry(void *ptr, size_t size); +static size_t readOneEntry(void *ptr, size_t size); +int restoreIPsecPolicies(MobilityAgentEntry *, MobilityAgentEntry *); + +extern char *validIPsecAction[]; +extern char *ntoa(uint32_t, char *); + +/* + * Function: saveAgentState + * + * Arguments: None. + * + * Description: Save mobile node binding entries. ret 1 if ok, 0 otherwise. + * + * Note: This routine must be called only when everything + * is quiescent. Otherwise inconsistent state may result + * if new security associations, mobile node entries + * or binding entries are being created as the state + * is being saved. + * + * Returns: 1 if ok, 0 otherwise. + */ + +int +saveAgentState(void) +{ + HashEntry *hashEntry; + HaMobileNodeEntry *hamne; + HaBindingEntry *habe; + MipSecAssocEntry *sae; + MobilityAgentEntry *mae; + int EntriesSaved, numBindings; + int i; + + /* Prepare for security association file access. */ + if (preFileAccess(_B_FALSE) == -1) { + mipverbose(("Could not prepare state file for writing.\n")); + return (0); + } + + /* + * Only save the *dynamic* security associations. + * First: count them, and write that number. + * Then: do the actual saves. + */ + EntriesSaved = 0; + for (i = 0; i < HASH_TBL_SIZE; i++) { + if (mipSecAssocHash.buckets[i]) { + for (hashEntry = mipSecAssocHash.buckets[i]; + hashEntry != NULL; + hashEntry = hashEntry->next) { + sae = hashEntry->data; + if (sae == NULL) + continue; + if (! sae->mipSecIsEntryDynamic) + continue; + ++EntriesSaved; + } + } + } + + /* + * First item to write out: the number of dynamic security + * associations which follow. + */ + if (saveOneEntry((void *) &EntriesSaved, sizeof (EntriesSaved)) != 1) { + mipverbose(("Problem saving the number of dynamic of" + "security associations.\n")); + (void) postFileAccess(); + (void) rw_unlock(&sae->mipSecNodeLock); + (void) rw_unlock(&mipSecAssocHash.bucketLock[i]); + return (0); + } + + /* + * Now: write out the actual dynamic security + * associations. + */ + for (i = 0; (EntriesSaved > 0) && (i < HASH_TBL_SIZE); i++) { + if (mipSecAssocHash.buckets[i]) { + for (hashEntry = mipSecAssocHash.buckets[i]; + hashEntry != NULL; + hashEntry = hashEntry->next) { + + sae = hashEntry->data; + if (sae == NULL) + continue; + + /* + * If the entry is static there is + * no need to save it, as it will + * get restored out of the configuration + * file. + */ + if (! sae->mipSecIsEntryDynamic) + continue; + /* + * Now it's safe to write out the sec + * association entry. + */ + if (saveOneEntry((void *) sae, + sizeof (MipSecAssocEntry)) != 1) { + mipverbose(("Problem saving a mobile " + "node entry.\n")); + (void) postFileAccess(); + return (0); + } + --EntriesSaved; + } + } + } + + /* + * Now we'll save the agent-peer entries. + * First: count them, and write that number. + * Then: do the actual saves. + */ + EntriesSaved = 0; + for (i = 0; i < HASH_TBL_SIZE; i++) { + if (mipAgentHash.buckets[i]) { + for (hashEntry = mipAgentHash.buckets[i]; + hashEntry != NULL; + hashEntry = hashEntry->next) { + mae = hashEntry->data; + if (mae == NULL) + continue; + ++EntriesSaved; + } + } + } + + /* + * Now write out the number of agent-peer entries which follow + */ + if (saveOneEntry((void *) &EntriesSaved, sizeof (EntriesSaved)) != 1) { + mipverbose(("Problem saving the number of " + "agent-peer entries.\n")); + (void) postFileAccess(); + (void) rw_unlock(&mipAgentHash.bucketLock[i]); + return (0); + } + + /* + * Now: write out the actual agent-peer entries. + */ + for (i = 0; (EntriesSaved > 0) && (i < HASH_TBL_SIZE); i++) { + if (mipAgentHash.buckets[i]) { + for (hashEntry = mipAgentHash.buckets[i]; + hashEntry != NULL; + hashEntry = hashEntry->next) { + + mae = hashEntry->data; + + if (mae == NULL) + continue; + + /* + * Write out the agent-peer entry + */ + if (saveOneEntry((void *) mae, + sizeof (MobilityAgentEntry)) != 1) { + mipverbose(("Problem saving an agent-" + "peer entry.\n")); + (void) postFileAccess(); + return (0); + } + --EntriesSaved; + } + } + } + + + /* + * Now save each mobile node entry. + */ + for (i = 0; i < HASH_TBL_SIZE; i++) { + if (haMobileNodeHash.buckets[i]) { + + for (hashEntry = haMobileNodeHash.buckets[i]; + hashEntry != NULL; + hashEntry = hashEntry->next) { + + hamne = hashEntry->data; + /* + * This should have been != NULL, instead + * of == NULL. The issue is that we would + * never properly reload existing registrations + * if the agent was re-started. + */ + if (hamne != NULL) + /* + * Instead of trusting it to really + * know how many bindings it has, i'll + * go ahead and count them just to really + * make sure. Otherwise we could end up with + * null pointers, core dumps, etc... it's + * one more traversal, but most of the time + * there's zero or one binding, and the max + * is small anyway... Little extra price to pay + * to be able to sleep at night... + * This way, when we read the mn entry we + * know we can trust the number of bindings to + * know how many binding entries to read after + * that. + */ + for (numBindings = 0, + habe = hamne->bindingEntries; + habe != NULL && + (numBindings < + MAX_SIMULTANEOUS_BINDINGS); + ++numBindings, habe = habe->next); + + /* + * finished counting the number of + * bindings... + */ + if (numBindings != hamne->haMnBindingCnt) { + mipverbose(("Miscounted number of " + "bindings! (fixing...)\n")); + hamne->haMnBindingCnt = numBindings; + } + + if (numBindings != 0) { + /* + * Now it's safe to write out the + * mobile node entry. + */ + if (saveOneEntry((void *) hamne, + sizeof (HaMobileNodeEntry)) != 1) { + mipverbose(("Problem saving " + "a mobile node entry.\n")); + (void) postFileAccess(); + return (0); + } + +#ifdef RADIUS_ENABLED + /* + * Save any haRadiusState as + * len:radiusState + */ + + if (MobileNodeEntry->haRadiusState != + NULL) { + size_t len = strlen( + hamne->haRadiusState); + if (1 != fwrite((void *) &len, + sizeof (size_t), 1, + agentStateFile)) { + mipverbose(( + "Problem saving " + "length %d of " + "radius state" + "%s.\n", len, + hamne-> + haRadiusState)); + (void) postFileAccess(); + return (0); + } + if (len != fwrite((void *) + hamne->haRadiusState, + sizeof (char), + len, agentStateFile)) { + mipverbose(( + "Problem saving " + "radius state %s." + "\n", + hamne-> + haRadiusState)); + (void) postFileAccess(); + return (0); + } + } +#endif /* RADIUS_ENABLED */ + + /* + * 2nd traversal of the bindings chain: + * save each binding + */ + for (habe = hamne->bindingEntries; + habe != NULL; + habe = habe->next) { + + if (saveOneEntry((void *) habe, + sizeof (HaBindingEntry)) + != 1) { + mipverbose(("Problem " + "saving a binding" + "entry.\n")); + (void) postFileAccess(); + return (0); + } + } + } + } + } +} + +if (postFileAccess() == -1) + return (0); + return (1); + } /* saveAgentState(void) */ + +/* returns 1 if ok, 0 otherwise. */ +static int +restoreAllMobilityBindings(void) +{ + HaMobileNodeEntry hamne, *mnEntry = NULL; + HaBindingEntry habe; + MipSecAssocEntry sa, *sap; + MobilityAgentEntry ma, *map; + time_t currentTime; + time_t timeout; + boolean_t existing; + uint32_t sessionLifetime; + int EntriesSaved = 0; + int i; + + if (preFileAccess(_B_TRUE) == -1) { + mipverbose(("Could not prepare state file for reading.\n")); + return (0); + } + + /* + * First: how many dynamic security assoc's are there? + */ + + if ((int)readOneEntry((void *) &EntriesSaved, sizeof (EntriesSaved)) + != 1) { + mipverbose(("Problem reading the number of dynamic sa's.\n")); + (void) postFileAccess(); + return (0); + } + + for (i = 0; i < EntriesSaved; i++) { + if ((int)readOneEntry((void *) &sa, + sizeof (MipSecAssocEntry)) != 1) { + mipverbose(("Problem reading a security assoc.\n")); + (void) postFileAccess(); + return (0); + } + + /* + * Create the relevant security association + * (locked upon return). + * NOTE: Must rewrite the key lifetime as + * the create routing clobbers the previous + * value. + */ + sap = CreateSecAssocEntry(sa.mipSecIsEntryDynamic, + sa.mipSecSPI, + sa.mipSecReplayMethod, + sa.mipSecAlgorithmType, + sa.mipSecAlgorithmMode, + sa.mipSecKeyLen, + (char *)&sa.mipSecKey[0], + sa.mipSecKeyLifetime); + + if (sap == NULL) { + mipverbose(("Unable to create dynamic SA Entry\n")); + haCounters.haInsufficientResourceCnt++; + (void) postFileAccess(); + return (0); + } + + sap->mipSecKeyLifetime = sa.mipSecKeyLifetime; + mipverbose(("Created a dynamic Mobile Node Entry\n")); + + /* + * The Create function ends up locking the sa, so + * we need to free it. + */ + (void) rw_unlock(&sap->mipSecNodeLock); + } + + /* + * the next entry should indicate the number of agent-peer entries. + */ + if ((int)readOneEntry((void *) &EntriesSaved, sizeof (EntriesSaved)) + != 1) { + mipverbose(("Problem reading the number of agent-peers.\n")); + (void) postFileAccess(); + return (0); + } + + /* now restore that many agent-peer entries */ + for (i = 0; i < EntriesSaved; i++) { + if ((int)readOneEntry((void *) &ma, + sizeof (MobilityAgentEntry)) != 1) { + mipverbose(("Problem reading an agent-peer entry.\n")); + (void) postFileAccess(); + return (0); + } + + /* + * Agent entries are read from the config file BEFORE this + * function is called. Therefore, any we find here that + * aren't in the config file must have been deleted, and + * hence we don't have a SA with them any longer. Conversely + * if there are new agent's configured, any SA that's + * configued with them is obviously not currently active. + */ + if ((map = findMaeFromIp(ma.maAddr, LOCK_READ)) == NULL) { + /* + * This is the former case - we saved this agent, + * but it hasn't been read from the config file, + * and so was delted. We no longer have to worry + * about this agent-peer, but let the user know + * in case the deletion was accidental. + */ + char peerAddr[IPv4_ADDR_LEN]; + + (void) ntoa(ma.maAddr, peerAddr); + mipverbose(("agent-peer entry for %s " + "no longer configured\n", peerAddr)); + continue; + } + + /* Restore the active IPsec Policies */ + (void) restoreIPsecPolicies(map, &ma); + + /* + * The Create function ends up locking the map, so + * we need to free it. + */ + (void) rw_unlock(&map->maNodeLock); + } + + /* + * Read the mobile node entries till eof. + */ + /* CONSTCOND */ + while (_B_TRUE) { + rwlock_t nl; + + if ((int)readOneEntry((void *) &hamne, + sizeof (HaMobileNodeEntry)) != 1) { + if (ferror(agentStateFile)) { + mipverbose(( + "Problem reading a mobile node entry.\n")); + (void) postFileAccess(); + return (0); + } else if (feof(agentStateFile)) { + mipverbose(("Done restoring agent state.\n")); + clearerr(agentStateFile); + } + return ((postFileAccess() == -1) ? 0 : 1); + } + + /* + * if its a dynamic type, we must explicitly create it here + * Otherwise, it was created upon initialization. + * Note: creation produces a *locked* node. + */ + + if (hamne.haMnIsEntryDynamic) { + /* First, create the mobile node. */ + + mnEntry = CreateMobileNodeEntry(_B_TRUE, + hamne.haMnAddr, + (char *)&hamne.haMnNAI[0], + MAX_NAI_LENGTH, + hamne.haBindingIfaceAddr, + hamne.haMnSPI, + NULL, + hamne.haPoolIdentifier); + + if (mnEntry == NULL) { + mipverbose(( + "Unable to create dynamic MN Entry\n")); + haCounters.haInsufficientResourceCnt++; + (void) postFileAccess(); + return (0); + } + mipverbose(("Created a dynamic Mobile Node Entry\n")); + } else { + mnEntry = findHashTableEntryUint(&haMobileNodeHash, + hamne.haMnAddr, LOCK_WRITE, NULL, 0, 0, 0); + + if (mnEntry == NULL) { + /* + * Search for the MobileNodeEntry based on the + * NAI. + */ + mnEntry = findHashTableEntryString( + &haMobileNodeHash, + (unsigned char *)&hamne.haMnNAI, + strlen((char *)&hamne.haMnNAI), + LOCK_WRITE, + NULL, 0, 0, 0); + + if (mnEntry == NULL) { + mipverbose(("Unable to find a " + "static MN Entry\n")); + (void) postFileAccess(); + return (0); + } + } + mipverbose(("Found a static Mobile Node Entry\n")); + } + + /* + * Copy all the fields to the (locked) mobile node entry. + * Must make sure the lock info does not get clobbered. + * Also, make sure we explicitly clobber the bindingEntries + * pointer, as it has no significance until we restore those + * entries one by one. + * Must also clobber the haMnBindingCnt and let restoreHABE + * increment that upon successful restoration of each binding + * entry. + */ + + nl = mnEntry->haMnNodeLock; + (void) memcpy((void *)mnEntry, (void *)&hamne, + sizeof (HaMobileNodeEntry)); + mnEntry->haMnNodeLock = nl; + mnEntry->bindingEntries = NULL; + mnEntry->haMnBindingCnt = 0; + +#if 0 + /* This is not persistent friendly yet. */ + /* read the radiusState string if needed. */ + if (mnEntry->haRadiusState != NULL) { + size_t len; + if (1 != fread((void *) &len, sizeof (size_t), 1, + agentStateFile)) { + mipverbose(( + "Problem reading radius state length.\n")); + (void) postFileAccess(); + (void) rw_unlock(&mnEntry->haMnNodeLock); + return (0); + } + + /* allocate some space for the radius state */ + if (len != fread((void *) mnEntry->haRadiusState, + sizeof (char), len, agentStateFile)) { + mipverbose(( + "Problem reading radius state.\n")); + (void) postFileAccess(); + (void) rw_unlock(&mnEntry->haMnNodeLock); + return (0); + } + } + mnEntry->haRadiusState = NULL; +#endif + + /* + * Read all binding entries for this + * mn entry. + */ + for (i = 0; i < (int)hamne.haMnBindingCnt; i++) { + if ((int)readOneEntry((void *) &habe, + sizeof (HaBindingEntry)) != 1) { + mipverbose(("Problem reading a " + "binding entry.\n")); + (void) postFileAccess(); + (void) rw_unlock(&mnEntry->haMnNodeLock); + return (0); + } + + /* + * Figure out when the entry should expire. + */ + GET_TIME(currentTime); + + if (habe.haBindingTimeExpires > currentTime) { + timeout = habe.haBindingTimeExpires - + currentTime; + /* create the relevant binding entry */ + (void) addHABE(mnEntry, habe.haBindingSrcAddr, + habe.haBindingSrcPort, NULL, + habe.haBindingRegFlags, + habe.haBindingMN, + habe.haBindingCOA, + mnEntry->haBindingIfaceAddr, timeout, + &existing, &sessionLifetime); + } + } + + /* + * Done with this mn entry, but before + * moving on to the next, let's unlock it. + */ + (void) rw_unlock(&mnEntry->haMnNodeLock); + } + + return (0); +} /* restoreAllMobilityBindings(void) */ + +int +restoreAgentState(void) +{ + (void) restoreAllMobilityBindings(); + removeStateFile(); + return (0); +} + +/* ------------------------------------------------------------ */ +/* FILE FUNCTIONS */ +/* ------------------------------------------------------------ */ + +/* + * Prepares the file to write out the state. + */ + +static char host_file[MAXLINELENGTH] = ""; +#ifdef LOCKFILE +static char lock_file[MAXLINELENGTH] = ""; +#endif /* LOCKFILE */ + +/* returns -1 if error, 0 if ok */ + +static int +preFileAccess(boolean_t forReading) +{ + char *envres; + mode_t mask; + + /* find out which files we should be using */ + + if ((envres = getenv(ENVVAR)) == NULL) { + (void) strcpy(host_file, SAVE_BINDINGS_FILE); +#ifdef LOCKFILE + (void) strcpy(lock_file, SAVE_BINDINGS_LOCK_FILE); +#endif /* LOCKFILE */ + } else { + (void) strcpy(host_file, envres); +#ifdef LOCKFILE + (void) strcpy(lock_file, envres); + (void) strcat(lock_file, ".lock"); +#endif /* LOCKFILE */ + } + +#ifdef LOCKFILE + /* open the lock file */ + + if ((lockFile = open(lock_file, O_RDWR | O_CREAT)) == -1) { + mipverbose(("preFileAccess: cannot open lock file\n")); + return (-1); + } + + /* lock it; block if already locked */ + + if ((lockf(lockFile, F_LOCK, 0L)) == -1) { + mipverbose(("preFileAccess: cannot lock %s\n", + lock_file)); + return (-1); + } +#endif /* LOCKFILE */ + + /* + * Must first set umask so as not to allow anybody else + * to read these files. They may have keyeing material. + */ + mask = umask(~(S_IRUSR|S_IWUSR)); + + /* open for reading/writing the file */ + if ((agentStateFile = fopen(host_file, (forReading ? "r" : "w"))) + == NULL) { + mipverbose(("preFileAccess: can't open %s for %s\n", + host_file, (forReading ? "reading" : "writing"))); +#ifdef LOCKFILE + if ((lockf(lockFile, F_ULOCK, 0L)) == -1) { + mipverbose(("preFileAccess: can't unlock %s\n", + lock_file)); + } + (void) close(lockFile); +#endif /* LOCKFILE */ + (void) umask(mask); + return (-1); + } + (void) umask(mask); + return (0); +} /* preFileAccess() */ + +/* + * Called after file access. + * Returns 0 if ok, -1 if error. + */ +static int +postFileAccess(void) +{ + int ret = 0; + + (void) fclose(agentStateFile); + +#ifdef LOCKFILE + /* unlock the lock file */ + + if ((lockf(lockFile, F_ULOCK, 0L)) == -1) { + mipverbose(("postFileAccess can't unlock %s\n", + lock_file)); + ret = -1; + } + (void) close(lockFile); +#endif /* LOCKFILE */ + return (ret); +} /* postFileAccess() */ + +/* + * Delete the state and lock file after restoring. + */ +static void +removeStateFile(void) +{ + (void) unlink(host_file); +#ifdef LOCKFILE + (void) unlink(lock_file); +#endif /* LOCKFILE */ +} /* removeStateFile() */ + +/* returns 0 if error, otherwise 1 (nitems) */ +static size_t +saveOneEntry(void *ptr, size_t size) +{ + size_t nitems = fwrite(ptr, size, 1, agentStateFile); + + if (nitems != 1) { + if (feof(agentStateFile)) { + mipverbose(("saveOneEntry: eof! \n")); + (void) postFileAccess(); + return (0); + } + if (ferror(agentStateFile)) { + mipverbose(("saveOneEntry: error! \n")); + (void) postFileAccess(); + return (0); + } + } + return (nitems); +} + +/* returns 0 if error, otherwise 1 (nitems) */ +static size_t +readOneEntry(void *ptr, size_t size) +{ + size_t nitems = fread(ptr, size, 1, agentStateFile); + + if (nitems != 1) { + if (feof(agentStateFile)) { + mipverbose(("readOneEntry: eof! \n")); + (void) postFileAccess(); + return (0); + } + if (ferror(agentStateFile)) { + mipverbose(("readOneEntry: error! \n")); + (void) postFileAccess(); + return (0); + } + } + return (nitems); +} + +/* + * Function: restoreIPsecPolicies() + * + * Arguments: new - Pointer to the new MobilityAgentEntry info. + * This is what we've just read from the config file. + * saved - Pointer to what we read as our exit config. + * This is how we were configured, and what IPsec + * policies were in place when we were told to shutdown. + * + * Description: Compares what was parsed from the config file with how we were + * configured when we exited. Config file settings, and hence + * IPsec policies can change between executions. We want to + * restore those that were installed with the new settings, + * informing the user when policies have changed, and which have + * been restored - especially when those that were in place have + * been removed. + * + * Returns: 1 if OK, 0 if not (like the others called from + * restoreAllMobilityBindings()). + */ +int +restoreIPsecPolicies(MobilityAgentEntry *new, MobilityAgentEntry *saved) +{ + /* + * Check the new policies, and restore any that were installed. We're + * really just doing this as a convenience for the user. Those that + * were installed because of bound mobile nodes will again be installed + * even if the policies are changed (we do NOT second-guess that sort + * of thing). However, since this sort of thing can be confusing + * when it fails, we'll log the new policies so the user has a place + * to start if there are problems. + */ + int action; + char peerAddr[IPv4_ADDR_LEN]; + + (void) ntoa(new->maAddr, peerAddr); + + /* + * maPeerFlags will be restored when we restore the MN entries. + * + * We don't copy maIPsecFlags because the tunnel flags will be restored + * when the MN entries are restored, and the registration flags will + * be set as we [re]install each one. + * + * The maIPsecSAFlags[] aren't overwritten since they've been parsed + * based on the potentially new settings in conf-land! + * + * For readability, we first run through the policies, and see what's + * changed, then restore whatever was installed. + */ + for (action = FIRST_IPSEC_ACTION; + action < LAST_IPSEC_ACTION; + action++) { + /* check all for IPSEC_APPLY, then IPSEC_PERMIT */ + if (memcmp(&new->maIPsecRequestIPSR[action], + &saved->maIPsecRequestIPSR[action], + sizeof (ipsec_req_t)) != 0) { + /* SA has changed, tell the user. */ + mipverbose(("IPsecRequest %s policy for %s changed.\n", + validIPsecAction[action], peerAddr)); + + /* was the policy active? */ + if (saved->maIPsecFlags & REQUEST(action)) { + /* A problem if the user *unconfigured* it! */ + if (*new->maIPsecRequest[action] != 0) + /* tell the user we know */ + mipverbose(("new IPsecRequest %s policy" + " will be installed.\n", + validIPsecAction[action])); + } + } + + if (memcmp(&new->maIPsecReplyIPSR[action], + &saved->maIPsecReplyIPSR[action], + sizeof (ipsec_req_t)) != 0) { + /* SA has changed, tell the user. */ + mipverbose(("IPsecReply %s policy for %s changed.\n", + validIPsecAction[action], peerAddr)); + + /* was the policy active? */ + if (saved->maIPsecFlags & REPLY(action)) { + /* A problem if the user *unconfigured* it! */ + if (*new->maIPsecReply[action] != 0) + /* tell the user we know */ + mipverbose(("new IPsecReply %s policy " + "will be installed.\n", + validIPsecAction[action])); + } + } + + if (memcmp(&new->maIPsecTunnelIPSR[action], + &saved->maIPsecTunnelIPSR[action], + sizeof (ipsec_req_t)) != 0) { + /* SA has changed, tell the user. */ + mipverbose(("IPsecTunnel %s policy for %s changed.\n", + validIPsecAction[action], peerAddr)); + + /* was the policy active? */ + if (saved->maIPsecFlags & TUNNEL(action)) { + /* A problem if the user *unconfigured* it! */ + if (!IPSEC_TUNNEL_ANY( + new->maIPsecSAFlags[action])) { + /* tell the user we know */ + mipverbose(("new IPsecTunnel %s policy " + "will be installed.\n", + validIPsecAction[action])); + } + } + } + + if (memcmp(&new->maIPsecReverseTunnelIPSR[action], + &saved->maIPsecReverseTunnelIPSR[action], + sizeof (ipsec_req_t)) != 0) { + /* SA has changed, tell the user. */ + mipverbose(( + "IPsecReverseTunnel %s policy for %s changed.\n", + validIPsecAction[action], peerAddr)); + + /* was the policy active? */ + if (saved->maIPsecFlags & REVERSE_TUNNEL(action)) { + /* A problem if the user *unconfigured* it! */ + if (!IPSEC_REVERSE_TUNNEL_ANY( + new->maIPsecSAFlags[action])) + /* tell the user we know. */ + mipverbose(( + "new IPsecReverseTunnel %s policy " + "will be installed.\n", + validIPsecAction[action])); + } + } + } + + /* + * Restore those that were installed. Warn the user if any of these + * went away! + */ + for (action = FIRST_IPSEC_ACTION; + action < LAST_IPSEC_ACTION; + action++) { + /* restore for IPSEC_APPLY, then IPSEC_PERMIT */ + + /* + * note: there is a potential problem with restoring REQUESTs. + * Before we restore, we parse the config file, which is when + * IPSEC_REQUEST_PERMIT policies need to be installed. That + * means if this is what we're restoring, it's been done (and + * it's the new = correct policy). + */ + if ((action != IPSEC_PERMIT) && + (saved->maIPsecFlags & REQUEST(action))) { + /* restore, IFF still configured */ + if (*new->maIPsecRequest[action] != 0) { + if (installIPsecPolicy( + new->maIPsecRequest[action]) < 0) { + /* we wont be able to communicate */ + mipverbose(( + "Can't restore %s's ipsec %s" + "registration request policy.\n", + validIPsecAction[action], + peerAddr)); + return (0); + } + + /* set the installed flag */ + new->maIPsecFlags |= REQUEST(action); + + } else { + /* one WAS installed, but isn't configured */ + mipverbose(("WARNING: IPsecRequest %s policy " + "for %s was installed but is no longer " + "configured! Registration request will be " + "in the clear!", validIPsecAction[action], + peerAddr)); + return (0); + } + } + + if (saved->maIPsecFlags & REPLY(action)) { + /* restore, IFF still configured */ + if (*new->maIPsecReply[action] != 0) { + if (installIPsecPolicy( + new->maIPsecReply[action]) < 0) { + /* we wont be able to communicate */ + mipverbose(( + "Can't restore %s's ipsec %s" + "registration reply policy.\n", + validIPsecAction[action], + peerAddr)); + return (0); + } + + /* set the installed flag */ + new->maIPsecFlags |= REPLY(action); + + } else { + /* one WAS installed, but isn't configured */ + mipverbose(("WARNING: IPsecReply %s policy " + "for %s was installed but is no longer " + "configured! Registration reply will be " + "in the clear!", validIPsecAction[action], + peerAddr)); + return (0); + } + } + + /* + * Note: + * tunnel entries are added when we restore the MNs still + * registered with us. An existing MN causes addHABE() to be + * called, which calls encapadd() where the correct ipsec_req_t + * is passed to ioctl() via settaddr() - exactly as if the MN + * registered. At this time, warn the user if any policies + * went away, yet we're likely to restore the policy with a MN! + */ + if (saved->maIPsecFlags & TUNNEL(action)) { + if (!IPSEC_TUNNEL_ANY(new->maIPsecSAFlags[action])) + /* tell the user the config's gone */ + mipverbose(( + "WARNING: IPsecTunnel %s policy for " + " %s was installed, but is no longer " + "configured. Restoring with no policy!", + validIPsecAction[action], peerAddr)); + } + + if (saved->maIPsecFlags & REVERSE_TUNNEL(action)) { + if (!IPSEC_REVERSE_TUNNEL_ANY( + new->maIPsecSAFlags[action])) + /* tell the user the config's gone */ + mipverbose(( + "WARNING: IPsecReverseTunnel %s policy for " + " %s was installed, but is no longer " + "configured. Restoring with no policy!", + validIPsecAction[action], peerAddr)); + } + } + + return (1); +} diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/auth.c b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/auth.c new file mode 100644 index 0000000000..6672556174 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/auth.c @@ -0,0 +1,1661 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999-2001 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * file: auth.c + * + * This function contains all of the routines + * necessary to authenticate Registration Requests, + * including the functions which add and validate + * the authentication extensions, the SPI lookup + * routines, etc. + */ + +#include <stdio.h> +#include <string.h> +#include <syslog.h> + +#include "agent.h" +#include "mip.h" +#include "md5.h" +#include "auth.h" + +#include <sys/types.h> +#include <netinet/in.h> + + +extern char msg[]; +extern AAA_Protocol_Code aaaProtocol; +extern boolean_t faChallengeAdv; +extern boolean_t mfAuthRequired; +extern boolean_t fhAuthRequired; +extern int logVerbosity; + +/* + * Default Values... + */ +extern uint32_t defaultPool; +extern uint32_t defaultNodeSPI; + +#ifdef RADIUS_ENABLED +HaMobileNodeEntry *radiusCheckUpdate(HaMobileNodeEntry *dest, + struct hash_table *htbl, ipaddr_t mnAddr); +#endif /* RADIUS_ENABLED */ + +static boolean_t isAuthExtOk(unsigned char *, int, MipSecAssocEntry *); +extern int hexdump(char *, unsigned char *, int); +extern uint32_t getRandomValue(); + +/* ----------------- Common to all mobility agents ------------------- */ +/* + * This table stores all of the Security Assocations + */ +extern HashTable mipSecAssocHash; + +/* + * This table has one entry for each known Mobility Agent + */ +extern HashTable mipAgentHash; + +/* + * This table has one entry for each pool defined in the config file + */ +extern HashTable mipPoolHash; + +/* ------------------ Specific to foreign agents -------------------- */ + +/* + * Counters maintained by Foreign Agents + */ +extern ForeignAgentCounters faCounters; + +/* + * The last two challenges advertised + */ +extern char faLastChallengeIssued[2][ADV_CHALLENGE_LENGTH]; + + +/* ------------------ Specific to home agents -------------------- */ +/* + * This table has one entry for each mobile node for which a mobility + * agent offers Home Agent services. + */ +extern HashTable haMobileNodeHash; + +/* + * Counters maintained by Home Agents + */ +extern HomeAgentCounters haCounters; + +/* + * Compute authenticator for the data in buffer based on the + * Mobile IP Security Association pointed to by msaEntry. + */ + +/* + * Function: computeAuth + * + * Arguments: buffer - Pointer to buffer + * buflen - Length of data in the buffer + * authenticator - Pointer to the output buffer + * authenticationlen - length of the output buffer + * msa - Pointer to the security association entry. + * + * Description: Compute authenticator for the data in buffer based on the + * Mobile IP Security Association pointed to by msaEntry. + * + * Returns: void + */ +static void +computeAuth(unsigned char buffer[], int buflen, + unsigned char authenticator[], int *authenticatorlen, + MipSecAssocEntry *msa) +{ + MD5_CTX context; + + /* + * Initialize the length. + */ + + if (msa) { + switch (msa->mipSecAlgorithmType) { + case MD5: + if (*authenticatorlen < AUTHENTICATOR_LEN) { + syslog(LOG_ERR, + "Not enough space for MD5 authenticator."); + } else if (msa->mipSecAlgorithmMode != PREFIXSUFFIX) { + syslog(LOG_ERR, "Unknown mode specified " \ + "for MD5 algorithm."); + } else { + /* + * No longer print MD5 results. + */ + *authenticatorlen = 0; + MD5Init(&context); + MD5Update(&context, msa->mipSecKey, + (unsigned int) msa->mipSecKeyLen); + MD5Update(&context, buffer, + (unsigned int) buflen); + MD5Update(&context, msa->mipSecKey, + (unsigned int) msa->mipSecKeyLen); + MD5Final(authenticator, &context); + *authenticatorlen = AUTHENTICATOR_LEN; + } + break; + + case NONE: + /* we leave the contents of authenticator unchanged */ + *authenticatorlen = AUTHENTICATOR_LEN; + break; + + default: + /* + * Any other authentication transform, which we + * currentlydo not support. + */ + syslog(LOG_ERR, "Invalid Authentication Type " \ + "requested"); + } + } +} + + +/* + * Function: appendAuthExt + * + * Arguments: buffer - Pointer to the packet + * buflen - Offset in the packet where extension is + * to be added. + * type - Extension Id + * msa - Pointer to the Security Assocation Entry + * + * Description: Append authentication extension to a registration + * reply contained in buffer based on the Mobile IP + * Security Association pointed to by MSA. Returns + * total number of bytes in the extension. + * + * Returns: The number of bytes added to the packet. + */ +int +appendAuthExt(unsigned char *buffer, size_t buflen, uint8_t type, + MipSecAssocEntry *msa) +{ + int authlen = 0; + authExt *aep; + uint32_t SPI; + uint16_t tempShort; + + if (msa) { + /* + * TODO: + * The length of authenticator actually depends on the + * algorithm. For now, we assume AUTHENTICATOR_LEN. + */ + + /* LINTED E_BAD_PTR_CAST_ALIGN */ + aep = (authExt *)(buffer + buflen); + aep->type = type; + + /* + * We need to set to length to the sizeof the SPI plus the + * length of the authenticator. + */ + aep->length = (sizeof (SPI) + AUTHENTICATOR_LEN); + SPI = (msa == NULL) ? 0 : msa->mipSecSPI; + tempShort = htons(SPI >> AUTHENTICATOR_LEN); + (void) memcpy(&aep->SPIhi, &tempShort, sizeof (uint16_t)); + tempShort = htons(SPI & 0xffff); + (void) memcpy(&aep->SPIlo, &tempShort, sizeof (uint16_t)); + + authlen = AUTHENTICATOR_LEN; + computeAuth(buffer, buflen + sizeof (authExt), + buffer + buflen + sizeof (authExt), &authlen, msa); + + if (authlen) { + authlen += sizeof (authExt); + } + } + + return (authlen); +} + + +/* + * Function: isAuthOk + * + * Arguments: buffer - Pointer to buffer + * buflen - Length of data in the buffer + * authenticator - Pointer to hash to compare against + * authenticationlen - length of hash buffer + * msa - Pointer to the security association entry + * + * Description: This function computes a hash using the buffer and + * compares the result with the data in the authenticator. + * If both values match, the packet is considered + * authenticated. + * + * Returns: boolean_t - _B_FALSE if packet is not authenticated. + */ +static boolean_t +isAuthOk(unsigned char buffer[], int buflen, + unsigned char authenticator[], int authenticatorlen, + MipSecAssocEntry *msa) +{ + static unsigned char newAuth[32]; + int newAuthLen = 32; + int i; + + if (msa == NULL) { + return (_B_FALSE); + } + + switch (msa->mipSecAlgorithmType) { + case MD5: + computeAuth(buffer, buflen, newAuth, &newAuthLen, msa); + mipverbose(("authenticator = %d bytes, newAuth = %d bytes\n", + authenticatorlen, newAuthLen)); + if (newAuthLen != authenticatorlen) + return (_B_FALSE); + + for (i = 0; i < newAuthLen; i++) { + if (newAuth[i] != authenticator[i]) { + syslog(LOG_ERR, + "isAuthOk: bad key at position %d (%02X <> %02X)\n", + i, authenticator[i], newAuth[i]); + return (_B_FALSE); + } + } + + break; + + case NONE: + /* No checks required */ + break; + } + + return (_B_TRUE); +} + + +/* + * Function: isAuthExtOk + * + * Arguments: buffer - Pointer to a packet + * buflen - Offset in the packet where the authentication + * extension can be found. + * msa - Pointer to a Security Assocation Entry + * + * Description: Buffer contains buflen bytes of a registration request + * and an immediately following authentication extension. + * Check if the authentication extension is correct + * according to the given msa. + * + * Returns: boolean_t - _B_TRUE if authentication extension was + * computed using the protocol security assocation. + */ +static boolean_t +isAuthExtOk(unsigned char buffer[], int buflen, MipSecAssocEntry *msa) +{ + int authLen; + boolean_t result = _B_FALSE; + authExt *aep; + genAuthExt *genAep; + uint32_t SPI; + + /* LINTED E_BAD_PTR_CAST_ALIGN */ + aep = (authExt *) (buffer + buflen); + + /* + * Support for the latest Challenge/response draft, which + * requires support for the generalized authentication header. + */ + switch (aep->type) { + case REG_MH_AUTH_EXT_TYPE: + case REG_MF_AUTH_EXT_TYPE: + case REG_FH_AUTH_EXT_TYPE: + GET_SPI(SPI, aep); + + if (SPI != msa->mipSecSPI) { + mipverbose(("Type: %d, Length %d\n", aep->type, + aep->length)); + mipverbose(("SPI mismatch got %d had %d.\n", + SPI, msa->mipSecSPI)); + result = _B_FALSE; + } else { + /* this length includes 4 bytes SPI */ + authLen = aep->length - 4; + result = isAuthOk(buffer, buflen + sizeof (authExt), + (buffer + buflen + sizeof (authExt)), + authLen, msa); + } + break; + + case REG_GEN_AUTH_EXT_TYPE: + genAep = (genAuthExt *) aep; + + GET_GEN_AUTH_SPI(SPI, genAep); + + if (SPI != msa->mipSecSPI) { + mipverbose(("Type: %d, subType: %d, Length %d\n", + genAep->type, genAep->subType, genAep->length)); + mipverbose(("SPI mismatch got %d had %d.\n", + SPI, msa->mipSecSPI)); + result = _B_FALSE; + } else { + /* This length includes 4 bytes SPI */ + authLen = ntohs(genAep->length) - 4; + result = isAuthOk(buffer, buflen + sizeof (genAuthExt), + (buffer + buflen + sizeof (genAuthExt)), + authLen, msa); + } + break; + + default: + /* + * Unknown authentication type.... reject + */ + result = _B_FALSE; + break; + } + + return (result); +} + +#ifdef TEST_AUTH +/* + * Function: main + * + * Arguments: argc - Number of command line parameters + * argv - Pointer to command line arguments + * + * Description: This function is used to validate our MD5 implementation. + * It is no longer in use, but is kept in case one needs + * to test the authentication computation in this file + * stand-alone. + * + * Returns: exits + */ +int +main(int argc, char *argv[]) +{ + int i; + unsigned char digest[AUTHENTICATOR_LEN]; + int digestlen = AUTHENTICATOR_LEN; + MipSecAssocEntry msae = { { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + 1, 0, MD5, PREFIXSUFFIX, 16, + { 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11 + }, + TIMESTAMPS, 0 }; + + unsigned char packet[30] = { + /* + * 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + * 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + */ + 0x01, 0x00, 0x00, 0x28, 0x81, 0x92, 0x7a, 0xcc, + 0x81, 0x92, 0x7a, 0xbf, 0x81, 0x92, 0xc9, 0x09, + 0x00, 0x00, 0x00, 0x00, 0xe4, 0xa8, 0x5f, 0xcb, + 0x20, 0x14, 0x00, 0x00, 0x00, 0x01 + /* + * 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + * 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 + */ + }; + /* + * 0x01, 0x00, 0x01, 0x2c, 0x81, 0x92, 0x7a, 0xc0, + * 0x81, 0x92, 0x7a, 0x7b, 0x81, 0x92, 0xc9, 0x09, + * 0x00, 0x00, 0x00, 0x00, 0x17, 0xe1, 0x2c, 0x23, + * 0x20, 0x14, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + * 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + * 0x11, 0x11 + * }; + * unsigned char packet[] = {'J', 'i', 'm'}; + */ + + printMSAE(&msae); + computeAuth(packet, 30, digest, &digestlen, &msae); + (void) printf("Authenticator for packet = "); + printBuffer(digest, digestlen); + (void) printf("\n"); + + /* Simulate data corruption or incorrect MSAE */ + msae.mipSecKeyLen = 2; + packet[2] = 0x00; + msae.mipSecKey[0] = 'A'; + printMSAE(&msae); + if (isAuthOk(packet, 3, digest, digestlen, &msae)) + (void) printf("Check succeeded.\n"); + +} +#endif /* TEST_AUTH */ + +/* + * Function: findSecAssocFromSPI + * + * Arguments: SPI - The Security Parameter Index value + * lockType - The Lock type, which can be: + * LOCK_NONE - No Lock + * LOCK_READ - Read Lock + * LOCK_WRITE - Write Lock + * + * Description: This function will look for a security assocation + * entry in the hash table matching on the SPI. If + * a lock type was requested, upon return the node + * will be locked. The caller will be responsible + * for unlocking the node when it no longer needs + * the security association entry. + * + * If a security association entry was found, and + * the entry is marked as dynamic and if the key + * has expired, a NULL value will be returned. + * + * Returns: If successful, a pointer to a Security Association + * Entry will be returned, otherwise NULL. + */ +MipSecAssocEntry * +findSecAssocFromSPI(uint32_t SPI, int lockType) +{ + MipSecAssocEntry *saEntry = NULL; + time_t currentTime; + + /* + * Let's see if we can find the SA using the SPI. + */ + if ((saEntry = findHashTableEntryUint(&mipSecAssocHash, + SPI, lockType, NULL, 0, 0, 0)) != NULL) { + /* + * Keys has a defined lifetime, which is set by the + * home AAA Server. We need to check whether the + * key being used is still valid. + */ + + GET_TIME(currentTime); + if (saEntry->mipSecIsEntryDynamic == TRUE && + saEntry->mipSecKeyLifetime < currentTime) { + /* + * The Security Association has expired. + * If the node was locked, we need to + * unlock it. We will be returning a NULL + * to the caller since this is no longer + * valid. + */ + if (lockType != LOCK_NONE) { + (void) rw_unlock(&saEntry->mipSecNodeLock); + } + saEntry = NULL; + } + } + + return (saEntry); +} + + +/* + * Note that upon return of a security association entry, the + * node will be locked. The caller must unlock the node once + * it is finished with the entry. + */ +/* + * Function: findSecAssocFromIp + * + * Arguments: address - Peer's IP Address + * lockType - The Lock type, which can be: + * LOCK_NONE - No Lock + * LOCK_READ - Read Lock + * LOCK_WRITE - Write Lock + * + * Description: This function will look for a security assocation + * entry in the hash table matching on the IP Address. + * If a lock type was requested, upon return the node + * will be locked. The caller will be responsible + * for unlocking the node when it no longer needs + * the security association entry. + * + * If a security association entry was found, and + * the entry is marked as dynamic, if the key has + * expired + * + * Returns: If successful, a pointer to a Security Association + * Entry will be returned + * If not successful, NULL is returned. + */ +MipSecAssocEntry * +findSecAssocFromIp(ipaddr_t address, int lockType) +{ + MobilityAgentEntry *maEntry; + MipSecAssocEntry *saEntry = NULL; + + /* + * First we need to find the MA structure to get + * the SPI value. + */ + if ((maEntry = findHashTableEntryUint(&mipAgentHash, + address, LOCK_READ, NULL, 0, 0, 0)) != NULL) { + /* + * Good, now let's find the SA itself. + */ + saEntry = findSecAssocFromSPI(maEntry->maSPI, lockType); + + (void) rw_unlock(&maEntry->maNodeLock); + } + + return (saEntry); +} + +/* + * Function: findMaeFromIp + * + * Arguments: address - Peer's IP Address + * lockType - The Lock type, which can be: + * LOCK_NONE - No Lock + * LOCK_READ - Read Lock + * LOCK_WRITE - Write Lock + * + * Description: This function will look for an IPsec Policy + * entry in the hash table matching on the IP Address. + * If a lock type was requested, upon return the node + * will be locked. The caller will be responsible + * for unlocking the node when it no longer needs + * the security association entry. + * + * Returns: If successful, a pointer to a Security Association + * Entry will be returned, otherwise NULL. + */ +MobilityAgentEntry * +findMaeFromIp(ipaddr_t address, int lockType) +{ + MobilityAgentEntry *maEntry; + + /* + * First we need to find the MA structure to get + * the SPI value. + */ + if ((maEntry = findHashTableEntryUint(&mipAgentHash, + address, lockType, NULL, 0, 0, 0)) == NULL) + return (0); + + return (maEntry); +} + + +#ifdef KEY_DISTRIBUTION +/* + * KEY_DISTRIBUTION MUST ONLY BE COMPILED FOR TESTING!!! + * + * This version of mipagent supports a AAA/DIAMETER + * 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. + * + * Since DIAMETER/AAA is not currently a product, and key + * 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. + */ +#define MAX_SESSION_KEY_LEN 16 +/* + * Function: createSessionKey + * + * Arguments: key - Pointer to session key buffer + * keyLen - Pointer to Length of session key + * spi - Pointer to SPI + * + * Description: This function is used to create pseudo-random + * session keys, and SPI values. Note that the + * keys created here are by no means random, and + * this function is only used for testing purposes. + * + * Returns: none + */ +static void +createSessionKey(uint8_t *key, uint32_t *keyLen, uint32_t *spi) +{ + int i; + + /* + * First we create the SPI value. + */ + *spi = htonl(getRandomValue()); + + /* + * Now we create the session key + */ + for (i = 0; i < MAX_SESSION_KEY_LEN; i++) { + key[i] = getRandomValue(); + } + + /* + * Set the length + */ + *keyLen = MAX_SESSION_KEY_LEN; + +} + +/* + * Function: createSessionKey + * + * Arguments: keyData - Pointer to Genrealized key extension + * keyLen - Length of key extension + * spi - Pointer to SPI + * + * Description: This function will create a local Security + * association, using the information found in + * a generalized key extension. Note that this + * function is only used for testing purposes. + * + * Returns: _B_TRUE if successful + */ +static boolean_t +createSecAssocFromKeyData(keyDataExt *keyData, int keyDataLen, uint32_t *SPI) +{ + uint32_t spi; + uint32_t lifetime; + + /* + * Extract the information from the generalized key ext + */ + (void) memcpy(&spi, &keyData->nodeSPI, sizeof (uint32_t)); + (void) memcpy(&lifetime, &keyData->lifetime, sizeof (uint32_t)); + + /* + * Create a new Security Association Entry + */ + if (aaaCreateKey(ntohl(spi), (uint8_t *)((char *)keyData) + + sizeof (keyDataExt), keyDataLen - sizeof (keyDataExt), + ntohl(lifetime))) { + syslog(LOG_CRIT, "Unable to create SA from keydata"); + return (_B_FALSE); + } + + /* + * Set the SPI value + */ + *SPI = ntohl(spi); + + return (_B_TRUE); +} + +#endif /* KEY_DISTRIBUTION */ + +/* + * Function: faCheckRegReqAuth + * + * Arguments: messageHdr - Pointer to Message Control Block + * mnSPI - Pointer to Mobile Node's SPI + * mnChallenge - Pointer to the FA Challenge + * mnChallengeLen - Length of the Challenge + * forwardFlag - Pointer to the forward msg flag. + * + * Description: This function is responsible for authenticating + * the Registration Request. First, the function + * will check whether the Challenge is present, which + * MUST be if the agent is configured to advertise + * challenges. Next, the Mobile-Foreign is checked + * to ensure that the message is authenticated. If + * the extension was not found, and the agent is + * configured to require this extension, authentication + * will fail. + * + * Lastly, if the Mobile-AAA authentication extension + * is present, we will send a request to the AAA + * infrastructure. If this request is successfully sent, + * the forward flag will be set to _B_FALSE to ensure that the + * caller does not forward the Registration Request to + * the Home Agent. + * + * Returns: int - 0 if successful, otherwise the Mobile-IP error code + * is returned. The forwardFlag will be set to _B_FALSE if + * the message is being sent to the AAA infrastructure. + */ +/* ARGSUSED */ +int +faCheckRegReqAuth(MessageHdr *messageHdr, FaVisitorEntry *favePtr, + FaVisitorEntry *acceptedFave, unsigned char *mnChallenge, + uint32_t mnChallengeLen, boolean_t *forwardFlag) +{ + regRequest *reqPtr; + MipSecAssocEntry *mipSecAssocEntry; + authExt *mnAuthExt; + /* + * Support for the latest Challenge/response draft. + */ + genAuthExt *mnAAAAuthExt; + uint32_t SPI; + uint32_t aaaSPI; + size_t length; + int mnAAAAuthExtLen; + int mnAuthExtLen; + int index; + int result; + + /* LINTED E_BAD_PTR_CAST_ALIGN */ + reqPtr = (regRequest *)messageHdr->pkt; + *forwardFlag = _B_TRUE; + + /* + * We have two different authentication types that we need + * to worry about. First, and foremost, we need to be able + * to support the case where a Mobile-Foreign Security + * Association exists. In the AAA world, an authenticated + * and authorized Mobile Node would have the keys setup in + * the mnFaNodeHash, and this case would apply. + * + * The next case is when we are unaware of the Mobile Node. + * In this case, the Mobile Node should have include the + * Challenge/Response extensions which are used for AAA + * purposes. When this is found, we issue a call to the local + * AAA daemon to authenticate and authorize the MN. + */ + + if (faChallengeAdv) { + if (mnChallengeLen == 0) { + syslog(LOG_ERR, + "Missing Challenge Extention"); + faCounters.faMNAuthFailureCnt++; + /* + * Support for the latest Challenge/response draft. + * If the challenge was expected, and found present, + * return a missing challenge error. + */ + return (FA_MISSING_CHALLENGE); + } + + /* + * Obviously, we need to validate the challenge. + */ + if (memcmp(faLastChallengeIssued[0], mnChallenge, + ADV_CHALLENGE_LENGTH) != 0) { + /* + * Let's try our backup. + */ + if (memcmp(faLastChallengeIssued[1], + mnChallenge, ADV_CHALLENGE_LENGTH) != 0) { + /* + * If the visitor entry is present, then we + * can ALSO check whether a challenge was + * previously issued to the mobile node + * in a registration reply. + */ + if (acceptedFave && + acceptedFave->faVisitorChallengeAdvLen) { + if (memcmp( + acceptedFave->faVisitorChallengeAdv, + mnChallenge, + acceptedFave-> \ + faVisitorChallengeAdvLen) != 0) { + syslog(LOG_ERR, + "Invalid Challenge Extention"); + faCounters.faMNAuthFailureCnt++; + return (FA_UNKNOWN_CHALLENGE); + } + } else { + syslog(LOG_ERR, + "Invalid Challenge Extention"); + faCounters.faMNAuthFailureCnt++; + return (FA_UNKNOWN_CHALLENGE); + } + } + } + } + + + mipverbose(("Checking authext")); + + /* + * Support for the latest Challenge/Response I-D + */ + /* LINTED E_BAD_PTR_CAST_ALIGN */ + GET_GEN_AUTH_EXT(messageHdr, index, + GEN_AUTH_MN_AAA, mnAAAAuthExt, mnAAAAuthExtLen); + + /* + * If a Mobile node Foreign agent authentication extension exists + * check it. + */ + /* LINTED E_BAD_PTR_CAST_ALIGN */ + GET_AUTH_EXT(messageHdr, index, REG_MF_AUTH_EXT_TYPE, + mnAuthExt, mnAuthExtLen); + + if (mnAuthExtLen) { + GET_SPI(SPI, mnAuthExt); + + /* + * Remember that the node will be locked upon return. + * We need to unlock it when we are done... + */ + if ((mipSecAssocEntry = + findSecAssocFromSPI(SPI, LOCK_READ)) == NULL) { + syslog(LOG_ERR, "Error: No SA for Mobile Node"); + faCounters.faMNAuthFailureCnt++; + return (FA_MN_AUTH_FAILURE); + } + + if (isAuthExtOk(messageHdr->pkt, + (messageHdr->extIdx[index] - messageHdr->pkt), + mipSecAssocEntry) == _B_FALSE) { + (void) rw_unlock(&mipSecAssocEntry->mipSecNodeLock); + syslog(LOG_ERR, "Failed MN-FA authentication"); + faCounters.faMNAuthFailureCnt++; + return (FA_MN_AUTH_FAILURE); + } + + /* + * ... and now we are done, let's unlock it. + */ + (void) rw_unlock(&mipSecAssocEntry->mipSecNodeLock); + + /* + * Support for differing extension header formats. + * + * Remove the extension by playing with the + * packet's length. + */ + messageHdr->pktLen = (messageHdr->extIdx[index-1] - + messageHdr->pkt) + messageHdr->extHdrLength[index-1] + + messageHdr->extLength[index-1]; + } else { + /* + * If we are advertising challenges, and the Mobile-AAA + * authentication extension is present, then the + * Mobile-Foreign does not need to be present. If the + * Mobile-AAA is NOT present, and we are configured to + * require Mobile-Foreign, then we will fail + * authentication. + */ + if (faChallengeAdv == _B_TRUE && mnChallengeLen && + mnAAAAuthExtLen) { + mipverbose(("Found a challenge and response\n")); + + /* + * First, it is necessary for us to have the NAI in + * order to interact with the AAA. + */ + if (messageHdr->mnNAI == NULL) { + syslog(LOG_ERR, + "MN-AAA present without an NAI"); + faCounters.faMNAuthFailureCnt++; + return (FA_MN_AUTH_FAILURE); + } + + /* + * Is AAA Enabled? + */ + if (aaaProtocol == AAA_NONE) { + /* WORK -- why is this here? (PRC?) */ + return (0); +#if 0 + syslog(LOG_ERR, + "Not configured to interact with AAA"); + faCounters.faMNAuthFailureCnt++; + return (FA_MN_AUTH_FAILURE); +#endif + } + + if (mnAAAAuthExtLen) { + /* + * If the MN-AAA Authentication extension was + * present, retrieve the SPI value. + */ + GET_GEN_AUTH_SPI(aaaSPI, mnAAAAuthExt); + } + + /* + * If we are using Radius only, then the SPI must be 2. + */ + if (aaaProtocol == RADIUS && aaaSPI != RADIUS_SPI) { + syslog(LOG_ERR, "Failed MN-FA authentication " + "- wrong SPI"); + faCounters.faMNAuthFailureCnt++; + return (FA_MN_AUTH_FAILURE); + } + + /* + * Good, we've made it this far. Now let's go + * check with the AAA Infrastructure, if this + * was configured. + */ + /* + * Support for the latest Challenge response I-D + */ + length = ((char *)mnAAAAuthExt) - + ((char *)messageHdr->pkt) + sizeof (genAuthExt); + + /* + * If using Radius, we'd like to preserve messageHdr + * until we get a reply from the Radius server + */ + if (aaaProtocol == RADIUS) + messageHdr->dontDeleteNow = _B_TRUE; + + result = AAAAuthenticateRegReq(messageHdr->pkt, + messageHdr->pktLen, messageHdr->mnNAI, + messageHdr->mnNAILen, aaaSPI, + (unsigned char *)&mnAAAAuthExt[1], + mnAAAAuthExtLen - sizeof (mnAAAAuthExt), length, + reqPtr->homeAddr, reqPtr->haAddr, _B_FALSE, + messageHdr->inIfindex, + (void *)messageHdr, mnChallenge, mnChallengeLen); + + if (result) { + /* + * Now we look at the result code to determine + * what the error was. + */ + faCounters.faMNAuthFailureCnt++; + return (FA_MN_AUTH_FAILURE); + } else { + /* + * Make sure that we notify the caller that we + * should not forward the request to the Home + * Agent since: + * - if diameter: it is being done via + * diameter server. + * - if radius: we need to wait for the auth + * answer. + */ + *forwardFlag = _B_FALSE; + } + } else if (mfAuthRequired) { + syslog(LOG_ERR, "Failed MN-FA authentication - No Ext"); + faCounters.faMNAuthFailureCnt++; + return (FA_MN_AUTH_FAILURE); + } + } + + return (0); +} + +/* + * Function: faCheckRegRepAuth + * + * Arguments: messageHdr - Pointer to the Message Control Block + * favePtr - Pointer to the Visitor Entry + * + * Description: This function is used to authenticate a Registration + * Reply. If the agent is configured to advertise + * challenges, we will make sure that the challenge was + * returned by the Home Agent, and that the challenge + * value is identical to the value that was used by the + * Mobile Node. + * + * Next, if the Foreign-Home Authentication extension + * is present, it is authenticated. If it is present and + * the agent is configured to require it, we will fail + * authentication. + * + * Returns: int - 0 if successful, otherwise the Mobile-IP error code + * is returned. + */ +int +faCheckRegRepAuth(MessageHdr *messageHdr, FaVisitorEntry *favePtr) +{ + authExt *haAuthExt; + MipSecAssocEntry *mipSecAssocEntry; +#ifdef KEY_DISTRIBUTION + keyDataExt *keyData; + uint32_t keyDataLen; +#endif /* KEY_DISTRIBUTION */ + unsigned char *challenge; + uint32_t SPI; + int haAuthExtLen; + int challengeLen; + int index; + + /* + * If a Challenge was received by the Mobile Node (due to our + * advertisement, let's make sure that the same challenge is + * present in the response. + */ + if (favePtr->faVisitorChallengeToHALen) { + /* + * Retrieve the Challenge + */ + GET_EXT_DATA(messageHdr, index, REG_MF_CHALLENGE_EXT_TYPE, + challenge, challengeLen); + + if (challengeLen == 0 || challengeLen > ADV_CHALLENGE_LENGTH) { + /* + * Protect against buffer overflows... + */ + syslog(LOG_ERR, + "excessively large or missing Challenge"); + faCounters.faPoorlyFormedRepliesCnt++; + /* + * Support for the latest Challenge/response I-D. + * If the challenge was expected and not present, + * return a missing challenge error. + */ + return (FA_MISSING_CHALLENGE); + } + + if (memcmp(challenge, favePtr->faVisitorChallengeToHA, + challengeLen) != 0) { + /* + * Protect against buffer overflows... + */ + syslog(LOG_ERR, + "invalid Challenge in Registration Reply"); + faCounters.faPoorlyFormedRepliesCnt++; + /* + * Support for the latest Challenge/response I-D. + * If the challenge was invalid, return + * an unknown challenge error. + */ + return (FA_UNKNOWN_CHALLENGE); + } + } + +#ifdef KEY_DISTRIBUTION + /* + * If KEY_DISTRIBUTION is defined (testing purpose only), we will + * extract the FA session keys from the registration reply. + */ + /* LINTED E_BAD_PTR_CAST_ALIGN */ + GET_VEND_KEY_EXT(messageHdr, index, VENDOR_ID_SUN, REG_MN_FA_KEY_EXT, + keyData, keyDataLen); + + if (keyDataLen) { + /* + * We have a key!!! Let's create our security assoc. + */ + if (createSecAssocFromKeyData(keyData, keyDataLen, &SPI) == + _B_FALSE) { + syslog(LOG_ERR, + "unable to create dynamic MN-FA SA"); + return (HA_FA_AUTH_FAILURE); + } + favePtr->faVisitorSPI = SPI; + } + + /* + * If KEY_DISTRIBUTION is defined (testing purpose only), we will + * extract the FA session keys from the registration reply. + */ + /* LINTED E_BAD_PTR_CAST_ALIGN */ + GET_VEND_KEY_EXT(messageHdr, index, VENDOR_ID_SUN, REG_FA_HA_KEY_EXT, + keyData, keyDataLen); + + if (keyDataLen) { + /* + * We have a key!!! Let's create our security assoc. + */ + if (createSecAssocFromKeyData(keyData, keyDataLen, &SPI) == + _B_FALSE) { + syslog(LOG_ERR, + "unable to create dynamic FA-HA SA"); + return (HA_FA_AUTH_FAILURE); + } + } +#endif /* KEY_DISTRIBUTION */ + + /* + * If a Home agent Foreign agent authentication extension exists + * check it. + */ + /* LINTED E_BAD_PTR_CAST_ALIGN */ + GET_AUTH_EXT(messageHdr, index, REG_FH_AUTH_EXT_TYPE, haAuthExt, + haAuthExtLen); + + if (haAuthExtLen) { + GET_SPI(SPI, haAuthExt); + + /* + * Remember that the node will be locked upon return. + * We need to unlock it when we are done... + */ + if ((mipSecAssocEntry = + findSecAssocFromSPI(SPI, LOCK_READ)) == NULL) { + syslog(LOG_ERR, "Error: No Home Agent SA (%d)", SPI); + faCounters.faHAAuthFailureCnt++; + return (HA_FA_AUTH_FAILURE); + } + + if (isAuthExtOk(messageHdr->pkt, + (messageHdr->extIdx[index] - messageHdr->pkt), + mipSecAssocEntry) == _B_FALSE) { + syslog(LOG_ERR, "Failed FA-HA authentication"); + faCounters.faHAAuthFailureCnt++; + (void) rw_unlock(&mipSecAssocEntry->mipSecNodeLock); + return (HA_FA_AUTH_FAILURE); + } + (void) rw_unlock(&mipSecAssocEntry->mipSecNodeLock); + + /* + * Remove the extension by playing with the + * packet's length. + */ + messageHdr->pktLen = (messageHdr->extIdx[index-1] - + messageHdr->pkt) + messageHdr->extHdrLength[index-1] + + messageHdr->extLength[index-1]; + + if (aaaProtocol == DIAMETER && + messageHdr->pktSource == MIP_PKT_FROM_AAA) { + /* + * We probably ended up getting a new SPI from the + * AAA Server. Update the Visitor Entry with the + * new SPI. + */ + favePtr->faVisitorSPI = messageHdr->mnFaSPI; + } + } else { + if (fhAuthRequired) { + faCounters.faHAAuthFailureCnt++; + return (HA_FA_AUTH_FAILURE); + } + } + + + return (0); +} + + +/* + * Function: haCheckRegReqAuth + * + * Arguments: messageHdr - Pointer to the Message Control Block + * hamnePtr - Pointer to a pointer to a mobile node entry + * mnSPI - Pointer to the Mobile Node SPI + * faSPI - Pointe to the Foreign Agent SPI + * + * Description: This function is used to authenticate a Registration + * request on the Home Agent. First we attempt to find + * the Mobile Node Entry using the Home Address. If the + * Home Address in the request was set to zero, we will + * attempt to find it using the Mobile Node's NAI. + * + * Next we will ensure that either the Mobile-Home or the + * Mobile-AAA autentication extension is present. If none + * is present, and the packet was marked as being received + * by the Foreign Agent (as opposed to the AAA), we will + * make sure that the unknown Mobile Node is attempting + * to authenticate using the default SPI. If the packet + * was received via the AAA infrastructure, we will + * not require any authentication from the Mobile Node. + * + * Lastly, we will check the Foreign-Home Authentication + * extension. If one was not found, and the packet was + * not received by the AAA, we will fail authentication. + * + * Note that if a Mobile Node Entry pointer is returned + * by this function, the node will be locked. The caller + * is responsible to unlock the node. + * + * Returns: int - 0 if successful, otherwise the Mobile-IP error code + * is returned. + */ +int +haCheckRegReqAuth(MessageHdr *messageHdr, HaMobileNodeEntry **hamnePtr, + uint32_t *mnSPI, uint32_t *faSPI) +{ + regRequest *reqPtr; + int code = 0; + int result; + MipSecAssocEntry *mipSecAssocEntry; + genAuthExt *maAuthExt = NULL; + authExt *mnAuthExt = NULL; + authExt *faAuthExt = NULL; + int mnAuthExtLen; + int faAuthExtLen; + int index; + uint32_t SPI; + + /* LINTED E_BAD_PTR_CAST_ALIGN */ + reqPtr = (regRequest *)messageHdr->pkt; + *hamnePtr = NULL; + +#ifdef RADIUS_ENABLED + if (radiusEnabled) { + /* + * We always have to force a RADIUS lookup. + */ + *hamnePtr = radiusCheckUpdate(*hamnePtr, + &haMobileNodeHash, + reqPtr->homeAddr); + } +#endif /* RADIUS_ENABLED */ + + /* + * If a Foreign agent Home Agent authentication extension exists + * check it. + */ + /* LINTED E_BAD_PTR_CAST_ALIGN */ + GET_AUTH_EXT(messageHdr, index, REG_FH_AUTH_EXT_TYPE, faAuthExt, + faAuthExtLen); + + if (faAuthExtLen) { + GET_SPI(SPI, faAuthExt); + *faSPI = SPI; + /* + * if an SA is returned, the node will be locked so we + * need to unlock it when we are done. + */ + if ((mipSecAssocEntry = + findSecAssocFromSPI(SPI, LOCK_READ)) == NULL) { + syslog(LOG_ERR, + "Failed FA-HA authentication - SPI (%d) " + "defined", SPI); + haCounters.haFAAuthFailureCnt++; + return (HA_FA_AUTH_FAILURE); + } + + if (isAuthExtOk(messageHdr->pkt, + (messageHdr->extIdx[index] - messageHdr->pkt), + mipSecAssocEntry) == _B_FALSE) { + syslog(LOG_ERR, "Failed FA-HA authentication"); + haCounters.haFAAuthFailureCnt++; + (void) rw_unlock( + &mipSecAssocEntry->mipSecNodeLock); + return (HA_FA_AUTH_FAILURE); + } + + (void) rw_unlock(&mipSecAssocEntry->mipSecNodeLock); + + } else if ((messageHdr->pktSource != MIP_PKT_FROM_AAA) && + (messageHdr->pktSource != MIP_PKT_FROM_RADIUS)) { + /* + * If the packet comes from the AAA, we do not need + * the FA-HA auth, otherwise we may be configured + * to require it. + */ + if (fhAuthRequired) { + haCounters.haFAAuthFailureCnt++; + return (HA_FA_AUTH_FAILURE); + } + } else { + *faSPI = messageHdr->faHaSPI; + } + + /* + * If a Mobile Node Home Agent authentication extension exists + * check it. + */ + + /* LINTED E_BAD_PTR_CAST_ALIGN */ + GET_AUTH_EXT(messageHdr, index, REG_MH_AUTH_EXT_TYPE, mnAuthExt, + mnAuthExtLen); + + if (mnAuthExtLen) { + GET_SPI(SPI, mnAuthExt); + /* + * if an SA is returned, the node will be locked so we + * need to unlock it when we are done. + */ + if ((mipSecAssocEntry = + findSecAssocFromSPI(SPI, LOCK_READ)) == NULL) { + syslog(LOG_ERR, "Failed MN-HA authentication - " + "No SPI defined"); + haCounters.haMNAuthFailureCnt++; + return (HA_MN_AUTH_FAILURE); + } + if ((messageHdr->pktSource == MIP_PKT_FROM_AAA) || + (messageHdr->pktSource == MIP_PKT_FROM_RADIUS)) { + if (mipSecAssocEntry->mipSecIsEntryDynamic != + TRUE) { + /* + * So the packet came from the AAA. We + * need to ensure that the key being + * used is in fact a dynamic key. + * Otherwise we are leaving a security + * hole wide open. + */ + (void) rw_unlock( + &mipSecAssocEntry->mipSecNodeLock); + syslog(LOG_WARNING, "A AAA Mobile " + "Node is attempting to use a " + "static key - security violation!"); + haCounters.haMNAuthFailureCnt++; + return (HA_MN_AUTH_FAILURE); + } + } else if (isAuthExtOk(messageHdr->pkt, + (messageHdr->extIdx[index] - + messageHdr->pkt), mipSecAssocEntry) == + _B_FALSE) { + syslog(LOG_ERR, "Failed MN-HA " + "authentication"); + haCounters.haMNAuthFailureCnt++; + (void) rw_unlock( + &mipSecAssocEntry->mipSecNodeLock); + return (HA_MN_AUTH_FAILURE); + } + + (void) rw_unlock(&mipSecAssocEntry->mipSecNodeLock); + + } + if (aaaProtocol == RADIUS) { + + /* + * Validate MN_AAA ext exists before AAA call + * This way if an error we don't need + * to call on AAA. + */ + + /* LINTED E_BAD_PTR_CAST_ALIGN */ + GET_GEN_AUTH_EXT(messageHdr, index, + GEN_AUTH_MN_AAA, maAuthExt, mnAuthExtLen); + + if (mnAuthExtLen == 0) { + syslog(LOG_ERR, "Missing MN AAA Ext"); + haCounters.haMNAuthFailureCnt++; + return (HA_MN_AUTH_FAILURE); + } + /* + * Get the MN-AAA SPI + */ + GET_GEN_AUTH_SPI(*mnSPI, maAuthExt); + + /* + * Make sure SPI used is the Radius SPI (2). + */ + if (*mnSPI != RADIUS_SPI) { + haCounters.haMNAuthFailureCnt++; + return (HA_MN_AUTH_FAILURE); + } + + /* + * If using Radius, we'd like to preserve messageHdr + * until we get a reply from the Radius server + */ + + messageHdr->dontDeleteNow = _B_TRUE; + + result = AAAAuthenticateRegReq(messageHdr->pkt, + messageHdr->pktLen, messageHdr->mnNAI, + messageHdr->mnNAILen, *mnSPI, + (unsigned char *)NULL, 0, 0, + reqPtr->homeAddr, reqPtr->haAddr, _B_TRUE, + 0, (void *)messageHdr, NULL, 0); + + if (result) { + /* + * Now we look at the result code to determine + * what the error was. + */ + haCounters.haMNAuthFailureCnt++; + return (HA_MN_AUTH_FAILURE); + } + + } + + /* + * If talking to RADIUS client, you must wait for a reponse + * back (from AAAAuthenticateRegReq() call) before + * continuing on with haCheckRegReqAuthContinue(). + * As such, wait until RADIUS responds then continue on + * with authentication process. + */ + + if (aaaProtocol != RADIUS) { + code = haCheckRegReqAuthContinue(messageHdr, hamnePtr, + mnSPI, faSPI); + return (code); + } + return (0); +} + +/* + * Function: haCheckRegReqAuthContinue + * + * Arguments: messageHdr - Pointer to the Message Control Block + * hamnePtr - Pointer to a pointer to a mobile node entry + * mnSPI - Pointer to the Mobile Node SPI + * faSPI - Pointe to the Foreign Agent SPI + * + * Description: This function is used to authenticate a Registration + * request on the Home Agent. First we attempt to find + * the Mobile Node Entry using the Home Address. If the + * Home Address in the request was set to zero, we will + * attempt to find it using the Mobile Node's NAI. + * + * if aaaProtocol is RADIUS, this funtion will be called after + * an ANSWER is received from the Radius client. + * Otherwise, the processing will continue from + * haCheckRegReqAuth() function. + * + * Next we will ensure that either the Mobile-Home or the + * Mobile-AAA autentication extension is present. If none + * is present, and the packet was marked as being received + * by the Foreign Agent (as opposed to the AAA), we will + * make sure that the unknown Mobile Node is attempting + * to authenticate using the default SPI. If the packet + * was received via the AAA infrastructure, we will + * not require any authentication from the Mobile Node. + * + * Lastly, we will check the Foreign-Home Authentication + * extension. If one was not found, and the packet was + * not received by the AAA, we will fail authentication. + * + * Note that if a Mobile Node Entry pointer is returned + * by this function, the node will be locked. The caller + * is responsible to unlock the node. + * + * Returns: int - 0 if successful, otherwise the Mobile-IP error code + * is returned. + */ +/* ARGSUSED */ +int +haCheckRegReqAuthContinue(MessageHdr *messageHdr, HaMobileNodeEntry **hamnePtr, + uint32_t *mnSPI, uint32_t *faSPI) +{ + regRequest *reqPtr; + authExt *mnAuthExt = NULL; + genAuthExt *maAuthExt = NULL; + MipSecAssocEntry *mipSecAssocEntry; + uint32_t SPI; + int index; + int mnAuthExtLen; + + /* LINTED E_BAD_PTR_CAST_ALIGN */ + reqPtr = (regRequest *)messageHdr->pkt; + + if (reqPtr->homeAddr) { + /* + * Find the Mobile Node. Remember that this node will + * be locked upon return. As it turns out, the caller + * to this function will have to unlock the node since + * we are passing it the pointer as part of an argument. + */ + *hamnePtr = findHashTableEntryUint(&haMobileNodeHash, + reqPtr->homeAddr, LOCK_WRITE, NULL, 0, 0, 0); + } + + if (*hamnePtr == NULL) { + /* + * Search for the MobileNodeEntry based on the + * NAI. + */ + + *hamnePtr = findHashTableEntryString(&haMobileNodeHash, + messageHdr->mnNAI, messageHdr->mnNAILen, LOCK_WRITE, + NULL, 0, 0, 0); + } + + + /* LINTED E_BAD_PTR_CAST_ALIGN */ + GET_AUTH_EXT(messageHdr, index, REG_MH_AUTH_EXT_TYPE, mnAuthExt, + mnAuthExtLen); + + /* + * If aaaProtocol != RADIUS/DIAMETER, then the home agent CAN + * accept Mobile-AAA Authentication extensions, so if we cannot + * find the Authentication Extension, find the MN-AAA. + * + * Happy Dave? + */ + if ((mnAuthExtLen == 0) && (aaaProtocol == AAA_NONE)) { + /* + * Support for the latest Challenge/Response I-D + * + * This code does not belong in the HA, this is + * really targetted to the AAA Server. We will + * include it to fully support the protocol. + */ + /* LINTED E_BAD_PTR_CAST_ALIGN */ + GET_GEN_AUTH_EXT(messageHdr, index, + GEN_AUTH_MN_AAA, maAuthExt, mnAuthExtLen); + + if (mnAuthExtLen == 0) { + syslog(LOG_ERR, "Missing Challenge or Response"); + haCounters.haMNAuthFailureCnt++; + return (HA_MN_AUTH_FAILURE); + } + /* + * Get the MN-AAA SPI + */ + GET_GEN_AUTH_SPI(SPI, maAuthExt); +#ifdef KEY_DISTRIBUTION + /* + * If this code is compiled, the Home Agent will provide AAA + * like functionality by creating Session Keys for: + * MN-HA + * MN-FA + * FA-HA + * The last one is normally not seen by the Home Agent when + * keys are received from DIAMETER, but since we are providing + * this functionality (mostly for testing purposes) we will + * send it to the Foreign Agent as a vendor specific extension. + */ + createSessionKey(messageHdr->mnHaKey, &messageHdr->mnHaKeyLen, + &messageHdr->mnHaSPI); + + createSessionKey(messageHdr->mnFaKey, &messageHdr->mnFaKeyLen, + &messageHdr->mnFaSPI); + + createSessionKey(messageHdr->faHaKey, &messageHdr->faHaKeyLen, + &messageHdr->faHaSPI); + + messageHdr->kdcKeysPresent = _B_TRUE; + messageHdr->mnAAASPI = SPI; +#endif /* KEY_DISTRIBUTION */ + } else if (mnAuthExt) { + /* + * Get the MN-HA SPI + */ + GET_SPI(SPI, mnAuthExt); + } else { + SPI = 0; + } + + if (*hamnePtr == NULL) { + /* + * So we have a couple of options here. The first being + * where the packet is received by the AAA. In this + * case, the Mobile Node will not exist locally, and the + * key would have been installed as a dynamic key. + * The second option is where the default node is being + * used. When this occurs, it is mandatory that the + * mobile node use the default SPI. + */ + if (messageHdr->pktSource == MIP_PKT_FROM_FA) { + /* + * So, it looks like we don't know who this is. If a + * default SA is setup, we will check if we can + * create a dynamic Mobile Node Entry. + */ + if (defaultNodeSPI == 0 || defaultNodeSPI != SPI) { + syslog(LOG_ERR, + "As far as I'm concerned, this " + "mobile node doesn't exist"); + return (HA_ADM_PROHIBITED); + } + } else { + SPI = messageHdr->mnHaSPI; + } + } else { + if ((messageHdr->pktSource == MIP_PKT_FROM_AAA) || + (messageHdr->pktSource == MIP_PKT_FROM_RADIUS)) { + SPI = messageHdr->mnHaSPI; + (*hamnePtr)->haMnSPI = SPI; + } else { + /* + * Did the Mobile Node specify the correct SPI? + */ + if ((*hamnePtr)->haMnSPI != SPI) { + syslog(LOG_ERR, "Failed MN-HA authentication - " + "Invalid SPI requested %d, looking for %d", + SPI, (*hamnePtr)->haMnSPI); + haCounters.haMNAuthFailureCnt++; + return (HA_MN_AUTH_FAILURE); + } + } + } + *mnSPI = SPI; + + /* + * if an SA is returned, the node will be locked so we + * need to unlock it when we are done. + */ + if ((mipSecAssocEntry = + findSecAssocFromSPI(SPI, LOCK_READ)) == NULL) { + syslog(LOG_ERR, "Failed MN-HA authentication - " + "No SPI defined"); + haCounters.haMNAuthFailureCnt++; + return (HA_MN_AUTH_FAILURE); + } + if ((messageHdr->pktSource == MIP_PKT_FROM_AAA) || + (messageHdr->pktSource == MIP_PKT_FROM_RADIUS)) { + if (mipSecAssocEntry->mipSecIsEntryDynamic != TRUE) { + /* + * So the packet came from the AAA. We need to + * ensure that the key being used is in fact a + * dynamic key. Otherwise we are leaving a security + * hole wide open. + */ + (void) rw_unlock(&mipSecAssocEntry->mipSecNodeLock); + syslog(LOG_WARNING, "A AAA Mobile Node is attempting" + " to use a static key - security violation!"); + haCounters.haMNAuthFailureCnt++; + return (HA_MN_AUTH_FAILURE); + } + } else if (isAuthExtOk(messageHdr->pkt, + (messageHdr->extIdx[index] - messageHdr->pkt), + mipSecAssocEntry) == _B_FALSE) { + syslog(LOG_ERR, "Failed MN-HA authentication"); + haCounters.haMNAuthFailureCnt++; + (void) rw_unlock(&mipSecAssocEntry->mipSecNodeLock); + return (HA_MN_AUTH_FAILURE); + } + + (void) rw_unlock(&mipSecAssocEntry->mipSecNodeLock); + + return (0); +} diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/auth.h b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/auth.h new file mode 100644 index 0000000000..e134dc1882 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/auth.h @@ -0,0 +1,86 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999-2001 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ifndef _AUTH_H +#define _AUTH_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * auth.h : Data structures and prototypes used by a Mobile IP agent + * for authentication purposes. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +int appendAuthExt(uint8_t *, size_t, uint8_t, MipSecAssocEntry *); + +/* + * Routines to find Security Associatios + */ +MipSecAssocEntry *findSecAssocFromIp(uint32_t, int); +MipSecAssocEntry *findSecAssocFromSPI(uint32_t, int); + +/* + * Support for the latest Challenge/Response I-D + */ +int faCheckRegReqAuth(MessageHdr *, FaVisitorEntry *, FaVisitorEntry *, + unsigned char *, uint32_t, boolean_t *); +int faCheckRegRepAuth(MessageHdr *, FaVisitorEntry *); +int haCheckRegReqAuth(MessageHdr *, HaMobileNodeEntry **, uint32_t *, + uint32_t *); + +#define AUTHENTICATOR_LEN 16 + +#define GET_SPI(SPI, authExt) \ + { \ + uint16_t SPIlo; \ + uint16_t SPIhi; \ + \ + (void) memcpy(&SPIhi, &authExt->SPIhi, sizeof (SPIhi)); \ + (void) memcpy(&SPIlo, &authExt->SPIlo, sizeof (SPIlo)); \ + SPI = ntohs(SPIhi) << AUTHENTICATOR_LEN | ntohs(SPIlo); \ + } + +/* + * Support for the latest Challenge/Response I-D + */ +#define GET_GEN_AUTH_SPI(SPI, genAuthExt) \ + { \ + uint16_t SPIlo; \ + uint16_t SPIhi; \ + \ + (void) memcpy(&SPIhi, &genAuthExt->SPIhi, sizeof (SPIhi)); \ + (void) memcpy(&SPIlo, &genAuthExt->SPIlo, sizeof (SPIlo)); \ + SPI = ntohs(SPIhi) << AUTHENTICATOR_LEN | ntohs(SPIlo); \ + } +#ifdef __cplusplus +} +#endif + +#endif /* _AUTH_H */ diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/fakeDiameter.pl b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/fakeDiameter.pl new file mode 100644 index 0000000000..518244c620 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/fakeDiameter.pl @@ -0,0 +1,632 @@ +#!/usr/local/bin/perl -w +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 +# +# +# ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1999 by Sun Microsystems, Inc. +# All rights reserved. +# +# This script will fake a diameter server for testing. +# + + +$DEFAULT_PORT = 1234; + +use Socket; +use Sys::Hostname; +use Fcntl; + +require "errno.ph"; + +#define MOBILE_IP_OPEN_SESSION_REQUEST 1 +#define MOBILE_IP_OPEN_SESSION_ANSWER 2 +#define MOBILE_IP_OPEN_SESSION_INDICATOIN 3 +#define MOBILE_IP_OPEN_SESSION_INDICATION_RESPONSE 4 +#define MOBILE_IP_ACCOUNTING_START_REQUEST 5 +#define MOBILE_IP_ACCOUNTING_START_ANSWER 6 +#define MOBILE_IP_ACCOUNTING_INTERIM_REQUEST 7 +#define MOBILE_IP_ACCOUNTING_INTERIM_ANSWER 8 +#define MOBILE_IP_ACCOUNTING_STOP_REQUEST 9 +#define MOBILE_IP_ACCOUNTING_STOP_ANSWER 10 +#define MOBILE_IP_CLOSE_SESSION_REQUEST 11 +#define MOBILE_IP_CLOSE_SESSION_ANSWER 12 + +#define MOBILE_NODE_NAI 1 +#define FOREIGN_AGENT_NAI 2 +#define REGISTRATION_REQUEST 3 +#define NUMBER_OF_CHALLENGE_BYTES_IN_RR 4 +#define MOBILE_NODE_RESPONSE 5 +#define MOBILE_NODE_HOME_ADDRESS 6 +#define HOME_AGENT_ADDRESS 7 +#define RESULT_CODE 8 +#define REGISTRATION_REPLY 9 +#define MN_FA_SPI 10 +#define MN_FA_KEY 11 +#define FA_HA_SPI 12 +#define FA_HA_KEY 13 +#define SESSION_TIMEOUT 14 +#define HA_FA_KEY 15 +#define FA_MN_KEY 16 +#define MN_HA_SPI 17 +#define MN_HA_KEY 18 +#define HA_MN_KEY 19 +#define SESSION_TIMEOUT_1 20 +#define SESSION_TIME 21 + +my $CONVERT_FROM = 0; +my $CONVERT_TO = 1; + +my %commandCodes; +$commandCodes{MOBILE_IP_OPEN_SESSION_REQUEST} = 1; +$commandCodes{MOBILE_IP_OPEN_SESSION_ANSWER} = 2; +$commandCodes{MOBILE_IP_OPEN_SESSION_INDICATOIN} = 3; +$commandCodes{MOBILE_IP_OPEN_SESSION_INDICATION_RESPONSE} = 4; +$commandCodes{MOBILE_IP_ACCOUNTING_START_REQUEST} = 5; +$commandCodes{MOBILE_IP_ACCOUNTING_START_ANSWER} = 6; +$commandCodes{MOBILE_IP_ACCOUNTING_INTERIM_REQUEST} = 7; +$commandCodes{MOBILE_IP_ACCOUNTING_INTERIM_ANSWER} = 8; +$commandCodes{MOBILE_IP_ACCOUNTING_STOP_REQUEST} = 9; +$commandCodes{MOBILE_IP_ACCOUNTING_STOP_ANSWER} = 10; +$commandCodes{MOBILE_IP_CLOSE_SESSION_REQUEST} = 11; +$commandCodes{MOBILE_IP_CLOSE_SESSION_ANSWER} = 12; + +my @commandCodesRev; +$commandCodesRev[1] = { name => "MOBILE_IP_OPEN_SESSION_REQUEST", + func => \&processOpenSessionRequest }; +$commandCodesRev[2] = { name => "MOBILE_IP_OPEN_SESSION_ANSWER", + func => \&niy }; +$commandCodesRev[3] = { name => "MOBILE_IP_OPEN_SESSION_INDICATOIN", + func => \&niy }; +$commandCodesRev[4] = { name => "MOBILE_IP_OPEN_SESSION_INDICATION_RESPONSE", + func => \&niy }; +$commandCodesRev[5] = { name => "MOBILE_IP_ACCOUNTING_START_REQUEST", + func => \&processAccountingStart }; +$commandCodesRev[6] = { name => "MOBILE_IP_ACCOUNTING_START_ANSWER", + func => \&niy }; +$commandCodesRev[7] = { name => "MOBILE_IP_ACCOUNTING_INTERIM_REQUEST", + func => \&processAccountingInterim }; +$commandCodesRev[8] = { name => "MOBILE_IP_ACCOUNTING_INTERIM_ANSWER", + func => \&niy }; +$commandCodesRev[9] = { name => "MOBILE_IP_ACCOUNTING_STOP_REQUEST", + func => \&processAccountingStop }; +$commandCodesRev[10] = { name => "MOBILE_IP_ACCOUNTING_STOP_ANSWER", + func => \&niy }; +$commandCodesRev[11] = { name => "MOBILE_IP_CLOSE_SESSION_REQUEST", + func => \&processCloseSession }; +$commandCodesRev[12] = { name => "MOBILE_IP_CLOSE_SESSION_ANSWER", + func => \&niy }; + +my %avpCodes; +$avpCodes{MOBILE_NODE_NAI} = 1; +$avpCodes{FOREIGN_AGENT_NAI} = 2; +$avpCodes{REGISTRATION_REQUEST} = 3; +$avpCodes{NUMBER_OF_CHALLENGE_BYTES_IN_RR} = 4; +$avpCodes{MOBILE_NODE_RESPONSE} = 5; +$avpCodes{MOBILE_NODE_HOME_ADDRESS} = 6; +$avpCodes{HOME_AGENT_ADDRESS} = 7; +$avpCodes{RESULT_CODE} = 8; +$avpCodes{REGISTRATION_REPLY} = 9; +$avpCodes{MN_FA_SPI} = 10; +$avpCodes{MN_FA_KEY} = 11; +$avpCodes{FA_HA_SPI} = 12; +$avpCodes{FA_HA_KEY} = 13; +$avpCodes{SESSION_TIMEOUT} = 14; +$avpCodes{HA_FA_KEY} = 15; +$avpCodes{FA_MN_KEY} = 16; +$avpCodes{MN_HA_SPI} = 17; +$avpCodes{MN_HA_KEY} = 18; +$avpCodes{HA_MN_KEY} = 19; +$avpCodes{SESSION_TIMEOUT_1} = 20; +$avpCodes{SESSION_TIME} = 21; + +my @avpCodesRev; +$avpCodesRev[1] = { name => "MOBILE_NODE_NAI", + func => \&ConvertString }; +$avpCodesRev[2] = { name => "FOREIGN_AGENT_NAI", + func => \&ConvertString }; +$avpCodesRev[3] = { name => "REGISTRATION_REQUEST", + func => \&ConvertData }; +$avpCodesRev[4] = { name => "NUMBER_OF_CHALLENGE_BYTES_IN_RR", + func => \&ConvertInteger }; +$avpCodesRev[5] = { name => "MOBILE_NODE_RESPONSE", + func => \&ConvertData }; +$avpCodesRev[6] = { name => "MOBILE_NODE_HOME_ADDRESS", + func => \&ConvertIpAddr }; +$avpCodesRev[7] = { name => "HOME_AGENT_ADDRESS", + func => \&ConvertIpAddr }; +$avpCodesRev[8] = { name => "RESULT_CODE", + func => \&ConvertInteger }; +$avpCodesRev[9] = { name => "REGISTRATION_REPLY", + func => \&ConvertData }; +$avpCodesRev[10] = { name => "MN_FA_SPI", + func => \&ConvertInteger }; +$avpCodesRev[11] = { name => "MN_FA_KEY", + func => \&ConvertData }; +$avpCodesRev[12] = { name => "FA_HA_SPI", + func => \&ConvertInteger }; +$avpCodesRev[13] = { name => "FA_HA_KEY", + func => \&ConvertData }; +$avpCodesRev[14] = { name => "SESSION_TIMEOUT", + func => \&ConvertInteger }; +$avpCodesRev[15] = { name => "HA_FA_KEY", + func => \&ConvertData }; +$avpCodesRev[16] = { name => "FA_MN_KEY", + func => \&ConvertData }; +$avpCodesRev[17] = { name => "MN_HA_SPI", + func => \&ConvertInteger }; +$avpCodesRev[18] = { name => "MN_HA_KEY", + func => \&ConvertData }; +$avpCodesRev[19] = { name => "HA_MN_KEY", + func => \&ConvertData }; +$avpCodesRev[20] = { name => "SESSION_TIMEOUT_1", + func => \&ConvertInteger }; +$avpCodesRev[21] = { name => "SESSION_TIME", + func => \&ConvertInteger }; + + +my $CurrentHandle = 1; + +# Data Handling routines + +# Takes a NULL terminated string, and unpacks it +sub ConvertString($;$;) { + my ($data,$fromOrTo) = @_; + if ($fromOrTo == $CONVERT_FROM) { + return unpack("A*", $data); + } else { + return pack("A*",$data); + } +} # ConvertString + +#Converts Data to a printable string +sub ConvertData($;) { + my ($data,$fromOrTo) = @_; + my $buffer; + my $returnBuffer=""; + my $i; + + if ($fromOrTo == $CONVERT_FROM) { + for ($i=0;$i < length($data); $i ++) { + $char = unpack("c", substr($data,$i,1)); + $char = $char & 0xff; + $buffer = sprintf("0x%02x ", $char); + $returnBuffer = $returnBuffer . $buffer; + } + # remove the final space + return substr($returnBuffer,0,length($returnBuffer) -1 ); + } else { + # Assume it's already binary. + return $data; + } +} # ConvertData + +sub ConvertInteger($;) { + my ($data,$fromOrTo) = @_; + + if ($fromOrTo == $CONVERT_FROM) { + if (length($data) != 4) { + print "Error: Integer is not 4 bytes long . . treating as data"; + return ConvertData($data); + } + return unpack("N", $data); + } else { + + return pack("N", $data); + } +} #ConvertInteger +sub ConvertIpAddr($;) { + my ($data,$fromOrTo) = @_; + + if ($fromOrTo == $CONVERT_FROM) { + if (length($data) != 4) { + print "Error: IPAddr is not 4 bytes long . . treating as data"; + return ConvertData($data); + } + return inet_ntoa($data); + } else { + return inet_aton($data); + } + +} # ConvertIpAddr + +sub initSocket { + my $port = shift; + $port = $DEFAULT_PORT if (!defined $port); + + my $proto = getprotobyname('tcp'); + my $paddr = sockaddr_in($port,INADDR_ANY) ; + + socket(SOCKET,PF_INET,SOCK_STREAM,$proto) or die "socket: $!\n"; + setsockopt(SOCKET, SOL_SOCKET, SO_REUSEADDR, + pack("l", 1)) || die "setsockopt: $!"; + bind (SOCKET,$paddr) or die "bind: $!\n"; + + # make socket non-blocking + select SOCKET; $|=1; select STDOUT; + + my $fh = \*SOCKET; + return $fh; +} # initSocket + +sub REAPER { + $waitedpid = wait; + $SIG{CHLD} = \&REAPER; # loathe sysV + print "reaped $waitedpid" . ($? ? " with exit $?" : '') . "\n"; +} # REAPER + +sub spawn { + my $pid; + if (!defined($pid = fork)) { + warn "cannot fork: $!\n"; + return; + } elsif ($pid) { + warn "begat $pid\n"; + return; # I'm the parent + } + # else I'm the child -- go spawn + sleep (1); + exit &processMessages(\*Client); +} # spawn + +# seperate the avps out into a hash containing +# the data (indexed by AVP name) +sub processAVPs($;) { + my $avpBuffer = shift; + my ($avpCode, $avpLength, $data); + my %entry; + my $avpName; + my %ReturnHash; + my %EntryHash; + my $entry; + + print "DEBUG: AVPS:\n"; + while (length($avpBuffer) > 0) { + ($avpCode,$avpLength) = unpack("N N", $avpBuffer); + # Now validate the code. + $entry = $avpCodesRev[$avpCode]; + if (!defined($entry)) { + print "ERROR: Invalid AVP Code: $avpCode\n"; + } else { + %EntryHash = %$entry; + # Valid Avp . . . add it + $avpName = $EntryHash{name}; + $ReturnHash{$avpName} = convertAvp($avpName, + substr($avpBuffer,4+4, $avpLength - (4+4)), + $CONVERT_FROM); + print "DEBUG: $avpName(" . $ReturnHash{$avpName} . ")\n"; + } + # And, fix the buffer + $avpBuffer = substr($avpBuffer,$avpLength); + } + + return \%ReturnHash; + +} # processAVPs + +sub processMessages { + my $fh = shift; + my $buffer; + my $bytesLeftToRead; + my ($commandCode, $handle, $length); + my ($avpCode,$avpLength); + my $avpBytesLeftToRead; + my $rc; + my $response; + + print "processMessages: executing!\n"; + + while ( 1 ) { +# print "Reading in 4+4+4 bytes!\n"; + $rc = recv ($fh,$buffer,4+4+4,0); + die "Unable to read in header ($!)\n" if (!defined $rc); + return (0) if (!length($buffer)); +# print "DEBUG: read " . length($buffer) . " bytes when expecing 4+4+4\n"; + ($commandCode, $handle, $length) = unpack("N N N", $buffer); + print "Received commandCode $commandCode, handle $handle" . + ", length $length\n"; + + $bytesLeftToRead = $length - (4+4+4); + + my $offset=0; + my $bytesRead = 0; + # And, read in the rest of the packet. + while ($bytesLeftToRead) { + $rc = recv($fh,$buffer,$bytesLeftToRead,$offset); + die "Unable to read AVPs" if (!defined $rc); + + $bytesRead = length($buffer) - $offset; + return (0) if ($bytesRead == 0); +# print "DEBUG: readChunk " . $bytesRead . " bytes\n"; + $bytesLeftToRead -= $bytesRead; + $offset += $bytesRead; + } + + print "DEBUG: read " . length($buffer) . " bytes total.\n"; + + # Ok, now take apart the packets + $response = processMessage($commandCode, $handle, $length, $buffer); + print $fh $response; + } +} # processMessages + +sub processMessage($;$;$;$;) { + my ($commandCode, $handle, $length, $avpBuffer) = @_; + + my $entry = $commandCodesRev[$commandCode]; + if (!defined $entry) { + print "IllegalCommand Code! <" . $commandCode . ">\n"; + sendError(); + return 0; + } + my %hash = %$entry; + print "Recieved " . $hash{name} . "\n"; + + # Now that we have a good entry, take apart the AVPs + my $avpRef = processAVPs($avpBuffer); + my %avps = %$avpRef; + + my $func = $hash{func}; + return &$func($hash{name}, $handle, \%avps); +} # processMessage + + +sub convertAvp($;$;$;) { + my ($avpName,$data,$fromOrTo) = @_; + my $avpCode = $avpCodes{$avpName}; + my $entry = $avpCodesRev[$avpCode]; + my %entryHash; + my $conversionFunc; + + if (!defined($entry)) { + print "ERROR: Invalid AVP: $avpName\n"; + return undef; + } else { + %entryHash = %$entry; + # Valid Avp . . . add it + $conversionFunc = $entryHash{func}; + return + &$conversionFunc($data, $fromOrTo); + } +} #addAvp + +sub processOpenSessionRequest($;$;$;) { + my ($name, $handle, $avpRef) = @_; + my %InAvpHash = %$avpRef; + my %OutAvpHash; + + print "OpenSessionRequest($name)\n"; + + # MobileNode NAI + $OutAvpHash{MOBILE_NODE_NAI} = convertAvp("MOBILE_NODE_NAI", + $InAvpHash{MOBILE_NODE_NAI}, + $CONVERT_TO); + + # ResultCode + $OutAvpHash{RESULT_CODE} = convertAvp("RESULT_CODE",0,$CONVERT_TO); + + # ForeignAgentNAI + $OutAvpHash{FOREIGN_AGENT_NAI} = convertAvp("FOREIGN_AGENT_NAI", + $InAvpHash{FOREIGN_AGENT_NAI}, + $CONVERT_TO); + + # Registration Reply + # WORK + + # MN-FA SPI + $OutAvpHash{MN_FA_SPI} = convertAvp("MN_FA_SPI",257,$CONVERT_TO); + # WORK + + # MN-FA Key + # WORK + + # FA-HA SPI + $OutAvpHash{FA_HA_SPI} = convertAvp("FA_HA_SPI",258,$CONVERT_TO); + # WORK + + # FA-HA Key + # WORK + + # HomeAgentAddress + $OutAvpHash{HOME_AGENT_ADDRESS} = convertAvp("HOME_AGENT_ADDRESS", + "192.168.168.1", + $CONVERT_TO); + + # Mobile Node Home ADdress + $OutAvpHash{MOBILE_NODE_HOME_ADDRESS} = convertAvp("MOBILE_NODE_HOME_ADDRESS", + "192.168.168.2", + $CONVERT_TO); + + # Session Timeout + $OutAvpHash{SESSION_TIMEOUT} = convertAvp("SESSION_TIMEOUT",10,$CONVERT_TO); + + # Send back a changing hancle of one. + return &buildResponse(\%OutAvpHash,$commandCodes{MOBILE_IP_OPEN_SESSION_ANSWER}, + $CurrentHandle++); + + + return 0; + +} #processOpenSessionRequest + +sub processAccountingStart($;$;$;) { + my ($name, $handle, $avpRef) = @_; + my %InAvpHash = %$avpRef; + my %OutAvpHash; + + print "ProcessAccountingStart($name) handle = $handle\n"; + + # MobileNode NAI + $OutAvpHash{MOBILE_NODE_NAI} = convertAvp("MOBILE_NODE_NAI", + $InAvpHash{MOBILE_NODE_NAI}, + $CONVERT_TO); + # ResultCode + $OutAvpHash{RESULT_CODE} = convertAvp("RESULT_CODE",0,$CONVERT_TO); + + # ForeignAgentNAI + $OutAvpHash{FOREIGN_AGENT_NAI} = convertAvp("FOREIGN_AGENT_NAI", + $InAvpHash{FOREIGN_AGENT_NAI}, + $CONVERT_TO); + # Send back the passed in handle. + return &buildResponse(\%OutAvpHash,$commandCodes{MOBILE_IP_ACCOUNTING_START_ANSWER}, + $handle); + +} #processAccountingStart + +sub processAccountingInterim($;$;$;) { + my ($name, $handle, $avpRef) = @_; + my %InAvpHash = %$avpRef; + my %OutAvpHash; + + print "ProcessAccountingInterim($name)\n"; + + # MobileNode NAI + $OutAvpHash{MOBILE_NODE_NAI} = convertAvp("MOBILE_NODE_NAI", + $InAvpHash{MOBILE_NODE_NAI}, + $CONVERT_TO); + # ResultCode + $OutAvpHash{RESULT_CODE} = convertAvp("RESULT_CODE",0,$CONVERT_TO); + + # ForeignAgentNAI + $OutAvpHash{FOREIGN_AGENT_NAI} = convertAvp("FOREIGN_AGENT_NAI", + $InAvpHash{FOREIGN_AGENT_NAI}, + $CONVERT_TO); + # Send back the passed in handle. + return &buildResponse(\%OutAvpHash,$commandCodes{MOBILE_IP_ACCOUNTING_INTERIM_ANSWER}, + $handle); + +} #processAccountingInterim + +sub processAccountingStop($;$;$;) { + my ($name, $handle, $avpRef) = @_; + my %InAvpHash = %$avpRef; + my %OutAvpHash; + + print "ProcessAccountingStop($name)\n"; + + # MobileNode NAI + $OutAvpHash{MOBILE_NODE_NAI} = convertAvp("MOBILE_NODE_NAI", + $InAvpHash{MOBILE_NODE_NAI}, + $CONVERT_TO); + # ResultCode + $OutAvpHash{RESULT_CODE} = convertAvp("RESULT_CODE",0,$CONVERT_TO); + + # ForeignAgentNAI + $OutAvpHash{FOREIGN_AGENT_NAI} = convertAvp("FOREIGN_AGENT_NAI", + $InAvpHash{FOREIGN_AGENT_NAI}, + $CONVERT_TO); + # Send back the passed in handle. + return &buildResponse(\%OutAvpHash,$commandCodes{MOBILE_IP_ACCOUNTING_STOP_ANSWER}, + $handle); + +} #processAccountingStop + +sub processCloseSession($;$;$;) { + my ($name, $handle, $avpRef) = @_; + my %InAvpHash = %$avpRef; + my %OutAvpHash; + + print "ProcessCloseSession($name)\n"; + + # MobileNode NAI + $OutAvpHash{MOBILE_NODE_NAI} = convertAvp("MOBILE_NODE_NAI", + $InAvpHash{MOBILE_NODE_NAI}, + $CONVERT_TO); + # ResultCode + $OutAvpHash{RESULT_CODE} = convertAvp("RESULT_CODE",0,$CONVERT_TO); + + # ForeignAgentNAI + $OutAvpHash{FOREIGN_AGENT_NAI} = convertAvp("FOREIGN_AGENT_NAI", + $InAvpHash{FOREIGN_AGENT_NAI}, + $CONVERT_TO); + # Send back the passed in handle. + return &buildResponse(\%OutAvpHash,$commandCodes{MOBILE_IP_CLOSE_SESSION_ANSWER}, + $handle); + +} #processCloseSession + +# This routine will package up the passed in AVPS +sub buildResponse($;$;$;) { + my ($avpRef,$code,$handle) = @_; + my %avps = %$avpRef; + + my $header; + my $body = ""; + + my $avp; + my $key; + + foreach $key (keys(%avps)) { + print "Adding Key = $key length = " . (4+4+length($avps{$key})) . + " to response\n"; + $avp = pack("N N", $avpCodes{$key}, (4+4+length($avps{$key}))) . + $avps{$key}; + $body = $body . $avp; + } + + print "Building response with code = $code, handle = $handle, length = " . + (length($body) +4 +4 +4) . "\n"; + + # Now build header + $header = pack ("N N N",$code, $handle, length($body)+4+4+4); + + return $header . $body; + +} #buildResponse + +sub niy($;$;$;$) { + my ($name, $handle, $length, $avpBuffer) = @_; + print "Error: I don't know how to handle $name (Not Implemented Yet)\n"; +} #niy + + # Main ( multithreaded ) + + +my $socket = initSocket(); + +listen($socket,5); + +my $paddr; + +$SIG{CHLD} = \&REAPER; # Catch zombies + +print "Waiting for connections to port $DEFAULT_PORT\n"; + +while (1) { + $paddr = accept(Client,$socket); + if (defined($paddr)) { + my ($port,$iaddr) = sockaddr_in($paddr); + my $name = gethostbyaddr($iaddr,AF_INET); + print "connection from $name [" . inet_ntoa($iaddr) . + "] at port $port\n"; + select Client; $|=1; select STDOUT; + + &spawn; + } else { + if ($! != &EINTR) { + die "Error on accept! $! != ". &EINTR . " ($!)\n"; + } + } +} # main for + + + diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/hash.c b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/hash.c new file mode 100644 index 0000000000..7b6daed7e7 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/hash.c @@ -0,0 +1,1013 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999-2001 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * file: hash.c + * + * This file contains all routines used to manage hash tables. + * + * The locking strategy behind hash.c is actually quite simple, + * but does need some explaining. Basically, we have three different + * locks to worry about; one at the hash table level, one at the + * bucket level and one at the node level. + * + * +===================+ + * | Hash | Hash | +---------+ +---------+ + * | Table | Bucket |<--->|HashEntry|<--->|HashEntry| + * | | | +---------+ +---------+ + * | * | * | / \ / \ + * | | | | | + * | | | \ / \ / + * | | | +---------+ +---------+ + * | | | | * Node | | * Node | + * +===================+ +---------+ +---------+ + * + * * = Lock is present + * + * When we walk through the Hash Table to add an item, it first + * gets the hash bucket index, and locks the whole row (or bucket) + * with a write lock. a HashEntry is then added at the head of the + * bucket queue. If a node lock was requested, via a function + * parameter, the node is locked. This is particularly useful if + * additional work will be done to the node. The Hash Table lock + * is then locked with a write lock, and the table counter is + * incremented, then the lock is unlocked. Lastly, the hash + * bucket is unlocked, and the function returns. + * + * When the code needs to find a node in the hash table, the + * hash bucket (row) is locked, and all nodes in the row are + * compare with the key provided. The caller may also provide + * a pointer to a helper routine, which is used to further + * qualify searches. If a match is found, the node is locked + * (if requested), and the pointer to the node is retruned to + * the caller. + * + * If a node is to be deleted from the table, the row is write + * locked, the row is searched for a match, based on the key and + * the data to the pointer. If a match is found, the HashEntry + * is deleted. The table lock is then write locked, decremented + * and unlocked. Finally, the bucket lock is released. + * + */ +#include <stdio.h> +#include <syslog.h> +#include <stdlib.h> +#include <string.h> +#include "md5.h" +#include "mip.h" +#include "agent.h" + +extern boolean_t shutdown_flag; + +/* + * The following macro is used to lock a node. + */ +#define LOCK_NODE(lockType, data) \ + switch (lockType) { \ + case LOCK_WRITE: \ + (void) rw_wrlock((rwlock_t *)data); \ + break; \ + case LOCK_READ: \ + (void) rw_rdlock((rwlock_t *)data); \ + break; \ + case LOCK_NONE: \ + default: \ + break; \ + } + +/* + * Function: InitHash + * + * Arguments: htbl - Pointer to Hash Table + * + * Description: This function will memset the Hash Table and + * initialize the hash table's read/write locks. + * We do not need to destroy the locks since + * Hash Tables are never released until the daemon + * is shutdown. + * + * Returns: int, 0 if successful + */ +int +InitHash(struct hash_table *htbl) +{ + int i; + + (void) memset(htbl, 0, sizeof (struct hash_table)); + if (rwlock_init(&htbl->hashLock, USYNC_THREAD, NULL)) { + syslog(LOG_CRIT, "Unable to initialize read/write lock"); + return (-1); + } + for (i = 0; i < HASH_TBL_SIZE; i++) { + if (rwlock_init(&htbl->bucketLock[i], USYNC_THREAD, NULL)) { + syslog(LOG_CRIT, "Unable to initialize read/write lock"); + return (-1); + } + } + + return (0); +} + +/* + * Function: hashStr + * + * Arguments: str - String to be hashed + * length - Length of string + * + * Description: This function will generate a hash + * based on the string provided to + * allow for strings to be used as keys + * in the hashing functions. + * + * Note that we currently use MD5, and a + * more suitable algorithm will be implemented + * in the future (i.e. patricia) + * + * Returns: unsigned char containing the hash value. + */ +static unsigned char +hashStr(unsigned char *str, int length) +{ +#define TRY_EFFICIENT_HASH +#ifdef TRY_EFFICIENT_HASH + int h = 0; + int i; + + for (i = 0; i < length; i++) + h = (64 * h + str[i]) % 256; /* Keep it within a char */ + return (h); +#else + MD5_CTX context; + unsigned char authenticator[16]; + + if (str == NULL || length <= 0) + return (0); + + MD5Init(&context); + MD5Update(&context, str, length); + MD5Final(authenticator, &context); + + return (authenticator[0]); +#endif + +} /* hashStr */ + +/* + * Function: linkHashTableEntryUint + * + * Arguments: htbl - Pointer to Hash Table + * key - key to be used for bucket generation + * data - Pointer to the data + * lockType - The Lock type, which can be: + * LOCK_NONE - No Lock + * LOCK_READ - Read Lock + * LOCK_WRITE - Write Lock + * + * Description: This function will allocate a Hash Entry, + * find the appropriate bucket based on the key + * provided, and add the node to the bucket's + * queue. + * + * If a lock type was selected, the node's will + * be locked upon return. The caller is then + * responsible for unlocking the node when it is + * finished with the data. + * + * Returns: int, 0 if successful + */ +int +linkHashTableEntryUint(HashTable *htbl, uint32_t key, void *data, int lockType) +{ + HashEntry *p; + HashEntry *q; + int index; + + if ((p = (HashEntry *)malloc(sizeof (HashEntry))) == NULL) { + syslog(LOG_CRIT, "FATAL: Unable to allocate HashEntry"); + return (-1); + } + + index = HASHIT(key); + + (void) rw_wrlock(&htbl->bucketLock[index]); + + q = htbl->buckets[index]; + + /* + * If the unique flag is set, make sure the entry + * is not in this bucket. + */ + if (htbl->uniqueData) { + HashEntry *r; + /* Make sure value is not already in the table */ + for (r = q; r != NULL; r = r->next) + if (r->key == key) { + /* Error! It is here! */ + syslog(LOG_ERR, "ERROR: Key already exists!"); + (void) rw_unlock(&htbl->bucketLock[index]); + return (-2); + } + } /* end if unuque */ + + htbl->buckets[index] = p; + p->next = q; + p->data = (void *)data; + p->key = key; + p->hashKeyType = HASH_INT_KEY; + + /* + * Lock and increment the counter. + */ + (void) rw_wrlock(&htbl->hashLock); + htbl->size++; + (void) rw_unlock(&htbl->hashLock); + + /* + * We now lock the data structure using the locking type + * specified by the caller. + */ + LOCK_NODE(lockType, data); + + (void) rw_unlock(&htbl->bucketLock[index]); + + + return (0); +} + +/* + * Function: linkHashTableEntryString + * + * Arguments: htbl - Pointer to Hash Table + * p - Pointer to Hash Entry (if available) + * key - Pointer to the keying information + * keyLen - Length of the keying information + * data - Pointer to the data + * lockType - The Lock type, which can be: + * LOCK_NONE - No Lock + * LOCK_READ - Read Lock + * LOCK_WRITE - Write Lock + * + * Description: This function will allocate a Hash Entry, + * find the appropriate bucket based on the key + * provided, and add the node to the bucket's + * queue. + * + * It is possible to provide a HashEntry pointer, + * and if one is provided this function will not + * allocate a new one. This allows for the caller + * to move a Hash Entry from one Hash Table to + * another. + * + * If a lock type was selected, the node's will + * be locked upon return. The caller is then + * responsible for unlocking the node when it is + * finished with the data. + * + * Returns: int, 0 if successful + */ +int +linkHashTableEntryString(HashTable *htbl, unsigned char *key, uint32_t keyLen, + void *data, int lockType) +{ + HashEntry *p; + HashEntry *q; + int index; + + if (keyLen > 255) { + syslog(LOG_ERR, "FATAL: Keys must be 255 chars or less"); + return (-1); + } + + if ((p = (HashEntry *)malloc(sizeof (HashEntry))) == NULL) { + syslog(LOG_CRIT, "FATAL: Unable to allocate HashEntry"); + return (-1); + } + + if ((p->keyData = (unsigned char *)malloc(keyLen)) == NULL) { + syslog(LOG_CRIT, "FATAL: Unable to allocate HashEntry"); + free(p); + return (-1); + } + + + index = hashStr(key, keyLen); + + (void) rw_wrlock(&htbl->bucketLock[index]); + + q = htbl->buckets[index]; + + /* + * If the unique flag is set, make sure the entry + * is not in this bucket. + */ + if (htbl->uniqueData) { + HashEntry *r; + /* Make sure value is not already in the table */ + for (r = q; r != NULL; r = r->next) + if (r->keyLen == keyLen && + strncmp((const char *)r->keyData, + (const char *)key, + keyLen) == 0) { + /* Error! It is here! */ + syslog(LOG_ERR, "ERROR: Key already exists!"); + (void) rw_unlock(&htbl->bucketLock[index]); + return (-2); + } + } /* end if unuque */ + + htbl->buckets[index] = p; + p->next = q; + p->data = (void *)data; + p->key = 0; + p->hashKeyType = HASH_STR_KEY; + (void) memcpy(p->keyData, key, keyLen); + p->keyLen = keyLen; + + /* + * Lock and increment the counter. + */ + (void) rw_wrlock(&htbl->hashLock); + htbl->size++; + (void) rw_unlock(&htbl->hashLock); + + /* + * We now lock the data structure using the locking type + * specified by the caller. + */ + LOCK_NODE(lockType, data); + + (void) rw_unlock(&htbl->bucketLock[index]); + + return (0); +} + +/* + * Function: delHashTableEntryUint + * + * Arguments: htbl - Pointer to Hash Table + * data - Pointer to the data + * key - key to be used for bucket generation + * lockType - The Lock type, which can be: + * LOCK_NONE - No Lock + * LOCK_READ - Read Lock + * LOCK_WRITE - Write Lock + * + * Description: This function will find the node in the + * hash table, and delete the entry. + * + * If a lock type was selected, the node's will + * be locked upon return. The caller is then + * responsible for unlocking the node when it is + * finished with the data. + * + * Returns: int, 0 if successful + */ +boolean_t +delHashTableEntryUint(HashTable *htbl, void *data, uint32_t key, + int lockType) +{ + HashEntry *p, *tmp; + HashEntry *q = NULL; + int index; + int found = _B_FALSE; + + index = HASHIT(key); + + (void) rw_wrlock(&htbl->bucketLock[index]); + + p = htbl->buckets[index]; + while (p) { + if (p->hashKeyType == HASH_INT_KEY && + p->data == data && p->key == key) { + if (p == htbl->buckets[index]) + htbl->buckets[index] = p->next; + else + q->next = p->next; + + tmp = p; + p = p->next; + + free(tmp); + + /* + * We delete the entry, let's decrement the counter. + */ + (void) rw_wrlock(&htbl->hashLock); + htbl->size--; + (void) rw_unlock(&htbl->hashLock); + + found = _B_TRUE; + + break; + } else { + q = p; + p = p->next; + } + } + + /* + * We now lock the data structure using the locking type + * specified by the caller. + */ + LOCK_NODE(lockType, data); + + (void) rw_unlock(&htbl->bucketLock[index]); + + return (found); +} + + +/* + * Function: delHashTableEntryString + * + * Arguments: htbl - Pointer to Hash Table + * data - Pointer to the data + * key - key to be used for bucket generation + * lockType - The Lock type, which can be: + * LOCK_NONE - No Lock + * LOCK_READ - Read Lock + * LOCK_WRITE - Write Lock + * + * Description: This function will find the node in the + * hash table, and delete the entry. + * + * If a lock type was selected, the node's will + * be locked upon return. The caller is then + * responsible for unlocking the node when it is + * finished with the data. + * + * Returns: int, 0 if successful + */ +boolean_t +delHashTableEntryString(HashTable *htbl, void *data, unsigned char *key, + uint32_t keyLen, int lockType) +{ + HashEntry *p, *tmp; + HashEntry *q = NULL; + int index; + int found = _B_FALSE; + + index = hashStr(key, keyLen); + + /* + * Lock the bucket + */ + (void) rw_wrlock(&htbl->bucketLock[index]); + + p = htbl->buckets[index]; + while (p) { + if (p->hashKeyType == HASH_STR_KEY && p->data == data && + p->keyLen == keyLen && + !memcmp(p->keyData, key, keyLen)) { + if (p == htbl->buckets[index]) + htbl->buckets[index] = p->next; + else + q->next = p->next; + + tmp = p; + p = p->next; + + /* + * Free the key data AND the Hash Entry. + */ + free(tmp->keyData); + free(tmp); + + /* + * We delete the entry, let's decrement the counter. + */ + (void) rw_wrlock(&htbl->hashLock); + htbl->size--; + (void) rw_unlock(&htbl->hashLock); + + found = _B_TRUE; + + break; + } else { + q = p; + p = p->next; + } + } + + /* + * We now lock the data structure using the locking type + * specified by the caller. + */ + LOCK_NODE(lockType, data); + + (void) rw_unlock(&htbl->bucketLock[index]); + + return (found); +} + + +/* + * Function: findHashTableEntryUint + * + * Arguments: htbl - Pointer to Hash Table + * key - key to be used for bucket generation + * lockType - The Lock type, which can be: + * LOCK_NONE - No Lock + * LOCK_READ - Read Lock + * LOCK_WRITE - Write Lock + * fcnt() - Function Pointer + * p1 - First parameter to match + * p2 - Second parameter to match + * p3 - Third parameter to match + * + * Description: This function will find the node in the + * hash table using the key, and return the + * data associated with the entry. If a function + * pointer was passed, this function will call + * the pointer to further qualify the search. + * + * If the function called returns _B_TRUE, this + * function will assume that the hash entry in + * question is the one we were looking for. + * + * If a lock type was selected, the node's will + * be locked upon return. The caller is then + * responsible for unlocking the node when it is + * finished with the data. + * + * Returns: int, 0 if successful + */ +void * +findHashTableEntryUint(HashTable *htbl, uint32_t key, int lockType, + boolean_t (*fcnt)(void *, uint32_t, uint32_t, uint32_t), uint32_t p1, + uint32_t p2, uint32_t p3) +{ + HashEntry *p; + int index; + + index = HASHIT(key); + + /* + * Lock the bucket + */ + (void) rw_rdlock(&htbl->bucketLock[index]); + + p = htbl->buckets[index]; + while (p) { + if (p->hashKeyType == HASH_INT_KEY && p->key == key) { + if ((fcnt == NULL) || + (fcnt && fcnt(p->data, p1, p2, p3))) { + /* + * We now lock the data structure using the + * locking type specified by the caller. + */ + LOCK_NODE(lockType, p->data); + break; + } + } + p = p->next; + } + + /* + * Unlock the bucket + */ + (void) rw_unlock(&htbl->bucketLock[index]); + + if (p) { + return (p->data); + } else { + return (NULL); + } +} + + +/* + * Function: findHashTableEntryString + * + * Arguments: htbl - Pointer to Hash Table + * key - Pointer to the keying information + * keyLen - Length of the keying information + * lockType - The Lock type, which can be: + * LOCK_NONE - No Lock + * LOCK_READ - Read Lock + * LOCK_WRITE - Write Lock + * fcnt() - Function Pointer + * p1 - First parameter to match + * p2 - Second parameter to match + * p3 - Third parameter to match + * + * Description: This function will find the node in the + * hash table using the key, which is a string, + * and return the data associated with the entry. + * + * If a lock type was selected, the node's will + * be locked upon return. The caller is then + * responsible for unlocking the node when it is + * finished with the data. + * + * Returns: int, 0 if successful + */ +void * +findHashTableEntryString(HashTable *htbl, unsigned char *key, + uint32_t keyLen, int lockType, + boolean_t (*fcnt)(void *, uint32_t, uint32_t, uint32_t), uint32_t p1, + uint32_t p2, uint32_t p3) +{ + HashEntry *p; + int index; + + index = hashStr(key, keyLen); + + /* + * Lock the bucket + */ + (void) rw_rdlock(&htbl->bucketLock[index]); + + p = htbl->buckets[index]; + while (p) { + if (p->hashKeyType == HASH_STR_KEY && p->keyLen == keyLen && + !memcmp(p->keyData, key, keyLen)) { + if ((fcnt == NULL) || + (fcnt && fcnt(p->data, p1, p2, p3))) { + /* + * We now lock the data structure using the + * locking type specified by the caller. + */ + LOCK_NODE(lockType, p->data); + break; + } + } + p = p->next; + } + + /* + * Unlock the bucket + */ + (void) rw_unlock(&htbl->bucketLock[index]); + + if (p) { + return (p->data); + } else { + return (NULL); + } +} /* findHashTableEntryString */ + +/* + * Function: findHashTableEntryString + * + * Arguments: htbl - Pointer to Hash Table + * data - Pointer to the data + * key - Pointer to the keying information + * keyLen - Length of the keying information + * newkey - key of type uint32_t used to find new bucket + * + * Description: This function is used to move a node that + * was previously hashed based on a string to + * a new bucket, now hashed with a 32 bit integer. + * + * Returns: boolean_t, _B_TRUE if successful + */ +boolean_t +changeHashEntryStringToUint(HashTable *htbl, void *data, unsigned char *key, + uint32_t keyLen, uint32_t newKey) +{ + HashEntry *p; + HashEntry *q = NULL; + HashEntry *pToMove = NULL; + int index; + + /* + * First let's remove the Hash Entry from the old bucket + */ + index = hashStr(key, keyLen); + + (void) rw_wrlock(&htbl->bucketLock[index]); + + p = htbl->buckets[index]; + while (p) { + if (p->data == data && p->keyLen == keyLen && + !memcmp(p->keyData, key, keyLen) && + p->hashKeyType == HASH_STR_KEY) { + if (p == htbl->buckets[index]) + htbl->buckets[index] = p->next; + else + q->next = p->next; + + /* + * Free the keyData since this one was + * a string. + */ + p->keyLen = 0; + free(p->keyData); + p->keyData = NULL; + + pToMove = p; + + break; + } else { + q = p; + p = p->next; + } + } + + /* + * Unlock the bucket + */ + (void) rw_unlock(&htbl->bucketLock[index]); + + if (pToMove) { + /* + * Cool, we've found it. Now let's move it to + * a new bucket, index on an uint32_t instead. + * If uniqueness is requested, we need to make + * the check here. XXX + */ + index = HASHIT(newKey); + + (void) rw_wrlock(&htbl->bucketLock[index]); + + q = htbl->buckets[index]; + + htbl->buckets[index] = pToMove; + + pToMove->next = q; + + pToMove->hashKeyType = HASH_INT_KEY; + pToMove->key = newKey; + + (void) rw_unlock(&htbl->bucketLock[index]); + } + + return (pToMove != NULL); +} /* changeHashEntryStringToUint */ + +/* + * Function: getAllHashTableEntries + * + * Arguments: htbl - Pointer to Hash Table + * fcnt() - Function Pointer + * lockType - The Lock type, which can be: + * LOCK_NONE - No Lock + * LOCK_READ - Read Lock + * LOCK_WRITE - Write Lock + * p1 - First parameter to match + * shutdown_flag - If set, we are shutting down + * + * Description: This function is mostly used by the gargabe collected + * to get all the items in the hash table, and perform + * a check. The function provided MAY delete the node, and + * will inform this function by returning a _B_FALSE. If + * such a return code is seen, we will delete the Hash + * Entry. + * + * This function is also called by the shutdown routine, + * so the shutdown flag is used to determine if we need + * to lock the buckets and the hash table. + * + * Returns: int, 0 if successful + */ +void +getAllHashTableEntries(HashTable *htbl, boolean_t (*fcnt)(void *, uint32_t), + int lockType, uint32_t p1, boolean_t shutdown_flag) +{ + HashEntry *p; + HashEntry *q = NULL; + HashEntry *tmp; + int i; + int nentry; + int result; + + /* + * If we are shutting down, we do not want to lock. + */ + if (shutdown_flag == _B_TRUE) { + lockType = LOCK_NONE; + } + + for (i = 0, nentry = 0; + i < HASH_TBL_SIZE && (nentry < htbl->size); i++) { + + /* + * If we are shutting down, we do not want to lock. + */ + if (shutdown_flag == _B_FALSE) { + (void) rw_wrlock(&htbl->bucketLock[i]); + } + + p = htbl->buckets[i]; + while (p) { + nentry++; + /* + * The calling function is responsible for unlocking + * the node!!!! Note that since this function is + * mostly called by the garbage collector, we do not + * REALLY need to lock right away. If the lock + * request fails, we can try later. + */ + switch (lockType) { + case LOCK_WRITE: + result = rw_trywrlock((rwlock_t *)p->data); + break; + case LOCK_READ: + result = rw_tryrdlock((rwlock_t *)p->data); + break; + case LOCK_NONE: + default: + result = 0; + break; + } + + if (result == 0 && (fcnt(p->data, p1) == _B_FALSE)) { + /* + * If a failure was returned, we need to + * free this one. + */ + if (p == htbl->buckets[i]) + htbl->buckets[i] = p->next; + else + q->next = p->next; + + tmp = p; + p = p->next; + + free(tmp); + + if (shutdown_flag == _B_FALSE) { + /* + * We delete the entry, let's decrement + * the counter. + */ + (void) rw_wrlock(&htbl->hashLock); + htbl->size--; + (void) rw_unlock(&htbl->hashLock); + } else { + htbl->size--; + } + /* + * We need to reduce the entry + * table size, otherwise resources aren't + * released properly. + */ + nentry--; + } else { + if (result == 0) { + switch (lockType) { + case LOCK_WRITE: + case LOCK_READ: + (void) rw_unlock( + (rwlock_t *)p->data); + break; + } + } + + q = p; + p = p->next; + } + } + + if (shutdown_flag == _B_FALSE) { + /* + * Unlock the bucket + */ + (void) rw_unlock(&htbl->bucketLock[i]); + } + } +} + +/* + * Function: enumerateAllHashTableEntries + * + * Arguments: table - Pointer to Hash Table + * bucket - IN/OUT determines which bucket to start + * enumerating from + * offset - IN/OUT determines which offset from bucket + * the last enumeration operation reached + * lockType - IN The Lock type, which can be: + * LOCK_NONE - No Lock + * LOCK_READ - Read Lock + * LOCK_WRITE - Write Lock + * + * Description: Enumerates synchronously the entire HashTable + * refered to by table; each call will set bucket + * and offset appropriately, and return the next + * HashEntry in the table. The caller should + * generally not need to mess with bucket and offset, + * except to ensure that the enumerator cookie + * (an array of uint32_ts) has been initialized + * the first time around with initEnumeratorState. + * + * If a lock type was selected, the node's will + * be locked upon return. The caller is then + * responsible for unlocking the node when it is + * finished with the data. + * + * This function is similar to getAllHashTableEntries, + * except that entries are returned to the caller + * directly, rather than through a callback, and + * the entries are not freed after enumeration (hence + * this enumeration function is read-only WRT the + * HashTable). + * + * Note that this function has snapshot semantics -- + * that is, it returns the next entry in the table + * as the table state is when the next enumeration + * call is made, not when the enumeration started. + * Hence if entries are removed or added while the + * the enumeration is proceeding, they may or may not + * show up in the enumeration. As such, this function + * is most useful for gathering stats for mechanisms + * like SNMP and mipagentstat. + * + * Returns: void * on success (this implies more entries to come) + * NULL on enumeration completion + */ +void *enumerateAllHashTableEntries(HashTable *table, + uint32_t *bucket, + uint32_t *offset, + int lockType) { + HashEntry *p; + void *answer = NULL; + int i; + + /* + * Traverse the buckets of the hashtable, starting at the given + * bucket. Increment the offset here as well. + */ + for (; *bucket < HASH_TBL_SIZE; (*bucket)++) { + (void) rw_rdlock(&(table->bucketLock[*bucket])); + p = table->buckets[*bucket]; + + /* + * Walk down the bucket's chain until either we find the + * next offset, or the chain ends. + */ + for (i = 0; p; p = p->next, i++) { + if (i == *offset) { + /* + * got it; lock the node if requested, and + * bump the offset. + */ + LOCK_NODE(lockType, p->data); + + (*offset)++; + answer = p->data; + break; + } + } + + (void) rw_unlock(&(table->bucketLock[*bucket])); + + if (answer != NULL) { + return (answer); + } + + /* + * If we get here, the offset given was at the end of + * the chain. Reset it now to zero and move on to the + * next bucket. + */ + *offset = 0; + } + + /* + * If we get here, there are no more elements in the table, + * so the enumeration is finished. Inform the caller by + * returning NULL; + */ + return (NULL); +} + +/* + * Function: initEnumeratorState + * + * Arguments: state - IN/OUT a pointer to the state cookie + * statelen - IN size of the state cookie + * + * Description: Initializes the enumerator state used by + * enumerateAllHashTableEntries such that when this + * state cookie is passed to enumerateAllHashTableEntries, + * the enumeration will commence at the first entry. + */ +void initEnumeratorState(void *state, size_t statelen) { + (void) memset(state, 0, statelen); +} diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/hash.h b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/hash.h new file mode 100644 index 0000000000..fef4ce9470 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/hash.h @@ -0,0 +1,156 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999, 2001 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ifndef _HASH_H +#define _HASH_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * hash.h: Hash Table structures, defines, and prototypes. + * + * The locking strategy behind hash.c is actually quite simple, + * but does need some explaining. Basically, we have three different + * locks to worry about; one at the hash table level, one at the + * bucket level and one at the node level. + * + * +===================+ + * | Hash | Hash | +---------+ +---------+ + * | Table | Bucket |<--->|HashEntry|<--->|HashEntry| + * | | | +---------+ +---------+ + * | * | * | / \ / \ + * | | | | | + * | | | \ / \ / + * | | | +---------+ +---------+ + * | | | | * Node | | * Node | + * +===================+ +---------+ +---------+ + * + * * = Lock is present + * + * When we walk through the Hash Table to add an item, it first + * gets the hash bucket index, and locks the whole row (or bucket) + * with a write lock. a HashEntry is then added at the head of the + * bucket queue. If a node lock was requested, via a function + * parameter, the node is locked. This is particularly useful if + * additional work will be done to the node. The Hash Table lock + * is then locked with a write lock, and the table counter is + * incremented, then the lock is unlocked. Lastly, the hash + * bucket is unlocked, and the function returns. + * + * When the code needs to find a node in the hash table, the + * hash bucket (row) is locked, and all nodes in the row are + * compare with the key provided. The caller may also provide + * a pointer to a helper routine, which is used to further + * qualify searches. If a match is found, the node is locked + * (if requested), and the pointer to the node is retruned to + * the caller. + * + * If a node is to be deleted from the table, the row is write + * locked, the row is searched for a match, based on the key and + * the data to the pointer. If a match is found, the HashEntry + * is deleted. The table lock is then write locked, decremented + * and unlocked. Finally, the bucket lock is released. + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + LOCK_NONE, + LOCK_READ, + LOCK_WRITE +}; + +typedef struct hash_entry { + struct hash_entry *next; + enum { + HASH_INT_KEY, + HASH_STR_KEY + } hashKeyType; + void *data; + uint32_t key; /* Hopefully somewhere in *data */ + unsigned char keyLen; /* keyLen can't be more than 255 chars now */ + unsigned char *keyData; +} HashEntry; + +#define HASH_TBL_SIZE 256 + +/* + * If uniqueData is set to non-zero, then the bucket will be searched for + * for uniqueness. + */ +typedef struct hash_table { + size_t size; + int uniqueData; + rwlock_t hashLock; + rwlock_t bucketLock[HASH_TBL_SIZE]; + HashEntry *buckets[HASH_TBL_SIZE]; +} HashTable; + +#define HASH_BIT_COUNT 8 + +#ifdef _BIG_ENDIAN +#define HASHIT(key) \ + ((uint32_t)((key >> HASH_BIT_COUNT) ^ (key)) \ + & ~(~0 << HASH_BIT_COUNT)) +#else +#define HASHIT(key) \ + ((uint32_t)((key << HASH_BIT_COUNT) ^ (key)) >> \ + (uint32_t)(32 - HASH_BIT_COUNT)) +#endif + +extern int InitHash(HashTable *); +extern int linkHashTableEntryUint(HashTable *, uint32_t, void *, int); +extern int linkHashTableEntryString(HashTable *, unsigned char *, uint32_t, + void *, int); +extern boolean_t delHashTableEntryUint(HashTable *, void *, + uint32_t, int); +extern boolean_t delHashTableEntryString(HashTable *, void *, unsigned char *, + uint32_t, int); +extern void *findHashTableEntryUint(HashTable *, uint32_t, int, + boolean_t (*fcnt)(void *, uint32_t, uint32_t, uint32_t), uint32_t, + uint32_t, + uint32_t); +extern void *findHashTableEntryString(HashTable *, unsigned char *, uint32_t, + int, boolean_t (*fcnt)(void *, uint32_t, uint32_t, uint32_t), uint32_t, + uint32_t, uint32_t); +extern boolean_t changeHashEntryStringToUint(HashTable *, void *, + unsigned char *, uint32_t, uint32_t); +extern void getAllHashTableEntries(HashTable *, boolean_t (*fcnt)(void *, + uint32_t), int, uint32_t, boolean_t shutdown_flag); +extern void *enumerateAllHashTableEntries(HashTable *, + uint32_t *, + uint32_t *, + int); +extern void initEnumeratorState(void *, size_t); + +#ifdef __cplusplus +} +#endif + +#endif /* _HASH_H */ diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/inc.flg b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/inc.flg new file mode 100644 index 0000000000..a555ad557f --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/inc.flg @@ -0,0 +1,34 @@ +#!/bin/sh +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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. +# +# ident "%Z%%M% %I% %E% SMI" + +find_files "s.*" usr/src/cmd/cmd-inet/common +echo_file usr/src/cmd/agents/snmp/agent/node.h +echo_file usr/src/cmd/agents/snmp/agent/pagent.h +echo_file usr/src/cmd/agents/snmp/snmplib/impl.h +echo_file usr/src/cmd/agents/snmp/snmplib/snmp.h +echo_file usr/src/cmd/agents/snmp/snmplib/asn1.h diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/mip.h b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/mip.h new file mode 100644 index 0000000000..c16c0a90c1 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/mip.h @@ -0,0 +1,432 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999-2001 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ifndef _MIP_H +#define _MIP_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This file contains definitions for structures used in all + * Mobile IP-aware entities. + */ + +#include <sys/time.h> +#include <sys/types.h> +#include <synch.h> +#include <sys/socket.h> +#include <net/if.h> + +#define mipverbose(a) if (logVerbosity) (void)printf a + +#define MAX_KEY_LEN 32 +#define MAX_NAI_LENGTH 256 + +/* Reason why a MN session terminates */ +#define REASON_UNKNOWN 0 +#define REG_EXPIRED 1 +#define REG_REVOKED 2 +#define MN_DEREGISTERED 3 + +/* Flag to indicate if Reverse Tunneling is Required */ +#define REVTUN_NOTREQUIRED 0 +#define REVTUN_REQUIRED 1 + +#ifdef LINUX +/* + * For linux only. + */ +typedef char boolean_t; +#endif + +/* + * The MipSecAssocEntry structure contains information necessary + * to authenticate messages. Each peer has one security association, + * which includes a key and replay information. + */ +typedef struct { + rwlock_t mipSecNodeLock; + boolean_t mipSecIsEntryDynamic; + uint32_t mipSecSPI; + int mipSecAlgorithmType; + int mipSecAlgorithmMode; + int mipSecKeyLen; + unsigned char mipSecKey[MAX_KEY_LEN]; + int mipSecReplayMethod; + time_t mipSecKeyLifetime; +} MipSecAssocEntry; + + +/* + * The MipSecViolationEntry structure is not currently used, + * but is intended to contain information about security + * failures from peers. + */ +typedef struct { + rwlock_t mipSecNodeLock; + ipaddr_t mipSecViolatorAddr; + uint32_t mipSecViolationCounter; + int mipSecRecentViolationSPI; + time_t mipSecRecentViolationTime; + int mipSecRecentViolationIDLow; + int mipSecRecentViolationIDHigh; + int mipSecRecentViolationReason; +} MipSecViolationEntry; + +/* Flags used in mobility agent advertisements */ +#define ADV_REVERSE_TUNNEL 0x01 +#define ADV_VJ_COMPRESSION 0x02 +#define ADV_GRE_ENCAP 0x04 +#define ADV_MIN_ENCAP 0x08 +#define ADV_IS_FOREIGN_AGENT 0x10 +#define ADV_IS_HOME_AGENT 0x20 +#define ADV_IS_BUSY 0x40 +#define ADV_REGISTRATION_REQUIRED 0x80 + +/* Possible addresses for agent advertisements */ +#define LINK_MCAST_ADV_ADDR "224.0.0.1" +#define LINK_MCAST_ADV_ADDR2 "224.0.0.2" +#define LINK_BCAST_ADDR "255.255.255.255" +#define LINK_MCAST_REG_ADDR "224.0.0.11" + +/* Boolean values */ +#define TRUE 1 +#define FALSE 0 + +/* Flags used in registrations */ +#define REG_BIT_UNUSED 0x01 +#define REG_REVERSE_TUNNEL 0x02 +#define REG_VJ_COMPRESSION 0x04 +#define REG_GRE_ENCAP 0x08 +#define REG_MIN_ENCAP 0x10 +#define REG_DECAPSULATION_BY_MN 0x20 +#define REG_FWD_BROADCASTS 0x40 +#define REG_SIMULTANEOUS_BINDINGS 0x80 + +/* Successful Mobile-IP Codes */ +#define MIP_SUCCESSFUL_REGISTRATION 0 +/* + * Successful, but an indication that simultaneous bindings + * is not supported. + */ +#define MIP_SIMULTANEOUS_NOT_SUPPORTED 1 + +/* Drop the signalling packet due to unknown extension */ +#define MA_DROP_PACKET -1 + +/* Rejection codes from Foreign Agent */ +#define FA_REASON_UNSPECIFIED 64 +#define FA_ADM_PROHIBITED 65 +#define FA_INSUFFICIENT_RESOURCES 66 +#define FA_MN_AUTH_FAILURE 67 +#define FA_HA_AUTH_FAILURE 68 +#define FA_REG_LIFETIME_TOO_LONG 69 +#define FA_POORLY_FORMED_REQUEST 70 +#define FA_POORLY_FORMED_REPLY 71 +#define FA_ENCAP_UNAVAILABLE 72 +#define FA_VJ_UNAVAILABLE 73 +#define FA_REVERSE_TUNNEL_UNAVAILABLE 74 +#define FA_REVERSE_TUNNEL_REQUIRED 75 +#define FA_MN_TOO_DISTANT 76 +#define FA_INVALID_CARE_OF_ADDR 77 +#define FA_DELIVERY_STYLE_UNAVAILABLE 79 +#define FA_HA_NET_UNREACHABLE 80 +#define FA_HA_HOST_UNREACHABLE 81 +#define FA_HA_PORT_UNREACHABLE 82 +#define FA_HA_UNREACHABLE 88 +/* + * Support for the error codes defined in the latest + * challenge/response and NAI I-D. + */ +#define FA_NONZERO_HOMEADDR_REQD 96 +#define FA_MISSING_NAI 97 +#define FA_MISSING_HOME_AGENT 98 +#define FA_MISSING_HOMEADDR 99 +#define FA_UNKNOWN_CVSE_FROM_MN 100 /* MN extension error at FA */ +#define FA_UNKNOWN_CVSE_FROM_HA 101 /* HA extension error at FA */ +#define FA_UNKNOWN_CHALLENGE 104 +#define FA_MISSING_CHALLENGE 105 +#define FA_STALE_CHALLENGE 106 +#define FA_MISSING_MN_FA_KEY 107 + +/* Rejection codes from Home Agent */ +#define HA_REASON_UNSPECIFIED 128 +#define HA_ADM_PROHIBITED 129 +#define HA_INSUFFICIENT_RESOURCES 130 +#define HA_MN_AUTH_FAILURE 131 +#define HA_FA_AUTH_FAILURE 132 +#define HA_ID_MISMATCH 133 +#define HA_POORLY_FORMED_REQUEST 134 +#define HA_TOO_MANY_SIMULTANEOUS 135 +#define HA_UNKNOWN_HOME_AGENT 136 +#define HA_REVERSE_TUNNEL_UNAVAILABLE 137 +#define HA_REVERSE_TUNNEL_REQUIRED 138 +#define HA_ENCAPSULATION_UNAVAILABLE 139 /* Used for Reverse Tunnel */ +#define HA_UNKNOWN_CVSE_FROM_MN 140 /* MN extension error at HA */ +#define HA_UNKNOWN_CVSE_FROM_FA 141 /* FA extension error at HA */ + +#define NONE 0 +/* Authentication algorithm types */ +#define MD5 1 + +/* Authentication algorithm modes */ +#define PREFIXSUFFIX 1 + +/* Replay method style */ +#define TIMESTAMPS 1 + +/* Encapsulation style */ +#define IPIP 1 +#define GRE 2 +#define MINIMAL 3 + +#ifdef LINUX +/* ICMP messages (we define them here for portability) */ +#define ICMP_UNREACH_PORT 3 +#define ICMP_ROUTERADVERT 9 +#define ICMP_ROUTERSOLICIT 10 +#endif + +/* + * We need to redefine the ICMP header here because we need + * the Mobile-IP router advertisement extension, which is not + * currently in ip_icmp.h. This should be added in the future. + */ +typedef struct icmphdr { + unsigned char type; + unsigned char code; + unsigned short checksum; + union { + struct { + unsigned char u_adv_num_addr; + unsigned char u_adv_addr_entry_size; + unsigned short u_adv_lifetime; + } u_adv; + uint32_t u_unused; + } icmphdr_u; +} icmph; + +#define icmpAdvNumAddr icmphdr_u.u_adv.u_adv_num_addr +#define icmpAdvAddrEntrySize icmphdr_u.u_adv.u_adv_addr_entry_size +#define icmpAdvLifetime icmphdr_u.u_adv.u_adv_lifetime + +/* Mobile IP Agent Advertisement Extension */ + +#define ADV_EXT_TYPE 16 +#define ADV_PREFIX_EXT_TYPE 19 +#define ADV_PADDING_EXT_TYPE 0 +#define ADV_CHALLENGE_EXT_TYPE 24 +#define ADV_AGENT_NAI_EXT_TYPE 25 + +/* + * The length of our challenges, and the maximum + * challenge size our Home Agent will accept. + */ +#define ADV_CHALLENGE_LENGTH 16 +#define ADV_MAX_CHALLENGE_LENGTH 256 +#define ADV_MAX_NAI_LENGTH 256 + +typedef struct aaext { + uint8_t type; + uint8_t length; + uint16_t seqNum; + uint16_t regLifetime; + uint8_t advFlags; + uint8_t reserved; +} advExt; + +/* Mobile IP Registration Request and Reply */ + +#define REG_REQUEST_TYPE 1 +#define REG_REPLY_TYPE 3 +#define REG_MH_AUTH_EXT_TYPE 32 +#define REG_MF_AUTH_EXT_TYPE 33 +#define REG_FH_AUTH_EXT_TYPE 34 +/* + * Support for the latest challenge/response, + * Vendor Specific and AAA Keys I-D. + */ +#define REG_GEN_AUTH_EXT_TYPE 36 +#define REG_CRIT_VENDOR_SPEC_EXT_TYPE 38 +#define REG_GEN_MN_FA_KEY_EXT_TYPE 40 +#define REG_GEN_MN_HA_KEY_EXT_TYPE 42 +#define ENCAPSULATING_DELIVERY_TYPE 130 /* for reverse tunneling */ +#define REG_MN_NAI_EXT_TYPE 131 +#define REG_MF_CHALLENGE_EXT_TYPE 132 +#define REG_NORMAL_VENDOR_SPEC_EXT_TYPE 134 + +typedef struct rreq { + uint8_t type; + uint8_t regFlags; + uint16_t regLifetime; + uint32_t homeAddr; + uint32_t haAddr; + uint32_t COAddr; + uint32_t IDHigh; + uint32_t IDLow; +} regRequest; + +typedef struct rrep { + uint8_t type; + uint8_t code; + uint16_t regLifetime; + uint32_t homeAddr; + uint32_t haAddr; + uint32_t IDHigh; + uint32_t IDLow; +} regReply; + +#define MIP_EXT_LENGTH 1 +#define MIP_EXT_DATA 2 + +typedef struct rrext { + uint8_t type; + uint8_t length; +} regExt; + +typedef struct authext { + uint8_t type; + uint8_t length; + uint16_t SPIhi; + uint16_t SPIlo; +} authExt; + +#define KEY_ALG_NONE 0 +#define KEY_ALG_MD5_PREFIXSUFFIX 2 +#define KEY_ALG_HMAC_MD5 3 + +typedef struct keydataext { + /* + * Key data is a MIER extension, and contains a lifetime + */ + uint32_t lifetime; + uint32_t mnAAASPI; + uint32_t nodeSPI; +}keyDataExt; + +/* + * Support for the latest challenge/response, + * Vendor Specific and AAA Keys I-D. + */ +typedef struct keyext { + uint8_t type; + uint8_t subType; + uint16_t length; + keyDataExt keyData; +} keyExt; + +#define GEN_KEY_MN_FA 7 +#define GEN_KEY_MN_HA 1 + +typedef struct mierlongext { + uint8_t type; + uint8_t subType; + uint16_t length; +} mierLongExt; + +/* + * The following are the offsets in the + * extension header for mier style extensions. + */ +#define MIP_EXT_GEN_SUB_TYPE 1 +#define MIP_EXT_LONG_LENGTH 2 +#define MIP_EXT_LONG_LENGTH_DATA 4 + +/* + * The following structure is the Generalized + * Authentication Extension, specified in the + * Challenge/Response I-D. + */ +typedef struct genauthext { + uint8_t type; + uint8_t subType; + uint16_t length; + uint16_t SPIhi; + uint16_t SPIlo; +} genAuthExt; + +#define GEN_AUTH_MN_AAA 1 + +#ifdef KEY_DISTRIBUTION +/* + * Support for vendor specific extensions. + * + * The following is the definition of the vendor + * specific extension. Although we don't really care + * about this draft, we define it so that we do + * recognize the critical vendor specific extension, + * which has a two octet length. + */ +typedef +struct vendorspecext { + uint8_t type; + uint8_t reserved; + uint16_t length; + uint32_t vendorId; + uint16_t vendorType; +} vendorSpecExt; +#else /* KEY_DISTRIBUTION */ +#define VENDOR_SPEC_EXT_HDR_LEN 10 +#endif /* KEY_DISTRIBUTION */ +/* + * The following are the offsets in the + * extension header for CVSE style extensions. + */ +#define MIP_EXT_CVSE_VENDOR_ID_TYPE 4 +#define MIP_EXT_CVSE_VENDOR_SUB_TYPE 8 +#define MIP_EXT_CVSE_VENDOR_ID_DATA 10 + +/* + * The following are the offsets in the + * extension header for NVSE style extensions. + */ +#define MIP_EXT_NVSE_VENDOR_ID_TYPE 3 +#define MIP_EXT_NVSE_VENDOR_SUB_TYPE 4 +#define MIP_EXT_NVSE_VENDOR_ID_DATA 9 + +/* + * And a few vendor Id's for your convenience. + */ +#define VENDOR_ID_CISCO 9 +#define VENDOR_ID_SUN 42 +#define VENDOR_ID_3COM 43 + +/* + * And lastly, here are a few vendor specific + * extension numbers + */ +#define REG_MN_FA_KEY_EXT 1 +#define REG_FA_HA_KEY_EXT 2 + +#ifdef __cplusplus +} +#endif + +#endif /* _MIP_H */ diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/mipagent.acl b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/mipagent.acl new file mode 100644 index 0000000000..36ba40037e --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/mipagent.acl @@ -0,0 +1,108 @@ +# +#pragma ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 +# +# Configuration file of an SNMP agent +# + + +################## +# access control # +################## + +# The list of community names needed for read/write access +# to the entire MIB. +# If the list is empty, the only valid community name is "public" +# and its access type is read-only + +acl = { + { + communities = public, private + access = read-write + managers = * + } +} + + +#communities = { +# public read-write +# private read-write +#} + +# The list of hosts that can send SNMP queries. +# If this list is empty, all the hosts are allowed to +# send SNMP queries. + +#managers = { +# hellcat +#} + + +################### +# trap parameters # +################### + +trap = { +# { +# trap-community = SNMP-trap +# hosts = corsair +# { +# enterprise = "atlp" +# trap-num = 0-4 +# } +# { +# enterprise = "sun" +# trap-num = 0, 1, 2-5, 6-16 +# } +# { +# enterprise = "snmp" +# trap-num = 0-5 +# } +# } +# { +# trap-community = jerry-trap +# hosts = jerry, nanak, hubble +# { +# enterprise = "sun" +# trap-num = 1, 3 +# } +# { +# enterprise = "snmp" +# trap-num = 1-3 +# } +# } +} + +# The community name to be used in traps. + +#trap-community = SNMP-trap + +# The list of hosts where traps should be sent. + +#trap-recipients = +#{ +# corsair +#} + diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/mipagent.reg b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/mipagent.reg new file mode 100644 index 0000000000..f7abd0d6c7 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/mipagent.reg @@ -0,0 +1,46 @@ +# +#pragma ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 +# +# Configuration file of the SNMP Relay +# for the SNMP agent bundled with SNM +# + + +########## +# agents # +########## + +agents = +{ + { + name = "mipagent" + subtrees = { 1.3.6.1.2.1.44 } + timeout = 2000000 + watch-dog-time = 86400 + } +} + + diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/mipagentstat_server.c b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/mipagentstat_server.c new file mode 100644 index 0000000000..18acef8f51 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/mipagentstat_server.c @@ -0,0 +1,446 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <unistd.h> +#include <door.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <syslog.h> +#include <sys/socket.h> +#include "mipagentstat_door.h" +#include "conflib.h" +#include "mip.h" +#include "hash.h" +#include "agent.h" + +/* + * Server for mipagentstat. This uses the protocol defined in + * "mipagentstat_door.h" to act as a door server for home and + * foreign agent statistics. + * + * The door server is created with the entry point dispatch; + * the door itself is created and bound to the rendezvous point + * on the filesystem by start_stat_server. dispatch simply + * sets up the enumeration if the operation is FIRST_ENT, and + * dispatches the enumeration call and it parameters to either + * the home or foreign agent enumeration function. + * + * This module and the hash module both use the enumeration state + * passed to and from the client. The are currently two different + * types of hash tables to enumerate: the faVisitorHash is two + * dimensional, the first being the hash buckets, and the second + * being the chains on each bucket; the haMobileNodeHash is three + * dimensional, the first and second dimensions being the same + * as faVisitorHash, and the extra third dimension being chains + * of bindings off each node in the hash chain. + * + * We use the notion of dimensions to optimize hash table + * enumeration. The first dimension corresponds to the hash + * table bucket, the second to the offset from that bucket, + * and the third (in the case of haMobileNodeHash) to the + * binding (which is an offset from the second offset). The state + * is decomposed into four 32-bit counters, of which only the + * first three are currently used. The first holds the bucket + * counter, the second the offset counter, and the third the + * binding offset counter. enumerateAllHashTableEntries handles + * the bucket and offset state, which enumerateHABindings handles + * the binding offset state. + * + * The counters are used as follows: we first jump to the bucket + * indicated by the bucket counter; next we count off into the + * chain until we reach the node following the node indicated by + * the offset counter, and finally, in the case of haMobileNodeHash, + * we count off from that node into the bindings list up to the + * node following the binding counter. If either the offset or + * binding offset counter reaches the end of its chain, we reset + * it to zero, and proceed with the next bucket or chain. This + * algorithm has the same computational complexity as the hash + * algorithm itself, with respect to finding the next node. + * + * The following #defines specify which 32-bit words in the enumeration + * state are used for what: + */ + +#define BUCKET 0 +#define OFFSET 1 +#define BINDING 2 + +extern HashTable faVisitorHash; /* Foreign agent hashtable */ +extern HashTable haMobileNodeHash; /* Home agent hashtable */ +extern HashTable mipAgentHash; /* Mobility agent peers */ + +extern int logVerbosity; + +static int did = -1; /* file-descriptor for stat server door; -1 means unset */ + +/* + * Function: enumerateHABindings + * + * Arguments: state - IN/OUT 128 bits of enumeration state + * lck - IN/OUT lock which protects the binding + * entry returned. If an entry was returned, + * lck will point to the node lock which + * the caller MUST unlock when done. + * + * Description: This function gets the next mobile node binding + * from the hash table haMobileNodeHash. The HA + * hastable is three dimensional: The first is the + * hashtable bucket array, the second is the linked + * list of HashEntries off each bucket, and the + * third is the linked list of bindings associated + * with each HaMobileNodeEntry. Hence we need three + * state counters for this enumeration. + * + * The enumeration state is contained in the state + * parameter, which is here cast to an array + * of four 32-bit unsigned integers. This function + * only used the first three words; the first two + * are used as enumeration state for + * enumerateAllHashTableEntries, while the third is + * used to find the next HaBindingEntry. + * + * Returns: a HaBindingEntry on success + * NULL if there are no more entries in the table + */ +static HaBindingEntry *enumerateHABindings(uint32_t state[4], rwlock_t **lck) { + HaMobileNodeEntry *hamne; + HaBindingEntry *habe; + uint32_t i; + + /* Find the next HaMobileNodeEntry */ + while ((hamne = enumerateAllHashTableEntries(&haMobileNodeHash, + state + BUCKET, + state + OFFSET, + LOCK_READ)) != NULL) { + habe = hamne->bindingEntries; + + /* Find the next HaBindingEntry */ + for (i = 0; habe; habe = habe->next, i++) { + if (i == state[BINDING]) { + /* got it */ + (state[BINDING])++; + + /* Pass the nodeLock back to the caller to unlock */ + *lck = &(hamne->haMnNodeLock); + return (habe); + } + } + + /* If we got here, there are no more bindings for this node */ + state[BINDING] = 0; + + (void) rw_unlock(&(hamne->haMnNodeLock)); + } + + /* If we got here, we have enumerated the whole table */ + return (NULL); +} + +/* + * Function: enumerateHAStats + * + * Arguments: args - IN/OUT The stat call/reply buffer + * + * Description: This function uses enumerateHABindings to retrieve the + * next binding in the enumeration and then extracts + * the data needed for the stats call into the + * DoorStatArgs args. + * + * Returns: 1 on success, more entries to come + * 0 on success, no more entries + */ +static int enumerateHAStats(DoorStatArgs *args) { + HaBindingEntry *habe; + /*LINTED pointer cast may result in improper alignment*/ + uint32_t *state = (uint32_t *)args->enum_state; + rwlock_t *nodeLock = NULL; + + if ((habe = enumerateHABindings(state, &nodeLock)) == NULL) { + /* enumeration has completed */ + return (0); + } + + /* copy out mobile node's address */ + args->node_af = AF_INET; + (void) memcpy(args->node, + &(habe->haBindingMN), + sizeof (habe->haBindingMN)); + /* copy out foreign agent's address */ + args->agent_af = AF_INET; + (void) memcpy(args->agent, + &(habe->haBindingCOA), + sizeof (habe->haBindingCOA)); + /* Copy out time granted and remaining */ + args->granted = (uint32_t)habe->haBindingTimeGranted; + args->expires = (uint32_t)habe->haBindingTimeExpires; + /* Finally, copy in the flags! */ + args->service_flags = (uint8_t)habe->haBindingRegFlags; + + (void) rw_unlock(nodeLock); + return (1); +} + +/* + * Function: enumerateFAStats + * + * Arguments: args - IN/OUT The stat call/reply buffer + * + * Description: This function uses enumerateAllHashTableEntries + * to retrieve the next FaVisitorEntry in the enumeration + * and then extracts the data needed for the stats call + * into the DoorStatArgs args. + * + * Returns: 1 on success, more entries to come + * 0 on success, no more entries + */ +static int enumerateFAStats(DoorStatArgs *args) { + FaVisitorEntry *fave; + /*LINTED pointer cast may result in improper alignment*/ + uint32_t *state = (uint32_t *)args->enum_state; + + if ((fave = enumerateAllHashTableEntries(&faVisitorHash, + state + BUCKET, + state + OFFSET, + LOCK_READ)) == NULL) { + /* enumeration has completed */ + return (0); + } + + /* copy out mobile node's home address */ + args->node_af = AF_INET; + (void) memcpy(args->node, + &(fave->faVisitorHomeAddr), + sizeof (fave->faVisitorHomeAddr)); + /* copy out home agent's address */ + args->agent_af = AF_INET; + (void) memcpy(args->agent, + &(fave->faVisitorHomeAgentAddr), + sizeof (fave->faVisitorHomeAgentAddr)); + /* Copy out time granted and remaining */ + args->granted = fave->faVisitorTimeGranted; + args->expires = fave->faVisitorTimeExpires; + /* Finally, copy in the flags! */ + args->service_flags = (uint8_t)fave->faVisitorRegFlags; + + (void) rw_unlock(&(fave->faVisitorNodeLock)); + return (1); +} + + +/* + * Function: enumerateAgentPeerStats + * + * Arguments: args - IN/OUT The stat call/reply buffer + * + * Description: This function uses enumerateAllHashTableEntres to + * retrieve the next MobilityAgentEntry in mipAgentHash, + * and then extracts the data needed for the stats call + * into the DoorStatArgs args. + * + * Returns: 1 on success, more entries to come + * 0 on success, no more entries + */ +int enumerateAgentPeerStats(DoorStatArgs *args, uint8_t flags) { + MobilityAgentEntry *mae; + + /* LINTED pointer cast may result in improper alignment */ + uint32_t *state = (uint32_t *)args->enum_state; + + /* skip the agent-peers that we're not looking for */ + do { + mae = enumerateAllHashTableEntries(&mipAgentHash, + state + BUCKET, state + OFFSET, LOCK_READ); + + if (mae == NULL) + return (0); + + } while ((mae->maPeerFlags & flags) == 0); + + /* copy out agent-peer's address */ + args->agent_af = AF_INET; + (void) memcpy(args->agent, &(mae->maAddr), sizeof (mae->maAddr)); + + /* Copy the flags */ + if (flags == FA_PEER) + /* + * User wants FA_PEER SAs, so this is us as the HA. Pass + * the SA bits which are relevant to us as HA peer, namely: + * request apply, and tunnel apply, and reply permit and + * reverse tunnel permit. Also make sure we're only showing + * what's invoked (not just what's configured)! + */ + args->service_flags = (mae->maIPsecFlags & + ((mae->maIPsecSAFlags[IPSEC_APPLY] & HA_PEER_APPLY_MASK) | \ + (mae->maIPsecSAFlags[IPSEC_PERMIT] & HA_PEER_PERMIT_MASK))); + else + /* + * For us as FA peer, we pass: request apply, reply permit, + * tunnel permit, and reverse tunnel apply. + */ + args->service_flags = (mae->maIPsecFlags & + ((mae->maIPsecSAFlags[IPSEC_APPLY] & FA_PEER_APPLY_MASK) | \ + (mae->maIPsecSAFlags[IPSEC_PERMIT] & FA_PEER_PERMIT_MASK))); + + /* fin */ + (void) rw_unlock(&(mae->maNodeLock)); + return (1); +} + +/* + * Function: dispatch + * + * Arguments: see door_create(3x) for the description of the + * arguments passed to this function. The DoorStatArgs + * structure used for the IPC is in argp. + * + * Description: Sets up the enumeration if the operation is FIRST_ENT, + * and then dispatches to either enumerateHAStats or + * enumerateFAStats. This is entry point to the door + * created by start_stat_server. + */ +/*ARGSUSED*/ +static void dispatch(void *cookie, char *argp, size_t argsize, + door_desc_t *dp, size_t ndesc) +{ + + /*LINTED pointer cast may result in improper alignment*/ + DoorStatArgs *args = (DoorStatArgs *)argp; + + if (argsize < sizeof (*args)) { + mipverbose(("stats server: call buffer too small\n")); + (void) door_return(NULL, 0, NULL, 0); + } + + /* Set up the enumeration operation */ + if (args->op == FIRST_ENT) { + initEnumeratorState(args->enum_state, + sizeof (*(args->enum_state))); + } else if (args->op != NEXT_ENT) { + /* sanity check: if the op isn't FIRST_ENT, it must be NEXT_ENT */ + mipverbose(("stats server: Unknown enumeration operation\n")); + (void) door_return(NULL, 0, NULL, 0); + } + + /* Dispatch to the HA or FA stat function */ + switch (args->type) { + case HOME_AGENT: + if (enumerateHAStats(args) == 0) + (void) door_return(NULL, 0, NULL, 0); + break; + + case FOREIGN_AGENT: + if (enumerateFAStats(args) == 0) + (void) door_return(NULL, 0, NULL, 0); + break; + + case HOME_AGENT_PEER: + if (enumerateAgentPeerStats(args, HA_PEER) == 0) + (void) door_return(NULL, 0, NULL, 0); + break; + + case FOREIGN_AGENT_PEER: + if (enumerateAgentPeerStats(args, FA_PEER) == 0) + (void) door_return(NULL, 0, NULL, 0); + break; + + default: + mipverbose(("stats server: Unknown agent type requested\n")); + (void) door_return(NULL, 0, NULL, 0); + } + + (void) door_return((char *)args, argsize, NULL, 0); +} + +/* + * Function: startStatServer + * + * Description: Creates the server door for receiving stat requests. + * If the door rendezvous file does not exist, creates it. + * This is the only entry point from mipagent into this + * module. + * + * Returns: 1 on error + * 0 on success + */ +int startStatServer() { + struct stat buf; + + if (did != -1) { + /* Door server is already running */ + return (0); + } + + /* Create the filesystem rendezvous point if not already there */ + if (stat(MIPAGENTSTAT_DOOR, &buf) < 0) { + int fd; + if ((fd = creat(MIPAGENTSTAT_DOOR, 0444)) < 0) { + syslog(LOG_ERR, "Cannot create %s", MIPAGENTSTAT_DOOR); + return (1); + } + (void) close(fd); + } + + /* Create the door ... */ + if ((did = door_create(dispatch, NULL, + DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) < 0) { + syslog(LOG_ERR, "door_create failed: %s", strerror(errno)); + return (1); + } + + /* + * And attach it to the rendezvous point, cleaning up any + * stale associations first. + */ + (void) fdetach(MIPAGENTSTAT_DOOR); + + if (fattach(did, MIPAGENTSTAT_DOOR) < 0) { + syslog(LOG_ERR, "Cannot attach door to %s: %s", + MIPAGENTSTAT_DOOR, strerror(errno)); + return (1); + } + + return (0); +} + +/* + * Function: killStatServer + * + * Description: This function is used to shut down the stat + * door server. + * + * Returns: 0 if successful, -1 on failure + */ +int killStatServer() { + int err = door_revoke(did); + did = -1; + return (err); +} diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/pool.c b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/pool.c new file mode 100644 index 0000000000..28cc5cccff --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/pool.c @@ -0,0 +1,241 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999-2001 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * file: pool.c + * + * This file contains all of the routines that manage + * the Home Agent's Home Address pools. This is used + * when a Mobile Node requests a Home Address by including + * a Home Address of zero (0) in the Registration + * request. + */ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <syslog.h> +#include <stdlib.h> + +#include "mip.h" +#include "agent.h" +#include "pool.h" + +/* + * This table has one entry for each pool defined in the config file + */ +extern HashTable mipPoolHash; + +extern int logVerbosity; +extern char *ntoa(uint32_t, char *); + +/* + * Function: CreateAddressPool + * + * Arguments: poolIdentifier - Numerical Pool Identifier + * baseAddress - The base IP address of the pool + * length - The number of addresses in the pool + * + * Description: This function will create a Pool structure + * and add it to the Hash Table. Pools are used + * to allocate Home Agent addresses to Mobile + * Nodes that request one by inserting a zero (0) + * Home Address in the Registration Request. + * + * The Pool entry will be locked upon return. + * The caller is responsible for unlocking the + * node when it is finished with it. + * + * Returns: if successful a pointer to a Pool structure + * is returned, otherwise NULL + */ +Pool * +CreateAddressPool(uint32_t poolIdentifier, ipaddr_t baseAddress, + uint32_t length) +{ + Pool *pool; + int poolSize; + int i; + + /* + * First, let's see if we already have this pool. + */ + if (findHashTableEntryUint(&mipPoolHash, poolIdentifier, + LOCK_NONE, NULL, 0, 0, 0) != NULL) { + syslog(LOG_ERR, "Pool %d already defined\n", poolIdentifier); + return (NULL); + } + + /* + * First we allocate the memory + */ + poolSize = sizeof (Pool) + (sizeof (PoolEntry) * length); + pool = (Pool *)calloc(1, poolSize); + + if (pool == NULL) { + syslog(LOG_CRIT, "FATAL: Unable to allocate address pool"); + return (NULL); + } + + /* + * Initialize the pool's parameters. + */ + if (rwlock_init(&pool->poolNodeLock, USYNC_THREAD, NULL)) { + syslog(LOG_ERR, "Unable to initialize read/write lock"); + free(pool); + return (NULL); + } + + pool->poolIdentifier = poolIdentifier; + pool->poolBaseAddress = baseAddress; + pool->poolLength = length; + + /* + * Setup each Pool Entry within the Pool structure (one + * per address). + */ + for (i = 0; i < length; i++) { + /* Setup the entry's address. */ + pool->poolEntry[i].poolStatus = POOL_FREE; + pool->poolEntry[i].poolHomeAddress = baseAddress + htonl(i); + } + + /* + * Add it to the Hash Table. + */ + if (linkHashTableEntryUint(&mipPoolHash, poolIdentifier, pool, + LOCK_WRITE)) { + syslog(LOG_ERR, "FATAL: Unable to add pool to hash table"); + free(pool); + return (NULL); + } + + return (pool); +} + +/* + * Function: GetAddressFromPool + * + * Arguments: poolIdentifier - Pool Identifier + * + * Description: This function will step through the Pool + * entry identified via the Pool Identifier + * and will return the first available + * Home Address. + * + * Returns: int, Home Address if successful, otherwise + * zero (0). + */ +uint32_t +GetAddressFromPool(uint32_t poolIdentifier) +{ + + Pool *pool; + int i; + ipaddr_t homeAddress = 0; + char buffer[INET_ADDRSTRLEN]; + + /* + * Let's get the pool entry, using the pool identifier. + */ + if ((pool = findHashTableEntryUint(&mipPoolHash, + poolIdentifier, LOCK_WRITE, NULL, 0, 0, 0)) == NULL) { + mipverbose(("Pool %d not found\n", poolIdentifier)); + return (0); + } + + for (i = 0; i < pool->poolLength; i++) { + if (pool->poolEntry[i].poolStatus == POOL_FREE) { + /* + * This one is free, let's allocate it. + */ + pool->poolEntry[i].poolStatus = POOL_TAKEN; + mipverbose(("allocated %s from pool %d\n", + ntoa(pool->poolEntry[i].poolHomeAddress, buffer), + poolIdentifier)); + homeAddress = pool->poolEntry[i].poolHomeAddress; + break; + } + } + + /* + * And now we unlock the node... + */ + (void) rw_unlock(&pool->poolNodeLock); + + return (homeAddress); +} + +/* + * Function: freeAddressFromPool + * + * Arguments: poolIdentifier - Pool Identifier + * homeAddr - Home Address + * + * Description: This function will put a Home Address + * back into the address pool by marking + * the entry as being free. + * + * Returns: boolean, _B_TRUE if the Home Address was freed. + */ +boolean_t +freeAddressFromPool(uint32_t poolIdentifier, ipaddr_t homeAddr) +{ + Pool *pool; + int i; + boolean_t found = _B_FALSE; + char buffer[INET_ADDRSTRLEN]; + + /* + * First, let's see if we already have this pool. + */ + if ((pool = findHashTableEntryUint(&mipPoolHash, + poolIdentifier, LOCK_WRITE, NULL, 0, 0, 0)) == NULL) { + mipverbose(("Pool %d not found\n", poolIdentifier)); + return (found); + } + + for (i = 0; i < pool->poolLength; i++) { + if (pool->poolEntry[i].poolStatus == POOL_TAKEN && + pool->poolEntry[i].poolHomeAddress == homeAddr) { + mipverbose(("Freed %s from pool %d\n", + ntoa(homeAddr, buffer), poolIdentifier)); + pool->poolEntry[i].poolStatus = POOL_FREE; + found = _B_TRUE; + break; + } + } + + /* + * And now we unlock the node... + */ + (void) rw_unlock(&pool->poolNodeLock); + + return (found); +} diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/pool.h b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/pool.h new file mode 100644 index 0000000000..aecd62f561 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/pool.h @@ -0,0 +1,72 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ifndef _POOL_H +#define _POOL_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * pool.h : Data structures and prototypes used by a Mobile IP agent + * to support Address Pools. + */ + + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct { + enum { + POOL_FREE = 0, + POOL_TAKEN + } poolStatus; + ipaddr_t poolHomeAddress; + char poolMnNAI[MAX_NAI_LENGTH]; +} PoolEntry; + +typedef struct { + rwlock_t poolNodeLock; + uint32_t poolIdentifier; + ipaddr_t poolBaseAddress; + uint32_t poolLength; + PoolEntry poolEntry[1]; +} Pool; + + +Pool *CreateAddressPool(uint32_t, ipaddr_t, uint32_t); + +uint32_t GetAddressFromPool(uint32_t); + +boolean_t freeAddressFromPool(uint32_t, ipaddr_t); + + +#ifdef __cplusplus +} +#endif + +#endif /* _POOL_H */ diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/setup.c b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/setup.c new file mode 100644 index 0000000000..91c048a181 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/setup.c @@ -0,0 +1,749 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * file: setup.c + * + * This file contains the routines used to create data + * structures, such as Mobile Nodes, Visitor Entries, + * interfaces and security association. + */ +#include <stdio.h> +#include <syslog.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <arpa/inet.h> +#include <limits.h> + +#include <errno.h> +#include "agent.h" +#include "mip.h" +#include "setup.h" +#include "agentKernelIntfce.h" + +/* ----------------- Common to all mobility agents ------------------- */ +extern struct hash_table maAdvConfigHash; + +/* + * This table stores all of the Security Associations + */ +extern HashTable mipSecAssocHash; + +/* + * This table has one entry for each known Mobility Agent + */ +extern HashTable mipAgentHash; + +/* + * This table has one entry for each pool defined in the config file + */ +extern HashTable mipPoolHash; + +/* + * This table has one entry for each active tunnel number + */ +extern HashTable mipTunlHash; + +/* Home Agent specific data structures. */ +extern struct hash_table haMobileNodeHash; + +/* Other external declarations */ +extern int logVerbosity; + +/* MipTunlEntryLookup function defined in agentKernelIntfce.c */ +extern boolean_t MipTunlEntryLookup(void *, ipaddr_t, uint32_t, uint32_t); +/* + * Given that we are acting as an SNMP Sub-Agent, we will need + * to register our address with the SNMP Master Agent. The + * subagent_addr variable is used for this purpose. + */ +ipaddr_t subagent_addr = 0; +static ipaddr_t haAddr = 0; + + +extern void HAinitID(uint32_t *, uint32_t *, int); +#define VNI "vni" +#define VNISTRLEN 3 + +/* + * Function: CreateMobileNodeEntry + * + * Arguments: mnEntryType - Whether the entry is dynamic or + * static + * homeAddr - The Mobile Node's Home Address + * mnNAI - The Mobile Node's NAI + * mnNAILen - The length of the NAI + * homeAgentAddr - The Mobile Node's Home Agent + * SPI - The Mobile Node's SPI + * state - A RADIUS thing. not needed for now + * poolIdentifier - The Pool Identifier + * + * Description: This function is used to create a Mobile Node + * entry, which is added to the hash table. The + * SPI provided MUST have been previously defined + * as is the pool (if a non-zero value was provided + * as the pool id). + * + * If a Home Address was provided, we will add the + * node to the hash table based on the Home Address + * otherwise the NAI will be used. + * + * The Mobile Node entry will be locked upon return. + * The caller is responsible for unlocking the + * node when it is finished with it. + * + * Returns: upon successful return, this function will + * return the Mobile Node Entry pointer, otherwise + * NULL. + * + */ +/* ARGSUSED */ +HaMobileNodeEntry * +CreateMobileNodeEntry(boolean_t isDynamic, ipaddr_t homeAddr, char *mnNAI, + uint32_t mnNaiLen, ipaddr_t homeAgentAddr, uint32_t SPI, char *state, + uint32_t poolIdentifier) +{ + HaMobileNodeEntry *entry = NULL; + MipSecAssocEntry *saEntry; +#ifdef RADIUS_ENABLED + time_t currentTime; +#endif /* RADIUS_ENABLED */ + + if (homeAddr == INADDR_ANY && (mnNAI == NULL || mnNaiLen == 0)) { + syslog(LOG_ERR, "Home Address OR NAI Must be specified"); + return (NULL); + } + /* + * First, let's make sure that we already have + * this SPI defined. + */ + if ((saEntry = findHashTableEntryUint(&mipSecAssocHash, + SPI, LOCK_NONE, NULL, 0, 0, 0)) == NULL) { + syslog(LOG_ERR, "SPI entry %d not found", SPI); + return (NULL); + } + + /* + * Let's see if we already have this pool. + */ + if (poolIdentifier) { + if (findHashTableEntryUint(&mipPoolHash, + poolIdentifier, LOCK_NONE, NULL, 0, 0, 0) == NULL) { + syslog(LOG_CRIT, "Pool entry %d not found.", + poolIdentifier); + return (NULL); + } + } + + /* + * If an NAI is provided, make sure that it is legal + */ + if (mnNAI) { + if (mnNaiLen > MAX_NAI_LENGTH) { + syslog(LOG_ERR, "Error: Mobile Node NAI too long"); + return (NULL); + } + } + + + entry = (HaMobileNodeEntry *)calloc(1, sizeof (HaMobileNodeEntry)); + + if (!entry) { + syslog(LOG_CRIT, "FATAL: Unable to allocate Mobile Node Entry"); + return (NULL); + } + + /* Now add our values */ + entry->haMnIsEntryDynamic = isDynamic; + entry->haMnAddr = homeAddr; + if (homeAgentAddr == 0) { + entry->haBindingIfaceAddr = haAddr; + } else { + entry->haBindingIfaceAddr = homeAgentAddr; + } + entry->haMnBindingCnt = 0; +#ifdef RADIUS_ENABLED + GET_TIME(currentTime); + entry->haRadiusState = state; + entry->haRadiusLastLookupTime = currentTime; +#endif /* RADIUS_ENABLED */ + entry->haMnSPI = SPI; + entry->haPoolIdentifier = poolIdentifier; + + if (mnNAI) { + (void) strncpy((char *)entry->haMnNAI, mnNAI, mnNaiLen); + entry->haMnNAI[mnNaiLen] = '\0'; + entry->haMnNAILen = mnNaiLen; + } + + HAinitID(&entry->haMnRegIDHigh, &entry->haMnRegIDLow, + saEntry->mipSecReplayMethod); + + if (rwlock_init(&entry->haMnNodeLock, USYNC_THREAD, NULL)) { + syslog(LOG_ERR, "Unable to initialize read/write lock"); + free(entry); + return (NULL); + } + + if (poolIdentifier && mnNaiLen) { + /* Add the entry to the NAI hash */ + if (linkHashTableEntryString(&haMobileNodeHash, + (unsigned char *)entry->haMnNAI, mnNaiLen, + entry, LOCK_WRITE)) { + syslog(LOG_ERR, "Unable to add Mobile Node entry to " + "hash table"); + (void) rwlock_destroy(&entry->haMnNodeLock); + free(entry); + return (NULL); + } + } else { + if (linkHashTableEntryUint(&haMobileNodeHash, entry->haMnAddr, + entry, LOCK_WRITE)) { + syslog(LOG_ERR, "Unable to add Mobile Node entry to " + "hash table"); + (void) rwlock_destroy(&entry->haMnNodeLock); + free(entry); + return (NULL); + } + } + + return (entry); +} + +/* + * Function: CreateMobilityAgentEntry + * + * Arguments: maEntryType - Whether the entry is dynamic or + * static + * address - The Mobility Agent's IP Address + * SPI - The Mobility Agent's SPI + * lifetime - The lifetime of the entry (for + * dynamic entries only) + * + * Description: This function will create the Mobility Agent + * Entry, and will add it to the Hash table. + * The SPI provided MUST have been previously + * defined, otherwise an error will occur. + * + * If the node is created as a dynamic entry, + * we will setup the entry's expiration time. + * + * The entry will be locked upon return. + * The caller is responsible for unlocking the + * node when it is finished with it. + * + * Returns: upon successful return, this function will + * return the Mobility Agent Entry pointer, + * otherwise NULL. + */ +MobilityAgentEntry * +CreateMobilityAgentEntry(boolean_t isDynamic, ipaddr_t address, + uint32_t SPI, uint32_t lifetime) +{ + MobilityAgentEntry *entry = NULL; + time_t currentTime; + + /* + * First, let's make sure that we do not already have + * this SPI defined. + */ + if (findHashTableEntryUint(&mipSecAssocHash, + SPI, LOCK_NONE, NULL, 0, 0, 0) == NULL) { + syslog(LOG_ERR, "SPI entry %d not found", SPI); + return (NULL); + } + + entry = (MobilityAgentEntry *)calloc(1, sizeof (MobilityAgentEntry)); + + if (!entry) { + syslog(LOG_CRIT, "FATAL: Unable to allocate MIP Agent Entry"); + return (NULL); + } + + /* Now add our values */ + entry->maAddr = address; + entry->maSPI = SPI; + entry->maIsEntryDynamic = isDynamic; + + if (isDynamic) { + /* + * Setup when the key expires... + */ + GET_TIME(currentTime); + entry->maExpiration = currentTime + lifetime; + } else { + entry->maExpiration = TIME_INFINITY; + } + + if (rwlock_init(&entry->maNodeLock, USYNC_THREAD, NULL)) { + syslog(LOG_ERR, "Unable to initialize read/write lock"); + free(entry); + return (NULL); + } + + if (linkHashTableEntryUint(&mipAgentHash, entry->maAddr, entry, + LOCK_WRITE)) { + syslog(LOG_ERR, "Unable to add MIP Agent entry to hash " + "table"); + (void) rwlock_destroy(&entry->maNodeLock); + free(entry); + return (NULL); + } + + return (entry); +} + +/* + * Function: CreateSecAssocEntry + * + * Arguments: SPI - Security Parameter Index + * SaType - Whether the entry is dynamic or + * static + * ReplayProtection - The replay protection + * type + * AlgorithmType - The authentication algorithm + * type + * AlgorithmMode - The mode used for the + * algorithm. + * keyLength - The length of the key + * key - A pointer to the key + * lifetime - The lifetime of the entry (for + * dynamic entries only) + * + * Description: This function will create a Security Association + * entry, and will add it to the hash table. If the + * SPI already exists, we will return an error. + * + * If the node is created as a dynamic entry, + * we will setup the entry's expiration time. + * + * Also, if the SA is dynamic and a duplicate SA + * is received, it is updated, and no error is + * returned. (if the SA is *not* dynamic, an + * error *is* returned.) + * + * The entry will be locked upon return. + * The caller is responsible for unlocking the + * node when it is finished with it. + * + * Returns: upon successful return, this function will + * return the Security Association Entry + * pointer, otherwise NULL. + */ +MipSecAssocEntry * +CreateSecAssocEntry(boolean_t isDynamic, uint32_t SPI, int ReplayProtection, + int AlgorithmType, int AlgorithmMode, int keyLength, char *key, + int lifetime) +{ + MipSecAssocEntry *entry = NULL; + time_t currentTime; + boolean_t alreadyInserted = _B_FALSE; + + /* + * First, let's make sure that we do not already have + * this SPI defined. + */ + if ((entry = findHashTableEntryUint(&mipSecAssocHash, SPI, + LOCK_WRITE, NULL, 0, 0, 0)) != NULL) { + if (isDynamic == _B_FALSE) { + syslog(LOG_ERR, "Duplicate SPI entry requested %d", + SPI); + (void) rw_unlock(&entry->mipSecNodeLock); + return (NULL); + } else { + alreadyInserted = _B_TRUE; + (void) fprintf(stderr, "Updating SPI %d\n", SPI); + } + } + + /* Entry is set if dynamic and already found */ + if (!entry) { + entry = (MipSecAssocEntry *)calloc(1, + sizeof (MipSecAssocEntry)); + if (!entry) { + syslog(LOG_CRIT, + "FATAL: Unable to allocate Sec Assoc Entry"); + return (NULL); + } + } + + entry->mipSecSPI = SPI; + entry->mipSecReplayMethod = ReplayProtection; + entry->mipSecAlgorithmType = AlgorithmType; + entry->mipSecAlgorithmMode = AlgorithmMode; + entry->mipSecKeyLen = keyLength; + entry->mipSecIsEntryDynamic = isDynamic; + + if (isDynamic) { + /* + * Setup when the key expires... + */ + GET_TIME(currentTime); + entry->mipSecKeyLifetime = currentTime + lifetime; + } else { + entry->mipSecKeyLifetime = TIME_INFINITY; + } + + (void) memcpy(entry->mipSecKey, key, keyLength); + + /* If it is already in table, we already own it with the RWLOCK set */ + if (!alreadyInserted) { + if (rwlock_init(&entry->mipSecNodeLock, USYNC_THREAD, NULL)) { + syslog(LOG_ERR, "Unable to initialize " + "read/write lock"); + free(entry); + return (NULL); + } + + if (linkHashTableEntryUint(&mipSecAssocHash, SPI, + entry, LOCK_WRITE)) { + syslog(LOG_ERR, "Unable to add Security " + "Assoc. entry to hash tabl"); + (void) rwlock_destroy(&entry->mipSecNodeLock); + free(entry); + return (NULL); + } + } + return (entry); +} + +/* + * Function: CreateInterfaceEntry + * + * Arguments: dev - A pointer to the device name + * regLifetime - The maximum registration lifetime that + * are willing to accept. + * advertiseOnBcast - Whether we will advertise on the + * broadcast address. + * minInterval - The minimum interval between adv. + * maxInterval - The maximum interval between adv. + * advLifetime - The maximum advertisement lifetime + * lifetime that we will advertise on this + * interface. + * advSeqNum - The sequence number that we will + * initially advertise. + * servicesFlags - The flags that we will advertise + * on the interface. + * prefixFlags - determines whether we will advertise + * the prefix length extension. + * reverseTunnelAllowed - are we going to allow MN's to + * request the reverse tunnel, and thereby send + * FA_REVERSE_TUNNEL_UNAVAILABLE errors to MN's + * requesting a reverse tunnel? Note, this is set to + * RT_NONE, RT_FA, RT_HA, or RT_BOTH depending on which + * of our agents is allowing the reverse tunnel. + * reverseTunnelRequired - are we going to require MN's to + * request the reverse tunnel, and thereby send + * FA_REVERSE_TUNNEL_REQUIRED errors to MN's not + * requesting a reverse tunnel? Note, this is set to + * RT_NONE, RT_FA, RT_HA, or RT_BOTH depending on which + * of our agents is requiring the reverse tunnel. + * advInterval - Advertisement interval for this interface + * + * Description: This function will create an interface entry, + * and will add it to the hash table. We will + * directly retrieve the interface's IP address and + * MAC address. + * + * Returns: int, 0 if successful. + * + * Comment: This function takes too many arguments. If this function + * ever needs a major change, passing a structure with all + * arguments should be considered. + * + */ +int +CreateInterfaceEntry(char *dev, int regLifetime, boolean_t advertiseOnBcast, + int minInterval, int maxInterval, int advLifetime, uint16_t advSeqNum, + int servicesFlags, boolean_t prefixFlags, uint8_t reverseTunnelAllowed, + uint8_t reverseTunnelRequired, boolean_t advLimitUnsolicited, uint8_t + advInitCount, uint32_t advInterval, boolean_t isDynamic) +{ + MaAdvConfigEntry *entry; + char *cp; + + /* If a virtual network interface is specified, warn the user */ + if (dev != NULL) { + if ((strncmp(dev, VNI, VNISTRLEN) == 0)) { + cp = dev + VNISTRLEN; + cp += strspn(cp, "0123456789"); + if (*cp == '\0' || *cp == ':' || *cp == '*') + syslog(LOG_WARNING, "%s specified. vni is a" + " virtual interface that does not transmit" + " or receive packets. See vni(7D)", dev); + } + } + + /* Let's check for dynamic interface entry */ + if (strchr(dev, '*') == NULL) { + entry = (MaAdvConfigEntry *) calloc(1, + sizeof (MaAdvConfigEntry)); + if (entry == NULL) { + syslog(LOG_CRIT, "FATAL: Unable to allocate " + "AdvConfigEntry"); + return (-2); + } + } else { + int len; + DynamicIfaceTypeEntry *dyn_entry; + DynamicIfaceTypeEntry *save_entry; + + /* + * Since devicename contains '*', it must be an entry + * for dynamic interface.For dynamic interface entry + * in the config file, we do not create entry in the + * MaAdvConfigEntry[], rather we keep a linked list + * of dynamic interface types. For each type of dynamic + * interface entry, the attributes will be common and + * saved in DynamicIfaceTypeEntry data structure. + * When mipagent detects one new interface that matches + * with the same type and that is not an exisisting one + * that went through down-up cycle, then it creates a new + * entry and attaches to the MaAdvConfigEntry list + */ + len = strlen(dev); + if (len > 0 && dev[len - 1] != '*') { + syslog(LOG_ERR, + "Invalid dynamic interface %s in mipagent.conf", + dev); + return (-1); + } + /* Replace '*' with null character */ + dev[len -1] = '\0'; + mipverbose(("CreateInterfaceEntry: dynamic device %s\n", + dev)); + + + if (dynamicIfaceHead == NULL) { + dynamicIfaceHead = (DynamicIfaceTypeEntry *) calloc(1, + sizeof (DynamicIfaceTypeEntry)); + dyn_entry = dynamicIfaceHead; + } else { + + /* search if this type exists already */ + dyn_entry = dynamicIfaceHead; + while (dyn_entry != NULL) { + if (strcmp(dyn_entry->dynamicIfcetype, dev) + == 0) { + mipverbose(("CreateInterfaceEntry:" + " Dynamic Entry already exists" + " %s\n", dev)); + return (0); + } + save_entry = dyn_entry; + dyn_entry = dyn_entry->next; + } + + dyn_entry = (DynamicIfaceTypeEntry *) calloc(1, + sizeof (DynamicIfaceTypeEntry)); + if (dyn_entry != NULL) { + /* Link to the dynamicEntry list */ + save_entry->next = dyn_entry; + } + } + + /* Fill in the structure with the parameter values */ + (void) strncpy(dyn_entry->dynamicIfcetype, dev, LIFNAMSIZ); + dyn_entry->AdvLimitUnsolicited = advLimitUnsolicited; + dyn_entry->AdvInitCount = advInitCount; + dyn_entry->AdvInterval = advInterval; + dyn_entry->AdvServiceflag = servicesFlags; + dyn_entry->AdvPrefixflag = prefixFlags; + dyn_entry->RevtunReqd = reverseTunnelRequired; + dyn_entry->RevtunAllowed = reverseTunnelAllowed; + dyn_entry->RegLifetime = regLifetime; + dyn_entry->AdvLifetime = advLifetime; + dyn_entry->advertiseOnBcast = advertiseOnBcast; + dyn_entry->next = NULL; + + /* Set the global variable DynamicInterface */ + DynamicInterface = _B_TRUE; + return (0); + } /* else dynamic entry */ + + /* Now add our interface values */ + (void) strncpy(entry->maIfaceName, dev, (LIFNAMSIZ -1)); + + /* + * Simplify the configuration effort, read IP address, netmask + * and hardware address directly from the interface. + */ + if (getIfaceInfo(entry->maIfaceName, &entry->maIfaceAddr, + &entry->maIfaceNetmask, &entry->maIfaceFlags, + &entry->maIfindex)) { + free(entry); + syslog(LOG_ERR, "Unable to get interface information: %m"); + return (-1); + } + + /* + * Save the first address usable for registering with the + * SNMP master. + */ + if (subagent_addr != 0) + subagent_addr = entry->maIfaceAddr; + + /* + * Don't attempt to get the hardware address if it's a point-to-point + * interface. + */ + if ((entry->maIfaceFlags & IFF_POINTOPOINT) == 0) { + if (getEthernetAddr(entry->maIfaceName, entry->maIfaceHWaddr)) { + syslog(LOG_ERR, "Unable to get interface address " + "information on %s (%s)", dev, strerror(errno)); + mipverbose(("Unable to get interface address " + "information on %s (%s)\n", dev, strerror(errno))); + free(entry); + return (-1); + } + } + + entry->maAdvMaxRegLifetime = regLifetime; + + /* + * TODO: Under Solaris, pkts for LINK_BCAST_ADDR seem to + * be sent on all of a host's interfaces. Don't know if this + * can be controlled using some options similar to + * IP_MULTICAST_IF. + */ + if (advertiseOnBcast == 1) { + entry->maAdvAddr = inet_addr(LINK_BCAST_ADDR); + } else { + entry->maAdvAddr = inet_addr(LINK_MCAST_ADV_ADDR); + } + + entry->maAdvMaxInterval = maxInterval; + entry->maAdvMinInterval = minInterval; + entry->maAdvMaxAdvLifetime = advLifetime; + entry->maAdvSeqNum = advSeqNum; + entry->maAdvServiceFlags = (char)servicesFlags; + entry->maAdvPrefixLenInclusion = prefixFlags; + entry->maReverseTunnelAllowed = reverseTunnelAllowed; + entry->maReverseTunnelRequired = reverseTunnelRequired; + entry->maAdvLimitUnsolicited = advLimitUnsolicited; + if (advLimitUnsolicited == _B_FALSE) + entry->maAdvInitCount = 1; + else + entry->maAdvInitCount = advInitCount; + entry->maAdvInterval = advInterval; + /* Set maNextAdvTime in getAndDispatchNetwork */ + entry->maNextAdvTime = LONG_MAX; + /* The follwoing is always set false in this routine */ + entry->maAdvDynamicInterface = isDynamic; + + if (rwlock_init(&entry->maIfaceNodeLock, USYNC_THREAD, NULL)) { + syslog(LOG_ERR, "Unable to initialize read/write lock"); + free(entry); + return (NULL); + } + + /* + * Ok, this is just a temp hack, but we need to save the + * local address of the interface. Otherwise we will need to + * configure the home agent for each Mobile Node, which is + * just too much config for everybody. Given that we really + * only work with one interface, this is not a big deal, but + * this DOES need to be cleaned up. + */ + haAddr = entry->maIfaceAddr; + + /* + * We do not request that the node be locked in this case since + * we do not need the pointer to be returned. We are just calling + * and ensuring that a pointer was in fact returned. + */ + if (linkHashTableEntryUint(&maAdvConfigHash, entry->maIfaceAddr, entry, + LOCK_NONE)) { + syslog(LOG_ERR, "Unable to add interface entry to hash table"); + (void) rwlock_destroy(&entry->maIfaceNodeLock); + free(entry); + return (-1); + } + + return (0); +} + + +/* + * Function: CreateTunlEntry + * + * Arguments: tnum - Tunnel number + * target - target address + * tunsrc - Tunnel source endpoint address + * muxfd - file desc of the stream that is + * associated with the tunnel. + * + * Description: This function will create a Tunnel + * entry, and will add it to the hash table. + * + * Returns: upon successful return, this function will + * return the Tunnel Entry pointer, otherwise NULL. + */ + +MipTunlEntry * +CreateTunlEntry(int tnum, ipaddr_t target, ipaddr_t tunsrc, int muxfd) +{ + MipTunlEntry *entry = NULL; + + /* + * First, let's make sure that we do not already have + * this target defined. + */ + if ((findHashTableEntryUint(&mipTunlHash, target, + LOCK_NONE, MipTunlEntryLookup, tunsrc, 0, 0)) != NULL) { + syslog(LOG_ERR, "Duplicate target entry requested %x", target); + return (NULL); + } + + entry = (MipTunlEntry *)calloc(1, sizeof (MipTunlEntry)); + if (!entry) { + syslog(LOG_CRIT, "FATAL: Unable to allocate Tunl Entry"); + return (NULL); + } + + entry->tunnelno = tnum; + entry->tunnelsrc = tunsrc; + entry->mux_fd = muxfd; + + if (rwlock_init(&entry->TunlNodeLock, USYNC_THREAD, NULL)) { + syslog(LOG_ERR, "Unable to initialize read/write lock"); + free(entry); + return (NULL); + } + + + if (linkHashTableEntryUint(&mipTunlHash, target, entry, LOCK_WRITE)) { + syslog(LOG_ERR, "Unable to add Tunnel entry to hash table"); + (void) rwlock_destroy(&entry->TunlNodeLock); + free(entry); + return (NULL); + } + + return (entry); +} diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/setup.h b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/setup.h new file mode 100644 index 0000000000..0cde6dd4cf --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/setup.h @@ -0,0 +1,57 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999-2001 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ifndef _SETUP_H +#define _SETUP_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * setup.h : Data structures and prototypes used by a Mobile IP agent + * to create data structures. + */ + +#ifdef __cplusplus +extern "C" { +#endif + + +#define TIME_INFINITY -1 + +HaMobileNodeEntry *CreateMobileNodeEntry(boolean_t, ipaddr_t, char *, + uint32_t, ipaddr_t, uint32_t, char *, uint32_t); +MobilityAgentEntry *CreateMobilityAgentEntry(boolean_t, ipaddr_t, uint32_t, + uint32_t); +MipSecAssocEntry *CreateSecAssocEntry(boolean_t, uint32_t, int, int, int, + int, char *, int); +int CreateInterfaceEntry(char *, int, boolean_t, int, int, int, uint16_t, int, + boolean_t, uint8_t, uint8_t, boolean_t, uint8_t, uint32_t, boolean_t); + +#ifdef __cplusplus +} +#endif + +#endif /* _SETUP_H */ diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_appl.c b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_appl.c new file mode 100644 index 0000000000..a28dd89456 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_appl.c @@ -0,0 +1,409 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999-2001 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * file: mipagentsnmp_appl.c + * + * This file contains the main SNMP routines used for + * initialization and shutdown. + */ + +#include <sys/types.h> +#include <netinet/in.h> +#include <pthread.h> +#include <stdlib.h> +#include <syslog.h> + +#include <impl.h> +#include <pagent.h> + +#include "snmp_stub.h" +#include "mip.h" + +/* GLOBAL VARIABLES */ + +#ifndef lint +char default_config_file[] = "/etc/snmp/conf/mipagent.reg"; +char default_sec_config_file[] = "/etc/snmp/conf/mipagent.acl"; +char default_error_file[] = "/var/snmp/mipagent.log"; +#endif + +static pthread_t snmpThreadId = 0; + +typedef struct { + int argc; + char *argv; +} StartupArgs; + +static void mipagent_snmp_thread(StartupArgs *args); + +#define DEFAULT_SNMP_PORT 161 + +extern ipaddr_t subagent_addr; /* this was set in setup.c */ + +extern int SSASubagentOpen(int, char *); +extern int SSARegSubagent(Agent *); +extern int SSAMain(int, char **); + +/* + * Function: register_with_master + * + * Arguments: subagent_addr - Sub-Agent Address + * + * Description: This function will register the SNMP + * sub-agent with the master SNMP agent. + * + * Returns: int, 0 if successful + */ +static int +/* LINTED E_FUNC_ARG_UNUSED */ +register_with_master(ipaddr_t subagent_addr) +{ + /* LINTED E_FUNC_VAR_UNUSED */ + Agent subagent; + + return (0); + +#if 0 + /* NOTREACHED */ + + agentid = SSASubagentOpen(0, "mipagent"); + (void) memset(&subagent, 0, sizeof (Agent)); + subagent.agent_id = agentid; + + /* + * Tell master we are ready + */ + subagent.agent_status = SSA_OPER_STATUS_ACTIVE; + subagent.address.sin_family = AF_INET; + subagent.address.sin_port = DEFAULT_SNMP_PORT; + subagent.address.sin_addr.s_addr = subagent_addr; + if ((SSARegSubagent(&subagent)) == 0) { + return (-1); + } + return (0); +#endif +} + +/* + * Function: deregister_with_master + * + * Arguments: subagent_addr - Sub-Agent Address + * + * Description: This function will inform the + * SNMP Master agent that we are + * going away. + * + * Returns: int, 0 if successful + */ +static int +/* LINTED E_FUNC_ARG_UNUSED */ +deregister_with_master(ipaddr_t subagent_addr) +{ + /* LINTED E_FUNC_VAR_UNUSED */ + Agent subagent; + + return (0); +#if 0 + /* NOTREACHED */ + + if (agentid) { + (void) memset(&subagent, 0, sizeof (Agent)); + subagent.agent_id = agentid; + + /* + * Tell master we are going away + */ + subagent.agent_status = SSA_OPER_STATUS_DESTROY; + subagent.address.sin_family = AF_INET; + subagent.address.sin_port = DEFAULT_SNMP_PORT; + subagent.address.sin_addr.s_addr = subagent_addr; + if ((SSARegSubagent(&subagent)) == 0) { + return (-1); + } + + agentid = 0; + } + return (0); +#endif +} + +#ifndef lint +/* + * Function: agent_init + * + * Arguments: + * + * Description: Stub provided for the SNMP Sub-Agent + * initialization. We do not have anything + * to do here. + * + * Returns: + */ +void +agent_init() +{ +} + + +/* + * Function: agent_end + * + * Arguments: + * + * Description: Stub provided for the SNMP Sub-Agent + * shutdown. We do not have anything + * to do here. + * + * Returns: + */ +void +agent_end() +{ +} + + +/* + * Function: agent_loop + * + * Arguments: + * + * Description: The SNMP Loop function, which is + * provided because the sub-agent needs it. + * + * Returns: + */ +void +agent_loop() +{ +} + + +/* + * Function: agent_select_info + * + * Arguments: fdset - File Descriptor set + * numfds - number of file descriptors + * + * Description: Another stub provided for the SNMP + * sub-agent. + * + * Returns: + */ +/* ARGSUSED */ +void +agent_select_info(fd_set *fdset, int *numfds) +{ +} + + +/* + * Function: agent_select_callback + * + * Arguments: fdset - File Descriptor set + * + * Description: Callback routine for the SNMP Sub-Agent, + * which we are providing as a stub. + * + * Returns: + */ +/* ARGSUSED */ +void +agent_select_callback(fd_set *fdset) +{ +} +#endif +/* + * Function: startSNMPTaskThread + * + * Arguments: none + * + * Description: This function will start the SNMP + * sub-agent thread, and register with + * the Master SNMP thread. + * + * Returns: int, 0 if successful + */ +int +startSNMPTaskThread(void) +{ + StartupArgs *args; + static char *all_args[3]; + static char arg0[] = "mipagent"; + static char arg1[] = "-d"; + static char arg2[] = "1"; + pthread_attr_t pthreadAttribute; + int result; + + result = pthread_attr_init(&pthreadAttribute); + if (result) { + syslog(LOG_CRIT, "Error Initializing pthread."); + return (-1); + } + + args = (StartupArgs *) malloc(sizeof (StartupArgs)); + if (args == NULL) { + syslog(LOG_CRIT, "Unable to allocate memory."); + return (-1); + } + + /* + * Call the SSAMain() with "-d 1" argument, so that it doesn't + * daemonize the process. "-d 1" attempts to generate debug output. + * When mipagent is daemonized, since the stdout is closed, this + * will have no effect. When mipagent is not deamonized for debugging + * purposes, this will generate useful debug info for SNMP. + */ + all_args[0] = (char *)arg0; + all_args[1] = (char *)arg1; + all_args[2] = (char *)arg2; + + args->argc = 3; + args->argv = (char *)all_args; + + /* + * The thread is then started It is mandatory that all + * applications have a slaveThread() function declared, + * which will be called with the TCB. + */ + result = pthread_create(&snmpThreadId, &pthreadAttribute, + (void *(*)()) mipagent_snmp_thread, + (void *)args); + + if (result) { + syslog(LOG_CRIT, "pthread_create() failed."); + free(args); + 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. + */ + result = pthread_detach(snmpThreadId); + + if (result) { + syslog(LOG_CRIT, "pthread_detach() failed."); + free(args); + return (-1); + } + + return (0); + +} + +/* + * Function: killSNMPTaskThread + * + * Arguments: + * + * Description: This function is used to shutdown the + * SNMP Sub-Agent thread. + * + * Returns: + */ +int +killSNMPTaskThread() +{ + int result; + + if (snmpThreadId) { + if (deregister_with_master(subagent_addr)) { + syslog(LOG_CRIT, "Unable to deregister with sub-agent"); + } + + /* + * Next we need to kill the dispatching thread. + */ + result = pthread_cancel(snmpThreadId); + + if (result) { + /* + * Well, there's not much we can do here.. + */ + syslog(LOG_CRIT, "Unable to kill snmp thread"); + } + } + + return (0); +} + +/* + * Function: mipagent_snmp_thread + * + * Arguments: args - Command Line Arguments + * + * Description: This function is the main SNMP Sub-Agent + * thread. The function will call SSAMain, which + * never returns (unless an error occured). + * + * This thread will remain active until either + * the SNMP Sub-Agent main routines returns or + * the killSNMPTaskThread() function is called. + * + * Returns: + */ +static void +mipagent_snmp_thread(StartupArgs *args) +{ + int argc; + int result; + char **argv; + + /* + * Register ourselves as a sub-agent with the master SNMP + * agent. + */ + result = register_with_master(subagent_addr); + + if (result) { + syslog(LOG_CRIT, "Could not register with master SNMP agent."); + free(args); + pthread_exit(NULL); + } + + /* + * Let's do the SSAMain thingy... Note that this function should, + * in theory, never return. This function will interface with the + * SNMP Master Agent. + */ + argc = args->argc; + /* LINTED E_BAD_PTR_CAST_ALIGN */ + argv = (char **)args->argv; + + SSAMain(argc, argv); + + free(args); + + if (deregister_with_master(subagent_addr)) { + syslog(LOG_CRIT, "Unable to deregister with sub-agent"); + } + + pthread_exit(NULL); +} diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_faCOAEntry.c b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_faCOAEntry.c new file mode 100644 index 0000000000..df378ec69d --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_faCOAEntry.c @@ -0,0 +1,94 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999-2001 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * file: mipagentsnmp_faCOAEntry.c + * + * This file contains the SNMP routines used to retrieve + * the Foreign Agent's Care of Address Information. + */ + +#include <stdlib.h> +#include <sys/types.h> +#include <netinet/in.h> + +#include <impl.h> + +#include "snmp_stub.h" +#include "agent.h" + +/* faCOAEntry */ + +/* + * Function: get_faCOAEntry + * + * Arguments: search_type - The type of search (first, next, exact) + * faCOAEntry_data - Pointer to a pointer + * which will contain the COA entry upon + * successful completion. + * index - Pointer to the current index + * + * Description: Since we currently do not support this, we will + * simply return and end of table SNMP error code. + * + * Returns: END_OF_TABLE, meaning there are no more entries + * in our table. + */ +/* ARGSUSED */ +extern int +get_faCOAEntry(int search_type, FaCOAEntry_t **faCOAEntry_data, + IndexType *index) +{ + /* + * Perhaps one day we will support Care of Addresses, but + * for now we will return an end of table error. + */ + return (END_OF_TABLE); + +} + + +/* + * Function: free_faCOAEntry + * + * Arguments: faCOAEntry - Pointer to a previously + * allocated SNMP COA entry + * + * Description: This function is called to free a previously + * allocated SNMP COA entry. + * + * Returns: + */ +void +free_faCOAEntry(FaCOAEntry_t *faCOAEntry) +{ + if (faCOAEntry) { + free(faCOAEntry); + faCOAEntry = NULL; + } +} diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_faVisitorEntry.c b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_faVisitorEntry.c new file mode 100644 index 0000000000..58dc49b19f --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_faVisitorEntry.c @@ -0,0 +1,356 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 1999-2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * file: mipagentsnmp_faVisitorEntry.c + * + * This file contains the SNMP routines used to retrieve + * the Foreign Agent's Visitor Entry. + */ + +#include <sys/types.h> +#include <netinet/in.h> +#include <memory.h> +#include <string.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> + +#include <impl.h> +#include <snmp.h> + +#include "snmp_stub.h" +#include "agent.h" + +extern HashTable faVisitorHash; +extern char *ntoa(uint32_t, char *); + +/* faVisitorEntry */ + +/* + * Function: get_faVisitorEntry + * + * Arguments: search_type - The type of search (first, next, exact) + * faVisitorEntry_data - Pointer to a pointer which + * will contain the visitor entry upon + * successful completion. + * index - Pointer to the current index + * + * Description: This function will allocate the memory required for + * the visitor entry, and will find the appropriate + * visitor entry based on the index provided. If the + * search type is set to FIRST_ENTRY, we will return + * the first visitor entry in the Hash Table, otherwise + * the index is used. + * + * The visitor entry is then setup with the values found + * in the entry from the hash table and returned to the + * caller. + * + * Note, the caller is responsible for either freeing the + * memory, or calling free_faVisitorEntry() + * + * Returns: int, 0 if successful + */ +int +get_faVisitorEntry(int search_type, FaVisitorEntry_t **faVisitorEntry_data, + IndexType *index) +{ + Integer *integer; + String *string; + FaVisitorEntry *faVisitorEntry = NULL; + HashEntry *hashEntry; + int i; + int j; + int return_code = SNMP_ERR_NOERROR; + time_t currentTime; + char buffer[258]; + boolean_t found = _B_FALSE; + struct ether_addr ether; + char *tmp_buf; + + /* + * Allocate some memory to handle the request. + */ + *faVisitorEntry_data = + (FaVisitorEntry_t *)calloc(1, sizeof (FaVisitorEntry_t)); + + if (faVisitorEntry_data == NULL) { + return (SNMP_ERR_GENERR); + } + + /* + * In the case, the search_type is FIRST_ENTRY or NEXT_ENTRY + * this function should modify the index argument to the + * appropriate value + */ + switch (search_type) { + case FIRST_ENTRY: + /* + * We are looking for the first entry in the list. + */ + index->value[0] = 1; + index->len = 1; + break; + case NEXT_ENTRY: + /* + * Increment the index value. + */ + index->value[0]++; + break; + case EXACT_ENTRY: + /* + * We don't need to play around with the + * index for this search type. + */ + break; + default: + return_code = SNMP_ERR_GENERR; + goto the_end; + } + + /* + * Now search for the entry... + */ + for (i = 0, j = 1; i < HASH_TBL_SIZE && found == _B_FALSE; i++) { + if (faVisitorHash.buckets[i]) { + /* + * Lock the bucket + */ + (void) rw_rdlock(&faVisitorHash.bucketLock[i]); + + /* + * Look for the entry we need + */ + hashEntry = faVisitorHash.buckets[i]; + while (hashEntry != NULL) { + if (j == index->value[0]) { + faVisitorEntry = hashEntry->data; + found = _B_TRUE; + + /* + * Lock the node + */ + (void) rw_rdlock(&faVisitorEntry-> + faVisitorNodeLock); + + break; + } + hashEntry = hashEntry->next; + j++; + } + + /* + * Unlock the bucket + */ + (void) rw_unlock(&faVisitorHash.bucketLock[i]); + } + } + + if (faVisitorEntry == NULL) { + return_code = END_OF_TABLE; + goto the_end; + } + + /* + * Get the visitor entry's IP Address. + */ + (void) ntoa(faVisitorEntry->faVisitorAddr, buffer); + string = &((*faVisitorEntry_data)->faVisitorIPAddress); + string->chars = (unsigned char *)strdup(buffer); + if (string->chars == NULL) { + return_code = SNMP_ERR_GENERR; + goto the_end; + } + string->len = strlen(buffer); + + /* + * Get the visitor entry's link layer address. + */ + (void) memcpy(ether.ether_addr_octet, + faVisitorEntry->faVisitorSlla.sdl_data, ETHERADDRL); + tmp_buf = ether_ntoa(ðer); + if (tmp_buf == NULL) { + return_code = SNMP_ERR_GENERR; + goto the_end; + } + string = &((*faVisitorEntry_data)->faVisitorSlla); + string->chars = (unsigned char *)strdup(tmp_buf); + if (string->chars == NULL) { + return_code = SNMP_ERR_GENERR; + goto the_end; + } + string->len = strlen(tmp_buf); + + /* + * Let's get the visitor entry's Home Agent Address + */ + (void) ntoa(faVisitorEntry->faVisitorHomeAgentAddr, buffer); + string = &((*faVisitorEntry_data)->faVisitorHomeAgentAddress); + string->chars = (unsigned char *)strdup(buffer); + if (string->chars == NULL) { + return_code = SNMP_ERR_GENERR; + goto the_end; + } + string->len = strlen(buffer); + + /* + * Let's get the visitor entry's Home Address + */ + (void) ntoa(faVisitorEntry->faVisitorHomeAddr, buffer); + string = &((*faVisitorEntry_data)->faVisitorHomeAddress); + + string->chars = (unsigned char *)strdup(buffer); + if (string->chars == NULL) { + return_code = SNMP_ERR_GENERR; + goto the_end; + } + string->len = strlen(buffer); + + /* + * And now we return the amount of time that was granted to + * the visitor. + */ + integer = &((*faVisitorEntry_data)->faVisitorTimeGranted); + *integer = faVisitorEntry->faVisitorTimeGranted; + + /* + * And now we return the amount of time remaining for + * the visitor. + */ + integer = &((*faVisitorEntry_data)->faVisitorTimeRemaining); + GET_TIME(currentTime); + *integer = currentTime - + faVisitorEntry->faVisitorTimeExpires; + + /* + * And now we return the Registration Flags. + */ + integer = &((*faVisitorEntry_data)->faVisitorRegFlags); + *integer = (int)faVisitorEntry->faVisitorRegFlags; + + /* + * And now we return the lower 32-bits of the visitor's ID. + */ + integer = &((*faVisitorEntry_data)->faVisitorRegIDLow); + *integer = (int)faVisitorEntry->faVisitorRegIDLow; + + /* + * And now we return the high 32-bits of the visitor's ID. + */ + integer = &((*faVisitorEntry_data)->faVisitorRegIDHigh); + *integer = (int)faVisitorEntry->faVisitorRegIDHigh; + + + /* + * And now we return the high 32-bits of the visitor's ID. + */ + integer = &((*faVisitorEntry_data)->faVisitorRegIsAccepted); + if (faVisitorEntry->faVisitorRegIsAccepted == _B_TRUE) { + *integer = 1; + } else { + *integer = 2; + } + + /* + * And now we return the inbound interface index on which the + * registration request was received + */ + integer = &((*faVisitorEntry_data)->faVisitorInIfindex); + *integer = (int)faVisitorEntry->faVisitorInIfindex; + +the_end: + if (faVisitorEntry != NULL) { + /* + * Unlock the bucket + */ + (void) rw_unlock(&faVisitorEntry->faVisitorNodeLock); + } + + if (return_code != SNMP_ERR_NOERROR) { + free_faVisitorEntry(*faVisitorEntry_data); + *faVisitorEntry_data = NULL; + } + + return (return_code); +} + + +/* + * Function: free_faVisitorEntry + * + * Arguments: faVisitorEntry - Pointer to a previously + * allocated SNMP visitor entry + * + * Description: This function is called to free a previously + * allocated SNMP visitor entry. + * + * Returns: + */ +void +free_faVisitorEntry(FaVisitorEntry_t *faVisitorEntry) +{ + String *string; + + if (faVisitorEntry) { + /* + * The template generates code that checks both + * the pointer, and the length. I am not sure + * if this is excessive, so I will leave it as is. + */ + string = &(faVisitorEntry->faVisitorIPAddress); + if (string->chars != NULL && string->len != 0) { + free(string->chars); + string->len = 0; + } + + string = &(faVisitorEntry->faVisitorHomeAddress); + if (string->chars != NULL && string->len != 0) { + free(string->chars); + string->len = 0; + } + + string = &(faVisitorEntry->faVisitorHomeAgentAddress); + if (string->chars != NULL && string->len != 0) { + free(string->chars); + string->len = 0; + } + + string = &(faVisitorEntry->faVisitorSlla); + if (string->chars != NULL && string->len != 0) { + free(string->chars); + string->len = 0; + } + + free(faVisitorEntry); + faVisitorEntry = NULL; + } +} diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_haCounterEntry.c b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_haCounterEntry.c new file mode 100644 index 0000000000..8b3654a1e1 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_haCounterEntry.c @@ -0,0 +1,239 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999-2001 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * file: mipagentsnmp_haCounterEntry.c + * + * This file contains the SNMP routines used to retrieve + * the Home Agent's Mobile Node Counter Information. + */ + +#include <sys/types.h> +#include <netinet/in.h> +#include <stdlib.h> + +#include <impl.h> +#include <snmp.h> + +#include "snmp_stub.h" +#include "agent.h" + +extern HashTable haMobileNodeHash; + + +/* + * Function: get_haCounterEntry + * + * Arguments: search_type - The type of search (first, next, exact) + * haCounterEntry_data - Pointer to a pointer which + * will contain the Mobile Node counter entry + * upon successful completion. + * index - Pointer to the current index + * + * Description: This function will allocate the memory required for + * the Mobile Node counter entry, and will find the + * appropriate Mobile Node counter based on the index + * provided. If the search type is set to FIRST_ENTRY, + * we will return the first Mobile Node counter in the + * Hash Table, otherwise the index is used. + * + * The Mobile Node counter entry is then setup with the + * values found in the entry from the hash table and + * returned to the caller. + * + * Note, the caller is responsible for either freeing the + * memory, or calling free_haCounterEntry() + * + * Returns: int, 0 if successful + */ +extern int +get_haCounterEntry(int search_type, + HaCounterEntry_t **haCounterEntry_data, IndexType *index) +{ + + Integer *integer; + HaMobileNodeEntry *haMobileNodeEntry = NULL; + HashEntry *hashEntry; + int i; + int j; + int return_code = SNMP_ERR_NOERROR; + boolean_t found = _B_FALSE; + + *haCounterEntry_data = + (HaCounterEntry_t *)calloc(1, sizeof (HaCounterEntry_t)); + + if (haCounterEntry_data == NULL) { + return (SNMP_ERR_GENERR); + } + + /* + * In the case, the search_type is FIRST_ENTRY or NEXT_ENTRY + * this function should modify the index argument to the + * appropriate value + */ + switch (search_type) { + case FIRST_ENTRY: + /* + * We are looking for the first entry in the list. + */ + index->value[0] = 1; + index->len = 1; + break; + case NEXT_ENTRY: + /* + * Increment the index value. + */ + index->value[0]++; + break; + case EXACT_ENTRY: + /* + * We don't need to play around with the + * index for this search type. + */ + break; + default: + return_code = SNMP_ERR_GENERR; + goto the_end; + } + + /* + * Now search for the entry... + */ + for (i = 0, j = 1; i < HASH_TBL_SIZE && found == _B_FALSE; i++) { + if (haMobileNodeHash.buckets[i]) { + /* + * Lock the bucket + */ + (void) rw_rdlock(&haMobileNodeHash.bucketLock[i]); + + hashEntry = haMobileNodeHash.buckets[i]; + while (hashEntry != NULL) { + if (j == index->value[0]) { + haMobileNodeEntry = hashEntry->data; + found = _B_TRUE; + + /* + * Lock the node + */ + (void) rw_rdlock(&haMobileNodeEntry-> + haMnNodeLock); + + break; + } + hashEntry = hashEntry->next; + j++; + } + + /* + * Unlock the bucket + */ + (void) rw_unlock(&haMobileNodeHash.bucketLock[i]); + } + } + + if (haMobileNodeEntry == NULL) { + return_code = END_OF_TABLE; + goto the_end; + } + + /* + * And now we return the number of times service was accepted for the + * Mobile Node. + */ + integer = &((*haCounterEntry_data)->haServiceRequestsAccepted); + *integer = (int)haMobileNodeEntry->haServiceRequestsAcceptedCnt; + + /* + * And now we return the number of times service was denied for the + * Mobile Node. + */ + integer = &((*haCounterEntry_data)->haServiceRequestsDenied); + *integer = (int)haMobileNodeEntry->haServiceRequestsDeniedCnt; + + /* + * And now we return the total amount of time (in seconds) that + * service was provided to the Mobile Node. + */ + integer = &((*haCounterEntry_data)->haOverallServiceTime); + *integer = (int)haMobileNodeEntry->haOverallServiceTime; + + /* + * And now we return the last time service was accepted. + */ + integer = &((*haCounterEntry_data)->haRecentServiceAcceptedTime); + *integer = (int)haMobileNodeEntry->haRecentServiceAcceptedTime; + + /* + * And now we return the last time service was denied. + */ + integer = &((*haCounterEntry_data)->haRecentServiceDeniedTime); + *integer = (int)haMobileNodeEntry->haRecentServiceDeniedTime; + + /* + * And now we return the reason for the last denial of service. + */ + integer = &((*haCounterEntry_data)->haRecentServiceDeniedCode); + *integer = (int)haMobileNodeEntry->haRecentServiceDeniedCode; + +the_end: + if (haMobileNodeEntry != NULL) { + /* + * Unlock the node + */ + (void) rw_unlock(&haMobileNodeEntry->haMnNodeLock); + } + + if (return_code != SNMP_ERR_NOERROR) { + free_haCounterEntry(*haCounterEntry_data); + *haCounterEntry_data = NULL; + } + + return (return_code); +} + + +/* + * Function: free_haCounterEntry + * + * Arguments: haCounterEntry - Pointer to a previously + * allocated SNMP Mobile Node counter + * entry + * + * Description: This function is called to free a previously + * allocated SNMP Mobile Node counter entry. + * + * Returns: + */ +void +free_haCounterEntry(HaCounterEntry_t *haCounterEntry) +{ + if (haCounterEntry) { + free(haCounterEntry); + haCounterEntry = NULL; + } +} diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_haMobilityBindingEntry.c b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_haMobilityBindingEntry.c new file mode 100644 index 0000000000..8d1e7fbcab --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_haMobilityBindingEntry.c @@ -0,0 +1,322 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 1999-2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * file: mipagentsnmp_haMobilityBindingEntry.c + * + * This file contains the SNMP routines used to retrieve + * the Home Agent's Mobile Node Binding Information. + */ + +#include <sys/types.h> +#include <netinet/in.h> +#include <string.h> +#include <stdlib.h> + +#include <impl.h> +#include <snmp.h> + +#include "snmp_stub.h" +#include "agent.h" + +extern HashTable haMobileNodeHash; +extern char *ntoa(uint32_t, char *); + +/* + * Function: get_haMobilityBindingEntry + * + * Arguments: search_type - The type of search (first, next, exact) + * haMobilityBindingEntry_data - Pointer to a pointer + * which will contain the binding entry upon + * successful completion. + * index - Pointer to the current index + * + * Description: This function will allocate the memory required for + * the binding entry, and will find the appropriate + * binding entry based on the index provided. If the + * search type is set to FIRST_ENTRY, we will return + * the first binding entry in the Hash Table, otherwise + * the index is used. + * + * The binding entry is then setup with the values found + * in the entry from the hash table and returned to the + * caller. + * + * Note, the caller is responsible for either freeing the + * memory, or calling free_haMobilityBindingEntry() + * + * Returns: int, 0 if successful + */ +extern int +get_haMobilityBindingEntry(int search_type, + HaMobilityBindingEntry_t **haMobilityBindingEntry_data, + IndexType *index) +{ + Integer *integer; + String *string; + HaMobileNodeEntry *haMobileNodeEntry = NULL; + HaBindingEntry *haBindingEntry = NULL; + HashEntry *hashEntry; + int i; + int j; + int return_code = SNMP_ERR_NOERROR; + time_t currentTime; + char buffer[258]; + boolean_t found = _B_FALSE; + + *haMobilityBindingEntry_data = + (HaMobilityBindingEntry_t *)calloc(1, + sizeof (HaMobilityBindingEntry_t)); + + if (haMobilityBindingEntry_data == NULL) { + return (SNMP_ERR_GENERR); + } + + /* + * In the case, the search_type is FIRST_ENTRY or NEXT_ENTRY + * this function should modify the index argument to the + * appropriate value + */ + switch (search_type) { + case FIRST_ENTRY: + /* + * We are looking for the first entry in the list. + */ + index->value[0] = 1; + index->len = 1; + break; + case NEXT_ENTRY: + /* + * Increment the index value. + */ + index->value[0]++; + break; + case EXACT_ENTRY: + /* + * We don't need to play around with the + * index for this search type. + */ + break; + default: + return_code = SNMP_ERR_GENERR; + goto the_end; + } + + /* + * Now search for the entry... + */ + for (i = 0, j = 1; i < HASH_TBL_SIZE && found == _B_FALSE; i++) { + if (haMobileNodeHash.buckets[i]) { + /* + * Lock the bucket + */ + (void) rw_rdlock(&haMobileNodeHash.bucketLock[i]); + + hashEntry = haMobileNodeHash.buckets[i]; + while (hashEntry != NULL) { + if (j == index->value[0]) { + haMobileNodeEntry = hashEntry->data; + found = _B_TRUE; + + /* + * Lock the node + */ + (void) rw_rdlock(&haMobileNodeEntry-> + haMnNodeLock); + + break; + } + hashEntry = hashEntry->next; + j++; + } + + /* + * Unlock the bucket + */ + (void) rw_unlock(&haMobileNodeHash.bucketLock[i]); + } + } + + if (haMobileNodeEntry == NULL) { + return_code = END_OF_TABLE; + goto the_end; + } + + haBindingEntry = haMobileNodeEntry->bindingEntries; + + if (haBindingEntry != NULL) { + /* + * Get the Mobile Node's IP Address. + */ + (void) ntoa(haBindingEntry->haBindingMN, buffer); + + string = + &((*haMobilityBindingEntry_data)->haMobilityBindingMN); + string->chars = (unsigned char *)malloc(strlen(buffer) + 1); + if (string->chars == NULL) { + return_code = SNMP_ERR_GENERR; + goto the_end; + } + (void) strcpy((char *)string->chars, buffer); + string->len = strlen(buffer); + + /* + * Get the Care of Address. + */ + (void) ntoa(haBindingEntry->haBindingCOA, buffer); + string = + &((*haMobilityBindingEntry_data)->haMobilityBindingCOA); + + string->chars = (unsigned char *)malloc(strlen(buffer) + 1); + if (string->chars == NULL) { + return_code = SNMP_ERR_GENERR; + goto the_end; + } + (void) strcpy((char *)string->chars, buffer); + string->len = strlen(buffer); + + /* + * Get the Binding Source Address. + */ + (void) ntoa(haBindingEntry->haBindingSrcAddr, buffer); + + string = + &((*haMobilityBindingEntry_data)-> + haMobilityBindingSourceAddress); + + string->chars = (unsigned char *)malloc(strlen(buffer) + 1); + if (string->chars == NULL) { + return_code = SNMP_ERR_GENERR; + goto the_end; + } + (void) strcpy((char *)string->chars, buffer); + string->len = strlen(buffer); + + /* + * And now we return the Registration Flags. + */ + integer = + &((*haMobilityBindingEntry_data)-> + haMobilityBindingRegFlags); + *integer = (int)haBindingEntry->haBindingRegFlags; + + /* + * And now we return the Low order Registration ID. + */ + integer = &((*haMobilityBindingEntry_data)-> + haMobilityBindingRegIDLow); + *integer = (int)haMobileNodeEntry->haMnRegIDLow; + + /* + * And now we return the High order Registration ID. + */ + integer = + &((*haMobilityBindingEntry_data)-> + haMobilityBindingRegIDHigh); + *integer = (int)haMobileNodeEntry->haMnRegIDHigh; + + /* + * And now we return the Registration Time Granted. + */ + integer = + &((*haMobilityBindingEntry_data)-> + haMobilityBindingTimeGranted); + *integer = (int)haBindingEntry->haBindingTimeGranted; + + /* + * And now we return the Registration Time Remaining. + */ + integer = + &((*haMobilityBindingEntry_data)-> + haMobilityBindingTimeRemaining); + GET_TIME(currentTime); + *integer = currentTime - + (int)haBindingEntry->haBindingTimeExpires; + } + +the_end: + if (haMobileNodeEntry != NULL) { + /* + * Unlock the node + */ + (void) rw_unlock(&haMobileNodeEntry->haMnNodeLock); + } + + if (return_code != SNMP_ERR_NOERROR) { + free_haMobilityBindingEntry(*haMobilityBindingEntry_data); + *haMobilityBindingEntry_data = NULL; + } + + return (return_code); +} + + +/* + * Function: free_haMobilityBindingEntry + * + * Arguments: haMobilityBindingEntry - Pointer to a previously + * allocated SNMP binding entry + * + * Description: This function is called to free a previously + * allocated SNMP binding entry. + * + * Returns: + */ +void +free_haMobilityBindingEntry(HaMobilityBindingEntry_t *haMobilityBindingEntry) +{ + String *string; + + if (haMobilityBindingEntry) { + /* + * The template generates code that checks both + * the pointer, and the length. I am not sure + * if this is excessive, so I will leave it as is. + */ + string = &(haMobilityBindingEntry->haMobilityBindingMN); + if (string->chars != NULL && string->len != 0) { + free(string->chars); + string->len = 0; + } + + string = &(haMobilityBindingEntry->haMobilityBindingCOA); + if (string->chars != NULL && string->len != 0) { + free(string->chars); + string->len = 0; + } + + string = + &(haMobilityBindingEntry->haMobilityBindingSourceAddress); + if (string->chars != NULL && string->len != 0) { + free(string->chars); + string->len = 0; + } + free(haMobilityBindingEntry); + haMobilityBindingEntry = NULL; + } +} diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_maAdvConfigEntry.c b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_maAdvConfigEntry.c new file mode 100644 index 0000000000..8952083e18 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_maAdvConfigEntry.c @@ -0,0 +1,285 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999-2001 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * file: mipagentsnmp_maAdvConfigEntry.c + * + * This file contains the SNMP routines used to retrieve + * the Mobility Agent's Interface Information. + */ + +#include <sys/types.h> +#include <netinet/in.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include <impl.h> +#include <snmp.h> + +#include "snmp_stub.h" +#include "agent.h" + +extern HashTable maAdvConfigHash; +extern char *ntoa(uint32_t, char *); + +/* + * Function: get_maAdvConfigEntry + * + * Arguments: search_type - The type of search (first, next, exact) + * maAdvConfigEntry_data - Pointer to a pointer which + * will contain the interface entry upon + * successful completion. + * index - Pointer to the current index + * + * Description: This function will allocate the memory required for + * the interface entry, and will find the appropriate + * interface entry based on the index provided. If the + * search type is set to FIRST_ENTRY, we will return + * the first interface entry in the Hash Table, otherwise + * the index is used. + * + * The interface entry is then setup with the values found + * in the entry from the hash table and returned to the + * caller. + * + * Note, the caller is responsible for either freeing the + * memory, or calling free_maAdvConfigEntry() + * + * Returns: int, 0 if successful + */ +extern int +get_maAdvConfigEntry(int search_type, + MaAdvConfigEntry_t **maAdvConfigEntry_data, + IndexType *index) +{ + Integer *integer; + String *string; + MaAdvConfigEntry *maAdvConfigEntry = NULL; + HashEntry *hashEntry; + int i; + int j; + int len; + int return_code = SNMP_ERR_NOERROR; + char buffer[258]; + boolean_t found = _B_FALSE; + + *maAdvConfigEntry_data = + (MaAdvConfigEntry_t *)calloc(1, sizeof (MaAdvConfigEntry_t)); + + if (maAdvConfigEntry_data == NULL) { + return (SNMP_ERR_GENERR); + } + + /* + * In the case, the search_type is FIRST_ENTRY or NEXT_ENTRY + * this function should modify the index argument to the + * appropriate value + */ + switch (search_type) { + case FIRST_ENTRY: + /* + * We are looking for the first entry in the list. + */ + index->value[0] = 1; + index->len = 1; + break; + case NEXT_ENTRY: + /* + * Increment the index value. + */ + index->value[0]++; + break; + case EXACT_ENTRY: + /* + * We don't need to play around with the + * index for this search type. + */ + break; + default: + return_code = SNMP_ERR_GENERR; + goto the_end; + } + + /* + * Now search for the entry... + */ + for (i = 0, j = 1; i < HASH_TBL_SIZE && found == _B_FALSE; i++) { + if (maAdvConfigHash.buckets[i]) { + /* + * Lock the bucket + */ + (void) rw_rdlock(&maAdvConfigHash.bucketLock[i]); + + hashEntry = maAdvConfigHash.buckets[i]; + while (hashEntry != NULL) { + if (j == index->value[0]) { + maAdvConfigEntry = hashEntry->data; + found = _B_TRUE; + + /* + * Lock the node + */ + (void) rw_rdlock(&maAdvConfigEntry-> + maIfaceNodeLock); + + break; + } + hashEntry = hashEntry->next; + j++; + } + + /* + * Unlock the bucket + */ + (void) rw_unlock(&maAdvConfigHash.bucketLock[i]); + } + } + + if (maAdvConfigEntry == NULL) { + return_code = END_OF_TABLE; + goto the_end; + } + + /* + * And now we return the Maximum Registration Lifetime. + */ + integer = &((*maAdvConfigEntry_data)->maAdvMaxRegLifetime); + *integer = (int)maAdvConfigEntry->maAdvMaxRegLifetime; + + /* + * And now we return the Prefix Length Inclusion. + */ + integer = &((*maAdvConfigEntry_data)->maAdvPrefixLengthInclusion); + if (maAdvConfigEntry->maAdvPrefixLenInclusion) { + *integer = 1; + } else { + /* I need to validate this one. Should this be 2 or 0 ? */ + *integer = 2; + } + + /* + * Get the Advertised Address. + */ + (void) ntoa(maAdvConfigEntry->maAdvAddr, buffer); + len = strlen(buffer); + string = &((*maAdvConfigEntry_data)->maAdvAddress); + string->chars = (unsigned char *)calloc(1, len); + if (string == NULL) { + return_code = SNMP_ERR_GENERR; + goto the_end; + } + (void) memcpy(string->chars, buffer, len); + string->len = len; + + /* + * And now we return the Maximum Advertisement Interval. + */ + integer = &((*maAdvConfigEntry_data)->maAdvMaxInterval); + *integer = (int)maAdvConfigEntry->maAdvMaxInterval; + + /* + * And now we return the Minimum Advertisement Interval. + */ + integer = &((*maAdvConfigEntry_data)->maAdvMinInterval); + *integer = (int)maAdvConfigEntry->maAdvMinInterval; + +#if 0 + /* + * And now we return whether we only advertise if we receive + * a soliciation. + */ + integer = &((*maAdvConfigEntry_data)->maAdvResponseSolicitationOnly); + + if (maAdvConfigEntry->maAdvResponseSolicitationOnly) { + *integer = 1; + } else { + /* I need to validate this one. Should this be 2 or 0 ? */ + *integer = 2; + } +#endif + + /* + * And now we return whether the entry is active. In our case, + * all entries are active, so we can hardcode the value. + */ + integer = &((*maAdvConfigEntry_data)->maAdvStatus); + *integer = 1; + +the_end: + if (maAdvConfigEntry != NULL) { + /* + * Unlock the node + */ + (void) rw_unlock(&maAdvConfigEntry->maIfaceNodeLock); + } + + if (return_code != SNMP_ERR_NOERROR) { + free_maAdvConfigEntry(*maAdvConfigEntry_data); + *maAdvConfigEntry_data = NULL; + } + + (void) fprintf(stderr, "get_maAdvConfigEntry: returning %d (%p)\n", + return_code, (void *)*maAdvConfigEntry_data); + + return (return_code); +} + + +/* + * Function: free_maAdvConfigEntry + * + * Arguments: maAdvConfigEntry - Pointer to a previously + * allocated SNMP interface entry + * + * Description: This function is called to free a previously + * allocated SNMP interface entry. + * + * Returns: + */ +void +free_maAdvConfigEntry(MaAdvConfigEntry_t *maAdvConfigEntry) +{ + String *string; + + if (maAdvConfigEntry) { + /* + * The template generates code that checks both + * the pointer, and the length. I am not sure + * if this is excessive, so I will leave it as is. + */ + string = &(maAdvConfigEntry->maAdvAddress); + if (string->chars != NULL && string->len != 0) { + free(string->chars); + string->len = 0; + } + + free(maAdvConfigEntry); + maAdvConfigEntry = NULL; + } +} diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_mipSecAssocEntry.c b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_mipSecAssocEntry.c new file mode 100644 index 0000000000..47419f18bd --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_mipSecAssocEntry.c @@ -0,0 +1,226 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999-2001 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * file: mipagentsnmp_mipSecAssocEntry.c + * + * This file contains the SNMP routines used to retrieve + * the Mobility Agent's Security Association Information. + */ + +#include <sys/types.h> +#include <netinet/in.h> +#include <stdlib.h> + +#include <impl.h> +#include <snmp.h> + +#include "snmp_stub.h" +#include "agent.h" + +/* + * This table has one entry for each mobile node for which a mobility + * agent offers Home Agent services. + */ +extern HashTable mipSecAssocHash; + +/* + * Function: get_mipSecAssocEntry + * + * Arguments: search_type - The type of search (first, next, exact) + * mipSecAssocEntry_data - Pointer to a pointer which + * will contain the Security Association entry + * upon successful completion. + * index - Pointer to the current index + * + * Description: This function will allocate the memory required for + * the Security Association entry, and will find the + * appropriate Security Association based on the index + * provided. If the search type is set to FIRST_ENTRY, + * we will return the first Security Association in the + * Hash Table, otherwise the index is used. + * + * The Security Association entry is then setup with the + * values found in the entry from the hash table and + * returned to the caller. + * + * Note, the caller is responsible for either freeing the + * memory, or calling free_mipSecAssocEntry() + * + * Returns: int, 0 if successful + */ +extern int +get_mipSecAssocEntry(int search_type, + MipSecAssocEntry_t **mipSecAssocEntry_data, IndexType *index) +{ + Integer *integer; + String *string; + MipSecAssocEntry *mipSecAssocEntry = NULL; + HashEntry *hashEntry; + int i; + int j; + boolean_t found = _B_FALSE; + + /* + * Allocate some memory to handle the request. + */ + *mipSecAssocEntry_data = + (MipSecAssocEntry_t *)calloc(1, sizeof (MipSecAssocEntry_t)); + + if (mipSecAssocEntry_data == NULL) { + return (SNMP_ERR_GENERR); + } + + /* + * In the case, the search_type is FIRST_ENTRY or NEXT_ENTRY + * this function should modify the index argument to the + * appropriate value + */ + switch (search_type) { + case FIRST_ENTRY: + /* + * We are looking for the first entry in the list. + */ + index->value[0] = 1; + index->len = 1; + break; + case NEXT_ENTRY: + /* + * Increment the index value. + */ + index->value[0]++; + break; + case EXACT_ENTRY: + /* + * We don't need to play around with the + * index for this search type. + */ + break; + default: + free_mipSecAssocEntry(*mipSecAssocEntry_data); + return (SNMP_ERR_GENERR); + } + + /* + * Now search for the entry... the problem here is that + * the Security Association Information spans three different + * tables, so we need to look through each one. + */ + for (i = 0, j = 1; i < HASH_TBL_SIZE && found == _B_FALSE; i++) { + if (mipSecAssocHash.buckets[i]) { + /* + * Lock the bucket + */ + (void) rw_rdlock(&mipSecAssocHash.bucketLock[i]); + + hashEntry = mipSecAssocHash.buckets[i]; + while (hashEntry != NULL) { + if (j == index->value[0]) { + mipSecAssocEntry = hashEntry->data; + found = _B_TRUE; + + /* + * Lock the node + */ + (void) rw_rdlock(&mipSecAssocEntry-> + mipSecNodeLock); + + break; + } + hashEntry = hashEntry->next; + j++; + } + + /* + * Unlock the bucket + */ + (void) rw_unlock(&mipSecAssocHash.bucketLock[i]); + } + } + + if (mipSecAssocEntry == NULL) { + free_mipSecAssocEntry(*mipSecAssocEntry_data); + *mipSecAssocEntry_data = NULL; + return (END_OF_TABLE); + } + + /* + * And now we return the Algorithm type. + */ + integer = &((*mipSecAssocEntry_data)->mipSecAlgorithmType); + *integer = (int)mipSecAssocEntry->mipSecAlgorithmType; + + /* + * And now we return the Algorithm mode. + */ + integer = &((*mipSecAssocEntry_data)->mipSecAlgorithmMode); + *integer = (int)mipSecAssocEntry->mipSecAlgorithmMode; + + /* + * And now we return the Key. Note that RFC2006 clearly states + * that this will always return 0 (then why does it exist in + * the MIB?!?). + */ + string = &((*mipSecAssocEntry_data)->mipSecKey); + string->len = 0; + + /* + * And now we return the Replay Method. + */ + integer = &((*mipSecAssocEntry_data)->mipSecReplayMethod); + *integer = (int)mipSecAssocEntry->mipSecReplayMethod; + + /* + * Unlock the node + */ + (void) rw_unlock(&mipSecAssocEntry->mipSecNodeLock); + + return (SNMP_ERR_NOERROR); +} + + +/* + * Function: free_mipSecAssocEntry + * + * Arguments: mipSecAssocEntry - Pointer to a previously + * allocated SNMP Security Association + * entry + * + * Description: This function is called to free a previously + * allocated SNMP Security Association entry. + * + * Returns: + */ +void +free_mipSecAssocEntry(MipSecAssocEntry_t *mipSecAssocEntry) +{ + if (mipSecAssocEntry) { + free(mipSecAssocEntry); + mipSecAssocEntry = NULL; + } +} diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_mipSecViolationEntry.c b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_mipSecViolationEntry.c new file mode 100644 index 0000000000..939ef97610 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_mipSecViolationEntry.c @@ -0,0 +1,277 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 1999-2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * file: mipagentsnmp_mipSecViolationEntry.c + * + * This file contains the SNMP routines used to retrieve + * the Mobility Agent's Security Violation Information. + */ + +#include <sys/types.h> +#include <netinet/in.h> +#include <string.h> +#include <stdlib.h> + +#include <impl.h> +#include <snmp.h> + +#include "snmp_stub.h" +#include "agent.h" + +extern char *ntoa(uint32_t, char *); + +/* + * This table stores all of the Security Violations + */ +HashTable mipSecViolationHash; + +/* + * Function: get_mipSecViolationEntry + * + * Arguments: search_type - The type of search (first, next, exact) + * mipSecViolationEntry_data - Pointer to a pointer which + * will contain the Security Violation entry + * upon successful completion. + * index - Pointer to the current index + * + * Description: This function will allocate the memory required for + * the Security Violation entry, and will find the + * appropriate Security Violation based on the index + * provided. If the search type is set to FIRST_ENTRY, + * we will return the first Security Assocication in the + * Hash Table, otherwise the index is used. + * + * The Security Violation entry is then setup with the + * values found in the entry from the hash table and + * returned to the caller. + * + * Note, the caller is responsible for either freeing the + * memory, or calling free_mipSecViolationEntry() + * + * Returns: int, 0 if successful + */ +extern int +get_mipSecViolationEntry(int search_type, + MipSecViolationEntry_t **mipSecViolationEntry_data, IndexType *index) +{ + Integer *integer; + String *string; + MipSecViolationEntry *mipSecViolationEntry = NULL; + HashEntry *hashEntry; + int i; + int j; + int return_code = SNMP_ERR_NOERROR; + char buffer[258]; + boolean_t found = _B_FALSE; + + /* + * Allocate some memory to handle the request. + */ + *mipSecViolationEntry_data = (MipSecViolationEntry_t *)calloc(1, + sizeof (MipSecViolationEntry_t)); + + if (mipSecViolationEntry_data == NULL) { + return (SNMP_ERR_GENERR); + } + + /* + * In the case, the search_type is FIRST_ENTRY or NEXT_ENTRY + * this function should modify the index argument to the + * appropriate value + */ + switch (search_type) { + case FIRST_ENTRY: + /* + * We are looking for the first entry in the list. + */ + index->value[0] = 1; + index->len = 1; + break; + case NEXT_ENTRY: + /* + * Increment the index value. + */ + index->value[0]++; + break; + case EXACT_ENTRY: + /* + * We don't need to play around with the + * index for this search type. + */ + break; + default: + return_code = SNMP_ERR_GENERR; + goto the_end; + } + + /* + * Now search for the entry... the problem here is that + * the Security Association Information spans three different + * tables, so we need to look through each one. + */ + for (i = 0, j = 1; i < HASH_TBL_SIZE && found == _B_FALSE; i++) { + if (mipSecViolationHash.buckets[i]) { + /* + * Lock the bucket + */ + (void) rw_rdlock(&mipSecViolationHash.bucketLock[i]); + + hashEntry = mipSecViolationHash.buckets[i]; + while (hashEntry != NULL) { + if (j == index->value[0]) { + mipSecViolationEntry = hashEntry->data; + found = _B_TRUE; + + /* + * Lock the node + */ + (void) rw_rdlock( + &mipSecViolationEntry-> + mipSecNodeLock); + + break; + } + hashEntry = hashEntry->next; + j++; + } + + /* + * Unlock the bucket + */ + (void) rw_unlock(&mipSecViolationHash.bucketLock[i]); + } + } + + if (mipSecViolationEntry == NULL) { + return_code = END_OF_TABLE; + goto the_end; + } + + /* + * Return the address of the offender. + */ + (void) ntoa(mipSecViolationEntry->mipSecViolatorAddr, buffer); + + string = &((*mipSecViolationEntry_data)->mipSecViolatorAddress); + + string->chars = (unsigned char *)malloc(strlen(buffer) + 1); + if (string->chars == NULL) { + return_code = SNMP_ERR_GENERR; + goto the_end; + } + (void) strcpy((char *)string->chars, buffer); + string->len = strlen(buffer); + + /* + * And now we return the number of security violations + * for this entry. + */ + integer = &((*mipSecViolationEntry_data)->mipSecViolationCounter); + *integer = (int)mipSecViolationEntry->mipSecViolationCounter; + + /* + * And now we return the SPI used. + */ + integer = &((*mipSecViolationEntry_data)->mipSecRecentViolationSPI); + *integer = (int)mipSecViolationEntry->mipSecRecentViolationSPI; + + /* + * And now we return time of the last violation. + */ + integer = + &((*mipSecViolationEntry_data)->mipSecRecentViolationTime); + *integer = (int)mipSecViolationEntry->mipSecRecentViolationTime; + + /* + * And now we return the low order bits of the Identifier used. + */ + integer = + &((*mipSecViolationEntry_data)->mipSecRecentViolationIDLow); + *integer = (int)mipSecViolationEntry->mipSecRecentViolationIDLow; + + /* + * And now we return the high order bits of the Identifier used. + */ + integer = + &((*mipSecViolationEntry_data)->mipSecRecentViolationIDHigh); + *integer = (int)mipSecViolationEntry->mipSecRecentViolationIDHigh; + + /* + * And finally, the reason for the violation. + */ + integer = + &((*mipSecViolationEntry_data)->mipSecRecentViolationReason); + *integer = (int)mipSecViolationEntry->mipSecRecentViolationReason; + +the_end: + if (mipSecViolationEntry != NULL) { + /* + * Unlock the node + */ + (void) rw_unlock(&mipSecViolationEntry->mipSecNodeLock); + } + + if (return_code != SNMP_ERR_NOERROR) { + free_mipSecViolationEntry(*mipSecViolationEntry_data); + *mipSecViolationEntry_data = NULL; + } + + return (return_code); +} + + +/* + * Function: free_mipSecViolationEntry + * + * Arguments: mipSecViolationEntry - Pointer to a previously + * allocated SNMP Security Violation + * entry + * + * Description: This function is called to free a previously + * allocated SNMP Security Violation entry. + * + * Returns: + */ +void +free_mipSecViolationEntry(MipSecViolationEntry_t *mipSecViolationEntry) +{ + String *string; + + if (mipSecViolationEntry) { + string = + &(mipSecViolationEntry->mipSecViolatorAddress); + if (string->chars != NULL && string->len != 0) { + free(string->chars); + string->len = 0; + } + + free(mipSecViolationEntry); + mipSecViolationEntry = NULL; + } +} diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_stub.c b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_stub.c new file mode 100644 index 0000000000..14fef4d2e2 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_stub.c @@ -0,0 +1,1083 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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: snmp_stub.c + * + * This file contains the SNMP routines used to retrieve + * the Mobility Agent's various counter and configurable + * information. + */ + +#include <sys/types.h> +#include <netinet/in.h> + +#include <impl.h> +#include <snmp.h> + +#include "agent.h" + +/* Counters common to all Mobility Agents */ +extern CommonCounters commonCounters; + +/* Counters maintained by Foreign Agents */ +extern ForeignAgentCounters faCounters; + +/* Counters maintained by Home Agents */ +extern HomeAgentCounters haCounters; + + +#define MIP_MOBILE_NODE 0x1 +#define MIP_FOREIGN_AGENT 0x2 +#define MIP_HOME_AGENT 0x4 + +#define MIP_ENABLE 1 +#define MIP_DISABLE 2 + +#define MIP_ENCAP_IP_IN_IP 0x1 +#define MIP_ENCAP_GRE 0x2 +#define MIP_ENCAP_MIN_ENCAP 0x4 +#define MIP_OTHER 0x8 + +/* + * Function: get_mipEntities + * + * Arguments: mipEntities - Pointer to Integer + * + * Description: Returns whether the agent is running + * as a Foreign and/or Home agent. + * + * Returns: int, 0 if successful + */ +int +get_mipEntities(Integer *mipEntities) +{ + /* + * We can only be both Mobility Agents + */ + *mipEntities = (MIP_FOREIGN_AGENT | MIP_HOME_AGENT); + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_mipEnable + * + * Arguments: mipEnable - Pointer to Integer + * + * Description: This function is called to determine if + * if the Mobile-IP Agent is in the + * active mode. + * + * Returns: int, 0 if successful + */ +int +get_mipEnable(Integer *mipEnable) +{ + /* + * If we get this far, then we are enabled :) + */ + *mipEnable = MIP_ENABLE; + return (SNMP_ERR_NOERROR); +} + +/* + * Function: set_mipEnable + * + * Arguments: pass - The SNMP Pass + * mipEnable - Pointer to an Integer + * + * Description: This function is called to start the + * SNMP Mobile-IP Agent. We do not currently + * support this option. + * + * Returns: int, 0 if successful + */ +int +set_mipEnable(int pass, Integer *mipEnable) +{ + switch (pass) { + case FIRST_PASS: + /* + * Check whether the argument provided was valid to begin with + */ + if (*mipEnable != MIP_ENABLE && *mipEnable != MIP_DISABLE) { + return (SNMP_ERR_GENERR); + } + return (SNMP_ERR_NOERROR); + + case SECOND_PASS: + /* + * Here is where we allow the value to be changed. We do + * not allow this at this time. + */ + return (SNMP_ERR_READONLY); + } + + return (SNMP_ERR_GENERR); +} + +/* + * Function: get_mipEncapsulationSupported + * + * Arguments: mipEncapsulationSupported - Pointer to Integer + * + * Description: This function is called to retrieve the + * encapsulation types supported by the + * agent. + * + * Returns: int, 0 if successful + */ +int +get_mipEncapsulationSupported(Integer *mipEncapsulationSupported) +{ + /* + * We currently only support IP in IP + */ + *mipEncapsulationSupported = MIP_ENCAP_IP_IN_IP; + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_mipSecTotalViolations + * + * Arguments: mipSecTotalViolations - Pointer to Integer + * + * Description: This function is called to retrieve the + * number of security violations since start-up. + * + * Returns: int, 0 if successful + */ +int +get_mipSecTotalViolations(Integer *mipSecTotalViolations) +{ + /* + * TODO: Return the total number of un-authenticated requests + */ + *mipSecTotalViolations = haCounters.haMNAuthFailureCnt + + haCounters.haFAAuthFailureCnt + faCounters.faMNAuthFailureCnt + + faCounters.faHAAuthFailureCnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_maAdvertisementsSent + * + * Arguments: maAdvertisementsSent - Pointer to Integer + * + * Description: This function is called to retrieve the + * number of advertisements transmitted. + * + * Returns: int, 0 if successful + */ +int +get_maAdvertisementsSent(Integer *maAdvertisementsSent) +{ + /* + * Return the total number of advertisements sent + */ + *maAdvertisementsSent = commonCounters.maAdvSentCnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_maAdvsSentForSolicitation + * + * Arguments: maAdvsSentForSolicitation - Pointer to Integer + * + * Description: This function is called to retrieve the + * number of advertisements transmitted as a + * result of a solicitation received. + * + * Returns: int, 0 if successful + */ +int +get_maAdvsSentForSolicitation(Integer *maAdvsSentForSolicitation) +{ + /* + * Return the total number of advertisements we've sent + * due to a solicitation. + */ + *maAdvsSentForSolicitation = + commonCounters.maAdvSentForSolicitationsCnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_maSolicitationsReceived + * + * Arguments: maSolicitationsReceived - Pointer to Integer + * + * Description: This function is called to retrieve the + * number of solicitations received. + * + * Returns: int, 0 if successful + */ +int +get_maSolicitationsReceived(Integer *maSolicitationsReceived) +{ + /* + * Return the total number of solicitations received. + */ + *maSolicitationsReceived = commonCounters.maSolicitationsRecvdCnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_faIsBusy + * + * Arguments: faIsBusy - Pointer to Integer + * + * Description: This function is called to retrieve the + * number of times we've advertised the fact + * that we were busy. + * + * Returns: int, 0 if successful + */ +int +get_faIsBusy(Integer *faIsBusy) +{ + /* + * Return the number of times that the foreign agent has + * responded as being too busy. + */ + *faIsBusy = faCounters.faIsBusyCnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_faRegistrationRequired + * + * Arguments: faRegistrationRequired - Pointer to Integer + * + * Description: This function is called to determine whether + * we require registrations to provide service. + * + * Returns: int, 0 if successful + */ +int +get_faRegistrationRequired(Integer *faRegistrationRequired) +{ + /* + * States whether the Foreign Agent REQUIRES that + * all Mobile Nodes register with it. We currently + * have no way of enforcing this (short of setting + * up a filter on the Foreign Agent). + */ + *faRegistrationRequired = _B_FALSE; + return (SNMP_ERR_NOERROR); +} + +/* + * Function: set_faRegistrationRequired + * + * Arguments: pass - The SNMP Pass + * faRegistrationRequired - Pointer to an Integer + * + * Description: This function is called to require the agent + * to receive a registration in order to provide + * service. We do not currently allow this to + * be set via SNMP. + * + * Returns: int, 0 if successful + */ +int +set_faRegistrationRequired(int pass, Integer *faRegistrationRequired) +{ + switch (pass) { + case FIRST_PASS: + /* + * Check whether a valid argument was passed. + */ + if (*faRegistrationRequired == _B_TRUE || + *faRegistrationRequired == _B_FALSE) { + return (SNMP_ERR_NOERROR); + } + return (SNMP_ERR_GENERR); + + case SECOND_PASS: + /* + * Sorry, we do not allow this at this time. + */ + return (SNMP_ERR_READONLY); + } + + return (SNMP_ERR_GENERR); +} + +/* + * Function: get_faRegRequestsReceived + * + * Arguments: faRegRequestsReceived - Pointer to Integer + * + * Description: This function is called to return the + * number of Registration Requests we've received. + * + * Returns: int, 0 if successful + */ +int +get_faRegRequestsReceived(Integer *faRegRequestsReceived) +{ + /* + * Return the total number of Registration Requests we've + * received. + */ + *faRegRequestsReceived = faCounters.faRegReqRecvdCnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_faRegRequestsRelayed + * + * Arguments: faRegRequestsRelayed - Pointer to Integer + * + * Description: This function is called to return the + * number of Registration Requests we've + * relayed to a Home Agent. + * + * Returns: int, 0 if successful + */ +int +get_faRegRequestsRelayed(Integer *faRegRequestsRelayed) +{ + /* + * Return the total number of Registration Requests we've + * replayed. + */ + *faRegRequestsRelayed = faCounters.faRegReqRelayedCnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_faReasonUnspecified + * + * Arguments: faReasonUnspecified - Pointer to Integer + * + * Description: This function is called to return the + * number of Registration Requests we've + * failed with the error set to reason + * unspecified. + * + * Returns: int, 0 if successful + */ +int +get_faReasonUnspecified(Integer *faReasonUnspecified) +{ + /* + * Return the total number of Registration Requests we've + * rejected for unspecified reasons (error 64). + */ + *faReasonUnspecified = faCounters.faReasonUnspecifiedCnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_faAdmProhibited + * + * Arguments: faAdmProhibited - Pointer to Integer + * + * Description: This function is called to return the + * number of Registration Requests we've + * failed with the error set to administratively + * prohibited. + * + * Returns: int, 0 if successful + */ +int +get_faAdmProhibited(Integer *faAdmProhibited) +{ + /* + * Return the total number of Registration Requests we've + * rejected for administrative purposes (error 65). + */ + *faAdmProhibited = faCounters.faAdmProhibitedCnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_faInsufficientResource + * + * Arguments: faInsufficientResource - Pointer to Integer + * + * Description: This function is called to return the + * number of Registration Requests we've + * failed with the error set to insufficient + * resources. + * + * Returns: int, 0 if successful + */ +int +get_faInsufficientResource(Integer *faInsufficientResource) +{ + /* + * Return the total number of Registration Requests we've + * rejected due to insufficient resources (error 66). + */ + *faInsufficientResource = faCounters.faInsufficientResourceCnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_faMNAuthenticationFailure + * + * Arguments: faMNAuthenticationFailure - Pointer to Integer + * + * Description: This function is called to return the + * number of Registration Requests we've + * failed with the error set to MN-FA + * Authentication Failure. + * + * Returns: int, 0 if successful + */ +int +get_faMNAuthenticationFailure(Integer *faMNAuthenticationFailure) +{ + /* + * Return the number of Mobile Node authentication + * failures. + */ + *faMNAuthenticationFailure = faCounters.faMNAuthFailureCnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_faRegLifetimeTooLong + * + * Arguments: faRegLifetimeTooLong - Pointer to Integer + * + * Description: This function is called to return the + * number of Registration Requests we've + * failed with the error set to lifetime + * too long. + * + * Returns: int, 0 if successful + */ +int +get_faRegLifetimeTooLong(Integer *faRegLifetimeTooLong) +{ + /* + * Return the number of failed Registration Requests + * due to a lifetime too long. + */ + *faRegLifetimeTooLong = faCounters.faRegLifetimeTooLongCnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_faPoorlyFormedRequests + * + * Arguments: faPoorlyFormedRequests - Pointer to Integer + * + * Description: This function is called to return the + * number of Registration Requests we've + * failed with the error set to poorly + * formed request. + * + * Returns: int, 0 if successful + */ +int +get_faPoorlyFormedRequests(Integer *faPoorlyFormedRequests) +{ + /* + * Returns the number of poorly formed requests we've + * received. + */ + *faPoorlyFormedRequests = faCounters.faPoorlyFormedRequestsCnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_faEncapsulationUnavailable + * + * Arguments: faEncapsulationUnavailable - Pointer to Integer + * + * Description: This function is called to return the + * number of Registration Requests we've + * failed with the error set to encapsulation + * unavailable. + * + * Returns: int, 0 if successful + */ +int +get_faEncapsulationUnavailable(Integer *faEncapsulationUnavailable) +{ + /* + * Returns the number of times we've rejected a request + * due to an unsupported encapsulation. + */ + *faEncapsulationUnavailable = faCounters.faEncapUnavailableCnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_faVJCompressionUnavailable + * + * Arguments: faVJCompressionUnavailable - Pointer to Integer + * + * Description: This function is called to return the + * number of Registration Requests we've + * failed with the error set to VJ compression + * unavailable. + * + * Returns: int, 0 if successful + */ +int +get_faVJCompressionUnavailable(Integer *faVJCompressionUnavailable) +{ + /* + * Returns the number of times we've returned an error + * stating that compression was unavailable. + */ + *faVJCompressionUnavailable = faCounters.faVJCompUnavailableCnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_faHAUnreachable + * + * Arguments: faHAUnreachable - Pointer to Integer + * + * Description: This function is called to return the + * number of Registration Requests we've + * failed with the error set to HA + * unreachable. + * + * Returns: int, 0 if successful + */ +int +get_faHAUnreachable(Integer *faHAUnreachable) +{ + /* + * Returns the number of times that we've replied to a + * mobile node stating that the home agent was unreachable. + */ + *faHAUnreachable = faCounters.faHAUnreachableCnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_faRegRepliesRecieved + * + * Arguments: faRegRepliesRecieved - Pointer to Integer + * + * Description: This function is called to return the + * number of Registration Replies we've + * received. + * + * Returns: int, 0 if successful + */ +int +get_faRegRepliesRecieved(Integer *faRegRepliesRecieved) +{ + /* + * Returns the number of Registration Replies we've received. + */ + *faRegRepliesRecieved = faCounters.faRegRepliesRecvdCnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_faRegRepliesRelayed + * + * Arguments: faRegRepliesRelayed - Pointer to Integer + * + * Description: This function is called to return the + * number of Registration Replies we've + * relayed. + * + * Returns: int, 0 if successful + */ +int +get_faRegRepliesRelayed(Integer *faRegRepliesRelayed) +{ + + /* + * Returns the number of Registration Replies we've relayed. + */ + *faRegRepliesRelayed = faCounters.faRegRepliesRelayedCnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_faHAAuthenticationFailure + * + * Arguments: faHAAuthenticationFailure - Pointer to Integer + * + * Description: This function is called to return the + * number of Registration Replies we've + * relayed with the error FA-HA Auth Failure. + * + * Returns: int, 0 if successful + */ +int +get_faHAAuthenticationFailure(Integer *faHAAuthenticationFailure) +{ + /* + * Returns the number of times that we've encountered an + * FA-HA Authentication failure. + */ + *faHAAuthenticationFailure = faCounters.faHAAuthFailureCnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_faPoorlyFormedReplies + * + * Arguments: faPoorlyFormedReplies - Pointer to Integer + * + * Description: This function is called to return the + * number of Registration Replies we've + * relayed with the error poorly formed reply. + * + * Returns: int, 0 if successful + */ +int +get_faPoorlyFormedReplies(Integer *faPoorlyFormedReplies) +{ + /* + * Return the number of times that we've received a poorly + * formed reply. + */ + *faPoorlyFormedReplies = faCounters.faPoorlyFormedRepliesCnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_haRegistrationAccepted + * + * Arguments: haRegistrationAccepted - Pointer to Integer + * + * Description: This function is called to return the + * number of Registration Requests we've + * accepted. + * + * Returns: int, 0 if successful + */ +int +get_haRegistrationAccepted(Integer *haRegistrationAccepted) +{ + /* + * Return the number of Registrations that we've accepted. + */ + *haRegistrationAccepted = haCounters.haRegAccepted0Cnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_haMultiBindingUnsupported + * + * Arguments: haMultiBindingUnsupported - Pointer to Integer + * + * Description: This function is called to return the + * number of Registration Replies we've sent + * with the error set to multiple bindings + * unsupported. + * + * Returns: int, 0 if successful + */ +int +get_haMultiBindingUnsupported(Integer *haMultiBindingUnsupported) +{ + /* + * Ret urn the number of Registrations that we've denied with + * code 1. + */ + *haMultiBindingUnsupported = haCounters.haRegAccepted1Cnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_haReasonUnspecified + * + * Arguments: haReasonUnspecified - Pointer to Integer + * + * Description: This function is called to return the + * number of Registration Replies we've sent + * with the error set to reason unspecified. + * + * Returns: int, 0 if successful + */ +int +get_haReasonUnspecified(Integer *haReasonUnspecified) +{ + /* + * Return the number of Registrations that we've denied with + * code 128. + */ + *haReasonUnspecified = haCounters.haReasonUnspecifiedCnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_haAdmProhibited + * + * Arguments: haAdmProhibited - Pointer to Integer + * + * Description: This function is called to return the + * number of Registration Replies we've sent + * with the error set to administratively + * prohibited. + * + * Returns: int, 0 if successful + */ +int +get_haAdmProhibited(Integer *haAdmProhibited) +{ + /* + * Return the number of Registrations that we've denied with + * code 129. + */ + *haAdmProhibited = haCounters.haAdmProhibitedCnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_haInsufficientResource + * + * Arguments: haInsufficientResource - Pointer to Integer + * + * Description: This function is called to return the + * number of Registration Replies we've sent + * with the error set to insufficient + * resources. + * + * Returns: int, 0 if successful + */ +int +get_haInsufficientResource(Integer *haInsufficientResource) +{ + /* + * Return the number of Registrations that we've denied with + * code 130. + */ + *haInsufficientResource = haCounters.haInsufficientResourceCnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_haMNAuthenticationFailure + * + * Arguments: haMNAuthenticationFailure - Pointer to Integer + * + * Description: This function is called to return the + * number of Registration Replies we've sent + * with the error set to MN-HA Authentication + * failed. + * + * Returns: int, 0 if successful + */ +int +get_haMNAuthenticationFailure(Integer *haMNAuthenticationFailure) +{ + + /* + * Return the number of Registrations that we've denied with + * code 131. + */ + *haMNAuthenticationFailure = haCounters.haMNAuthFailureCnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_haFAAuthenticationFailure + * + * Arguments: haFAAuthenticationFailure - Pointer to Integer + * + * Description: This function is called to return the + * number of Registration Replies we've sent + * with the error set to FA-HA Authentication + * failed. + * + * Returns: int, 0 if successful + */ +int +get_haFAAuthenticationFailure(Integer *haFAAuthenticationFailure) +{ + /* + * Return the number of Registrations that we've denied with + * code 132. + */ + *haFAAuthenticationFailure = haCounters.haFAAuthFailureCnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_haIDMismatch + * + * Arguments: haIDMismatch - Pointer to Integer + * + * Description: This function is called to return the + * number of Registration Replies we've sent + * with the error set to ID Mismatch. + * + * Returns: int, 0 if successful + */ +int +get_haIDMismatch(Integer *haIDMismatch) +{ + /* + * Return the number of Registrations that we've denied with + * code 133. + */ + *haIDMismatch = haCounters.haIDMismatchCnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_haPoorlyFormedRequest + * + * Arguments: haPoorlyFormedRequest - Pointer to Integer + * + * Description: This function is called to return the + * number of Registration Replies we've sent + * with the error set to poorly formed + * request. + * + * Returns: int, 0 if successful + */ +int +get_haPoorlyFormedRequest(Integer *haPoorlyFormedRequest) +{ + /* + * Return the number of Registrations that we've denied with + * code 134. + */ + *haPoorlyFormedRequest = haCounters.haPoorlyFormedRequestsCnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_haTooManyBindings + * + * Arguments: haTooManyBindings - Pointer to Integer + * + * Description: This function is called to return the + * number of Registration Replies we've sent + * with the error set to too many bindings. + * + * Returns: int, 0 if successful + */ +int +get_haTooManyBindings(Integer *haTooManyBindings) +{ + /* + * Return the number of Registrations that we've denied with + * code 135. + */ + *haTooManyBindings = haCounters.haTooManyBindingsCnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_haUnknownHA + * + * Arguments: haUnknownHA - Pointer to Integer + * + * Description: This function is called to return the + * number of Registration Replies we've sent + * with the error set to unknown Home Agent. + * + * Returns: int, 0 if successful + */ +int +get_haUnknownHA(Integer *haUnknownHA) +{ + /* + * Return the number of Registrations that we've denied with + * code 136. + */ + *haUnknownHA = haCounters.haUnknownHACnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_haGratuitiousARPsSent + * + * Arguments: haGratuitiousARPsSent - Pointer to Integer + * + * Description: This function is called to return the + * number of gratuitious ARPs sent. + * + * Returns: int, 0 if successful + */ +int +get_haGratuitiousARPsSent(Integer *haGratuitiousARPsSent) +{ + /* + * Return the total number of gratuitious ARPs sent + */ + *haGratuitiousARPsSent = haCounters.haGratuitousARPsSentCnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_haProxyARPsSent + * + * Arguments: haProxyARPsSent - Pointer to Integer + * + * Description: This function is called to return the + * number of proxy ARPs sent. + * + * Returns: int, 0 if successful + */ +int +get_haProxyARPsSent(Integer *haProxyARPsSent) +{ + /* + * Return the total number of proxy ARPs sent + */ + *haProxyARPsSent = haCounters.haProxyARPsSentCnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_haRegRequestsReceived + * + * Arguments: haRegRequestsReceived - Pointer to Integer + * + * Description: This function is called to return the + * number of registration requests received. + * + * Returns: int, 0 if successful + */ +int +get_haRegRequestsReceived(Integer *haRegRequestsReceived) +{ + /* + * Return the total number of Registration Requests received + */ + *haRegRequestsReceived = haCounters.haRegReqRecvdCnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_haDeRegRequestsReceived + * + * Arguments: haDeRegRequestsReceived - Pointer to Integer + * + * Description: This function is called to return the + * number of deregistration requests received. + * + * Returns: int, 0 if successful + */ +int +get_haDeRegRequestsReceived(Integer *haDeRegRequestsReceived) +{ + /* + * Return the total number of Deregistration Requests received + */ + *haDeRegRequestsReceived = haCounters.haDeRegReqRecvdCnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_haRegRepliesSent + * + * Arguments: haRegRepliesSent - Pointer to Integer + * + * Description: This function is called to return the + * number of registration replies sent. + * + * Returns: int, 0 if successful + */ +int +get_haRegRepliesSent(Integer *haRegRepliesSent) +{ + /* + * Return the total number of Registration Replies we've + * sent + */ + *haRegRepliesSent = haCounters.haRegRepliesSentCnt; + + return (SNMP_ERR_NOERROR); +} + +/* + * Function: get_haDeRegRepliesSent + * + * Arguments: haDeRegRepliesSent - Pointer to Integer + * + * Description: This function is called to return the + * number of deregistration replies sent. + * + * Returns: int, 0 if successful + */ +int +get_haDeRegRepliesSent(Integer *haDeRegRepliesSent) +{ + /* + * Return the total number of Registration Replies we've + * received + */ + *haDeRegRepliesSent = haCounters.haDeRegRepliesSentCnt; + + return (SNMP_ERR_NOERROR); +} + +int +get_i_dont_think_so(Integer *bogus) +{ + *bogus = 1; + + return (SNMP_ERR_NOERROR); +} diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_stub.h b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_stub.h new file mode 100644 index 0000000000..211d5ec3e0 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_stub.h @@ -0,0 +1,211 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999-2001 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ifndef _MIPAGENTSNMP_STUB_H_ +#define _MIPAGENTSNMP_STUB_H_ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _MipSecAssocEntry_t { + Integer mipSecAlgorithmType; + Integer mipSecAlgorithmMode; + String mipSecKey; + Integer mipSecReplayMethod; +} MipSecAssocEntry_t; + +typedef struct _MipSecViolationEntry_t { + String mipSecViolatorAddress; + Integer mipSecViolationCounter; + Integer mipSecRecentViolationSPI; + Integer mipSecRecentViolationTime; + Integer mipSecRecentViolationIDLow; + Integer mipSecRecentViolationIDHigh; + Integer mipSecRecentViolationReason; +} MipSecViolationEntry_t; + +typedef struct _MaAdvConfigEntry_t { + Integer maAdvMaxRegLifetime; + Integer maAdvPrefixLengthInclusion; + String maAdvAddress; + Integer maAdvMaxInterval; + Integer maAdvMinInterval; + Integer maAdvMaxAdvLifetime; + Integer maAdvResponseSolicitationOnly; + Integer maAdvStatus; +} MaAdvConfigEntry_t; + +typedef struct _FaCOAEntry_t { + Integer faCOAStatus; +} FaCOAEntry_t; + +typedef struct _FaVisitorEntry_t { + String faVisitorIPAddress; + String faVisitorHomeAddress; + String faVisitorHomeAgentAddress; + Integer faVisitorTimeGranted; + Integer faVisitorTimeRemaining; + Integer faVisitorRegFlags; + Integer faVisitorRegIDLow; + Integer faVisitorRegIDHigh; + Integer faVisitorRegIsAccepted; + Integer faVisitorInIfindex; + String faVisitorSlla; +} FaVisitorEntry_t; + +typedef struct _HaMobilityBindingEntry_t { + String haMobilityBindingMN; + String haMobilityBindingCOA; + String haMobilityBindingSourceAddress; + Integer haMobilityBindingRegFlags; + Integer haMobilityBindingRegIDLow; + Integer haMobilityBindingRegIDHigh; + Integer haMobilityBindingTimeGranted; + Integer haMobilityBindingTimeRemaining; +} HaMobilityBindingEntry_t; + +typedef struct _HaCounterEntry_t { + Integer haServiceRequestsAccepted; + Integer haServiceRequestsDenied; + Integer haOverallServiceTime; + Integer haRecentServiceAcceptedTime; + Integer haRecentServiceDeniedTime; + Integer haRecentServiceDeniedCode; +} HaCounterEntry_t; + +/* + * Prototype for functions in mipagentsnmp_stub.c + */ +extern int get_mipEntities(Integer *mipEntities); +extern int get_mipEnable(Integer *mipEnable); +extern int set_mipEnable(int pass, Integer* mipEnable); +extern int get_mipEncapsulationSupported(Integer *mipEncapsulationSupported); + +extern int get_mipSecTotalViolations(Integer *mipSecTotalViolations); +extern int get_maAdvertisementsSent(Integer *maAdvertisementsSent); +extern int get_maAdvsSentForSolicitation(Integer *maAdvsSentForSolicitation); +extern int get_maSolicitationsReceived(Integer *maSolicitationsReceived); +extern int get_faIsBusy(Integer *faIsBusy); +extern int get_faRegistrationRequired(Integer *faRegistrationRequired); +extern int set_faRegistrationRequired(int pass, + Integer *faRegistrationRequired); +extern int get_faRegRequestsReceived(Integer *faRegRequestsReceived); +extern int get_faRegRequestsRelayed(Integer *faRegRequestsRelayed); +extern int get_faReasonUnspecified(Integer *faReasonUnspecified); +extern int get_faAdmProhibited(Integer *faAdmProhibited); +extern int get_faInsufficientResource(Integer *faInsufficientResource); +extern int get_faMNAuthenticationFailure(Integer *faMNAuthenticationFailure); +extern int get_faRegLifetimeTooLong(Integer *faRegLifetimeTooLong); +extern int get_faPoorlyFormedRequests(Integer *faPoorlyFormedRequests); +extern int get_faEncapsulationUnavailable(Integer *faEncapsulationUnavailable); +extern int get_faVJCompressionUnavailable(Integer *faVJCompressionUnavailable); +extern int get_faHAUnreachable(Integer *faHAUnreachable); +extern int get_faRegRepliesRecieved(Integer *faRegRepliesRecieved); +extern int get_faRegRepliesRelayed(Integer *faRegRepliesRelayed); +extern int get_faHAAuthenticationFailure(Integer *faHAAuthenticationFailure); +extern int get_faPoorlyFormedReplies(Integer *faPoorlyFormedReplies); + +extern int get_haRegistrationAccepted(Integer *haRegistrationAccepted); +extern int get_haMultiBindingUnsupported(Integer *haMultiBindingUnsupported); +extern int get_haReasonUnspecified(Integer *haReasonUnspecified); +extern int get_haAdmProhibited(Integer *haAdmProhibited); +extern int get_haInsufficientResource(Integer *haInsufficientResource); +extern int get_haMNAuthenticationFailure(Integer *haMNAuthenticationFailure); +extern int get_haFAAuthenticationFailure(Integer *haFAAuthenticationFailure); +extern int get_haIDMismatch(Integer *haIDMismatch); +extern int get_haPoorlyFormedRequest(Integer *haPoorlyFormedRequest); +extern int get_haTooManyBindings(Integer *haTooManyBindings); +extern int get_haUnknownHA(Integer *haUnknownHA); +extern int get_haGratuitiousARPsSent(Integer *haGratuitiousARPsSent); +extern int get_haProxyARPsSent(Integer *haProxyARPsSent); +extern int get_haRegRequestsReceived(Integer *haRegRequestsReceived); +extern int get_haDeRegRequestsReceived(Integer *haDeRegRequestsReceived); +extern int get_haRegRepliesSent(Integer *haRegRepliesSent); +extern int get_haDeRegRepliesSent(Integer *haDeRegRepliesSent); + +extern int get_mipSecAssocEntry(int search_type, + MipSecAssocEntry_t **mipSecAssocEntry_data, IndexType *index); +extern void free_mipSecAssocEntry(MipSecAssocEntry_t *mipSecAssocEntry); + +/* + * Prototype for functions in mipagentsnmp_mipSecViolationEntry.c + */ +extern int get_mipSecViolationEntry(int search_type, + MipSecViolationEntry_t **mipSecViolationEntry_data, IndexType *index); +extern void free_mipSecViolationEntry(MipSecViolationEntry_t + *mipSecViolationEntry); + + +/* + * Prototype for functions in mipagentsnmp_maAdvConfigEntry.c + */ +extern int get_maAdvConfigEntry(int search_type, + MaAdvConfigEntry_t **maAdvConfigEntry_data, IndexType *index); +extern void free_maAdvConfigEntry(MaAdvConfigEntry_t *maAdvConfigEntry); + + +/* + * Prototype for functions in mipagentsnmp_faCOAEntry.c + */ +extern int get_faCOAEntry(int search_type, + FaCOAEntry_t **faCOAEntry_data, IndexType *index); +extern void free_faCOAEntry(FaCOAEntry_t *faCOAEntry); + + +/* + * Prototype for functions in mipagentsnmp_faVisitorEntry.c + */ +extern int get_faVisitorEntry(int search_type, + FaVisitorEntry_t **faVisitorEntry_data, IndexType *index); +extern void free_faVisitorEntry(FaVisitorEntry_t *faVisitorEntry); + + +/* + * Prototype for functions in mipagentsnmp_haMobilityBindingEntry.c + */ +extern int get_haMobilityBindingEntry(int search_type, + HaMobilityBindingEntry_t **haMobilityBindingEntry_data, IndexType *index); +extern void free_haMobilityBindingEntry(HaMobilityBindingEntry_t + *haMobilityBindingEntry); + + +/* + * Prototype for functions in mipagentsnmp_haCounterEntry.c + */ +extern int get_haCounterEntry(int search_type, + HaCounterEntry_t **haCounterEntry_data, IndexType *index); +extern void free_haCounterEntry(HaCounterEntry_t *haCounterEntry); + +extern int SSAGetTrapPort(); + +#ifdef __cplusplus +} +#endif + +#endif /* _MIPAGENTSNMP_STUB_H_ */ diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_trap.c b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_trap.c new file mode 100644 index 0000000000..4214a2fde4 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_trap.c @@ -0,0 +1,50 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999-2001 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * file: mipagentsnmp_trap.c + * + * This file contains the SNMP trap routines. + */ + +#include <sys/types.h> +#include <netinet/in.h> + +#include <impl.h> +#include <node.h> + +#include "snmp_stub.h" + +#ifndef lint +struct CallbackItem genCallItem[10]; +int genNumCallItem = 0; +int genNumTrapElem = 0; +int genTrapTableMap[10]; +struct TrapHndlCxt genTrapBucket[10]; +struct TrapAnyEnterpriseInfo genTrapAnyEnterpriseInfo[10]; +#endif diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_tree.c b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_tree.c new file mode 100644 index 0000000000..79c0c70a9c --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/snmp_tree.c @@ -0,0 +1,715 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999-2001 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> + +#include <impl.h> +#include <node.h> + +#include "snmp_stub.h" + +int get_i_dont_think_so(); + +static Subid subid_table[] = { +/* 0 */ 1, 3, 6, 1, 2, 1, 44, 1, 1, 1, +/* 10 */ 1, 3, 6, 1, 2, 1, 44, 1, 1, 2, +/* 20 */ 1, 3, 6, 1, 2, 1, 44, 1, 1, 3, +/* 30 */ 1, 3, 6, 1, 2, 1, 44, 1, 2, 1, 1, 1, +/* 42 */ 1, 3, 6, 1, 2, 1, 44, 1, 2, 1, 1, 3, +/* 54 */ 1, 3, 6, 1, 2, 1, 44, 1, 2, 1, 1, 4, +/* 66 */ 1, 3, 6, 1, 2, 1, 44, 1, 2, 1, 1, 5, +/* 78 */ 1, 3, 6, 1, 2, 1, 44, 1, 2, 1, 1, 6, +/* 90 */ 1, 3, 6, 1, 2, 1, 44, 1, 2, 2, +/* 100 */ 1, 3, 6, 1, 2, 1, 44, 1, 2, 3, 1, 1, +/* 112 */ 1, 3, 6, 1, 2, 1, 44, 1, 2, 3, 1, 2, +/* 124 */ 1, 3, 6, 1, 2, 1, 44, 1, 2, 3, 1, 3, +/* 136 */ 1, 3, 6, 1, 2, 1, 44, 1, 2, 3, 1, 4, +/* 148 */ 1, 3, 6, 1, 2, 1, 44, 1, 2, 3, 1, 5, +/* 160 */ 1, 3, 6, 1, 2, 1, 44, 1, 2, 3, 1, 6, +/* 172 */ 1, 3, 6, 1, 2, 1, 44, 1, 2, 3, 1, 7, +/* 184 */ 1, 3, 6, 1, 2, 1, 44, 1, 3, 1, 1, 1, 1, +/* 197 */ 1, 3, 6, 1, 2, 1, 44, 1, 3, 1, 1, 1, 2, +/* 210 */ 1, 3, 6, 1, 2, 1, 44, 1, 3, 1, 1, 1, 3, +/* 223 */ 1, 3, 6, 1, 2, 1, 44, 1, 3, 1, 1, 1, 4, +/* 236 */ 1, 3, 6, 1, 2, 1, 44, 1, 3, 1, 1, 1, 5, +/* 249 */ 1, 3, 6, 1, 2, 1, 44, 1, 3, 1, 1, 1, 6, +/* 262 */ 1, 3, 6, 1, 2, 1, 44, 1, 3, 1, 1, 1, 7, +/* 275 */ 1, 3, 6, 1, 2, 1, 44, 1, 3, 1, 1, 1, 8, +/* 288 */ 1, 3, 6, 1, 2, 1, 44, 1, 3, 1, 1, 1, 9, +/* 301 */ 1, 3, 6, 1, 2, 1, 44, 1, 3, 1, 2, +/* 312 */ 1, 3, 6, 1, 2, 1, 44, 1, 3, 1, 3, +/* 323 */ 1, 3, 6, 1, 2, 1, 44, 1, 3, 1, 4, +/* 334 */ 1, 3, 6, 1, 2, 1, 44, 1, 4, 1, 1, 1, 1, +/* 347 */ 1, 3, 6, 1, 2, 1, 44, 1, 4, 1, 1, 1, 2, +/* 360 */ 1, 3, 6, 1, 2, 1, 44, 1, 4, 2, 1, +/* 371 */ 1, 3, 6, 1, 2, 1, 44, 1, 4, 2, 2, +/* 382 */ 1, 3, 6, 1, 2, 1, 44, 1, 4, 3, 1, 1, 1, +/* 395 */ 1, 3, 6, 1, 2, 1, 44, 1, 4, 3, 1, 1, 2, +/* 408 */ 1, 3, 6, 1, 2, 1, 44, 1, 4, 3, 1, 1, 3, +/* 421 */ 1, 3, 6, 1, 2, 1, 44, 1, 4, 3, 1, 1, 4, +/* 434 */ 1, 3, 6, 1, 2, 1, 44, 1, 4, 3, 1, 1, 5, +/* 447 */ 1, 3, 6, 1, 2, 1, 44, 1, 4, 3, 1, 1, 6, +/* 460 */ 1, 3, 6, 1, 2, 1, 44, 1, 4, 3, 1, 1, 7, +/* 473 */ 1, 3, 6, 1, 2, 1, 44, 1, 4, 3, 1, 1, 8, +/* 486 */ 1, 3, 6, 1, 2, 1, 44, 1, 4, 3, 1, 1, 9, +/* 499 */ 1, 3, 6, 1, 2, 1, 44, 1, 4, 3, 2, +/* 510 */ 1, 3, 6, 1, 2, 1, 44, 1, 4, 3, 3, +/* 521 */ 1, 3, 6, 1, 2, 1, 44, 1, 4, 3, 4, +/* 532 */ 1, 3, 6, 1, 2, 1, 44, 1, 4, 3, 5, +/* 543 */ 1, 3, 6, 1, 2, 1, 44, 1, 4, 3, 6, +/* 554 */ 1, 3, 6, 1, 2, 1, 44, 1, 4, 3, 7, +/* 565 */ 1, 3, 6, 1, 2, 1, 44, 1, 4, 3, 8, +/* 576 */ 1, 3, 6, 1, 2, 1, 44, 1, 4, 3, 9, +/* 587 */ 1, 3, 6, 1, 2, 1, 44, 1, 4, 3, 10, +/* 598 */ 1, 3, 6, 1, 2, 1, 44, 1, 4, 3, 11, +/* 609 */ 1, 3, 6, 1, 2, 1, 44, 1, 4, 3, 12, +/* 620 */ 1, 3, 6, 1, 2, 1, 44, 1, 4, 3, 13, +/* 631 */ 1, 3, 6, 1, 2, 1, 44, 1, 4, 3, 14, +/* 642 */ 1, 3, 6, 1, 2, 1, 44, 1, 4, 3, 15, +/* 653 */ 1, 3, 6, 1, 2, 1, 44, 1, 4, 3, 16, +/* 664 */ 1, 3, 6, 1, 2, 1, 44, 1, 5, 3, 1, 1, 1, +/* 677 */ 1, 3, 6, 1, 2, 1, 44, 1, 5, 3, 1, 1, 2, +/* 690 */ 1, 3, 6, 1, 2, 1, 44, 1, 5, 3, 1, 1, 3, +/* 703 */ 1, 3, 6, 1, 2, 1, 44, 1, 5, 3, 1, 1, 4, +/* 716 */ 1, 3, 6, 1, 2, 1, 44, 1, 5, 3, 1, 1, 5, +/* 729 */ 1, 3, 6, 1, 2, 1, 44, 1, 5, 3, 1, 1, 6, +/* 742 */ 1, 3, 6, 1, 2, 1, 44, 1, 5, 3, 1, 1, 7, +/* 755 */ 1, 3, 6, 1, 2, 1, 44, 1, 5, 3, 1, 1, 8, +/* 768 */ 1, 3, 6, 1, 2, 1, 44, 1, 5, 3, 2, 1, 2, +/* 781 */ 1, 3, 6, 1, 2, 1, 44, 1, 5, 3, 2, 1, 3, +/* 794 */ 1, 3, 6, 1, 2, 1, 44, 1, 5, 3, 2, 1, 4, +/* 807 */ 1, 3, 6, 1, 2, 1, 44, 1, 5, 3, 2, 1, 5, +/* 820 */ 1, 3, 6, 1, 2, 1, 44, 1, 5, 3, 2, 1, 6, +/* 833 */ 1, 3, 6, 1, 2, 1, 44, 1, 5, 3, 2, 1, 7, +/* 846 */ 1, 3, 6, 1, 2, 1, 44, 1, 5, 3, 3, +/* 857 */ 1, 3, 6, 1, 2, 1, 44, 1, 5, 3, 4, +/* 868 */ 1, 3, 6, 1, 2, 1, 44, 1, 5, 3, 5, +/* 879 */ 1, 3, 6, 1, 2, 1, 44, 1, 5, 3, 6, +/* 890 */ 1, 3, 6, 1, 2, 1, 44, 1, 5, 3, 7, +/* 901 */ 1, 3, 6, 1, 2, 1, 44, 1, 5, 3, 8, +/* 912 */ 1, 3, 6, 1, 2, 1, 44, 1, 5, 3, 9, +/* 923 */ 1, 3, 6, 1, 2, 1, 44, 1, 5, 3, 10, +/* 934 */ 1, 3, 6, 1, 2, 1, 44, 1, 5, 3, 11, +/* 945 */ 1, 3, 6, 1, 2, 1, 44, 1, 5, 3, 12, +/* 956 */ 1, 3, 6, 1, 2, 1, 44, 1, 5, 3, 13, +/* 967 */ 1, 3, 6, 1, 2, 1, 44, 1, 5, 3, 14, +/* 978 */ 1, 3, 6, 1, 2, 1, 44, 1, 5, 3, 15, +/* 989 */ 1, 3, 6, 1, 2, 1, 44, 1, 5, 3, 16, +/* 1000 */ 1, 3, 6, 1, 2, 1, 44, 1, 5, 3, 17, +/* 1011 */ 1, 3, 6, 1, 2, 1, 44, 1, 5, 3, 18, +/* 1022 */ 1, 3, 6, 1, 2, 1, 44, 1, 5, 3, 19, +0 +}; +int subid_table_size = 1033; + +Enum enum_table[] = { +/* 0 */ { &enum_table[ 1], "mobileNode", 0 }, +/* 1 */ { &enum_table[ 2], "foreignAgent", 1 }, +/* 2 */ { NULL, "homeAgent", 2 }, +/* 3 */ { &enum_table[ 4], "enabled", 1 }, +/* 4 */ { NULL, "disabled", 2 }, +/* 5 */ { &enum_table[ 6], "ipInIp", 0 }, +/* 6 */ { &enum_table[ 7], "gre", 1 }, +/* 7 */ { &enum_table[ 8], "minEnc", 2 }, +/* 8 */ { NULL, "other", 3 }, +/* 9 */ { &enum_table[ 10], "other", 1 }, +/* 10 */ { NULL, "md5", 2 }, +/* 11 */ { &enum_table[ 12], "other", 1 }, +/* 12 */ { NULL, "prefixSuffix", 2 }, +/* 13 */ { &enum_table[ 14], "other", 1 }, +/* 14 */ { &enum_table[ 15], "timestamps", 2 }, +/* 15 */ { NULL, "nonces", 3 }, +/* 16 */ { &enum_table[ 17], "noMobilitySecurityAssociation", 1 }, +/* 17 */ { &enum_table[ 18], "badAuthenticator", 2 }, +/* 18 */ { &enum_table[ 19], "badIdentifier", 3 }, +/* 19 */ { &enum_table[ 20], "badSPI", 4 }, +/* 20 */ { &enum_table[ 21], "missingSecurityExtension", 5 }, +/* 21 */ { NULL, "other", 6 }, +/* 22 */ { &enum_table[ 23], "vjCompression", 0 }, +/* 23 */ { &enum_table[ 24], "gre", 1 }, +/* 24 */ { &enum_table[ 25], "minEnc", 2 }, +/* 25 */ { &enum_table[ 26], "decapsulationbyMN", 3 }, +/* 26 */ { &enum_table[ 27], "broadcastDatagram", 4 }, +/* 27 */ { NULL, "simultaneousBindings", 5 }, +/* 28 */ { &enum_table[ 29], "vjCompression", 0 }, +/* 29 */ { &enum_table[ 30], "gre", 1 }, +/* 30 */ { &enum_table[ 31], "minEnc", 2 }, +/* 31 */ { &enum_table[ 32], "decapsulationbyMN", 3 }, +/* 32 */ { &enum_table[ 33], "broadcastDatagram", 4 }, +/* 33 */ { NULL, "simultaneousBindings", 5 }, +/* 34 */ { &enum_table[ 35], "reasonUnspecified", 128 }, +/* 35 */ { &enum_table[ 36], "admProhibited", 129 }, +/* 36 */ { &enum_table[ 37], "insufficientResource", 130 }, +/* 37 */ { &enum_table[ 38], "mnAuthenticationFailure", 131 }, +/* 38 */ { &enum_table[ 39], "faAuthenticationFailure", 132 }, +/* 39 */ { &enum_table[ 40], "idMismatch", 133 }, +/* 40 */ { &enum_table[ 41], "poorlyFormedRequest", 134 }, +/* 41 */ { &enum_table[ 42], "tooManyBindings", 135 }, +/* 42 */ { NULL, "unknownHA", 136 }, +{ NULL, NULL, 0 } +}; +int enum_table_size = 43; + +Object object_table[] = { +/* 0 */ { { &subid_table[0], 10 }, INTEGER, &enum_table[0], + READ_FLAG, 1, get_mipEntities, NULL, NULL }, +/* 1 */ { { &subid_table[10], 10 }, INTEGER, &enum_table[3], + READ_FLAG | WRITE_FLAG, 1, get_mipEnable, set_mipEnable, NULL }, +/* 2 */ { { &subid_table[20], 10 }, INTEGER, &enum_table[5], + READ_FLAG, 1, get_mipEncapsulationSupported, NULL, NULL }, +/* 3 */ { { &subid_table[90], 10 }, COUNTER, NULL, + READ_FLAG, 1, get_mipSecTotalViolations, NULL, NULL }, +/* 4 */ { { &subid_table[301], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_maAdvertisementsSent, NULL, NULL }, +/* 5 */ { { &subid_table[312], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_maAdvsSentForSolicitation, NULL, NULL }, +/* 6 */ { { &subid_table[323], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_maSolicitationsReceived, NULL, NULL }, +/* 7 */ { { &subid_table[360], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_faIsBusy, NULL, NULL }, +/* 8 */ { { &subid_table[371], 11 }, COUNTER, NULL, + READ_FLAG | WRITE_FLAG, 1, get_faRegistrationRequired, + set_faRegistrationRequired, NULL }, +/* 9 */ { { &subid_table[499], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_faRegRequestsReceived, NULL, NULL }, +/* 10 */ { { &subid_table[510], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_faRegRequestsRelayed, NULL, NULL }, +/* 11 */ { { &subid_table[521], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_faReasonUnspecified, NULL, NULL }, +/* 12 */ { { &subid_table[532], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_faAdmProhibited, NULL, NULL }, +/* 13 */ { { &subid_table[543], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_faInsufficientResource, NULL, NULL }, +/* 14 */ { { &subid_table[554], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_faMNAuthenticationFailure, NULL, NULL }, +/* 15 */ { { &subid_table[565], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_faRegLifetimeTooLong, NULL, NULL }, +/* 16 */ { { &subid_table[576], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_faPoorlyFormedRequests, NULL, NULL }, +/* 17 */ { { &subid_table[587], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_faEncapsulationUnavailable, NULL, NULL }, +/* 18 */ { { &subid_table[598], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_faVJCompressionUnavailable, NULL, NULL }, +/* 19 */ { { &subid_table[609], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_faHAUnreachable, NULL, NULL }, +/* 20 */ { { &subid_table[620], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_faRegRepliesRecieved, NULL, NULL }, +/* 21 */ { { &subid_table[631], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_faRegRepliesRelayed, NULL, NULL }, +/* 22 */ { { &subid_table[642], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_faHAAuthenticationFailure, NULL, NULL }, +/* 23 */ { { &subid_table[653], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_faPoorlyFormedReplies, NULL, NULL }, +/* 24 */ { { &subid_table[846], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_haRegistrationAccepted, NULL, NULL }, +/* 25 */ { { &subid_table[857], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_haMultiBindingUnsupported, NULL, NULL }, +/* 26 */ { { &subid_table[868], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_haReasonUnspecified, NULL, NULL }, +/* 27 */ { { &subid_table[879], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_haAdmProhibited, NULL, NULL }, +/* 28 */ { { &subid_table[890], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_haInsufficientResource, NULL, NULL }, +/* 29 */ { { &subid_table[901], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_haMNAuthenticationFailure, NULL, NULL }, +/* 30 */ { { &subid_table[912], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_haFAAuthenticationFailure, NULL, NULL }, +/* 31 */ { { &subid_table[923], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_haIDMismatch, NULL, NULL }, +/* 32 */ { { &subid_table[934], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_haPoorlyFormedRequest, NULL, NULL }, +/* 33 */ { { &subid_table[945], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_haTooManyBindings, NULL, NULL }, +/* 34 */ { { &subid_table[956], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_haUnknownHA, NULL, NULL }, +/* 35 */ { { &subid_table[967], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_haGratuitiousARPsSent, NULL, NULL }, +/* 36 */ { { &subid_table[978], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_haProxyARPsSent, NULL, NULL }, +/* 37 */ { { &subid_table[989], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_haRegRequestsReceived, NULL, NULL }, +/* 38 */ { { &subid_table[1000], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_haDeRegRequestsReceived, NULL, NULL }, +/* 39 */ { { &subid_table[1011], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_haRegRepliesSent, NULL, NULL }, +/* 40 */ { { &subid_table[1022], 11 }, COUNTER, NULL, + READ_FLAG, 1, get_haDeRegRepliesSent, NULL, NULL }, +{ { NULL, 0}, 0, NULL, 0, NULL, NULL } +}; +int object_table_size = 41; + +Index index_table[] = { +/* 0 */ { &index_table[ 1], "mipSecPeerAddress", 5, 0, &node_table[16] }, +/* 1 */ { NULL, "mipSecSPI", 0, 0, &node_table[17] }, +/* 2 */ { NULL, "mipSecViolatorAddress", 5, 0, &node_table[25] }, +/* 3 */ { NULL, "maInterfaceAddress", 5, 0, &node_table[36] }, +/* 4 */ { NULL, "faSupportedCOA", 5, 0, &node_table[52] }, +/* 5 */ { NULL, "faVisitorIPAddress", 5, 0, &node_table[60] }, +/* 6 */ { &index_table[ 7], "haMobilityBindingMN", 5, 0, &node_table[88] }, +/* 7 */ { NULL, "haMobilityBindingCOA", 5, 0, &node_table[89] }, +/* 8 */ { NULL, "haMobilityBindingMN", 5, 0, &node_table[88] }, +{ NULL, NULL, NULL } +}; +int index_table_size = 9; + +Entry entry_table[] = { +/* 0 */ { &index_table[0], 2, get_mipSecAssocEntry, free_mipSecAssocEntry }, +/* 1 */ { &index_table[2], 1, get_mipSecViolationEntry, + free_mipSecViolationEntry }, +/* 2 */ { &index_table[3], 1, get_maAdvConfigEntry, free_maAdvConfigEntry }, +/* 3 */ { &index_table[4], 1, get_faCOAEntry, free_faCOAEntry }, +/* 4 */ { &index_table[5], 1, get_faVisitorEntry, free_faVisitorEntry }, +/* 5 */ { &index_table[6], 2, get_haMobilityBindingEntry, + free_haMobilityBindingEntry }, +/* 6 */ { &index_table[8], 1, get_haCounterEntry, free_haCounterEntry }, +{ NULL, 0, NULL } +}; +int entry_table_size = 7; + +Column column_table[] = { +/* 0 */ { { &subid_table[30], 12 }, IPADDRESS, NULL, + 0, 2, NULL, NULL, &entry_table[0], 0 }, +/* 1 */ { { &subid_table[42], 12 }, INTEGER, &enum_table[9], + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[0], 0 }, +/* 2 */ { { &subid_table[54], 12 }, INTEGER, &enum_table[11], + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[0], 4 }, +/* 3 */ { { &subid_table[66], 12 }, STRING, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[0], 8 }, +/* 4 */ { { &subid_table[78], 12 }, INTEGER, &enum_table[13], + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[0], 16 }, +/* 5 */ { { &subid_table[100], 12 }, IPADDRESS, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[1], 0 }, +/* 6 */ { { &subid_table[112], 12 }, COUNTER, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[1], 8 }, +/* 7 */ { { &subid_table[124], 12 }, COUNTER, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[1], 12 }, +/* 8 */ { { &subid_table[136], 12 }, TIMETICKS, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[1], 16 }, +/* 9 */ { { &subid_table[148], 12 }, COUNTER, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[1], 20 }, +/* 10 */ { { &subid_table[160], 12 }, COUNTER, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[1], 24 }, +/* 11 */ { { &subid_table[172], 12 }, INTEGER, &enum_table[16], + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[1], 28 }, +/* 12 */ { { &subid_table[184], 13 }, IPADDRESS, NULL, 0, 2, + NULL, NULL, &entry_table[2], 0 }, +/* 13 */ { { &subid_table[197], 13 }, COUNTER, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[2], 0 }, +/* 14 */ { { &subid_table[210], 13 }, COUNTER, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[2], 4 }, +/* 15 */ { { &subid_table[223], 13 }, IPADDRESS, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[2], 8 }, +/* 16 */ { { &subid_table[236], 13 }, COUNTER, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[2], 16 }, +/* 17 */ { { &subid_table[249], 13 }, COUNTER, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[2], 20 }, +/* 18 */ { { &subid_table[262], 13 }, COUNTER, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[2], 24 }, +/* 19 */ { { &subid_table[275], 13 }, COUNTER, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[2], 28 }, +/* 20 */ { { &subid_table[288], 13 }, COUNTER, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[2], 32 }, +/* 21 */ { { &subid_table[334], 13 }, IPADDRESS, NULL, 0, 2, + NULL, NULL, &entry_table[3], 0 }, +/* 22 */ { { &subid_table[347], 13 }, COUNTER, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[3], 0 }, +/* 23 */ { { &subid_table[382], 13 }, IPADDRESS, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[4], 0 }, +/* 24 */ { { &subid_table[395], 13 }, IPADDRESS, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[4], 8 }, +/* 25 */ { { &subid_table[408], 13 }, IPADDRESS, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[4], 16 }, +/* 26 */ { { &subid_table[421], 13 }, COUNTER, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[4], 24 }, +/* 27 */ { { &subid_table[434], 13 }, GAUGE, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[4], 28 }, +/* 28 */ { { &subid_table[447], 13 }, INTEGER, &enum_table[22], + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[4], 32 }, +/* 29 */ { { &subid_table[460], 13 }, COUNTER, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[4], 36 }, +/* 30 */ { { &subid_table[473], 13 }, COUNTER, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[4], 40 }, +/* 31 */ { { &subid_table[486], 13 }, COUNTER, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[4], 44 }, +/* 32 */ { { &subid_table[664], 13 }, IPADDRESS, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[5], 0 }, +/* 33 */ { { &subid_table[677], 13 }, IPADDRESS, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[5], 8 }, +/* 34 */ { { &subid_table[690], 13 }, IPADDRESS, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[5], 16 }, +/* 35 */ { { &subid_table[703], 13 }, INTEGER, &enum_table[28], + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[5], 24 }, +/* 36 */ { { &subid_table[716], 13 }, COUNTER, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[5], 28 }, +/* 37 */ { { &subid_table[729], 13 }, COUNTER, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[5], 32 }, +/* 38 */ { { &subid_table[742], 13 }, COUNTER, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[5], 36 }, +/* 39 */ { { &subid_table[755], 13 }, GAUGE, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[5], 40 }, +/* 40 */ { { &subid_table[768], 13 }, COUNTER, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[6], 0 }, +/* 41 */ { { &subid_table[781], 13 }, COUNTER, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[6], 4 }, +/* 42 */ { { &subid_table[794], 13 }, GAUGE, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[6], 8 }, +/* 43 */ { { &subid_table[807], 13 }, TIMETICKS, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[6], 12 }, +/* 44 */ { { &subid_table[820], 13 }, TIMETICKS, NULL, + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[6], 16 }, +/* 45 */ { { &subid_table[833], 13 }, INTEGER, &enum_table[34], + READ_FLAG, 2, get_i_dont_think_so, NULL, &entry_table[6], 20 }, +{ { NULL, 0 }, 0, NULL, 0, NULL, NULL, 0 } +}; +int column_table_size = 46; + +Node node_table[] = { +/* 0 */ { NULL, &node_table[ 1], + NULL, &node_table[ 10], "iso", 1, NODE, NULL }, +/* 1 */ { &node_table[ 0], &node_table[ 2], + NULL, &node_table[ 10], "org", 3, NODE, NULL }, +/* 2 */ { &node_table[ 1], &node_table[ 3], + NULL, &node_table[ 10], "dod", 6, NODE, NULL }, +/* 3 */ { &node_table[ 2], &node_table[ 4], + NULL, &node_table[ 10], "internet", 1, NODE, NULL }, +/* 4 */ { &node_table[ 3], + NULL, &node_table[ 5], &node_table[ 10], "directory", 1, + NODE, NULL }, +/* 5 */ { &node_table[ 3], &node_table[ 6], &node_table[ 140], + &node_table[ 10], "mgmt", 2, NODE, NULL }, +/* 6 */ { &node_table[ 5], &node_table[ 7], + NULL, &node_table[ 10], "mib-2", 1, NODE, NULL }, +/* 7 */ { &node_table[ 6], &node_table[ 8], + NULL, &node_table[ 10], "mipMIB", 44, NODE, NULL }, +/* 8 */ { &node_table[ 7], &node_table[ 9], &node_table[ 121], + &node_table[ 10], "mipMIBObjects", 1, NODE, NULL }, +/* 9 */ { &node_table[ 8], &node_table[ 10], &node_table[ 13], + &node_table[ 10], "mipSystem", 1, NODE, NULL }, +/* 10 */ { &node_table[ 9], + NULL, &node_table[ 11], &node_table[ 11], "mipEntities", 1, + OBJECT, (void *) &object_table[0] }, +/* 11 */ { &node_table[ 9], + NULL, &node_table[ 12], &node_table[ 12], "mipEnable", 2, + OBJECT, (void *) &object_table[1] }, +/* 12 */ { &node_table[ 9], + NULL, NULL, &node_table[18], "mipEncapsulationSupported", 3, + OBJECT, (void *) &object_table[2] }, +/* 13 */ { &node_table[ 8], &node_table[ 14], &node_table[ 32], + &node_table[ 18], "mipSecurity", 2, NODE, NULL }, +/* 14 */ { &node_table[ 13], &node_table[ 15], &node_table[ 22], + &node_table[ 18], "mipSecAssocTable", 1, NODE, NULL }, +/* 15 */ { &node_table[ 14], &node_table[ 16], NULL, &node_table[ 18], + "mipSecAssocEntry", 1, NODE, NULL }, +/* 16 */ { &node_table[ 15], NULL, &node_table[ 17], &node_table[ 18], + "mipSecPeerAddress", 1, COLUMN, (void *) &column_table[0] }, +/* 17 */ { &node_table[ 15], NULL, &node_table[ 18], &node_table[ 18], + "mipSecSPI", 2, NODE, NULL }, +/* 18 */ { &node_table[ 15], NULL, &node_table[ 19], &node_table[ 19], + "mipSecAlgorithmType", 3, COLUMN, (void *) &column_table[1] }, +/* 19 */ { &node_table[ 15], NULL, &node_table[ 20], &node_table[ 20], + "mipSecAlgorithmMode", 4, COLUMN, (void *) &column_table[2] }, +/* 20 */ { &node_table[ 15], NULL, &node_table[ 21], &node_table[ 21], + "mipSecKey", 5, COLUMN, (void *) &column_table[3] }, +/* 21 */ { &node_table[ 15], NULL, NULL, &node_table[ 22], + "mipSecReplayMethod", 6, COLUMN, (void *) &column_table[4] }, +/* 22 */ { &node_table[ 13], NULL, &node_table[ 23], &node_table[ 25], + "mipSecTotalViolations", 2, OBJECT, (void *) &object_table[3] }, +/* 23 */ { &node_table[ 13], &node_table[ 24], NULL, &node_table[ 25], + "mipSecViolationTable", 3, NODE, NULL }, +/* 24 */ { &node_table[ 23], &node_table[ 25], NULL, &node_table[ 25], + "mipSecViolationEntry", 1, NODE, NULL }, +/* 25 */ { &node_table[ 24], NULL, &node_table[ 26], &node_table[ 26], + "mipSecViolatorAddress", 1, COLUMN, (void *) &column_table[5] }, +/* 26 */ { &node_table[ 24], NULL, &node_table[ 27], &node_table[ 27], + "mipSecViolationCounter", 2, COLUMN, (void *) &column_table[6] }, +/* 27 */ { &node_table[ 24], NULL, &node_table[ 28], &node_table[ 28], + "mipSecRecentViolationSPI", 3, COLUMN, (void *) &column_table[7] }, +/* 28 */ { &node_table[ 24], NULL, &node_table[ 29], &node_table[ 29], + "mipSecRecentViolationTime", 4, COLUMN, (void *) &column_table[8] }, +/* 29 */ { &node_table[ 24], NULL, &node_table[ 30], &node_table[ 30], + "mipSecRecentViolationIDLow", 5, COLUMN, (void *) &column_table[9] }, +/* 30 */ { &node_table[ 24], NULL, &node_table[ 31], &node_table[ 31], + "mipSecRecentViolationIDHigh", 6, COLUMN, (void *) &column_table[10] }, +/* 31 */ { &node_table[ 24], NULL, NULL, &node_table[ 37], + "mipSecRecentViolationReason", 7, COLUMN, (void *) &column_table[11] }, +/* 32 */ { &node_table[ 8], &node_table[ 33], &node_table[ 48], + &node_table[ 37], "mipMA", 3, NODE, NULL }, +/* 33 */ { &node_table[ 32], &node_table[ 34], NULL, &node_table[ 37], + "maAdvertisement", 1, NODE, NULL }, +/* 34 */ { &node_table[ 33], &node_table[ 35], &node_table[ 45], + &node_table[ 37], "maAdvConfigTable", 1, NODE, NULL }, +/* 35 */ { &node_table[ 34], &node_table[ 36], NULL, &node_table[ 37], + "maAdvConfigEntry", 1, NODE, NULL }, +/* 36 */ { &node_table[ 35], NULL, &node_table[ 37], &node_table[ 37], + "maInterfaceAddress", 1, COLUMN, (void *) &column_table[12] }, +/* 37 */ { &node_table[ 35], NULL, &node_table[ 38], &node_table[ 38], + "maAdvMaxRegLifetime", 2, COLUMN, (void *) &column_table[13] }, +/* 38 */ { &node_table[ 35], NULL, &node_table[ 39], &node_table[ 39], + "maAdvPrefixLengthInclusion", 3, COLUMN, (void *) &column_table[14] }, +/* 39 */ { &node_table[ 35], NULL, &node_table[ 40], &node_table[ 40], + "maAdvAddress", 4, COLUMN, (void *) &column_table[15] }, +/* 40 */ { &node_table[ 35], NULL, &node_table[ 41], &node_table[ 41], + "maAdvMaxInterval", 5, COLUMN, (void *) &column_table[16] }, +/* 41 */ { &node_table[ 35], NULL, &node_table[ 42], &node_table[ 42], + "maAdvMinInterval", 6, COLUMN, (void *) &column_table[17] }, +/* 42 */ { &node_table[ 35], NULL, &node_table[ 43], &node_table[ 43], + "maAdvMaxAdvLifetime", 7, COLUMN, (void *) &column_table[18] }, +/* 43 */ { &node_table[ 35], NULL, &node_table[ 44], &node_table[ 44], + "maAdvResponseSolicitationOnly", 8, COLUMN, + (void *) &column_table[19] }, +/* 44 */ { &node_table[ 35], NULL, NULL, &node_table[ 45], + "maAdvStatus", 9, COLUMN, (void *) &column_table[20] }, +/* 45 */ { &node_table[ 33], NULL, &node_table[ 46], &node_table[ 46], + "maAdvertisementsSent", 2, OBJECT, (void *) &object_table[4] }, +/* 46 */ { &node_table[ 33], NULL, &node_table[ 47], &node_table[ 47], + "maAdvsSentForSolicitation", 3, OBJECT, (void *) &object_table[5] }, +/* 47 */ { &node_table[ 33], NULL, NULL, &node_table[ 53], + "maSolicitationsReceived", 4, OBJECT, (void *) &object_table[6] }, +/* 48 */ { &node_table[ 8], &node_table[ 49], &node_table[ 84], + &node_table[ 53], "mipFA", 4, NODE, NULL }, +/* 49 */ { &node_table[ 48], &node_table[ 50], &node_table[ 54], + &node_table[ 53], "faSystem", 1, NODE, NULL }, +/* 50 */ { &node_table[ 49], &node_table[ 51], NULL, &node_table[ 53], + "faCOATable", 1, NODE, NULL }, +/* 51 */ { &node_table[ 50], &node_table[ 52], NULL, &node_table[ 53], + "faCOAEntry", 1, NODE, NULL }, +/* 52 */ { &node_table[ 51], NULL, &node_table[ 53], &node_table[ 53], + "faSupportedCOA", 1, COLUMN, (void *) &column_table[21] }, +/* 53 */ { &node_table[ 51], NULL, NULL, &node_table[ 55], + "faCOAStatus", 2, COLUMN, (void *) &column_table[22] }, +/* 54 */ { &node_table[ 48], &node_table[ 55], &node_table[ 57], + &node_table[ 55], "faAdvertisement", 2, NODE, NULL }, +/* 55 */ { &node_table[ 54], NULL, &node_table[ 56], &node_table[ 56], + "faIsBusy", 1, OBJECT, (void *) &object_table[7] }, +/* 56 */ { &node_table[ 54], NULL, NULL, &node_table[ 60], + "faRegistrationRequired", 2, OBJECT, (void *) &object_table[8] }, +/* 57 */ { &node_table[ 48], &node_table[ 58], NULL, &node_table[ 60], + "faRegistration", 3, NODE, NULL }, +/* 58 */ { &node_table[ 57], &node_table[ 59], &node_table[ 69], + &node_table[ 60], "faVisitorTable", 1, NODE, NULL }, +/* 59 */ { &node_table[ 58], &node_table[ 60], NULL, &node_table[ 60], + "faVisitorEntry", 1, NODE, NULL }, +/* 60 */ { &node_table[ 59], NULL, &node_table[ 61], &node_table[ 61], + "faVisitorIPAddress", 1, COLUMN, (void *) &column_table[23] }, +/* 61 */ { &node_table[ 59], NULL, &node_table[ 62], &node_table[ 62], + "faVisitorHomeAddress", 2, COLUMN, (void *) &column_table[24] }, +/* 62 */ { &node_table[ 59], NULL, &node_table[ 63], &node_table[ 63], + "faVisitorHomeAgentAddress", 3, COLUMN, (void *) &column_table[25] }, +/* 63 */ { &node_table[ 59], NULL, &node_table[ 64], &node_table[ 64], + "faVisitorTimeGranted", 4, COLUMN, (void *) &column_table[26] }, +/* 64 */ { &node_table[ 59], NULL, &node_table[ 65], &node_table[ 65], + "faVisitorTimeRemaining", 5, COLUMN, (void *) &column_table[27] }, +/* 65 */ { &node_table[ 59], NULL, &node_table[ 66], &node_table[ 66], + "faVisitorRegFlags", 6, COLUMN, (void *) &column_table[28] }, +/* 66 */ { &node_table[ 59], NULL, &node_table[ 67], &node_table[ 67], + "faVisitorRegIDLow", 7, COLUMN, (void *) &column_table[29] }, +/* 67 */ { &node_table[ 59], NULL, &node_table[ 68], &node_table[ 68], + "faVisitorRegIDHigh", 8, COLUMN, (void *) &column_table[30] }, +/* 68 */ { &node_table[ 59], NULL, NULL, &node_table[ 69], + "faVisitorRegIsAccepted", 9, COLUMN, (void *) &column_table[31] }, +/* 69 */ { &node_table[ 57], NULL, &node_table[ 70], &node_table[ 70], + "faRegRequestsReceived", 2, OBJECT, (void *) &object_table[9] }, +/* 70 */ { &node_table[ 57], NULL, &node_table[ 71], &node_table[ 71], + "faRegRequestsRelayed", 3, OBJECT, (void *) &object_table[10] }, +/* 71 */ { &node_table[ 57], NULL, &node_table[ 72], &node_table[ 72], + "faReasonUnspecified", 4, OBJECT, (void *) &object_table[11] }, +/* 72 */ { &node_table[ 57], NULL, &node_table[ 73], &node_table[ 73], + "faAdmProhibited", 5, OBJECT, (void *) &object_table[12] }, +/* 73 */ { &node_table[ 57], NULL, &node_table[ 74], &node_table[ 74], + "faInsufficientResource", 6, OBJECT, (void *) &object_table[13] }, +/* 74 */ { &node_table[ 57], NULL, &node_table[ 75], &node_table[ 75], + "faMNAuthenticationFailure", 7, OBJECT, (void *) &object_table[14] }, +/* 75 */ { &node_table[ 57], NULL, &node_table[ 76], &node_table[ 76], + "faRegLifetimeTooLong", 8, OBJECT, (void *) &object_table[15] }, +/* 76 */ { &node_table[ 57], NULL, &node_table[ 77], &node_table[ 77], + "faPoorlyFormedRequests", 9, OBJECT, (void *) &object_table[16] }, +/* 77 */ { &node_table[ 57], NULL, &node_table[ 78], &node_table[ 78], + "faEncapsulationUnavailable", 10, OBJECT, (void *) &object_table[17] }, +/* 78 */ { &node_table[ 57], NULL, &node_table[ 79], &node_table[ 79], + "faVJCompressionUnavailable", 11, OBJECT, (void *) &object_table[18] }, +/* 79 */ { &node_table[ 57], NULL, &node_table[ 80], &node_table[ 80], + "faHAUnreachable", 12, OBJECT, (void *) &object_table[19] }, +/* 80 */ { &node_table[ 57], NULL, &node_table[ 81], &node_table[ 81], + "faRegRepliesRecieved", 13, OBJECT, (void *) &object_table[20] }, +/* 81 */ { &node_table[ 57], NULL, &node_table[ 82], &node_table[ 82], + "faRegRepliesRelayed", 14, OBJECT, (void *) &object_table[21] }, +/* 82 */ { &node_table[ 57], NULL, &node_table[ 83], &node_table[ 83], + "faHAAuthenticationFailure", 15, OBJECT, (void *) &object_table[22] }, +/* 83 */ { &node_table[ 57], NULL, NULL, &node_table[ 88], + "faPoorlyFormedReplies", 16, OBJECT, (void *) &object_table[23] }, +/* 84 */ { &node_table[ 8], &node_table[ 85], NULL, &node_table[ 88], + "mipHA", 5, NODE, NULL }, +/* 85 */ { &node_table[ 84], &node_table[ 86], NULL, &node_table[ 88], + "haRegistration", 3, NODE, NULL }, +/* 86 */ { &node_table[ 85], &node_table[ 87], &node_table[ 96], + &node_table[ 88], "haMobilityBindingTable", 1, NODE, NULL }, +/* 87 */ { &node_table[ 86], &node_table[ 88], NULL, &node_table[ 88], + "haMobilityBindingEntry", 1, NODE, NULL }, +/* 88 */ { &node_table[ 87], NULL, &node_table[ 89], &node_table[ 89], + "haMobilityBindingMN", 1, COLUMN, (void *) &column_table[32] }, +/* 89 */ { &node_table[ 87], NULL, &node_table[ 90], &node_table[ 90], + "haMobilityBindingCOA", 2, COLUMN, (void *) &column_table[33] }, +/* 90 */ { &node_table[ 87], NULL, &node_table[ 91], &node_table[ 91], + "haMobilityBindingSourceAddress", 3, COLUMN, + (void *) &column_table[34] }, +/* 91 */ { &node_table[ 87], NULL, &node_table[ 92], &node_table[ 92], + "haMobilityBindingRegFlags", 4, COLUMN, (void *) &column_table[35] }, +/* 92 */ { &node_table[ 87], NULL, &node_table[ 93], &node_table[ 93], + "haMobilityBindingRegIDLow", 5, COLUMN, (void *) &column_table[36] }, +/* 93 */ { &node_table[ 87], NULL, &node_table[ 94], &node_table[ 94], + "haMobilityBindingRegIDHigh", 6, COLUMN, (void *) &column_table[37] }, +/* 94 */ { &node_table[ 87], NULL, &node_table[ 95], &node_table[ 95], + "haMobilityBindingTimeGranted", 7, COLUMN, (void *) &column_table[38] }, +/* 95 */ { &node_table[ 87], NULL, NULL, &node_table[ 98], + "haMobilityBindingTimeRemaining", 8, COLUMN, + (void *) &column_table[39] }, +/* 96 */ { &node_table[ 85], &node_table[ 97], &node_table[ 104], + &node_table[ 98], "haCounterTable", 2, NODE, NULL }, +/* 97 */ { &node_table[ 96], &node_table[ 98], NULL, &node_table[ 98], + "haCounterEntry", 1, NODE, NULL }, +/* 98 */ { &node_table[ 97], NULL, &node_table[ 99], &node_table[ 99], + "haServiceRequestsAccepted", 2, COLUMN, (void *) &column_table[40] }, +/* 99 */ { &node_table[ 97], NULL, &node_table[ 100], &node_table[ 100], + "haServiceRequestsDenied", 3, COLUMN, (void *) &column_table[41] }, +/* 100 */ { &node_table[ 97], NULL, &node_table[ 101], &node_table[ 101], + "haOverallServiceTime", 4, COLUMN, (void *) &column_table[42] }, +/* 101 */ { &node_table[ 97], NULL, &node_table[ 102], &node_table[ 102], + "haRecentServiceAcceptedTime", 5, COLUMN, (void *) &column_table[43] }, +/* 102 */ { &node_table[ 97], NULL, &node_table[ 103], &node_table[ 103], + "haRecentServiceDeniedTime", 6, COLUMN, + (void *) &column_table[44] }, +/* 103 */ { &node_table[ 97], NULL, NULL, &node_table[ 104], + "haRecentServiceDeniedCode", 7, COLUMN, (void *) &column_table[45] }, +/* 104 */ { &node_table[ 85], NULL, &node_table[ 105], &node_table[ 105], + "haRegistrationAccepted", 3, OBJECT, (void *) &object_table[24] }, +/* 105 */ { &node_table[ 85], NULL, &node_table[ 106], &node_table[ 106], + "haMultiBindingUnsupported", 4, OBJECT, (void *) &object_table[25] }, +/* 106 */ { &node_table[ 85], NULL, &node_table[ 107], &node_table[ 107], + "haReasonUnspecified", 5, OBJECT, (void *) &object_table[26] }, +/* 107 */ { &node_table[ 85], NULL, &node_table[ 108], &node_table[ 108], + "haAdmProhibited", 6, OBJECT, (void *) &object_table[27] }, +/* 108 */ { &node_table[ 85], NULL, &node_table[ 109], &node_table[ 109], + "haInsufficientResource", 7, OBJECT, (void *) &object_table[28] }, +/* 109 */ { &node_table[ 85], NULL, &node_table[ 110], &node_table[ 110], + "haMNAuthenticationFailure", 8, OBJECT, (void *) &object_table[29] }, +/* 110 */ { &node_table[ 85], NULL, &node_table[ 111], &node_table[ 111], + "haFAAuthenticationFailure", 9, OBJECT, (void *) &object_table[30] }, +/* 111 */ { &node_table[ 85], NULL, &node_table[ 112], &node_table[ 112], + "haIDMismatch", 10, OBJECT, (void *) &object_table[31] }, +/* 112 */ { &node_table[ 85], NULL, &node_table[ 113], &node_table[ 113], + "haPoorlyFormedRequest", 11, OBJECT, + (void *) &object_table[32] }, +/* 113 */ { &node_table[ 85], NULL, &node_table[ 114], &node_table[ 114], + "haTooManyBindings", 12, OBJECT, (void *) &object_table[33] }, +/* 114 */ { &node_table[ 85], NULL, &node_table[ 115], &node_table[ 115], + "haUnknownHA", 13, OBJECT, (void *) &object_table[34] }, +/* 115 */ { &node_table[ 85], NULL, &node_table[ 116], &node_table[ 116], + "haGratuitiousARPsSent", 14, OBJECT, (void *) &object_table[35] }, +/* 116 */ { &node_table[ 85], NULL, &node_table[ 117], &node_table[ 117], + "haProxyARPsSent", 15, OBJECT, (void *) &object_table[36] }, +/* 117 */ { &node_table[ 85], NULL, &node_table[ 118], &node_table[ 118], + "haRegRequestsReceived", 16, OBJECT, (void *) &object_table[37] }, +/* 118 */ { &node_table[ 85], NULL, &node_table[ 119], &node_table[ 119], + "haDeRegRequestsReceived", 17, OBJECT, (void *) &object_table[38] }, +/* 119 */ { &node_table[ 85], NULL, &node_table[ 120], &node_table[ 120], + "haRegRepliesSent", 18, OBJECT, (void *) &object_table[39] }, +/* 120 */ { &node_table[ 85], NULL, NULL, NULL, "haDeRegRepliesSent", 19, + OBJECT, (void *) &object_table[40] }, +/* 121 */ { &node_table[ 7], &node_table[ 122], &node_table[ 124], + NULL, "mipMIBNotificationPrefix", 2, NODE, NULL }, +/* 122 */ { &node_table[ 121], &node_table[ 123], NULL, + NULL, "mipMIBNotifications", 0, NODE, NULL }, +/* 123 */ { &node_table[ 122], NULL, NULL, + NULL, "mipAuthFailure", 1, NODE, NULL }, +/* 124 */ { &node_table[ 7], &node_table[ 125], NULL, + NULL, "mipMIBConformance", 3, NODE, NULL }, +/* 125 */ { &node_table[ 124], &node_table[ 126], &node_table[ 138], + NULL, "mipGroups", 1, NODE, NULL }, +/* 126 */ { &node_table[ 125], NULL, &node_table[ 127], + NULL, "mipSystemGroup", 1, NODE, NULL }, +/* 127 */ { &node_table[ 125], NULL, &node_table[ 128], + NULL, "mipSecAssociationGroup", 2, NODE, NULL }, +/* 128 */ { &node_table[ 125], NULL, &node_table[ 129], + NULL, "mipSecViolationGroup", 3, NODE, NULL }, +/* 129 */ { &node_table[ 125], NULL, &node_table[ 130], + NULL, "mnSystemGroup", 4, NODE, NULL }, +/* 130 */ { &node_table[ 125], NULL, &node_table[ 131], + NULL, "mnDiscoveryGroup", 5, NODE, NULL }, +/* 131 */ { &node_table[ 125], NULL, &node_table[ 132], + NULL, "mnRegistrationGroup", 6, NODE, NULL }, +/* 132 */ { &node_table[ 125], NULL, &node_table[ 133], + NULL, "maAdvertisementGroup", 7, NODE, NULL }, +/* 133 */ { &node_table[ 125], NULL, &node_table[ 134], + NULL, "faSystemGroup", 8, NODE, NULL }, +/* 134 */ { &node_table[ 125], NULL, &node_table[ 135], + NULL, "faAdvertisementGroup", 9, NODE, NULL }, +/* 135 */ { &node_table[ 125], NULL, &node_table[ 136], + NULL, "faRegistrationGroup", 10, NODE, NULL }, +/* 136 */ { &node_table[ 125], NULL, &node_table[ 137], + NULL, "haRegistrationGroup", 11, NODE, NULL }, +/* 137 */ { &node_table[ 125], NULL, NULL, + NULL, "haRegNodeCountersGroup", 12, NODE, NULL }, +/* 138 */ { &node_table[ 124], &node_table[ 139], NULL, + NULL, "mipCompliances", 2, NODE, NULL }, +/* 139 */ { &node_table[ 138], NULL, NULL, + NULL, "mipCompliance", 1, NODE, NULL }, +/* 140 */ { &node_table[ 3], NULL, &node_table[ 141], + NULL, "experimental", 3, NODE, NULL }, +/* 141 */ { &node_table[ 3], &node_table[ 142], &node_table[ 151], + NULL, "private", 4, NODE, NULL }, +/* 142 */ { &node_table[ 141], &node_table[ 143], + NULL, NULL, "enterprises", 1, NODE, NULL }, +/* 143 */ { &node_table[ 142], &node_table[ 144], + NULL, NULL, "sun", 42, NODE, NULL }, +/* 144 */ { &node_table[ 143], &node_table[ 145], + NULL, NULL, "products", 2, NODE, NULL }, +/* 145 */ { &node_table[ 144], &node_table[ 146], + NULL, NULL, "messaging", 8, NODE, NULL }, +/* 146 */ { &node_table[ 145], &node_table[ 147], &node_table[ 150], + NULL, "agents", 1, NODE, NULL }, +/* 147 */ { &node_table[ 146], NULL, &node_table[ 148], + NULL, "snmpx400d", 1, NODE, NULL }, +/* 148 */ { &node_table[ 146], NULL, &node_table[ 149], + NULL, "snmpxapiad", 2, NODE, NULL }, +/* 149 */ { &node_table[ 146], NULL, NULL, + NULL, "snmpx500d", 3, NODE, NULL }, +/* 150 */ { &node_table[ 145], NULL, NULL, + NULL, "private-mibs", 2, NODE, NULL }, +/* 151 */ { &node_table[ 3], NULL, &node_table[ 152], + NULL, "security", 5, NODE, NULL }, +/* 152 */ { &node_table[ 3], &node_table[ 153], NULL, + NULL, "snmpV2", 6, NODE, NULL }, +/* 153 */ { &node_table[ 152], NULL, &node_table[ 154], + NULL, "snmpDomains", 1, NODE, NULL }, +/* 154 */ { &node_table[ 152], NULL, &node_table[ 155], + NULL, "snmpProxys", 2, NODE, NULL }, +/* 155 */ { &node_table[ 152], NULL, NULL, + NULL, "snmpModules", 3, NODE, NULL }, +{ NULL, NULL, NULL, NULL, NULL, 0, 0, NULL } +}; +int node_table_size = 156; diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/thq.c b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/thq.c new file mode 100644 index 0000000000..84fb3689c7 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/thq.c @@ -0,0 +1,645 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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: thq.c + * + * This file contains all of the routines used for thread + * queue management. Thread queue management provides an + * interface for an application to dispatch processing of a + * data object to a pool of threads. + */ +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <signal.h> +#include <pthread.h> +#include <unistd.h> + +#include "thq.h" + +#define DEFAULT_MIN_THREADS 10 +#define DEFAULT_MAX_THREADS 100 + +/* + * Function: tq_alloc + * + * Arguments: action - Pointer to the function that new threads + * must call. + * end - Pointer to a function that will be called + * if threads are being killed (optional). + * arg - Pointer that will be passed as an argument + * to new threads created (optional). + * shutdown - Pointer to the shutdown flag. If this + * is provided, if the pointer contains a + * non-zero value, the thread queueing system + * will assume that the process is shutting + * down (optional). + * max - The maximum number of threads + * min - The minimum number of threads + * + * Description: This function is used to create the thread + * queue. The end, arg and shutdown parameters + * MAY be set to NULL. If the max and min are + * not provided, we will use our own defaults. + * + * Once the thread queue has been allocated, we + * will initialize it, and init the the lock and + * condition variables. + * + * Returns: Upon successful completion, the function will + * return a pointer to a thread queue, otherwise + * NULL + */ +tqTp +tq_alloc(PFP action, PFP2 end, void *arg, int *shutdown, int max, int min, + boolean_t cleanup) +{ + tqTp queue; + if (action == NULL) { + /* no function passed, error */ + errno = EINVAL; + return (NULL); + } /* end if */ + /* if those parameters are not passed, take default ones */ + if (max <= 0) max = DEFAULT_MAX_THREADS; + if (min <= 0) min = DEFAULT_MIN_THREADS; + queue = (tqTp) calloc(1, sizeof (tqT)); + if (queue == NULL) { + return (NULL); + } /* end if */ + if (shutdown == NULL) { + shutdown = (int *)calloc(1, sizeof (int)); + if (shutdown == NULL) { + free(queue); + return (NULL); + } /* end if */ + queue->shutalloc = 1; + } + if (queue != NULL && shutdown != NULL) { + /* + * The wd_mask mechanism is used to accelerate the search of + * a "hole" in the queue->tid[] structure whenever we needed + * to create a new thread and to accelerate the search of a + * tid in the queue->tid[] structure whenever we needed to + * end a thread. The previous code(i.e., wd_mask = 0) was + * always parsing this structure sequentially with the + * consequent problems: + * + * + in thr creations, "holes" where not uniformly distributed + * through the queue->tid[] structure BUT condensed at the end + * of it. + * + * + in thr_ ends, finding the thread tid associated to the + * thread to be ended was not optimal + * + * With the wd_mask mechanism, on the contrary: + * + * + in thr creations, the new assigned tid is itself used + * for the indexation on the queue->tid[] and stored at the + * first "hole" found from that position. If we get to + * queue->tid[MAX], we round in circle and come back to + * queue->tid[0] + * + * + in thr_deletions, the old pid is itself used for the + * indexation on the queue->tid[], accelerating the search. + * + * This mechanism is much faster than the old one, specially + * considering that, as tid assignments are(were! when not + * detached) sequential, if the queue->tid[] contains 256 + * elements, by the time the thread with tid 259 will be + * created there are enormous chances that the thread(259-256 + * = 3) with tid 3 has already ended, hence, finding a + * "hole" in the queue->tid[] structure. + */ + queue->wd_mask = 0; + queue->doit = action; + queue->endit = end; + queue->arg = arg; + queue->shutdown = shutdown; + queue->max_thr = max; + queue->min_thr = min; + queue->cleanup = cleanup; + + if ((max << 1) < 32) { + queue->tids = (pthread_t *)calloc(32, + sizeof (pthread_t)); + queue->wd_mask = 0x1F; + } else if ((max << 1) < 64) { + queue->tids = (pthread_t *)calloc(64, + sizeof (pthread_t)); + queue->wd_mask = 0x3F; + } else if ((max << 1) < 128) { + queue->tids = (pthread_t *)calloc(128, + sizeof (pthread_t)); + queue->wd_mask = 0x7F; + } else if ((max << 1) < 256) { + queue->tids = (pthread_t *)calloc(256, + sizeof (pthread_t)); + queue->wd_mask = 0xFF; + } else if ((max << 1) < 512) { + queue->tids = (pthread_t *)calloc(512, + sizeof (pthread_t)); + queue->wd_mask = 0x01FF; + } else if ((max << 1) < 1024) { + queue->tids = (pthread_t *)calloc(1024, + sizeof (pthread_t)); + queue->wd_mask = 0x03FF; + } else if ((max << 1) < 2048) { + queue->tids = (pthread_t *)calloc(2048, + sizeof (pthread_t)); + queue->wd_mask = 0x07FF; + } else if (max < 4096) { + queue->tids = (pthread_t *)calloc(4096, + sizeof (pthread_t)); + queue->wd_mask = 0x0FFF; + } else if (max < 8192) { + queue->tids = (pthread_t *)calloc(8192, + sizeof (pthread_t)); + queue->wd_mask = 0x1FFF; + } else if (max < 16384) { + queue->tids = (pthread_t *)calloc(16384, + sizeof (pthread_t)); + queue->wd_mask = 0x3FFF; + } else { + queue->tids = (pthread_t *)calloc(max, + sizeof (pthread_t)); + } + + if (queue->tids == NULL) { + if (queue->shutalloc) { + free(shutdown); + } /* end if */ + free(queue); + return (NULL); + } /* end if */ + (void) pthread_mutex_init(&(queue->lock), NULL); + (void) pthread_cond_init(&(queue->cond), NULL); + } /* end if */ + return (queue); +} + + +/* + * Function: dump_queue + * + * Arguments: queue - Pointer to the thread queue + * + * Description: This function is provided for debugging purposes + * but is not currently used in the code, and will + * print out the contents of the thread queue. + * + * Returns: + */ +#ifndef lint +void +dump_queue(tqTp queue) +{ + tq_listTp cur; + (void) printf("first %p, last %p, ", (void *)queue->first, + (void *)queue->last); + for (cur = queue->first; cur; cur = cur->next) { + (void) printf("%p:%p ", (void *)cur, (void *)cur->arg); + } /* end for */ + (void) printf("\n"); +} +#endif + +/* + * Function: timedthread + * + * Arguments: arg - Pointer to an argument that will be + * provided to the new thread. + * + * Description: This strange function will sleep for 4 seconds + * before calling the thread callback routine. + * + * Returns: should never return. + */ +static void +timedthread(void * arg) +{ + tqTp queue = (tqTp)arg; + + (void) sleep(4); + (void) (*(queue->doit))(queue->arg); +} + +/* + * Function: create_new_thread + * + * Arguments: queue - Pointer to the thread queue + * timer - Determines whether we need to + * wait before we call the new + * thread. + * + * Description: This function is used to create a new + * thread. If the number of threads waiting + * is smaller than the number of items in + * our queue, and we have not reached our + * maximum number of threads, a new thread + * will be created. + * + * Returns: int, 0 if successful + */ +static int +create_new_thread(tqTp queue, int timer) +{ + int i; + pthread_t tid; + + if (queue->thr_waiting < queue->queue_size && + queue->nb_thr < queue->max_thr) { + /* create a thread to manage this request */ + ++(queue->nb_thr); + if (timer) { + if (pthread_create(&tid, NULL, + (void *(*)())timedthread, queue) != 0) { + return (-1); + } /* end if */ + } /* end if */ + else if (pthread_create(&tid, NULL, + (void *(*)())queue->doit, queue->arg) != 0) { + return (-1); + } /* end if */ + + if (pthread_detach(tid)) { + /* + * Unable to detach the thread, let's kill it. + */ + (void) pthread_cancel(tid); + } + + /* + * put the thread id into the saved array for the + * watchdog mechanism + */ + if (queue->wd_mask) { + int htid = tid & queue->wd_mask; + for (i = htid; i < queue->wd_mask; ++i) { + if (queue->tids[i] == 0) { + queue->tids[i] = tid; + break; + } /* end if */ + } /* end for */ + if (i == queue->wd_mask) { + for (i = 0; i < htid; ++i) { + if (queue->tids[i] == 0) { + queue->tids[i] = tid; + break; + } /* end if */ + } /* end for */ + } + } else { + for (i = 0; i < queue->max_thr; ++i) { + if (queue->tids[i] == 0) { + queue->tids[i] = tid; + break; + } /* end if */ + } /* end for */ + } + } /* end if */ + return (0); +} + +/* + * Function: tq_queue + * + * Arguments: queue - Pointer to the thread queue + * arg - Pointer to object to be processed + * + * Description: queue an action to be done in the arg queue + * and signal any waiting thread that something + * is to be processed. If we notice that we've + * reached our maximum number of threads, and no + * threads are in the waiting state, we will + * make sure that all threads stil exist. + * + * if arg is null, special case, just send the signal + * (probably in case of shutdown) + * + * Returns: int, 0 if successful + */ +int +tq_queue(tqTp queue, void *arg) +{ + tq_listTp cur; + int i; + static int times_called = 0; + static int gc = 0; + + if (!gc) { + if ((++times_called) >= (queue->max_thr >> 1)) { + times_called = 0; + gc = 1; + } + } + + if (queue == NULL) { + return (0); + } /* end if */ + if (*(queue->shutdown) || queue->stopping) { + /* + * shutdown condition, broadcast to all the threads waiting to + * terminate them + * and refuse new stuff in the queue + */ + (void) pthread_cond_broadcast(&(queue->cond)); + return (-1); + } + if (arg) { + if ((cur = (tq_listTp)calloc(1, sizeof (tq_listT))) == NULL) { + return (-1); + } /* end if */ + cur->arg = arg; + (void) pthread_mutex_lock(&(queue->lock)); + if (queue->last) { + queue->last->next = cur; + } /* end if */ + queue->last = cur; + cur->next = 0; + if (queue->first == NULL) { + queue->first = cur; + } /* end if */ + ++(queue->queue_size); + if (queue->thr_waiting == 0 && + queue->nb_thr == queue->max_thr && gc) { + /* + * Since it is possible that some threads have exited + * by themselves, if we reach the maximum number of + * threads, we will kill with signal 0, which simply + * ensures that the thread is still valid. If the + * thread is no longer valid, we will free the entry + * in the queue. + */ + int max; + gc = 0; + + max = (queue->wd_mask) ? queue->wd_mask : + queue->max_thr; + + for (i = 0; i < max; ++i) { + if (queue->tids[i] != 0) { + if (pthread_kill(queue->tids[i], 0)) { + queue->tids[i] = 0; + --(queue->nb_thr); + } /* end if */ + } /* end if */ + } /* end for */ + } /* end if */ + /* + * if size of the queue > nb of thread waiting and we + * didn't reach the maximum number of threads, create a + * new one + */ + if (create_new_thread(queue, 0)) { + return (-1); + } + } /* end if */ + else + (void) pthread_mutex_lock(&(queue->lock)); + /* just signal one of the waiting threads */ + (void) pthread_cond_signal(&(queue->cond)); + (void) pthread_mutex_unlock(&(queue->lock)); + return (0); +} + +/* + * Function: tq_end_thread + * + * Arguments: queue - Pointer to the thread queue + * endit_arg - parameter to be passed to + * the thread shutdown function. + * + * Description: This function is called when a thread + * needs to be shutdown. if a termination + * function was provided during tq_alloc(), + * we will call it with the argument provided. + * + * If the shutdown flag is not set, we will + * create another thread, otherwise we will + * send a broadcast that we are shutting down. + * + * Returns: + */ +static void +tq_end_thread(tqTp queue, void * endit_arg) +{ + pthread_t tid = pthread_self(); + int i; + /* + * call the finish function of the thread + */ + if (queue->endit) { + (void) (*(queue->endit))(queue->arg, endit_arg); + } /* end if */ + + if (queue->wd_mask) { + int htid = tid & queue->wd_mask; + for (i = htid; i < queue->wd_mask; ++i) { + if (queue->tids[i] == tid) { + queue->tids[i] = 0; + break; + } /* end if */ + } /* end for */ + if (i == queue->wd_mask) { + for (i = 0; i < htid; ++i) { + if (queue->tids[i] == tid) { + queue->tids[i] = 0; + break; + } /* end if */ + } /* end for */ + } + } else { + for (i = 0; i < queue->max_thr; ++i) { + if (queue->tids[i] == tid) { + queue->tids[i] = 0; + break; + } /* end if */ + } /* end for */ + } + + /* + * It is possible that while we started to shutdown, a new item + * showed up on the queue. By calling create_new_thread() we + * will create such a thread, only if necessary. + */ + if (!*(queue->shutdown)) + (void) create_new_thread(queue, 1); + /* + * and terminate the thread + */ + if (*(queue->shutdown)) { + /* shutdown condition, warn the waiting function if any */ + (void) pthread_cond_broadcast(&(queue->cond)); + } + /* + * update number of active threads + */ + --(queue->thr_waiting); + --(queue->nb_thr); + /* + * unlock the queue + */ + (void) pthread_mutex_unlock(&(queue->lock)); + pthread_exit(0); +} /* end static void tq_end_thread */ + +/* + * Function: tq_dequeue + * + * Arguments: queue - Pointer to the thread queue + * endit_arg - parameter to be passed to + * the thread shutdown function. + * + * Description: This function is called by the threads + * to retrieve an object to process. If + * the caller ends up waiting for 30 seconds + * without processing anything, we will + * terminate the thread. + * + * Returns: a pointer to an object to process taken + * from the queue. + */ +void * +tq_dequeue(tqTp queue, void * endit_arg) +{ + tq_listTp cur; + void * arg; + + if (queue == NULL) { + return (NULL); + } /* end if */ + (void) pthread_mutex_lock(&(queue->lock)); + ++(queue->thr_waiting); + /* dump_queue(queue); */ + while (!*(queue->shutdown)) { + /* + * if something in the queue, dequeue it and return the + * action to be done + */ + if (queue->first) { + cur = queue->first; + queue->first = queue->first->next; + if (queue->first == NULL) { + queue->last = NULL; + if (queue->stopping) { + (void) pthread_cond_broadcast( + &(queue->cond)); + } /* end if */ + } /* end if */ + --(queue->queue_size); + --(queue->thr_waiting); + (void) pthread_mutex_unlock(&(queue->lock)); + arg = cur->arg; + free(cur); + return (arg); + } else { + timestruc_t to; + int rc; + to.tv_sec = 30; + to.tv_nsec = 0; + /* + * wait for the condition arg_loop to be set + * or a signal occurs, or a timeout + */ + rc = pthread_cond_reltimedwait_np(&(queue->cond), + &(queue->lock), &to); + if ((rc == ETIME || rc == ETIMEDOUT) && + queue->nb_thr > queue->min_thr && + queue->cleanup == _B_TRUE) { + /* + * we don't want to keep this thread alive + * call shutdown function, release the lock + * and exit + */ + tq_end_thread(queue, endit_arg); + } + } /* end if */ + } /* end while */ + /* + * shutdown condition + * + * end the thread + * call shutdown function, release the lock and exit + */ + tq_end_thread(queue, endit_arg); + return (NULL); /* never called, just here for the compiler */ +} + +/* + * Function: tq_shutdown + * + * Arguments: queue - Pointer to the thread queue + * immediate - shutdown immediately flag + * + * Description: This function is called to free the thread + * queue, and to kill all threads that were + * allocated as a result of the creation of the + * thread queue. If the immediate flag is set + * to non-zero, we will kill all threads + * immediately, otherwise we will wait for all + * threads to shutdown. + * + * Returns: + */ +void +tq_shutdown(tqTp queue, int immediate) +{ + timestruc_t to; + (void) pthread_mutex_lock(&(queue->lock)); + queue->stopping = 1; + if (!immediate) { + while (queue->first != NULL && *(queue->shutdown) == 0) { + to.tv_sec = 1; + to.tv_nsec = 0; + (void) pthread_cond_reltimedwait_np(&(queue->cond), + &(queue->lock), + &to); + } + } /* end if */ + + /* + * shutdown condition, broadcast to all the threads waiting to + * terminate them + */ + *(queue->shutdown) = 1; + while (queue->nb_thr > 0) { + (void) pthread_cond_broadcast(&(queue->cond)); + to.tv_sec = 1; + to.tv_nsec = 0; + (void) pthread_cond_reltimedwait_np(&(queue->cond), + &(queue->lock), &to); + } /* end while */ + free(queue->tids); + if (queue->shutalloc) { + free(queue->shutdown); + } /* end if */ + free(queue); +} diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/thq.h b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/thq.h new file mode 100644 index 0000000000..90c190ece7 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/thq.h @@ -0,0 +1,111 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999-2001 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ifndef _THQ_H +#define _THQ_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * This file contains the definitions for the thread + * management module (thq.h). + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <pthread.h> + +typedef void * (*PFP)(void *); + +typedef void * (*PFP2)(void *, void *); + +typedef struct tq_listS { + void * arg; + struct tq_listS *next; +} tq_listT, * tq_listTp; + +typedef struct { + tq_listTp first; /* first element in the queue */ + tq_listTp last; /* last element in the queue */ + pthread_mutex_t lock; /* queue mutex */ + pthread_cond_t cond; /* queue condition to signal new elements */ + int *shutdown; /* variable to test for shutdown condition */ + int shutalloc; /* was shutdown variable allocated locally */ + int stopping; /* queue is currently stopping */ + int queue_size; /* current size of the queue */ + int nb_thr; /* current nb of threads pocessing the queue */ + int thr_waiting; /* current nb of threads waiting */ + int max_thr; /* max allowed threads to process the queue */ + int min_thr; /* min nb of threads to keep alive */ + int wd_mask; /* Watchdog mask */ + boolean_t cleanup; /* Will we kill inactive threads */ + PFP doit; /* function to call to process the queue */ + PFP2 endit; /* function called before to end the thread */ + void *arg; /* argument to pass to the doit/endit func. */ + pthread_t *tids; /* array of thread ids for watchdog */ +} tqT, * tqTp; + +extern tqTp tq_alloc(PFP, /* function to process the queue */ + PFP2, /* function called before to end */ + void *, /* arg passed to both functions */ + int *, /* shutdown variable to test */ + int, /* max allowed threads */ + int, /* min allowed threads */ + boolean_t); /* If TRUE all inactive threads are killed */ + +extern int tq_queue(tqTp, /* pointer to the queue */ + void *); /* element to be queued */ + +/* + * tq_dequeue returns the first "arg" passed to tq_queue + */ +extern void * tq_dequeue(tqTp, /* pointer to the queue */ + void *); /* pointer to "shutdown" arguments */ + +/* + * tq_shutdown, shutdown the queue (alternate way to shutdown if you don't + * have a global shutdown integer + * + * shutdown can be immediate (1) or delayed until there is nothing more + * in the queue (immediate = 0) + * + * when you call this function, no more argument can be queued using + * tq_queue. + * + * when tq_dequeue returns, the queue pointer is not allocated anymore + * + */ +extern void tq_shutdown(tqTp, /* pointer to the queue */ + int); /* 1: don't wait, 0: wait for queue */ + /* to be empty */ + +#ifdef __cplusplus +} +#endif + +#endif /* _THQ_H */ diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/utils.c b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/utils.c new file mode 100644 index 0000000000..c5e08f525a --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.lib/mipagent/utils.c @@ -0,0 +1,913 @@ +/* + * Copyright (c) 1999-2001 by Sun Microsystems, Inc. + * All rights reserved. + */ + +/* + * 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: utils.c + * + * This file contains the miscellaneous routines + * that don't seem to belong anywhere else, such + * as randomizers, address conversion, character + * manipulation, etc. + */ + +#include <stdio.h> +#include <string.h> +#include <sys/time.h> +#include <syslog.h> +#include <stdlib.h> +#include <sys/types.h> +#include <ctype.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> + +#include "mip.h" +#include "agent.h" +#include "auth.h" + +#define SECONDS_IN_A_DAY 86400 +#define NTP_ADJUSTMENT (SECONDS_IN_A_DAY *(((uint32_t)365*70) + 17)) + +#define _POSIX_THREAD_SAFE_FUNCTIONS 1 + +extern int logVerbosity; + +/* --------------------- debug utils ------------------------- */ +/* + * Function: hexdump + * + * Arguments: message, buffer, length + * + * Description: This function will dump out a buffer to stderr in hex and + * ascii. It is usefull in debugging. + * + * Returns: void + * + */ +int +hexdump(char *message, unsigned char *buffer, int length) +{ + int i; + char text[17]; + char TmpBuf[30]; + char output[200]; + int offset = 0; + int currBytes; + int result; + static pthread_mutex_t hexdumpMutex = PTHREAD_MUTEX_INITIALIZER; + + if (!length) { + /* don't waste our time with empty buffers */ + return (0); + } + + result = pthread_mutex_lock(&hexdumpMutex); + if (result) { + (void) fprintf(stderr, "Hexdump: Unable to unlock mutex"); + return (-1); + } + + text[16] = 0; /* Null our buffer, so we only have to do it once */ + output[0] = 0; + + (void) fprintf(stderr, "%s:\n", message); + + /* for each line . . */ + if (length <= 16) + currBytes = length; + else + currBytes = 16; + length -= currBytes; + + while (currBytes > 0) { + (void) sprintf(TmpBuf, "0x%08x: ", offset); + (void) strcat(output, TmpBuf); + + for (i = 0; i < currBytes; i++) { + (void) sprintf(TmpBuf, "%02x ", buffer[offset+i]); + (void) strcat(output, TmpBuf); + if (i == 7) + (void) strcat(output, " "); + text[i] = isprint(buffer[offset+i]) ? + buffer[offset + i] : '.'; + } + + for (i = currBytes; i < 16; i++) { + (void) strcat(output, " "); + if (i == 7) + (void) strcat(output, " "); + text[i] = ' '; + } + + (void) strcat(output, "| "); + (void) strcat(output, text); + (void) fprintf(stderr, "%s\n", output); + output[0] = 0; + offset += currBytes; + + if (length <= 16) + currBytes = length; + else + currBytes = 16; + length -= currBytes; + } + + result = pthread_mutex_unlock(&hexdumpMutex); + if (result) { + (void) fprintf(stderr, "Hexdump: Unable to unlock mutex"); + } + + return (0); +} /* hexdump */ + + + +/* --------------------- Platform-specific utilities -------------------- */ + +/* + * Function: randomInit + * + * Arguments: + * + * Description: initialize the random number generator + * + * Returns: + */ +void +randomInit() +{ + struct timeval time; + + if (gettimeofday(&time, 0) < 0) { + syslog(LOG_INFO, + "Gettimeofday failed in randominit(), using fixed seed."); + srand48(181067); + } else { + srand48(time.tv_sec); + } +} + + +/* + * Function: randomLong + * + * Arguments: + * + * Description: This function is used to retrieve a random + * 32-bit value. + * + * Returns: random value + */ +uint32_t +getRandomValue() +{ + return ((unsigned long) lrand48()); +} + +/* + * Function: CurrentTimeNTPSec + * + * Arguments: + * + * Description: Returns the number of seconds elapsed since + * Jan 1, 1990. Only the higher 32 bits of the 64-bit + * quantity representing current time in NTP format. + * + * Returns: uint32_t - the number of seconds since Jan 1, 1990. + */ +uint32_t +CurrentTimeNTPSec() +{ + struct timeval time; + + if (gettimeofday(&time, 0) < 0) { + syslog(LOG_ERR, + "Error: gettimeofday failed in CurrentTimeNTPSec()"); + return (0); + } else { + return ((uint32_t)(time.tv_sec + NTP_ADJUSTMENT)); + } +} + + +/* + * Function: sprintTime + * + * Arguments: buffer - Pointer to output buffer + * buflen - Length of output buffer + * + * Description: Print the current time in buffer. If buffer is large + * enough, the current time is printed in the format: + * Fri Sep 13 00:00:00 1986\0 + * + * This function is used for debugging purposes only. + * + * Returns: If successful, a pointer to the buffer is returned, otherwise + * NULL is returned. + */ +char * +sprintTime(char *buffer, int buflen) +{ + struct timeval clock; + + if (buflen >= 26) { + (void) gettimeofday(&clock, 0); +#ifndef lint + /* Lint has a problem picking the right one */ +#ifdef _POSIX_THREAD_SAFE_FUNCTIONS + ctime_r((time_t *)&(clock.tv_sec), buffer); +#else + ctime_r((time_t *)&(clock.tv_sec), buffer, buflen); +#endif /* _POSIX_THREAD_SAFE_FUNCTIONS */ +#endif /* lint */ + buffer[24] = '\0'; + return (buffer); + } else { + return (""); + } +} + + +/* + * Function: sprintRelativeTime + * + * Arguments: buffer - Pointer to output buffer + * buflen - Length of output buffer + * + * Description: Print relative time since first call to this routine + * in the form: + * seconds.xxxxxx\0 + * + * This function is used for debugging purposes only. + * + * Returns: If successful, a pointer to the buffer is returned, otherwise + * NULL is returned. + */ +char +*sprintRelativeTime(char *buffer, int buflen) +{ + static int i = 0; + static struct timeval starttime; + static struct timeval now; + time_t diff_sec; + useconds_t diff_usec; + + if (buflen < 20) { + return (""); + } + + if (i == 0) { + (void) gettimeofday(&starttime, 0); + (void) sprintf(buffer, "%d.%06d", 0, 0); + i = 1; + } else { + (void) gettimeofday(&now, 0); + diff_sec = now.tv_sec - starttime.tv_sec; + if (now.tv_usec < starttime.tv_usec) { + diff_usec = 1000000 + now.tv_usec - starttime.tv_usec; + diff_sec -= 1; + } else { + diff_usec = now.tv_usec - starttime.tv_usec; + } + (void) sprintf(buffer, "%ld.%06d", diff_sec, diff_usec); + } + + return (buffer); +} + + +/* --------------------- Platform-independent utilities -------------------- */ + +/* + * Function: inChecksum + * + * Arguments: addr - Pointer to address + * len - length of address + * + * Description: Compute the internet checksum for len number of + * bytes starting at addr + * + * Returns: a unsigned short containing the checksum. + */ +unsigned short +inChecksum(unsigned short *addr, int len) +{ + register int nleft = len; + register unsigned short *w = addr; + register unsigned short answer; + unsigned short odd_byte = 0; + register 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) { + *(unsigned char *)(&odd_byte) = *(unsigned char *)w; + sum += odd_byte; + } + + /* + * add back carry outs from top 16 bits to low 16 bits + */ + sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ + sum += (sum >> 16); /* add carry */ + answer = ~sum; /* truncate to 16 bits */ + return (answer); +} + + +/* + * Function: hwAddrWrite + * + * Arguments: hwaddr - Pointer to the string containing + * the MAC address + * hwStr - Pointer to the output buffer + * + * Description: This function will convert a MAC address + * to a text format (e.g. aa:bb:cc:dd:ee:ff). + * + * Returns: a pointer to the output buffer + */ +char * +hwAddrWrite(unsigned char hwaddr[], char *hwStr) { + + (void) sprintf(hwStr, "%x:%x:%x:%x:%x:%x", + (unsigned char) hwaddr[0], + (unsigned char) hwaddr[1], + (unsigned char) hwaddr[2], + (unsigned char) hwaddr[3], + (unsigned char) hwaddr[4], + (unsigned char) hwaddr[5]); + + return (hwStr); +} + + +/* + * Function: ntoa + * + * Arguments: addr_long - Address + * addr_string - Pointer to the output buffer + * + * Description: Converts the long value in addr_long to an internet + * address of the type a.b.c.d in addr_string and + * returns a pointer to addr_string. + * + * NOTE: addr_long is in network byte order and + * addr_string is assumed to be long enough (at + * least INET_ADDRSTRLEN in length). + * + * By having the caller supply its own buffer, we try + * to avoid problems associated with multiple threads + * writing the same buffer concurrently. + * + * Returns: the pointer to the output buffer + */ +char * +ntoa(uint32_t addr_long, char *addr_string) +{ + uint32_t temp; + + temp = ntohl(addr_long); + (void) sprintf(addr_string, "%d.%d.%d.%d", + ((temp >> 24) & 0xff), ((temp >> 16) & 0xff), + ((temp >> 8) & 0xff), (temp & 0xff)); + return (addr_string); +} + + + + +/* + * Function: hexDigit + * + * Arguments: c - character + * + * Description: This function is used to determine if a character + * is a valid hex digit, and returns the decimal + * equivalent. + * + * Returns: int, -1 if the character is not a valid hex digit. + * Otherwise, the decimal value is returned. + */ +static int +hexDigit(int c) +{ + if (c >= '0' && c <= '9') + return (c - '0'); + if (c >= 'a' && c <= 'f') + return (c - 'a' + 10); + if (c >= 'A' && c <= 'F') + return (c - 'A' + 10); + + return (-1); +} + + +/* + * Function: hexConvert + * + * Arguments: key - Pointer to output buffer + * len - length of key + * keystr - Pointer to input buffer containing the key. + * + * Description: Convert a string of hexadecimal digits into an array + * of len bytes each containing a byte represented by a + * pair of hex digits, e.g. keystr="12abC4De" is converted + * to key[]={0x12, 0xab, 0xC4, 0xDe} key has space for + * len bytes only. + * + * Returns: int, Returns -1 if the key has invalid data + */ +int +hexConvert(char *key, int len, char *keystr) +{ + int i, d1, d2; + + for (i = 0; i < len; ++i) { + if ((d1 = hexDigit(*keystr++)) == -1) + return (-1); + if ((d2 = hexDigit(*keystr++)) == -1) + return (-1); + *key++ = d1*16 + d2; + } + + return (0); +} + + +/* + * Function: prefixLen + * + * Arguments: netmask - Network Mask + * + * Description: Computes prefix length of a network mask. Assumes + * it is the same as the number of bits set to one. + * + * Returns: int, containing the netmask bits. + */ +int +prefixLen(uint32_t netmask) +{ + int len = 0; + + while (netmask) { + len++; + netmask &= (netmask - 1); + } + + return (len); +} + +/* + * Function: printBuffer + * + * Arguments: buffer - Pointer to input buffer + * buflen - Length of data in buffer + * + * Description: Prints a buffer in hexadecimal + * + * Returns: + */ +void +printBuffer(unsigned char buffer[], int buflen) +{ + unsigned int i; + + if (buflen == 6) { + /* Is likely an ethernet address */ + for (i = 0; i < buflen; i++) { + mipverbose(("%02x", buffer[i])); + if (i < (buflen-1)) + mipverbose((":")); + } + } else { + /* Short enough to be printed in one shot */ + if (buflen <= 16) { + for (i = 0; i < buflen; i++) + mipverbose(("%02x", buffer[i])); + } else { + /* Possibly a packet */ + mipverbose(("\t")); + for (i = 0; i < buflen; i++) { + mipverbose(("%02x", buffer[i])); + if ((i % 2) == 1) + mipverbose((" ")); + if ((i % 16) == 15) + mipverbose(("\n\t")); + } + } + } + + (void) fflush(stdout); +} + + +/* + * Function: printMaAdvConfigEntry + * + * Arguments: macep - Pointer to the interface entry. + * p1 - unused + * + * Description: Prints the contents of a MaAdvConfigEntry + * + * Returns: + */ +/* ARGSUSED */ +static boolean_t +printMaAdvConfigEntry(void *entry, uint32_t p1) +{ + MaAdvConfigEntry *macep = entry; + char addr[20]; + + mipverbose(("MaAdvConfigEntry contents:\n")); + mipverbose(("\tInterface: %s\n", macep->maIfaceName)); + mipverbose(("\tAddress : %s\n", ntoa(macep->maIfaceAddr, addr))); + mipverbose(("\tNetmask : %s\n", ntoa(macep->maIfaceNetmask, addr))); + if ((macep->maIfaceFlags & IFF_POINTOPOINT) == 0) { + mipverbose(("\tHWaddr : ")); + if (logVerbosity > 2) printBuffer(macep->maIfaceHWaddr, 6); + mipverbose(("\n")); + } + mipverbose(("\tAdv seq# : %d\n", macep->maAdvSeqNum)); + mipverbose(("\tFlags : %x (RBHFMGV_)\n", macep->maAdvServiceFlags)); + mipverbose(("\tPrefix : %s\n", + macep->maAdvPrefixLenInclusion ? "Yes" : "No")); + + return (_B_TRUE); +} + +#ifdef FIREWALL_SUPPORT +/* + * Function: printProtectedDomainInfo + * + * Arguments: domainInfo - Pointer to the Domain Info + * entry. + * + * Description: Prints information about a DomainInfo + * + * Returns: + */ +void +printProtectedDomainInfo(DomainInfo domainInfo) +{ + int i; + char addrstr1[INET_ADDRSTRLEN], addrstr2[INET_ADDRSTRLEN]; + + if (domainInfo.addrIntervalCnt > 0) { + mipverbose(("Protected Domain Info: Address - Netmask pairs\n")); + for (i = 0; i < domainInfo.addrIntervalCnt; i++) { + mipverbose((" %s/%s\n", + ntoa(domainInfo.addr[i], addr1), + ntoa(domainInfo.netmask[i], addr2))); + } + } + + if (domainInfo.firewallCnt > 0) { + mipverbose(("No. of firewalls : %d\n", domainInfo.firewallCnt)); + mipverbose(("List of firewall addresses : ")); + for (i = 0; i < domainInfo.firewallCnt; i++) { + mipverbose(("%s ", ntoa(domainInfo.fwAddr[i], addr1))); + } + } + + mipverbose(("\n")); + fflush(stdout); +} +#endif /* FIREWALL_SUPPORT */ + +/* + * Function: printMaAdvConfigHash + * + * Arguments: htbl - Pointer to the Hash Table + * + * Description: This function will print information about + * all interfaces in the hash. + * + * Returns: + */ +void +printMaAdvConfigHash(struct hash_table *htbl) +{ + + mipverbose(("------ MaAdvConfigHash contents ------\n")); + + getAllHashTableEntries(htbl, printMaAdvConfigEntry, LOCK_READ, 0, + _B_FALSE); +} + +#if 0 +/* + * Function: printFaVisitorEntry + * + * Arguments: favep - Pointer to the visitor entry + * + * Description: Prints the contents of a FaVisitorEntry. This + * function is not currently in use today, but will + * if static visitor entries are implemented. + * + * Returns: + */ +/* ARGSUSED */ +static boolean_t +printFaVisitorEntry(void *entry, uint32_t p1) +{ + FaVisitorEntry *favep = entry; + time_t currentTime; + char addr[INET_ADDRSTRLEN]; + struct ether_addr ether; + + mipverbose(("FaVisitorEntry contents:\n")); + mipverbose(("\tVisitor : %s\n", ntoa(favep->faVisitorAddr, addr))); + mipverbose(("\tIface : %s\n", + ntoa(favep->faVisitorIfaceAddr, addr))); + mipverbose(("\tStatus : %s\n", (favep->faVisitorRegIsAccepted ? + "Accepted" : "Pending"))); + mipverbose(("\tTimeGrant: %ld\n", favep->faVisitorTimeGranted)); + GET_TIME(currentTime); + mipverbose(("\tTimeLeft : %ld\n", + currentTime - favep->faVisitorTimeExpires)); + mipverbose(("\tHomeAddr : %s\n", ntoa(favep->faVisitorHomeAddr, addr))); + mipverbose(( + "\tHomeAgent: %s\n", ntoa(favep->faVisitorHomeAgentAddr, addr))); + mipverbose(("\tCOAddr : %s\n", ntoa(favep->faVisitorCOAddr, addr))); + mipverbose(("\tReg Flag : %x (SBDMGV__)\n", favep->faVisitorRegFlags)); + mipverbose(("\tID High : %x\n", favep->faVisitorRegIDHigh)); + mipverbose(("\tID Low : %x\n", favep->faVisitorRegIDLow)); + mipverbose(("\tIf. idx : %d\n", favep->faVisitorInIfindex)); + if (faevp->faVisitorSlla.sdl_data != NULL) { + (void) memcpy(ether.ether_addr_octet, + faevp->faVisitorSlla.sdl_data, ETHERADDRL); + mipverbose(("\tMN SLLA : %s\n", ether_ntoa(ðer))); + } else + mipverbose(("\tMN SLLA : unknown\n")); + return (_B_TRUE); +} + + +/* + * Function: printFaVisitorHash + * + * Arguments: htbl - Pointer to the Hash Table + * + * Description: Prints information about all visitor entries + * in the hash table. This function is not + * currently in use today, but will if static + * visitor entries are implemented. + * + * Returns: + */ +void +printFaVisitorHash(struct hash_table *htbl) +{ + mipverbose(("------ FaVisitorHash contents ------\n")); + + getAllHashTableEntries(htbl, printFaVisitorEntry, LOCK_READ, 0, + _B_FALSE); + +} + + +/* + * Function: printFaUnreachableEntry + * + * Arguments: fauep - Pointer to the unreachable entry. + * + * Description: Prints the contents of a FaUnreachableEntry. + * This function is not currently in use, but could + * be if a feature was implemented that allowed + * blocking of access (statically) to a Home Agent. + * + * Returns: + */ +/* ARGSUSED */ +static boolean_t +printFaUnreachableEntry(void *entry, uint32_t p1) +{ + FaUnreachableEntry *fauep = entry; + char addr[INET_ADDRSTRLEN]; + + mipverbose(("FaUnreachableEntry contents:\n")); + mipverbose(("\tAddr : %s\n", ntoa(fauep->faUnreachableAddr, addr))); + mipverbose(("\tExpires : %ld\n", fauep->faUnreachableTimeExpires)); + return (_B_TRUE); +} + + +/* + * Function: printFaUnreachableHash + * + * Arguments: htbl - Pointer to the Hash Table. + * + * Description: Prints out information about all unreachable + * entries in the hash. + * + * This function is not currently in use, but could + * be if a feature was implemented that allowed + * blocking of access (statically) to a Home Agent. + * + * Returns: + */ +void +printFaUnreachableHash(struct hash_table *htbl) +{ + mipverbose(("------ FaUnreachableHash contents ------\n")); + + getAllHashTableEntries(htbl, printFaUnreachableEntry, LOCK_READ, 0, + _B_FALSE); +} +#endif + +/* Prints the contents of a HaBindingEntry. */ +/* + * Function: printHaBindingEntry + * + * Arguments: habep - Pointer to the Binding Entry + * + * Description: This function will print out the contents + * of a binding entry. This function is not currently + * in use, and could be if static bindings were + * implemented. + * + * Returns: + */ +#ifndef lint +boolean_t +printHaBindingEntry(void *entry, uint32_t p1) +{ + HaBindingEntry *habep = entry; + char addr[INET_ADDRSTRLEN]; + time_t currentTime; + + mipverbose(("HaBindingEntry contents:\n")); + mipverbose(("\tMN addr : %s\n", ntoa(habep->haBindingMN, addr))); + mipverbose(("\tCO addr : %s\n", ntoa(habep->haBindingCOA, addr))); + mipverbose(("\tSrc addr : %s\n", ntoa(habep->haBindingSrcAddr, addr))); + mipverbose(("\tSrc port : %d\n", habep->haBindingSrcPort)); + mipverbose(("\tTimeGrant: %ld\n", habep->haBindingTimeGranted)); + GET_TIME(currentTime); + mipverbose(("\tExpires : %ld\n", + currentTime - habep->haBindingTimeExpires)); + mipverbose(( + "\tReg Flag : %x (SBDMGV__)\n", habep->haBindingRegFlags)); + + return (_B_TRUE); +} + +/* + * Function: printHaBindingHash + * + * Arguments: htbl - Pointer to the Hash Table + * + * Description: This function will print out the contents + * of all binding entries in the hash. This + * function is not currently in use, and could + * be if static bindings were implemented. + * + * Returns: + */ +void +printHaBindingHash(struct hash_table *htbl) +{ + + mipverbose(("------ HaBindingHash contents ------\n")); + + getAllHashTableEntries(htbl, printHaBindingEntry, LOCK_READ, 0, + _B_FALSE); +} + +#endif /* lint */ +/* + * Function: printMSAE + * + * Arguments: msae - Pointer to the Security Assoc Entry + * + * Description: This function will print out the contents of + * a security association entry. + * + * Returns: + */ +static void +printMSAE(MipSecAssocEntry *msae) +{ + mipverbose(("\tMipSecAssocEntry contents:\n")); + mipverbose(("\tSPI %d\n", msae->mipSecSPI)); + mipverbose(("\tAlgo type %d\n", msae->mipSecAlgorithmType)); + mipverbose(("\tAlgo Mode %d\n", msae->mipSecAlgorithmMode)); + mipverbose(("\tKey Len %d\n", msae->mipSecKeyLen)); + mipverbose(("\tReplay method %d\n", msae->mipSecReplayMethod)); +} + + +/* + * Function: printHaMobileNodeEntry + * + * Arguments: hamne - Pointer to the Mobile Node Entry + * + * Description: This function will print the contents of a + * Mobile Node Entry. + * + * Returns: + */ +static boolean_t +printHaMobileNodeEntry(void *entry, uint32_t p1) +{ + HaMobileNodeEntry *hamne = entry; + HaBindingEntry *habep; + MipSecAssocEntry *mnsae; + char addr[INET_ADDRSTRLEN]; + + mipverbose(("HaMobileNodeEntry contents:\n")); + mipverbose(("\tMN addr %s\n", ntoa(hamne->haMnAddr, addr))); + mipverbose(( + "\tHA's Iface Addr %s\n", ntoa(hamne->haBindingIfaceAddr, addr))); + mipverbose(("\tID High: 0x%x\n", hamne->haMnRegIDHigh)); + mipverbose(("\tID Low : 0x%x\n", hamne->haMnRegIDLow)); + mipverbose(("\tMN binding count %d\n", hamne->haMnBindingCnt)); + + habep = hamne->bindingEntries; + + while (habep) { + mipverbose(("\tHaMobileNodeEntry BindingEntry contents:\n")); + mipverbose(("\t\tMN addr : %s\n", ntoa(habep->haBindingMN, + addr))); + mipverbose(("\t\tCO addr : %s\n", ntoa(habep->haBindingCOA, + addr))); + mipverbose(("\t\tSrc addr : %s\n", ntoa(habep->haBindingSrcAddr, + addr))); + mipverbose(("\t\tSrc port : %d\n", habep->haBindingSrcPort)); + mipverbose(( + "\t\tTimeGrant: %ld\n", habep->haBindingTimeGranted)); + mipverbose(("\t\tExpires : %ld\n", + p1 - habep->haBindingTimeExpires)); + mipverbose(("\t\tReg Flag : %x (SBDMGV__)\n", + habep->haBindingRegFlags)); + habep = habep->next; + } + + if ((mnsae = findSecAssocFromSPI(hamne->haMnSPI, + LOCK_READ)) != NULL) { + printMSAE(mnsae); + (void) rw_unlock(&mnsae->mipSecNodeLock); + } + + return (_B_TRUE); +} + + +/* + * Print HaMobileNodeHash contents + */ +/* + * Function: printHaMobileNodeHash + * + * Arguments: htbl - Pointer to the Hash Table + * + * Description: This function will print the contents + * of all Mobile Node Entries in the hash. + * + * Returns: + */ +void +printHaMobileNodeHash(struct hash_table *htbl) +{ + time_t currentTime; + + mipverbose(("------ HaMobileNodeHash contents ------\n")); + + GET_TIME(currentTime); + + getAllHashTableEntries(htbl, printHaMobileNodeEntry, LOCK_READ, + currentTime, _B_FALSE); +} /* printHaMobileNodeHash */ diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/Makefile b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/Makefile new file mode 100644 index 0000000000..7b9e563f6c --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/Makefile @@ -0,0 +1,101 @@ +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 +# +# +# ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1999,2001 by Sun Microsystems, Inc. +# All rights reserved. +# +# cmd/cmd-inet/usr.sbin/mipagentconfig/Makefile +# + +include $(SRC)/cmd/Makefile.cmd +include $(SRC)/cmd/cmd-inet/Makefile.cmd-inet + +PROG= mipagentconfig + +LCLOBJS=addr.o \ + general.o \ + gsp.o \ + utils.o \ + advertisements.o \ + spi.o \ + pool.o \ + mipagentconfig.o + +COMOBJS= conflib.o + +HDRS= addr.h \ + advertisements.h \ + general.h \ + gsp.h \ + mipagentconfig.h \ + pool.h \ + spi.h \ + utils.h + + +OBJS= $(LCLOBJS) $(COMOBJS) + +# Currently used only for linting and style checking +SRCS=$(LCLOBJS:%.o=%.c) $(COMOBJS:%.o=$(CMDINETCOMMONDIR)/%.c) + +# I18n +POFILE=$(PROG)_prog.po +POFILES=$(LCLOBJS:%.o=%.po) + +CPPFLAGS += -I$(CMDINETCOMMONDIR) -D_XOPEN_SOURCE=500 -D__EXTENSIONS__ +CLOBBERFILES += $(PROG) + +# Only root should be able to run mipagentconfig +FILEMODE= 500 + +.KEEP_STATE: + +.PARALLEL: $(OBJS) + +all: $(PROG) + +$(PROG): $(OBJS) + $(LINK.c) -o $@ $(OBJS) $(LDLIBS) + $(POST_PROCESS) + +clean: + $(RM) *.o + +check: $(HDRS:%.h=%.hcheck) $(SRCS:%.c=%.check) + +%.hcheck: %.h + $(DOT_H_CHECK) + +%.check: %.c + $(DOT_C_CHECK) + +install: all $(ROOTUSRSBINPROG) + +$(POFILE): $(POFILES) + $(RM) $@ + cat $(POFILES) > $@ + +include $(SRC)/cmd/Makefile.targ + +lint: lint_SRCS diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/addr.c b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/addr.c new file mode 100644 index 0000000000..77c23ca9d2 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/addr.c @@ -0,0 +1,529 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999 - 2002 by Sun Microsystems, Inc. + * All rights reserved. + */ + + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * This source file contains functions that manupilate addresses. Addresses + * are sections in the config file that look like: + * + * [ Address xxx.xxx.xxx.xxx ] or [ Address foo@bar.com ] + * Type = agent + * SPI = 23 + * Pool = 7 + * + * Valid for "type = agent" entries ONLY (making these valid for type=node + * should be fairly easy): + * IPSecRequest = apply <properties> : permit <properties> + * IPSecReply = apply <properties> : permit <properties> + * IPSecTunnel = apply <properties> : permit <properties> + * IPSecReverseTunnel = apply <properties> : permit <properties> + */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <libintl.h> +#include <conflib.h> +#include <sys/types.h> +#include "mipagentconfig.h" +#include "utils.h" +#include "addr.h" + +/* Private Prototypes */ +static int addrTypeFunc(char *, char *, char *, int, int, char **); +static int ipsecFunc(char *, char *, char *, int, int, char **); + +/* + * This is the function table for the Addresses. All of the addresses + * use general functions found in utils.c, except the Type. + */ +static FuncEntry addrFunctions[] = { + /* TAG, Section, Label, AddFunc, ChangeFunc, DeleteFunc, GetFunc */ + { "SPI", NULL, "SPI", posIntFunc, posIntFunc, posIntFunc, posIntFunc}, + { "Pool", NULL, "Pool", posIntFunc, posIntFunc, posIntFunc, posIntFunc}, + { "Type", NULL, "Type", addrTypeFunc, addrTypeFunc, addrTypeFunc, + addrTypeFunc}, + { "IPSecRequest", NULL, "IPSecRequest", ipsecFunc, ipsecFunc, + ipsecFunc, ipsecFunc}, + { "IPSecReply", NULL, "IPSecReply", ipsecFunc, ipsecFunc, ipsecFunc, + ipsecFunc}, + { "IPSecTunnel", NULL, "IPSecTunnel", ipsecFunc, ipsecFunc, ipsecFunc, + ipsecFunc}, + { "IPSecReverseTunnel", NULL, "IPSecReverseTunnel", ipsecFunc, + ipsecFunc, ipsecFunc, ipsecFunc}, + { NULL, NULL, NULL, NULL, NULL } +}; + + +/* + * Function: addrFunc + * + * Arguments: char *configFile, char *Section, char *Label, int command + * int argc, char *argv[] + * Description: This function will take apart the argc/argv array, check the + * number of parameters, and call the appropriate function + * based on the command code. + * + * Returns: int (zero on success) + */ +int +addrFunc(char *configFile, char *Section, char *Label, int command, + int argc, char *argv[]) +{ + char DestSection[MAX_SECTION_LEN]; + FuncEntry *funcEntry = NULL; + int (*function)(char *, char *, char *, int, int, char **) = NULL; + char *validStrings[] = { + "Node-Default", + NULL + }; + + /* Use Section and label to get rid of lint warnings */ + Section = Label; + + /* ARGV[0] should be the Address */ + if (argc < 1) { + (void) fprintf(stderr, + gettext("Error: address identifier was not specified. " + "Please specify an identifier for the Address section. " + "Identifiers are either a valid IP address, an NAI " + "(e.g. bob@domain.com), or ")); + printValidStrings(validStrings); + (void) fprintf(stderr, ".\n"); + return (-1); + } + + /* Validate Address */ + if (!ipValid(argv[0]) && !naiValid(argv[0])) { + /* Ok not a valid address, check for Defaults */ + if (checkValidStrings(validStrings, argv[0])) { + (void) fprintf(stderr, + gettext("Error: invalid identifier for " + "Address section. Identifier must " + "be a valid IP address, a valid NAI " + "(e.g. bob@domain.com), or ")); + printValidStrings(validStrings); + (void) fprintf(stderr, ".\n"); + return (-1); + } + } + + /* Build our Section */ + (void) sprintf(DestSection, "Address %s", argv[0]); + + /* Finally, look up our functions and call them based on the dest */ + if (argc > 1) { + funcEntry = getFunctions(addrFunctions, argv[1]); + if (!funcEntry) { + (void) fprintf(stderr, + gettext("Error: command '%s' is not valid " + "for %s.\n"), + Command2Str(command), argv[1]); + return (-1); + } + } + + /* Now check the particular function we need. */ + switch (command) { + case Add: + if (argc == 1) { + /* A raw add Warn the user */ + (void) fprintf(stderr, + gettext("Warning: attributes will be created as " + "parameters are added.\n Example: " + "mipagentconfig add addr 192.168.168.1 SPI 5\n " + "will add the address, and add the SPI " + "configuration to it.\n")); + return (0); + } + function = funcEntry->addFunc; + break; + case Change: + if (argc == 1) { + (void) fprintf(stderr, + gettext("Error: cannot change the identifier of an " + "Address section. Delete, and make a new one.\n")); + return (-1); + } + function = funcEntry->changeFunc; + break; + case Delete: + if (argc == 1) { + return DeletePrivateProfileSection(DestSection, + configFile); + } + function = funcEntry->deleteFunc; + break; + case Get: + if (argc == 1) { + sectionDump(configFile, DestSection, + addrFunctions); + return (0); + } + function = funcEntry->getFunc; + break; + } + + /* Print error if this function is not allowed (null in table) */ + if (!function) { + (void) fprintf(stderr, + gettext("Error: <%s> is not valid for '%s' command.\n"), + argv[0], Command2Str(command)); + return (-1); + } + + /* And finally, call function */ + return (function(configFile, DestSection, funcEntry->Label, + command, argc-2, &argv[2])); + +} /* addrFunc */ + +/* + * Function: addrTypeFunc + * + * Arguments: char *configFile, char *Section, char *Label, int command + * int argc, char *argv[] + * Description: This function verifys the Type option in address sections. + * + * Returns: int + */ +static int +addrTypeFunc(char *configFile, char *Section, char *Label, int command, + int argc, char *argv[]) +{ + char buffer[MAX_VALUE_LEN]; + int rc, LabelExists; + char *validStrings[] = { + "Agent", + "Node", + NULL + }; + + /* Check to see if label already exists */ + rc = GetPrivateProfileString(Section, Label, "", buffer, + MAX_VALUE_LEN-1, configFile); + if (!rc) + LabelExists = TRUE; + else + LabelExists = FALSE; + + switch (command) { + case Add: + /* Now, check for the parameters. */ + if (argc != 1) { + (void) fprintf(stderr, + gettext("Error: entry type wasn't specified. " + "Please specify the type of entry for [%s]. " + "The type must be one of ("), Section); + printValidStrings(validStrings); + (void) fprintf(stderr, ").\n"); + return (-1); + } + + if (LabelExists) { + (void) fprintf(stderr, + gettext("Error: %s is already configured in [%s]:\n" + "\t%s = %s\n"), + Label, Section, Label, buffer); + return (-1); + } + if (!checkValidStrings(validStrings, argv[0])) { + /* Add it! */ + rc = WritePrivateProfileString(Section, Label, + argv[0], configFile); + if (rc) { + (void) fprintf(stderr, "%s\n", ErrorString); + return (rc); + } + return (0); + } else { + (void) fprintf(stderr, + gettext("Error: Address type must be one of (")); + printValidStrings(validStrings); + (void) fprintf(stderr, ").\n"); + return (-1); + } + break; + + + case Delete: + if (!LabelExists) { + (void) fprintf(stderr, + gettext("Error: %s is not configured in [%s].\n"), + Label, Section); + return (-1); + } + rc = DeletePrivateProfileLabel(Section, Label, configFile); + if (rc) { + (void) fprintf(stderr, "%s\n", ErrorString); + return (rc); + } + return (rc); + break; + + + case Change: + /* Now, check for the parameters. */ + if (argc != 1) { + (void) fprintf(stderr, + gettext("Error: entry type wasn't specified. " + "Please specify the type [%s] is to be changed to." + " Valid types are one of ("), Section); + printValidStrings(validStrings); + (void) fprintf(stderr, ").\n"); + return (-1); + } + + if (!LabelExists) { + (void) fprintf(stderr, + gettext("Error: %s is not configured in [%s].\n"), + Label, Section); + return (-1); + } + + if (!checkValidStrings(validStrings, argv[0])) { + /* Change it! */ + rc = WritePrivateProfileString(Section, Label, + argv[0], configFile); + if (rc) { + (void) fprintf(stderr, "%s\n", ErrorString); + return (rc); + } + return (0); + } else { + (void) fprintf(stderr, + gettext("Error: type must be one of (")); + printValidStrings(validStrings); + (void) fprintf(stderr, ").\n"); + return (-1); + } + break; + + case Get: + if (!LabelExists) { + (void) fprintf(stderr, + gettext("Error: %s is not configured in [%s].\n"), + Label, Section); + return (-1); + } + (void) printf(gettext("[%s]\n\t%s = %s\n"), + Section, Label, buffer); + return (0); + break; + + + + default: + (void) fprintf(stderr, + gettext("Error: Invalid command code!\n")); + return (-1); + } /* switch (command) */ +} /* addrTypeFunc */ + + +/* + * Function: iposecFunc() + * + * Arguments: char *configFile, char *Section, char *Label, int command + * int argc, char *argv[] + * Description: This function verifys the ipsec properties. + * + * Returns: int + */ +static int +ipsecFunc(char *configFile, char *Section, char *Label, int command, + int argc, char *argv[]) +{ + char buffer[MAX_VALUE_LEN], pbuf[MAX_VALUE_LEN] = "", + *policy, *policyP; + int rc, LabelExists; + extern char *validIPsecAction[]; + + /* Check to see if label already exists */ + rc = GetPrivateProfileString(Section, Label, "", buffer, + MAX_VALUE_LEN-1, configFile); + if (!rc) + LabelExists = TRUE; + else + LabelExists = FALSE; + + /* + * mipagentconfig differs from mipagent here in that the configuration + * is broken into argv[]'s, where as when we read this in mipagent it + * comes in one string. For the sake of common code, we put all the + * argv[]'s into one buffer + */ + for (rc = 0; rc < argc; rc++) { + (void) strcat(pbuf, argv[rc]); + (void) strcat(pbuf, " "); + } + + switch (command) { + case Add: + /* what are we adding? */ + if (argc < 2) { + /* + * Must have at least "<action> {<property>}" = 2. + * Then again, "<action> {<<tag> <alg>>} = 3... + */ + (void) fprintf(stderr, + gettext("Error: IPsec policy is incomplete. " + "Please specify the complete IPsec policy. " + "See ipsec(7p).\n")); + return (-1); + } + + if (LabelExists) { + (void) fprintf(stderr, + gettext("Error: %s is already configured in [%s]:\n" + "\t%s = %s\n"), + Label, Section, Label, buffer); + return (-1); + } + + /* + * Determine if this is a valid policy. Note: we have to do + * this one IPsec Policy at a time. + */ + policy = strdup(pbuf); + policyP = policy; /* strtok() is destructive */ + + while ((policy = strtok(policy, IPSP_SEPARATOR)) != NULL) { + if (isIPsecPolicyValid(policy, NULL) != TRUE) { + (void) fprintf(stderr, + gettext("Error: policy %s is not valid " + "Policy may only contain <"), policy); + (void) printValidStrings(validIPsecAction); + (void) fprintf(stderr, + gettext("> as actions, and valid IPsec" + "<properties>. See ipsec(7P).\n")); + return (-1); + } + policy = NULL; + } + + free(policyP); + + /* Checks out, so add it */ + rc = WritePrivateProfileString(Section, Label, pbuf, + configFile); + + if (rc) { + (void) fprintf(stderr, "%s\n", ErrorString); + return (rc); + } + + return (0); + + + case Delete: + if (!LabelExists) { + (void) fprintf(stderr, + gettext("Error: %s is not configured in [%s].\n"), + Label, Section); + return (-1); + } + + rc = DeletePrivateProfileLabel(Section, Label, configFile); + if (rc) + (void) fprintf(stderr, "%s\n", ErrorString); + return (rc); + + + case Change: + if (argc < 2) { + /* must have at least "<action> {<properties>}" = 2 */ + (void) fprintf(stderr, + gettext("Error: IPsec Policy incomplete. " + "Please specify the complete new IPsec Policy. " + "See ipsec(7P).\n")); + return (-1); + } + + if (!LabelExists) { + (void) fprintf(stderr, + gettext("Error: %s is not configured in [%s].\n"), + Label, Section); + return (-1); + } + + /* + * Is the format of this setting valid? Note: we have to do + * this one IPsec Policy at a time. + */ + policy = strdup(pbuf); + policyP = policy; /* strtok() is destructive */ + + while ((policy = strtok(policy, IPSP_SEPARATOR)) != NULL) { + if (isIPsecPolicyValid(policy, NULL) != TRUE) { + (void) fprintf(stderr, + gettext("Error: %s is not a valid IPsec " + "policy. Policy may only contain <"), + policy); + (void) printValidStrings(validIPsecAction); + (void) fprintf(stderr, + gettext("> as actions, and valid IPsec " + "<properties>. See ipsec(7P).\n")); + return (-1); + } + policy = NULL; + } + + free(policyP); + + /* Checks out, so change it */ + rc = WritePrivateProfileString(Section, Label, pbuf, + configFile); + + if (rc) { + (void) fprintf(stderr, "%s\n", ErrorString); + return (rc); + } + + return (0); + + + case Get: + if (!LabelExists) { + (void) fprintf(stderr, + gettext("Error: %s is not configigured in [%s].\n"), + Label, Section); + return (-1); + } + (void) printf(gettext("[%s]\n\t%s = %s\n"), + Section, Label, buffer); + return (0); + + + default: + (void) fprintf(stderr, + gettext("Error: Invalid command code!\n")); + return (-1); + } /* switch (command) */ +} /* ipsecFunc */ diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/addr.h b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/addr.h new file mode 100644 index 0000000000..0741cc16bf --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/addr.h @@ -0,0 +1,46 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ifndef _ADDR_H +#define _ADDR_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Address Pool Prototypes + */ + +#ifdef __cplusplus +extern "C" { +#endif + +int addrFunc(char *, char *, char *, int, int, char **); + +#ifdef __cplusplus +} +#endif + +#endif /* _ADDR_H */ diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/advertisements.c b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/advertisements.c new file mode 100644 index 0000000000..9feb1e2abc --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/advertisements.c @@ -0,0 +1,160 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999-2002 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Functions to manipulate advertisements + */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <libintl.h> +#include <conflib.h> +#include "mipagentconfig.h" +#include "utils.h" +#include "advertisements.h" + + +static FuncEntry advFunctions[] = { + { "advLifeTime", NULL, "advLifeTime", posIntFunc, posIntFunc, + posIntFunc, posIntFunc}, + { "regLifeTime", NULL, "regLifeTime", posIntFunc, posIntFunc, + posIntFunc, posIntFunc}, + { "advFrequency", NULL, "advFrequency", posIntFunc, posIntFunc, + posIntFunc, posIntFunc}, + { "homeAgent", NULL, "homeAgent", ynFunc, ynFunc, ynFunc, ynFunc}, + { "foreignAgent", NULL, "foreignAgent", ynFunc, ynFunc, ynFunc, + ynFunc}, + { "prefixLengthExt", NULL, "prefixLengthExt", ynFunc, ynFunc, ynFunc, + ynFunc}, + { "reverseTunnel", NULL, "reverseTunnel", fhFunc, fhFunc, fhFunc, + fhFunc}, + { "reverseTunnelRequired", NULL, "reverseTunnelRequired", fhFunc, + fhFunc, fhFunc, fhFunc}, + { "advInitCount", NULL, "advInitCount", posIntFunc, posIntFunc, + posIntFunc, posIntFunc}, + { "advLimitUnsolicited", NULL, "advLimitUnsolicited", ynFunc, + ynFunc, ynFunc, ynFunc}, + { NULL, NULL, NULL, NULL, NULL } +}; + +/* + * Function: advFunc + * + * Arguments: char *configFile, char *Section, char *Label, int command, + * int argc, char *argv[] + * + * Description: This function implements all the manipulation functions + * for the advertisements sections + * + * Returns: int + */ +int +advFunc(char *configFile, char *Section, char *Label, int command, int argc, + char *argv[]) +{ + char DestSection[MAX_SECTION_LEN]; + FuncEntry *funcEntry = NULL; + int (*function)(char *, char *, char *, int, int, char **) = NULL; + + /* Get rid of lint warnings about unused parameters */ + Section = Label; + + /* ARGV[0] should be the interface */ + if (argc < 1) { + (void) fprintf(stderr, + gettext("Error: advertisement interface not specified. " + "Please specify the interface name.\n")); + return (-1); + } + + /* Build our Section */ + (void) sprintf(DestSection, "Advertisements %s", argv[0]); + + /* Finally, look up our functions and call them based on the dest */ + if (argc > 1) { + funcEntry = getFunctions(advFunctions, argv[1]); + if (!funcEntry) { + (void) fprintf(stderr, + gettext("Error: %s does not support '%s'.\n"), + Command2Str(command), argv[1]); + return (-1); + } + } + + /* Now check the particular function we need. */ + switch (command) { + case Add: + if (argc == 1) { + /* + * A raw add. Add an empty section by adding + * a lable, then deleting it. + */ + return (addEmptySection(configFile, DestSection)); + } + function = funcEntry->addFunc; + break; + case Change: + if (argc == 1) { + (void) fprintf(stderr, + gettext("Error: cannot change the identifier of an " + "Address section. Delete, and make a new one.\n")); + return (-1); + } + function = funcEntry->changeFunc; + break; + case Delete: + if (argc == 1) { + return (DeletePrivateProfileSection(DestSection, + configFile)); + } + function = funcEntry->deleteFunc; + break; + case Get: + if (argc == 1) { + sectionDump(configFile, DestSection, + advFunctions); + return (0); + } + function = funcEntry->getFunc; + break; + } + + if (!function) { + (void) fprintf(stderr, + gettext("Error: %s does not support '%s'.\n"), + Command2Str(command), argv[0]); + return (-1); + } + + /* And finally, call function */ + return (function(configFile, DestSection, funcEntry->Label, + command, argc-2, &argv[2])); + +} /* advFunc */ diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/advertisements.h b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/advertisements.h new file mode 100644 index 0000000000..af2159995a --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/advertisements.h @@ -0,0 +1,42 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ifndef _ADVERTISEMENTS_H +#define _ADVERTISEMENTS_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +int advFunc(char *, char *, char *, int, int, char **); + +#ifdef __cplusplus +} +#endif + +#endif /* _ADVERTISEMENTS_H */ diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/general.c b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/general.c new file mode 100644 index 0000000000..9c76f799fc --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/general.c @@ -0,0 +1,188 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999 - 2002 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * general.c -- General variable modification + */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <libintl.h> +#include <conflib.h> +#include "mipagentconfig.h" +#include "utils.h" +#include "general.h" + + +/* + * Function: logFunc + * + * Arguments: char *configFile, char *Section, char *Label, int command + * int argc, char *argv[] + * + * Description: This function implements all the manipulation functions + * for the logVerbosity key. + * + * Returns: int + */ +int +logFunc(char *configFile, char *Section, char *Label, int command, + int argc, char *argv[]) +{ + char buffer[MAX_VALUE_LEN] = {0}; + int rc; + int LabelExists; + char *validStrings[] = { + "quiet", + "low", + "norm", + "all", + NULL + }; + + /* Check to see if label already exists */ + rc = GetPrivateProfileString(Section, Label, "", buffer, + MAX_VALUE_LEN-1, configFile); + if (!rc) + LabelExists = TRUE; + else + LabelExists = FALSE; + + switch (command) { + case Add: + /* Check to see if label already exists */ + if (LabelExists) { + (void) fprintf(stderr, + gettext("Error: %s is already configured in [%s]:\n" + "\t%s = %s\n"), + Label, Section, Label, buffer); + return (-1); + } + + /* Now, check for the parameters. */ + if (argc != 1) { + (void) fprintf(stderr, + gettext("Error: Must specify log level (one of: ")); + printValidStrings(validStrings); + (void) fprintf(stderr, ").\n"); + return (-1); + } + + if (!checkValidStrings(validStrings, argv[0])) { + /* Add it! */ + rc = WritePrivateProfileString(Section, Label, + argv[0], configFile); + if (rc) { + (void) fprintf(stderr, "%s\n", ErrorString); + return (rc); + } + return (0); + } else { + (void) fprintf(stderr, + gettext("Error: [%s] configuration for %s must be " + "one of ("), Section, Label); + printValidStrings(validStrings); + (void) fprintf(stderr, ").\n"); + return (-1); + } + break; + + + case Delete: + if (!LabelExists) { + (void) fprintf(stderr, + gettext("Error: %s is not configured in [%s].\n"), + Label, Section); + return (-1); + } + rc = DeletePrivateProfileLabel(Section, Label, configFile); + if (rc) + (void) fprintf(stderr, "Error: %s\n", ErrorString); + + return (rc); + + + case Change: + if (!LabelExists) { + (void) fprintf(stderr, + gettext("Error: %s is not configured in [%s].\n"), + Label, Section); + return (-1); + } + + /* Now, check for the parameters. */ + if (argc != 1) { + (void) fprintf(stderr, + gettext("Error: log level was not specified. " + "Please specify the desired log level. " + "Valid log levels are one of (")); + printValidStrings(validStrings); + (void) fprintf(stderr, ").\n"); + return (-1); + } + + if (!checkValidStrings(validStrings, argv[0])) { + /* Change it! */ + rc = WritePrivateProfileString(Section, Label, + argv[0], configFile); + if (rc) { + (void) fprintf(stderr, "%s\n", ErrorString); + return (rc); + } + return (0); + } else { + (void) fprintf(stderr, + gettext("Error: Log level %s is not supported. " + "Log level must be one of ("), + argv[0]); + printValidStrings(validStrings); + (void) fprintf(stderr, ").\n"); + return (-1); + } + break; + + case Get: + if (!LabelExists) { + (void) fprintf(stderr, + gettext("Error: %s is not configured in [%s].\n"), + Label, Section); + return (-1); + } + (void) printf(gettext("[%s]\n\t%s = %s\n"), + Section, Label, buffer); + return (0); + break; + + default: + (void) fprintf(stderr, + gettext("Error: Invalid command code!\n")); + return (-1); + } /* switch (command) */ +} /* logFunc */ diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/general.h b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/general.h new file mode 100644 index 0000000000..dd8b98e1da --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/general.h @@ -0,0 +1,46 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ifndef _GENERAL_H +#define _GENERAL_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * general.h -- General variable modification + */ + +#ifdef __cplusplus +extern "C" { +#endif + +int logFunc(char *, char *, char *, int, int, char **); + +#ifdef __cplusplus +} +#endif + +#endif /* _GENERAL_H */ diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/gsp.c b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/gsp.c new file mode 100644 index 0000000000..a3b344e3f2 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/gsp.c @@ -0,0 +1,188 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999 - 2002 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * gsp.c -- GlobalSecurityParameters variable modification + */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <libintl.h> +#include <conflib.h> +#include "mipagentconfig.h" +#include "utils.h" +#include "gsp.h" + +/* + * Function: keyDistributionFunc + * + * Arguments: configFile, command, arguments + * + * Description: This function sets the "keyDistribution" label of the + * GlobalSecurityParameters section. The only valid value + * at this time is "files". Eventually, we will allow some + * kind of external AAA to be configured here (diameter, + * RADIUS, SunDS, etc.) + * + * Returns: int + * + */ +int +keyDistributionFunc(char *configFile, char *Section, char *Label, int command, + int argc, char *argv[]) +{ + char buffer[MAX_VALUE_LEN] = {0}; + int rc; + int LabelExists; + char *validStrings[] = { + "files", + NULL + }; + + /* Check to see if label already exists */ + rc = GetPrivateProfileString(Section, Label, "", buffer, + MAX_VALUE_LEN-1, configFile); + if (!rc) + LabelExists = TRUE; + else + LabelExists = FALSE; + + switch (command) { + case Add: + if (LabelExists) { + (void) fprintf(stderr, + gettext("Error: %s is already configured in [%s]:\n" + "\t%s = %s\n"), + Label, Section, Label, buffer); + return (-1); + } + + /* Now, check for the parameters. */ + if (argc != 1) { + (void) fprintf(stderr, + gettext("Usage: add keyDistribution <type>\n" + "\tWhere <type> is one of (")); + printValidStrings(validStrings); + (void) fprintf(stderr, ").\n"); + return (-1); + } + + if (!checkValidStrings(validStrings, argv[0])) { + /* Add it! */ + rc = WritePrivateProfileString(Section, Label, + argv[0], configFile); + if (rc) { + (void) fprintf(stderr, "%s\n", ErrorString); + return (rc); + } + return (0); + } else { + (void) fprintf(stderr, + gettext("Error: keyDistribution must be one of (")); + printValidStrings(validStrings); + (void) fprintf(stderr, ").\n"); + return (-1); + } + break; + + + case Delete: + if (!LabelExists) { + (void) fprintf(stderr, + gettext("Error: %s is not configured in [%s].\n"), + Label, Section); + return (-1); + } + rc = DeletePrivateProfileLabel(Section, Label, configFile); + if (rc) { + (void) fprintf(stderr, "%s\n", ErrorString); + return (rc); + } + return (rc); + break; + + + case Change: + /* Now, check for the parameters. */ + if (argc != 1) { + (void) fprintf(stderr, + gettext("Usage: change keyDistribution <type>\n" + "<\tWhere <type> is one of (")); + printValidStrings(validStrings); + (void) fprintf(stderr, ").\n"); + return (-1); + } + + if (!LabelExists) { + (void) fprintf(stderr, + gettext("Error: %s is not configured in [%s].\n"), + Section, Label); + return (-1); + } + + if (!checkValidStrings(validStrings, argv[0])) { + /* Change it! */ + rc = WritePrivateProfileString(Section, Label, + argv[0], configFile); + if (rc) { + (void) fprintf(stderr, "%s\n", ErrorString); + return (rc); + } + return (0); + } else { + (void) fprintf(stderr, + gettext("Error: keyDistribution must be one of (")); + printValidStrings(validStrings); + (void) fprintf(stderr, ").\n"); + return (-1); + } + break; + + case Get: + rc = GetPrivateProfileString(Section, Label, "", buffer, + MAX_VALUE_LEN-1, configFile); + if (rc) { + (void) fprintf(stderr, + gettext("Error: %s is not configured in [%s].\n"), + Label, Section); + return (-1); + } + (void) printf(gettext("[%s]\n\t%s = %s\n"), + Section, Label, buffer); + + return (0); + break; + + default: + (void) fprintf(stderr, + gettext("Error: Invalid command code!\n")); + return (-1); + } /* switch (command) */ +} /* keyDistributionFunc */ diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/gsp.h b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/gsp.h new file mode 100644 index 0000000000..f1ca77e481 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/gsp.h @@ -0,0 +1,46 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ifndef _GSP_H +#define _GSP_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * gsp.h -- GlobalSecurityParameters variable modification + */ + +#ifdef __cplusplus +extern "C" { +#endif + +int keyDistributionFunc(char *, char *, char *, int, int, char **); + +#ifdef __cplusplus +} +#endif + +#endif /* _GSP_H */ diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/inc.flg b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/inc.flg new file mode 100644 index 0000000000..373eff0264 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/inc.flg @@ -0,0 +1,29 @@ +#!/bin/sh +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 (c) 1999 by Sun Microsystems, Inc. +# All rights reserved. +# +#ident "%Z%%M% %I% %E% SMI" + +find_files "s.*" usr/src/cmd/cmd-inet/common diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/mipagentconfig.c b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/mipagentconfig.c new file mode 100644 index 0000000000..dae83a8686 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/mipagentconfig.c @@ -0,0 +1,201 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999-2002 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * mipagentconfig.c + * + * This program is used to manipulate configuration files for mobile ip. + * It is used as follows (for more info on usage, check the man page(s): + * + * foo$ mipagentconfig add address 192.168.168.10 SPI 7 + * + * The parameters are: Command, destination, [values . . . ] + * + * For each command/destination, an entry is looked up in a function table, and + * the appropriate function is called with the rest of the command line as + * parameters. + */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <libintl.h> +#include <locale.h> +#include "mipagentconfig.h" +#include "utils.h" + +#include "general.h" +#include "gsp.h" +#include "advertisements.h" +#include "spi.h" +#include "pool.h" +#include "addr.h" + +/* + * This is the string - to - enum table for command codes. + */ +CommandTable Commands[] = { + { "add", Add }, + { "change", Change }, + { "delete", Delete }, + { "del", Delete }, /* for lazy typers */ + { "get", Get }, + { NULL, NULL } +}; + +/* + * Function Notes: + * + * The first parameter passed to all functions is the command. This + * is to allow the same function to be used for all commands, add + * change, delete or get. + * + * You do not have to support all commands. For any unsupported command, + * just use NULL. + */ +static FuncEntry Functions[] = { + /* Lable or tag, Section, SectionLabel, ADD, CHANGE, DELETE, GET */ + /* From general.h */ + { "logVerbosity", "General", "logVerbosity", logFunc, + logFunc, logFunc, logFunc }, + { "AdvertiseNAI", "General", "AdvertiseNAI", ynFunc, ynFunc, ynFunc, + ynFunc }, + /* from gsp.h */ + { "HA-FAauth", "GlobalSecurityParameters", "HA-FAauth", ynFunc, + ynFunc, ynFunc, ynFunc }, + { "MN-FAauth", "GlobalSecurityParameters", "MN-FAauth", ynFunc, + ynFunc, ynFunc, ynFunc }, + { "Challenge", "GlobalSecurityParameters", "Challenge", ynFunc, + ynFunc, ynFunc, ynFunc }, + { "maxClockSkew", "GlobalSecurityParameters", "maxClockSkew", + posIntFunc, posIntFunc, posIntFunc, posIntFunc }, + { "keyDistribution", "GlobalSecurityParameters", "keyDistribution", + keyDistributionFunc, keyDistributionFunc, keyDistributionFunc, + keyDistributionFunc }, + { "adv", NULL, NULL, advFunc, advFunc, advFunc, advFunc}, + { "SPI", NULL, NULL, spiFunc, spiFunc, spiFunc, spiFunc}, + { "Pool", NULL, NULL, poolFunc, poolFunc, poolFunc, poolFunc}, + { "addr", NULL, NULL, addrFunc, addrFunc, addrFunc, addrFunc }, + { NULL, NULL, NULL, NULL, NULL } +}; + +#define USAGE "%s: [ -f configfile ] command dest [parameters . . .] \n" + +#define CONFIG_FILE "/etc/inet/mipagent.conf" + +int +main(int argc, char *argv[]) +{ + extern char *optarg; + extern int optind; + int c; + char *configFile = CONFIG_FILE; + int argsLeft; + FuncEntry *funcEntry; + Command command = Add; + int (*function)(char *, char *, char *, int, int, char **) = NULL; + + (void) setlocale(LC_ALL, ""); +#if !defined(TEXT_DOMAIN) +#define TEXT_DOMAIN "SYS_TEST" +#endif + + (void) textdomain(TEXT_DOMAIN); + + while ((c = getopt(argc, argv, "f:?h")) != EOF) { + switch (c) { + case 'f' : /* Change the config file */ + configFile = optarg; + break; + case '?': + case 'h': /* print usage */ + (void) fprintf(stderr, USAGE, argv[0]); + return (0); + } + } /* while . . . getopt */ + + argsLeft = argc-optind; + + if (argsLeft < 2) { + (void) fprintf(stderr, + gettext("Error: Not enough arguments.\n")); + (void) fprintf(stderr, USAGE, argv[0]); + return (-1); + } + + /* Now, Check the command */ + command = Str2Command(argv[optind]); + if (command < 0) { + (void) fprintf(stderr, gettext("Error: Invalid command <%s>\n"), + argv[optind]); + (void) fprintf(stderr, USAGE, argv[0]); + return (-1); + } + + + /* Finally, look up our functions and call them based on the dest */ + funcEntry = getFunctions(Functions, argv[optind+1]); + + if (funcEntry) { + /* Now check the particular function we need. */ + switch (command) { + case Add: + function = funcEntry->addFunc; + break; + case Change: + function = funcEntry->changeFunc; + break; + case Delete: + function = funcEntry->deleteFunc; + break; + case Get: + function = funcEntry->getFunc; + break; + } + } else { + (void) fprintf(stderr, + gettext("Error: <%s> is not valid for <%s>\n"), + argv[optind+1], argv[optind]); + (void) fprintf(stderr, USAGE, argv[0]); + return (-1); + } + + if (!function) { + (void) fprintf(stderr, + gettext("Error: %s does not support '%s'.\n"), + argv[optind+1], argv[optind]); + (void) fprintf(stderr, USAGE, argv[0]); + return (-1); + } + + /* And finally, call function */ + return (function(configFile, funcEntry->Section, funcEntry->Label, + command, argsLeft-2, &argv[optind+2])); + +} /* main */ diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/mipagentconfig.h b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/mipagentconfig.h new file mode 100644 index 0000000000..b0acf45ab9 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/mipagentconfig.h @@ -0,0 +1,81 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _MIPAGENTCONFIG_H +#define _MIPAGENTCONFIG_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * mipagentconfig.h -- Header file + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * These entries are used to build tables of actions to manipulate the config + * file. The tag is the entry the user would type. Section is the section + * in the config file that this entry will modify, and Label is the label + * in the section of the config file to be modified. + * + * The functions are pointers to functions to be called to add, change, + * delete, or get the value. + */ +typedef struct { + char *tag; /* Tag used on command line */ + char *Section; /* Section in config file */ + char *Label; /* Label in section in config file */ + int (*addFunc)(char *, char *, char *, int, int, char **); + int (*changeFunc)(char *, char *, char *, int, int, char **); + int (*deleteFunc)(char *, char *, char *, int, int, char **); + int (*getFunc)(char *, char *, char *, int, int, char **); +} FuncEntry; + +/* + * Commands + */ +typedef enum c { + Add = 0, + Change, + Delete, + Get +} Command; + +/* + * This table is used to equate command codes with strings. + */ +typedef struct { + char *string; + Command command; +} CommandTable; + +#ifdef __cplusplus +} +#endif + +#endif /* _MIPAGENTCONFIG_H */ diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/pool.c b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/pool.c new file mode 100644 index 0000000000..902cf569bd --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/pool.c @@ -0,0 +1,171 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999 - 2002 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * pool.c - Functions to manipulate address pools for dynamically allocated + * ip numbers. + * + * Example of good entry: + * + * [ pool 7 ] + * BaseAddress = 192.168.168.1 + * Size = 10 + * + * The above entry would allocate 192.168.168.1 - 192.168.168.11 to incoming + * NAI users. + */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <libintl.h> +#include <conflib.h> +#include "mipagentconfig.h" +#include "utils.h" +#include "pool.h" + + +static FuncEntry poolFunctions[] = { + { "BaseAddress", NULL, "BaseAddress", ipFunc, ipFunc, ipFunc, ipFunc }, + { "Size", NULL, "Size", posIntFunc, posIntFunc, posIntFunc, + posIntFunc}, + { NULL, NULL, NULL, NULL, NULL } +}; + + + +/* + * Function: poolFunc + * + * Arguments: char *configFile, char *Section, char *Label, int command, + * int argc, char *argv[] + * + * Description: This function implements all the manipulation functions + * for the Pools. All the functions used are generic ones in + * utils.c + * Returns: int + */ +int +poolFunc(char *configFile, char *Section, char *Label, int command, int argc, + char *argv[]) +{ + char DestSection[MAX_SECTION_LEN]; + FuncEntry *funcEntry = NULL; + int (*function)(char *, char *, char *, int, int, char **) = NULL; + int value; + + /* Get rid of lint warnings about unused parameters */ + Section = Label; + + /* ARGV[0] should be the Number */ + if (argc < 1) { + (void) fprintf(stderr, + gettext("Error: pool number was not specified. " + "Please specify a Pool number.\n")); + return (-1); + } + + /* Build our Section */ + (void) sprintf(DestSection, "Pool %s", argv[0]); + + /* + * Now, verify that the label is valid. + */ + value = atoi(argv[0]); + if (value <= 0) { + (void) fprintf(stderr, + gettext("Error: SPI <%s> is not valid.\n"), + argv[0]); + return (-1); + } + + /* Finally, look up our functions and call them based on the dest */ + if (argc > 1) { + funcEntry = getFunctions(poolFunctions, argv[1]); + if (!funcEntry) { + (void) fprintf(stderr, + gettext("Error: <%s> is not valid for <%s>.\n"), + argv[1], Command2Str(command)); + return (-1); + } + } + + /* Now check the particular function we need. */ + switch (command) { + case Add: + if (argc == 1) { + /* A raw add Warn the user */ + (void) fprintf(stderr, + gettext("Warning: Pool will be created as " + "parameters are added.\n\tExample:" + "mipagentconfig add Pool 5 SPI 3\n" + "will add the Pool, and add the SPI to it.\n")); + return (0); + } + function = funcEntry->addFunc; + break; + case Change: + if (argc == 1) { + (void) fprintf(stderr, + gettext("Error: cannot change the identifier " + "of an [Address <identifier>] section. " + "Delete, and create a new section.\n")); + return (-1); + } + function = funcEntry->changeFunc; + break; + case Delete: + if (argc == 1) { + return (DeletePrivateProfileSection(DestSection, + configFile)); + } + function = funcEntry->deleteFunc; + break; + case Get: + if (argc == 1) { + sectionDump(configFile, DestSection, + poolFunctions); + return (0); + } + function = funcEntry->getFunc; + break; + } + + if (!function) { + (void) fprintf(stderr, + gettext("Error: %s does not support '%s'.\n"), + Command2Str(command), argv[0]); + return (-1); + } + + /* And finally, call function */ + return (function(configFile, DestSection, funcEntry->Label, + command, argc-2, &argv[2])); + +} /* poolFunc */ diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/pool.h b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/pool.h new file mode 100644 index 0000000000..c2e4d8f607 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/pool.h @@ -0,0 +1,42 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ifndef _POOL_H +#define _POOL_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +int poolFunc(char *, char *, char *, int, int, char **); + +#ifdef __cplusplus +} +#endif + +#endif /* _POOL_H */ diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/spi.c b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/spi.c new file mode 100644 index 0000000000..87048b0b57 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/spi.c @@ -0,0 +1,450 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999 - 2002 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * spi.c - Functions to manipulate Security parameters. + * + * Example of good entry: + * + * [ spi 7 ] + * Key = 0123456789abcdef0123456789abcdef + * replayMethod = timestamps + * + * The above entry would allocate a SPI with the provided key and replay + * method. + */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <libintl.h> +#include <conflib.h> +#include "mipagentconfig.h" +#include "utils.h" +#include "spi.h" + +/* Private Prototypes */ +static int spiKeyFunc(char *, char *, char *, int, int, char **); +static int spiReplayFunc(char *, char *, char *, int, int, char **); + + +static FuncEntry spiFunctions[] = { + { "key", NULL, "Key", spiKeyFunc, spiKeyFunc, spiKeyFunc, spiKeyFunc }, + { "replayMethod", NULL, "replayMethod", spiReplayFunc, spiReplayFunc, + spiReplayFunc, spiReplayFunc}, + { NULL, NULL, NULL, NULL, NULL } + +}; + + +/* + * Function: spiFunc + * + * Arguments: char *configFile, char *Section, char *Label, int command, + * int argc, char *argv[] + * + * Description: This function implements all the manipulation functions + * for the SPI sections. + * + * Returns: int + */ +int +spiFunc(char *configFile, char *Section, char *Label, int command, int argc, + char *argv[]) +{ + char DestSection[MAX_SECTION_LEN]; + FuncEntry *funcEntry = NULL; + int (*function)(char *, char *, char *, int, int, char **) = NULL; + int value; + + /* Get rid of lint warnings about unused parameters */ + Section = Label; + + /* ARGV[0] should be the Number */ + if (argc < 1) { + (void) fprintf(stderr, + gettext("Error: SPI value was not specified. " + "Please specify the SPI number.\n")); + return (-1); + } + + /* + * Now, verify that the label is valid. + */ + value = atoi(argv[0]); + if (value <= 0) { + (void) fprintf(stderr, + gettext("Error: <%s> is not a valid SPI.\n"), + argv[0]); + return (-1); + } + + /* Build our Section */ + (void) sprintf(DestSection, "SPI %s", argv[0]); + + /* Finally, look up our functions and call them based on the dest */ + if (argc > 1) { + funcEntry = getFunctions(spiFunctions, argv[1]); + if (!funcEntry) { + (void) fprintf(stderr, + gettext("Error: <%s> is not valid " + "for '%s' command.\n"), + argv[1], Command2Str(command)); + return (-1); + } + } + + /* Now check the particular function we need. */ + switch (command) { + case Add: + if (argc == 1) { + /* A raw add Warn the user */ + (void) fprintf(stderr, + gettext("Warning: SPI will need to be created as " + "parameters are added.\n\tExample: " + "mipagentconfig add SPI 5 key 123456\n" + "will add the SPI, and add the key to it.\n")); + return (0); + } + function = funcEntry->addFunc; + break; + case Change: + if (argc == 1) { + (void) fprintf(stderr, + gettext("Error: cannot change the identifier of an " + "Address section. Delete, and make a new one.\n")); + return (-1); + } + function = funcEntry->changeFunc; + break; + case Delete: + if (argc == 1) { + return (DeletePrivateProfileSection(DestSection, + configFile)); + } + function = funcEntry->deleteFunc; + break; + case Get: + if (argc == 1) { + sectionDump(configFile, DestSection, + spiFunctions); + return (0); + } + function = funcEntry->getFunc; + break; + } + + if (!function) { + (void) fprintf(stderr, + gettext("Error: %s does not support '%s'.\n"), + Command2Str(command), argv[0]); + return (-1); + } + + /* And finally, call function */ + return (function(configFile, DestSection, funcEntry->Label, + command, argc-2, &argv[2])); + +} /* spiFunc */ + + +/* + * Function: spiKeyFunc + * + * Arguments: char *configFile, char *Section, char *Label, int command + * int argc, char *argv[] + * + * Description: This function will get and validate an spi key. + * + * Returns: int + */ +static int +spiKeyFunc(char *configFile, char *Section, char *Label, int command, + int argc, char *argv[]) +{ + char buffer[MAX_VALUE_LEN] = {0}; + int rc, LabelExists; + + /* Check to see if label already exists */ + rc = GetPrivateProfileString(Section, Label, "", buffer, + MAX_VALUE_LEN-1, configFile); + if (!rc) + LabelExists = TRUE; + else + LabelExists = FALSE; + + switch (command) { + case Add: + /* Now, check for the parameters. */ + if (argc != 1) { + (void) fprintf(stderr, + gettext("Error: the SPI value wasn't specified. " + "Please specify a value.\n")); + return (-1); + } + if (LabelExists) { + (void) fprintf(stderr, + gettext("Error: %s is already configured in [%s]:\n" + "\t%s = %s\n"), + Label, Section, Label, buffer); + return (-1); + } + if (hexValid(argv[0])) { + /* Add it! */ + rc = WritePrivateProfileString(Section, Label, + argv[0], configFile); + if (rc) { + (void) fprintf(stderr, "%s\n", ErrorString); + return (rc); + } + return (0); + } else { + (void) fprintf(stderr, + gettext("Error: value must be a valid " + "hexadecimal string.\n")); + return (-1); + } + break; + + + case Delete: + if (!LabelExists) { + (void) fprintf(stderr, + gettext("Error: %s is not configured in [%s].\n"), + Label, Section); + return (-1); + } + rc = DeletePrivateProfileLabel(Section, Label, configFile); + if (rc) { + (void) fprintf(stderr, "%s\n", ErrorString); + return (rc); + } + return (rc); + break; + + + case Change: + /* Now, check for the parameters. */ + if (argc != 1) { + (void) fprintf(stderr, + gettext("Error: the new value wasn't specified. " + "Please specify a value to change %s to.\n"), + Label); + return (-1); + } + + if (!LabelExists) { + (void) fprintf(stderr, + gettext("Error: %s is not configured in [%s].\n"), + Section, Label); + return (-1); + } + + if (hexValid(argv[0])) { + /* Add it! */ + rc = WritePrivateProfileString(Section, Label, + argv[0], configFile); + if (rc) { + (void) fprintf(stderr, + "%s\n", ErrorString); + return (rc); + } + return (0); + } else { + (void) fprintf(stderr, + gettext("Error: SPI value must be a valid " + "hexadecimal string.\n")); + return (-1); + } + break; + + case Get: + if (!LabelExists) { + (void) fprintf(stderr, + gettext("Error: %s is not configured in [%s].\n"), + Label, Section); + return (-1); + } + (void) printf(gettext("[%s]\n\t%s = 0x%s\n"), + Section, Label, buffer); + return (0); + break; + + default: + (void) fprintf(stderr, + gettext("Error: Invalid command code!\n")); + return (-1); + } /* switch (command) */ + + +} /* spiKeyFunc */ + +/* + * Function: spiReplayFunc + * + * Arguments: char *configFile, char *Section, char *Label, int command + * int argc, char *argv[] + * + * Description: This function sets the SPI replay function to one of the + * allowed values. + * + * Returns: int + */ +static int +spiReplayFunc(char *configFile, char *Section, char *Label, int command, + int argc, char *argv[]) +{ + char buffer[MAX_VALUE_LEN] = {0}; + int rc, LabelExists; + char *validStrings[] = { + "timestamps", + "none", + NULL + }; + + /* Check to see if label already exists */ + rc = GetPrivateProfileString(Section, Label, "", buffer, + MAX_VALUE_LEN-1, configFile); + if (!rc) + LabelExists = TRUE; + else + LabelExists = FALSE; + + switch (command) { + case Add: + /* Now, check for the parameters. */ + if (argc != 1) { + (void) fprintf(stderr, + gettext("Usage: add spi <value> replayMethod <type>" + "\n\tWhere <type> is one of (")); + printValidStrings(validStrings); + (void) fprintf(stderr, ").\n"); + return (-1); + } + + if (LabelExists) { + (void) fprintf(stderr, + gettext("Error: %s is already configured in [%s]:\n" + "\t%s = %s\n"), + Label, Section, Label, buffer); + return (-1); + } + if (!checkValidStrings(validStrings, argv[0])) { + /* Add it! */ + rc = WritePrivateProfileString(Section, Label, + argv[0], configFile); + if (rc) { + (void) fprintf(stderr, "%s\n", ErrorString); + return (rc); + } + return (0); + } else { + (void) fprintf(stderr, + gettext("Error: replay method must be one of (")); + printValidStrings(validStrings); + (void) fprintf(stderr, ").\n"); + return (-1); + } + break; + + + case Delete: + if (!LabelExists) { + (void) fprintf(stderr, + gettext("Error: %s is not configured in [%s].\n"), + Label, Section); + return (-1); + } + rc = DeletePrivateProfileLabel(Section, Label, configFile); + if (rc) { + (void) fprintf(stderr, "%s\n", ErrorString); + return (rc); + } + return (rc); + break; + + + case Change: + /* Now, check for the parameters. */ + if (argc != 1) { + (void) fprintf(stderr, + gettext("Usage: " + "change spi <value> replayMethod <type>\n" + "\tWhere <type> is one of (")); + printValidStrings(validStrings); + (void) fprintf(stderr, ").\n"); + return (-1); + } + + if (!LabelExists) { + (void) fprintf(stderr, + gettext("Error: %s is not configured in [%s].\n"), + Label, Section); + return (-1); + } + + if (!checkValidStrings(validStrings, argv[0])) { + /* Add it! */ + rc = WritePrivateProfileString(Section, Label, + argv[0], configFile); + if (rc) { + (void) fprintf(stderr, + "%s\n", ErrorString); + return (rc); + } + return (0); + } else { + (void) fprintf(stderr, + gettext("Error: replay method must be one of (")); + printValidStrings(validStrings); + (void) fprintf(stderr, ").\n"); + return (-1); + } + break; + + case Get: + if (!LabelExists) { + (void) fprintf(stderr, + gettext("Error: %s is not configured in [%s].\n"), + Label, Section); + return (-1); + } + (void) printf(gettext("[%s]\n\t%s = %s\n"), + Section, Label, buffer); + return (0); + break; + + default: + (void) fprintf(stderr, + gettext("Error: Invalid command code!\n")); + return (-1); + } /* switch (command) */ + + +} /* spiReplayFunc */ diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/spi.h b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/spi.h new file mode 100644 index 0000000000..9af402db1b --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/spi.h @@ -0,0 +1,46 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 (c) 1999 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ifndef _SPI_H +#define _SPI_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * spi.h + */ + +#ifdef __cplusplus +extern "C" { +#endif + +int spiFunc(char *, char *, char *, int, int, char **); + +#ifdef __cplusplus +} +#endif + +#endif /* _SPI_H */ diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/utils.c b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/utils.c new file mode 100644 index 0000000000..104a706d72 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/utils.c @@ -0,0 +1,812 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * utils.c -- Generic variable modification functions + */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <libintl.h> +#include <conflib.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <ctype.h> +#include "utils.h" + +static int strFunc(char *configFile, char *Section, char *Label, int command, + int argc, char *argv[], char *validStrings[], char *usageString); + +/* + * Function: ynFunc + * + * Arguments: char *configFile, char *Section, char *Label, int command + * int argc, char *argv[] + * + * Description: This function implements all the manipulation functions + * for any yes no options + * + * Returns: int + */ +int +ynFunc(char *configFile, char *Section, char *Label, int command, + int argc, char *argv[]) +{ + char *validStrings[] = { + "yes", + "no", + NULL + }; + char *usageString = " (yes or no)"; + + return (strFunc(configFile, Section, Label, command, argc, argv, + validStrings, usageString)); + +} /* ynFunc */ + +/* + * Function: fhFunc + * + * Arguments: char *configFile, char *Section, char *Label, int command + * int argc, char *argv[] + * + * Description: This function implements all the manipulation functions + * for any no/neither, fa, ha, both/yes options + * + * Returns: int + */ +int +fhFunc(char *configFile, char *Section, char *Label, int command, + int argc, char *argv[]) +{ + char *validStrings[] = { + "yes", + "both", + "ha", + "fa", + "neither", + "no", + NULL + }; + char *usageString = " (yes|both, ha, fa, neither|no)"; + + return (strFunc(configFile, Section, Label, command, argc, argv, + validStrings, usageString)); + +} /* fin fhFunc() */ + + +/* + * Function: strFunc + * + * Arguments: char *configFile, char *Section, char *Label, int command, + * int argc, char *argv[], char *validStrings[], char *usageString + * + * Description: This function is called by wrapper functions needing to + * validate, and manipulate string data. It compares the + * user-setting to validStrings, then either returning + * usageString, passed in by each wrapper depending on the + * acceptable settings, or performing command appropriately. + * + * Note: Due to internationalization issues, this function can not print + * usage messages, etc, to the console - there are too many possible + * string combinations to consider. The wrapper functions, therefore, + * spit out there own usage functions on error. + * + * Return: 0 on success + * -1 on error + */ +static int +strFunc(char *configFile, char *Section, char *Label, int command, int argc, + char *argv[], char *validStrings[], char *usageString) +{ + char buffer[MAX_VALUE_LEN] = {0}; + int rc, LabelExists; + + /* Check to see if label already exists */ + rc = GetPrivateProfileString(Section, Label, "", buffer, + MAX_VALUE_LEN-1, configFile); + if (!rc) + LabelExists = TRUE; + else + LabelExists = FALSE; + + switch (command) { + case Add: + /* Now, check for the parameters. */ + if (argc != 1) { + (void) fprintf(stderr, + gettext("Error: invalid configuration for %s. " + "Please specify any of: %s.\n"), + Label, gettext(usageString)); + return (-1); + } + /* Now, check to make sure the item isn't already here */ + if (LabelExists) { + (void) fprintf(stderr, + gettext("Error: %s is already configured in [%s]:\n" + "\t%s = %s\n"), + Label, Section, Label, buffer); + return (-1); + } + if (!checkValidStrings(validStrings, argv[0])) { + /* Add it! */ + rc = WritePrivateProfileString(Section, Label, + argv[0], configFile); + if (rc) { + (void) fprintf(stderr, "%s\n", ErrorString); + return (rc); + } + return (0); + } else { + (void) fprintf(stderr, + gettext("Error: value must be one of (")); + printValidStrings(validStrings); + (void) fprintf(stderr, ").\n"); + return (-1); + } + break; + + + case Delete: + if (!LabelExists) { + (void) fprintf(stderr, + gettext("Error: %s is not configured in [%s].\n"), + Label, Section); + return (-1); + } + rc = DeletePrivateProfileLabel(Section, Label, configFile); + if (rc) { + (void) fprintf(stderr, + "Error: %s\n", ErrorString); + } + return (rc); + break; + + + case Change: + /* Now, check for the parameters. */ + if (argc != 1) { + (void) fprintf(stderr, + gettext("Error: new value for %s unspecified. " + "Please specify any of: %s.\n"), + Label, gettext(usageString)); + return (-1); + } + + if (!LabelExists) { + (void) fprintf(stderr, + gettext("Error: %s is not configured in [%s].\n"), + Label, Section); + return (-1); + } + + if (!checkValidStrings(validStrings, argv[0])) { + /* Change it! */ + rc = WritePrivateProfileString(Section, Label, + argv[0], configFile); + if (rc) { + (void) fprintf(stderr, "%s\n", ErrorString); + return (rc); + } + return (0); + } else { + (void) fprintf(stderr, + gettext("Error: value must be one of (")); + printValidStrings(validStrings); + (void) fprintf(stderr, ").\n"); + return (-1); + } + break; + + case Get: + rc = GetPrivateProfileString(Section, Label, "", + buffer, MAX_VALUE_LEN-1, configFile); + if (rc) { + (void) fprintf(stderr, + gettext("Error: %s is not configured in [%s].\n"), + Label, Section); + return (-1); + } + (void) printf(gettext("[%s]\n\t%s = %s\n"), + Section, Label, buffer); + return (0); + break; + + default: + (void) fprintf(stderr, + gettext("Error: Invalid command code!\n")); + return (-1); + } /* switch (command) */ + +} /* strFunc */ + +/* + * Function: posIntFunc + * + * Arguments: char *configFile, char *Section, char *Label, int command, + * int argc, char *argv[] + * + * Description: This function implements all the manipulation functions + * for any positive integer functions. + * + * Returns: int + */ +int +posIntFunc(char *configFile, char *Section, char *Label, int command, int argc, + char *argv[]) +{ + char buffer[MAX_VALUE_LEN] = {0}; + int rc, LabelExists; + int value; + + /* Check to see if label already exists */ + rc = GetPrivateProfileString(Section, Label, "", buffer, + MAX_VALUE_LEN-1, configFile); + if (!rc) + LabelExists = TRUE; + else + LabelExists = FALSE; + + switch (command) { + case Add: + /* Check for the parameters. */ + if (argc != 1) { + (void) fprintf(stderr, + gettext("Error: value for %s was not specified. " + "Please specify value.\n"), Label); + return (-1); + } + + /* Now, check to make sure it is not already here */ + if (LabelExists) { + (void) fprintf(stderr, + gettext("Error: %s is already configured in [%s].\n" + "\tvalue = %s\n"), + Label, Section, Label, buffer); + return (-1); + } + value = atoi(argv[0]); + if (value > 0) { + /* Add it! */ + rc = WritePrivateProfileInt(Section, Label, + value, configFile); + if (rc) { + (void) fprintf(stderr, "%s\n", ErrorString); + return (rc); + } + return (0); + } else { + (void) fprintf(stderr, + gettext("Error: value must be a positive," + " non-zero integer.\n")); + return (-1); + } + break; + + + case Delete: + if (!LabelExists) { + (void) fprintf(stderr, + gettext("Error: %s is not configured in [%s].\n"), + Label, Section); + return (-1); + } + rc = DeletePrivateProfileLabel(Section, Label, configFile); + if (rc) + (void) fprintf(stderr, "Error: %s\n", ErrorString); + return (rc); + break; + + + case Change: + /* Now, check for the parameters. */ + if (argc != 1) { + (void) fprintf(stderr, + gettext("Error: New value for %s was not specified." + " Please specify a value.\n")); + return (-1); + } + + if (!LabelExists) { + (void) fprintf(stderr, + gettext("Error: %s is not configured in [%s].\n"), + Label, Section); + return (-1); + } + + value = atoi(argv[0]); + + if (value > 0) { + /* Change it! */ + rc = WritePrivateProfileString(Section, Label, + argv[0], configFile); + if (rc) { + (void) fprintf(stderr, "%s\n", ErrorString); + return (rc); + } + return (0); + } else { + (void) fprintf(stderr, + gettext("Error: value must be a positive," + " non-zero integer.\n")); + return (-1); + } + break; + + case Get: + if (!LabelExists) { + (void) fprintf(stderr, + gettext("Error: %s is not configured in [%s].\n"), + Label, Section); + return (-1); + } + (void) printf(gettext("[%s]\n\t%s = %s\n"), + Section, Label, buffer); + return (0); + break; + + + + default: + (void) fprintf(stderr, + gettext("Error: Invalid command code!\n")); + return (-1); + } /* switch (command) */ +} /* posIntFunc */ + +/* + * Function: ipFunc + * + * Arguments: char *configFile, char *Section, char *Label, int command, + * int argc, char *argv[] + * + * Description: This function implements all the manipulation functions + * for any ip numbers or masks + * + * Returns: int + */ +int +ipFunc(char *configFile, char *Section, char *Label, int command, int argc, + char *argv[]) +{ + char buffer[MAX_VALUE_LEN] = {0}; + int rc, LabelExists; + + /* Check to see if label already exists */ + rc = GetPrivateProfileString(Section, Label, "", buffer, + MAX_VALUE_LEN-1, configFile); + if (!rc) + LabelExists = TRUE; + else + LabelExists = FALSE; + + switch (command) { + case Add: + /* Check for the parameters. */ + if (argc != 1) { + (void) fprintf(stderr, + gettext("Error: value for %s was not specified. " + "Please specify a value.\n"), Label); + return (-1); + } + + if (LabelExists) { + (void) fprintf(stderr, + gettext("Error: %s is already configured in [%s]:\n" + "\tvalue = %s\n"), + Label, Section, Label, buffer); + return (-1); + } + + + if (ipValid(argv[0])) { + /* Add it! */ + rc = WritePrivateProfileString(Section, Label, argv[0], + configFile); + if (rc) { + (void) fprintf(stderr, "%s\n", ErrorString); + return (rc); + } + return (0); + } else { + (void) fprintf(stderr, + gettext("Error: %s is not a valid IP address.\n"), + argv[0]); + return (-1); + } + break; + + + case Delete: + if (!LabelExists) { + (void) fprintf(stderr, + gettext("Error: %s is not configured in [%s].\n"), + Label, Section); + return (-1); + } + rc = DeletePrivateProfileLabel(Section, Label, configFile); + if (rc) + (void) fprintf(stderr, "Error: %s\n", ErrorString); + return (rc); + break; + + + case Change: + /* Now, check for the parameters. */ + if (argc != 1) { + (void) fprintf(stderr, + gettext("Error: new value for %s was not specified." + " Please specify a value.\n"), Label); + return (-1); + } + + if (!LabelExists) { + (void) fprintf(stderr, + gettext("Error: %s is not configured in [%s].\n"), + Label, Section); + return (-1); + } + + if (ipValid(argv[0])) { + /* Change it! */ + rc = WritePrivateProfileString(Section, Label, + argv[0], configFile); + if (rc) { + (void) fprintf(stderr, "%s\n", ErrorString); + return (rc); + } + return (0); + } else { + (void) fprintf(stderr, + gettext("Error: %s is not a valid IP address.\n"), + argv[0]); + return (-1); + } + break; + + case Get: + if (!LabelExists) { + (void) fprintf(stderr, + gettext("Error: %s is not configured in [%s].\n"), + Label, Section); + return (-1); + } + (void) printf(gettext("[%s]\n\t%s = %s\n"), + Section, Label, buffer); + return (0); + break; + + + + default: + (void) fprintf(stderr, + gettext("Error: Invalid command code!\n")); + return (-1); + } /* switch (command) */ + +} /* ipFunc */ + +/* + * Function: getFunctions + * + * Arguments: FunctionArray, string + * + * Description: This routine returns the func entry structure associated + * with the dest named, "string" + * + * Returns: FuncEntry + * + */ +FuncEntry * +getFunctions(FuncEntry Funcs[], char *string) +{ + int i; + for (i = 0; Funcs[i].tag; i++) + if (!strcasecmp(string, Funcs[i].tag)) { + return (&Funcs[i]); + } + return (NULL); +} /* getFunctions */ + + + +/* + * Function: Str2Command + * + * Arguments: string + * + * Description: This routine returns the command associated + * with the command string, "string" + * + * Returns: Command + * + */ +Command +Str2Command(char *string) +{ + extern CommandTable Commands[]; + int i; + for (i = 0; Commands[i].string; i++) + if (!strcasecmp(string, Commands[i].string)) { + return (Commands[i].command); + } + return (-1); +} /* Str2Command */ + +/* + * Function: Command2Str + * + * Arguments: command + * + * Description: This function translates a command into a string. + * + * Returns: char * + * + */ +char * +Command2Str(Command cmd) +{ + extern CommandTable Commands[]; + CommandTable *item; + for (item = Commands; item->string; item++) + if (item->command == cmd) + return (item->string); + return ("Unknown"); +} /* Command2Str */ + + +/* + * Function: sectionDump + * + * Arguments: configFile, Section, funcs + * + * Description: This funciton will dump the value of particular + * labels (Funcs) in the given section. + * + * Returns: void + * + */ +void +sectionDump(char *configFile, char *Section, FuncEntry Funcs[]) +{ + int i; + int rc; + char buffer[MAX_VALUE_LEN] = {0}; + + (void) printf(gettext("[%s]\n"), Section); + for (i = 0; Funcs[i].tag; i++) { + rc = GetPrivateProfileString(Section, Funcs[i].Label, "", + buffer, MAX_VALUE_LEN-1, configFile); + /* If the item was there, and it was not null, then print it */ + if (!rc && *buffer) { + (void) printf(gettext("\t%s = %s\n"), + Funcs[i].Label, buffer); + } + } +} /* sectionDump */ + +/* + * Function: checkValidStrings + * + * Arguments: validStrings, string + * + * Description: This function returns zero if the passed in string + * is in validStrings. + * + * Returns: int + * + */ +int +checkValidStrings(char *validStrings[], char *string) +{ + char *probe; + int i = 0; + + for (probe = validStrings[i]; probe; probe = validStrings[++i]) + if (!strcasecmp(probe, string)) + return (0); + + return (-1); +} /* checkValidStrings */ + + +/* + * Function: printValidStrings + * + * Arguments: validStrings + * + * Description: This routine prints out the valid strings for + * display messages. + * + * Returns: void + * + */ +void +printValidStrings(char *validStrings[]) +{ + char *probe; + int i = 0; + + for (probe = validStrings[i]; probe; probe = validStrings[++i]) + (void) fprintf(stderr, "%s ", probe); + +} /* printValidStrings */ + + +/* + * Function: ipValid + * + * Arguments: ipString + * + * Description: This function returns true if the string is valid. + * TODO: Use inet_pton to validate string. + * + * Returns: int + * + */ +int +ipValid(char *ipString) +{ +#if 0 + uint32_t in_addr; + + in_addr = inet_pton(ipString); + (void) fprintf(stderr, "DEBUG: inet_pton(\"%s\") =0x%08x\n", + ipString, in_addr); + return (-1); +#else + + int a, b, c, d; + int rc; + + rc = sscanf(ipString, "%d.%d.%d.%d", &a, &b, &c, &d); + /* Check the parsing */ + if (rc != 4) + return (0); + + /* Check the bounds of each number */ + if ((a < 0 || a > 255) || + (b < 0 || b > 255) || + (c < 0 || c > 255) || + (d < 0 || d > 255)) + return (0); + + /* otherwise, it's valid */ + return (1); +#endif +} /* ipValid */ + + +/* + * Function: naiValid + * + * Arguments: string + * + * Description: This function returns true if the strings looks like + * a valid NAI. + * TODO: use RFC to validate NAI. + * + * Returns: int + * + */ +int +naiValid(char *ipString) +{ + int atFound = FALSE; + + /* + * Walk through the string, checking for at least one at, + * and no wierd characters. + */ + + for (; *ipString; ipString++) { + if (*ipString == '@') { + if (atFound) { + /* Error: two @ symbols! */ + return (0); + } else { + atFound = TRUE; + } + continue; /* to keep the if from nesting */ + } + if (isspace(*ipString)) + return (0); + } + + if (atFound) + return (1); /* Success! */ + else + return (0); +} /* naiValid */ + +/* + * Function: hexCheck + * + * Arguments: string + * + * Description: Check the string to make sure it is a valid Hex string + * + * Returns: int + * + */ +int +hexValid(char *string) +{ + if (strlen(string) % 2) { + (void) fprintf(stderr, + gettext("Error: hex string must be of even length.\n")); + return (0); + } + + for (; *string; string++) { + if (!isxdigit(*string)) + return (0); + } + return (1); +} /* hexValid */ + + +/* + * Function: addEmptySection + * + * Arguments: char *configFile, char *SectionName + * + * Description: This routine will add an empty section to a config file, + * by creating a section with a dummy label, then deleting + * the label. NOTE: If the section already exists, this + * function is a NOP. Also, if the label "DummyLabel" + * already exists in the section, it will be deleted as a side + * effect. + * + * Returns: int + * + */ +int +addEmptySection(char *configFile, char *Section) +{ + int rc; + char *Label = "DummyLabel"; + char *Value = "DummyValue"; + + rc = WritePrivateProfileString(Section, Label, Value, configFile); + if (rc) { + (void) fprintf(stderr, "Error: %s\n", ErrorString); + return (1); + } + rc = DeletePrivateProfileLabel(Section, Label, configFile); + if (rc) { + (void) fprintf(stderr, "Error: %s\n", ErrorString); + return (1); + } + return (0); +} /* addEmptySection */ diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/utils.h b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/utils.h new file mode 100644 index 0000000000..d39a14f22e --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentconfig/utils.h @@ -0,0 +1,63 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _UTILS_H +#define _UTILS_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * utils.h -- Utilities, common functions + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "mipagentconfig.h" + + +FuncEntry *getFunctions(FuncEntry *, char *); +Command Str2Command(char *); +char *Command2Str(Command); + +int addEmptySection(char *, char *); +void sectionDump(char *, char *, FuncEntry *); +int fhFunc(char *, char *, char *, int, int, char **); +int ynFunc(char *, char *, char *, int, int, char **); +int ipFunc(char *, char *, char *, int, int, char **); +int posIntFunc(char *, char *, char *, int, int, char **); +int ipValid(char *); +int naiValid(char *); +int hexValid(char *); +int checkValidStrings(char **, char *); +void printValidStrings(char **); + +#ifdef __cplusplus +} +#endif + +#endif /* _UTILS_H */ diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentstat/Makefile b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentstat/Makefile new file mode 100644 index 0000000000..571efa33da --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentstat/Makefile @@ -0,0 +1,66 @@ +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include $(SRC)/cmd/Makefile.cmd +include $(SRC)/cmd/cmd-inet/Makefile.cmd-inet + +PROG= mipagentstat + +OBJS= main.o + +# For linting +SRCS= $(OBJS:%.o=%.c) +LINTFLAGS += -errchk=%all + +LDLIBS += -lnsl +CPPFLAGS += -I$(CMDINETCOMMONDIR) + +# I18n +POFILE= $(PROG).po +POFILES= $(OBJS:%.o=%.po) + +.KEEP_STATE: + +all: $(PROG) + +$(PROG): $(OBJS) + $(LINK.c) -o $@ $(OBJS) $(LDLIBS) + $(POST_PROCESS) + +install: all $(ROOTUSRSBINPROG) + +clean: + $(RM) *.o + +$(POFILE): $(POFILES) + $(RM) $@ + cat $(POFILES) > $@ + +include $(SRC)/cmd/Makefile.targ + +lint: lint_SRCS diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentstat/inc.flg b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentstat/inc.flg new file mode 100644 index 0000000000..373eff0264 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentstat/inc.flg @@ -0,0 +1,29 @@ +#!/bin/sh +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 (c) 1999 by Sun Microsystems, Inc. +# All rights reserved. +# +#ident "%Z%%M% %I% %E% SMI" + +find_files "s.*" usr/src/cmd/cmd-inet/common diff --git a/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentstat/main.c b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentstat/main.c new file mode 100644 index 0000000000..fe39e291b2 --- /dev/null +++ b/deleted_files/usr/src/cmd/cmd-inet/usr.sbin/mipagentstat/main.c @@ -0,0 +1,495 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <door.h> +#include <sys/types.h> +#include <fcntl.h> +#include <arpa/inet.h> +#include <string.h> +#include <unistd.h> +#include <sys/time.h> +#include <netdb.h> +#include <netinet/in.h> +#include <libintl.h> +#include <locale.h> +#include "conflib.h" +#include "mipagentstat_door.h" + +/* + * Main for mipagentstat. This uses the protocol defined in + * "mipagentstat_door.h" to act as a door client to mipagent. + * It displays statistics tables for home and foreign agents + * by enumerating the registration tables in mipagent. Each + * door call retrieves an single entry from the table. Doors + * are fast enough that performance is good for this approach, + * and memory usage (particularly in mipagent) is small and + * non-disruptive to the rest of the process. This is a priority + * since we expect that mipagent may eventually be required to + * service thousands of nodes. + * + * mipagentstat follows the following logic flow: + * + * 1. (main) Process command-line arguments + * 2. (main) Call enumerate_stats for each agent to stat + * 3. (enumerate_stats) Display table banner if there are any entries + * 4. (enumerate_stats) + * while more entries forthcoming + * get next entry via a door_call + * display the entry with display_entry + * 5. (display_entry) convert address to printable format; print it. + */ + +/* Flag to tell display function whether or not to resolve host names */ +#define NO_NAME_RESOLUTION 0x01 +#define PEER_PROTECTION 0x02 + +/* *80* columns for addrs/hostnames or NAIs, times, and registered flags. */ +#define MN_ADDR_COL_WIDTH 26 /* Mobile Node - NAI likely */ +#define MA_ADDR_COL_WIDTH 24 /* mipagent-peer - NAI unlikely */ +#define TIME_COL_WIDTH 9 /* lifetime, and remaining (ulongs) */ +#define FLAG_COL_WIDTH 8 /* services being given */ +#define PROT_TYPE_COL_WIDTH 8 /* enough to print protection types */ + +/* + * Displays the header for the mobile node stats listing. Column widths for + * the fields are defined by the macros M*_ADDR_COL_WIDTH and TIME_COL_WIDTH. + * + * type IN Foreign or Home Agent + */ +static void display_mn_header(enum_stat_type type) { + (void) printf("\n%-*.*s %-*.*s %-*.*s %-*.*s %-*.*s\n", + MN_ADDR_COL_WIDTH, MN_ADDR_COL_WIDTH, "Mobile Node", + MA_ADDR_COL_WIDTH, MA_ADDR_COL_WIDTH, + (type == FOREIGN_AGENT ? "Home Agent" : "Foreign Agent"), + TIME_COL_WIDTH, TIME_COL_WIDTH, "Time (s)", + TIME_COL_WIDTH, TIME_COL_WIDTH, "Time (s)", + FLAG_COL_WIDTH, FLAG_COL_WIDTH, "Service"); + (void) printf("%*s %-*.*s %-*.*s %-*.*s\n", + (MN_ADDR_COL_WIDTH + MA_ADDR_COL_WIDTH) + 1, "", + TIME_COL_WIDTH, TIME_COL_WIDTH, "Granted ", + TIME_COL_WIDTH, TIME_COL_WIDTH, "Remaining", + FLAG_COL_WIDTH, FLAG_COL_WIDTH, "Flags"); + (void) printf("%-*.*s %-*.*s %-*.*s %-*.*s %-*.*s\n", + MN_ADDR_COL_WIDTH, MN_ADDR_COL_WIDTH, + "-------------------------------------------------", + MA_ADDR_COL_WIDTH, MA_ADDR_COL_WIDTH, + "-------------------------------------------------", + TIME_COL_WIDTH, TIME_COL_WIDTH, + "-------------------------------------------------", + TIME_COL_WIDTH, TIME_COL_WIDTH, + "-------------------------------------------------", + FLAG_COL_WIDTH, FLAG_COL_WIDTH, + "-------------------------------------------------"); +} + +/* + * Displays the header for the agent stats listing. Column widths for the + * fields are defined by the macros PEER_ADDR_COL_WIDTH, and + * PROT_TYPE_COL_WIDTH. + */ +static void display_agent_header(enum_stat_type type) { + (void) printf("\n%-*.*s %-*.*s\n", + MA_ADDR_COL_WIDTH, MA_ADDR_COL_WIDTH, + (type == FOREIGN_AGENT_PEER ? "Foreign" : "Home"), + PROT_TYPE_COL_WIDTH * 4 + 3, PROT_TYPE_COL_WIDTH * 4 + 3, + "..... Security Association(s) ....."); + (void) printf("%-*.*s %-*.*s %-*.*s %-*.*s %-*.*s\n", + MA_ADDR_COL_WIDTH, MA_ADDR_COL_WIDTH, "Agent", + PROT_TYPE_COL_WIDTH, PROT_TYPE_COL_WIDTH, "Requests", + PROT_TYPE_COL_WIDTH, PROT_TYPE_COL_WIDTH, "Replies", + PROT_TYPE_COL_WIDTH, PROT_TYPE_COL_WIDTH, "FTunnel", + PROT_TYPE_COL_WIDTH, PROT_TYPE_COL_WIDTH, "RTunnel"); + (void) printf("%-*.*s %-*.*s %-*.*s %-*.*s %-*.*s\n", + MA_ADDR_COL_WIDTH, MA_ADDR_COL_WIDTH, + "-------------------------------------------------", + PROT_TYPE_COL_WIDTH, PROT_TYPE_COL_WIDTH, + "-------------------------------------------------", + PROT_TYPE_COL_WIDTH, PROT_TYPE_COL_WIDTH, + "-------------------------------------------------", + PROT_TYPE_COL_WIDTH, PROT_TYPE_COL_WIDTH, + "-------------------------------------------------", + PROT_TYPE_COL_WIDTH, PROT_TYPE_COL_WIDTH, + "-------------------------------------------------"); +} + + + +/* + * Converts the address in src to a string. If NO_NAME_RESOLUTION is + * not set in flags, we try to resolve the address to a host name + * using getipnodebyaddr. If this fails (for any reason) or if + * NO_NAME_RESOLUTION is set in flags, we just convert the address + * to presentation format using inet_ntop. + * + * af IN Address familiy of src + * src IN Address to resolve or convert to presentation + * srclen IN Length of src buffer + * buf IN/OUT Buffer to hold coverted string. Should be big + * enough to hold either an address or a fully + * qualified host name string. + * bufsz IN Size of buf + * flags IN Special flags + * + * Returns A pointer to a character buffer containing the + * printable address or host name. Never returns + * NULL. The pointer may point into buf; either + * way, the caller must not free the result. + */ +static char *addr2str(int af, + void *src, + size_t srclen, + char *buf, + size_t bufsz, + int flags) { + char *answer; + struct hostent *he; + int err; + size_t addrlen; + + /* + * If -n wasn't given at the command line, try to resolve + * the hostname into an address. + */ + if ((flags & NO_NAME_RESOLUTION) == 0) { + /* Set the addrlen according to the AF */ + switch (af) { + case AF_INET: + addrlen = sizeof (struct in_addr); + break; + case AF_INET6: + addrlen = sizeof (struct in6_addr); + break; + default: + addrlen = srclen; + break; + } + + he = getipnodebyaddr(src, addrlen, af, &err); + if (he && err != 0) { + (void) strncpy(buf, he->h_name, bufsz); + freehostent(he); + return (buf); + } + } + + /* + * Else we shouldn't or couldn't resolve the hostname, + * so just convert to presentation format. + */ + + answer = (char *)inet_ntop(af, src, buf, bufsz); + + return (answer ? answer : "<bad address>"); +} + +/* + * Displays a single mobile node entry, formatting the fields + * according to the macros M*_ADDR_COL_WIDTH and TIME_COL_WIDTH + * and using addr2str to conver the addresses in stat_args into + * printable strings. + * + * stat_args IN An entry returned from the stat door call + * flags IN Passed through to addr2str + */ +static void display_mn_entry(DoorStatArgs stat_args, int flags) { + char node_str[NI_MAXHOST]; + char agent_str[NI_MAXHOST]; + char service_str[FLAG_COL_WIDTH]; + struct timeval now; + ulong_t expires = stat_args.expires; + + (void) gettimeofday(&now, NULL); + + /* Calculate what to print in the Service Flags column */ + (void) snprintf(service_str, sizeof (service_str), "%s%s%s%s%s%s%s%s", + (stat_args.service_flags & SERVICE_SIMULTANEOUS_BINDINGS ? + "S" : "."), + (stat_args.service_flags & SERVICE_FWD_BROADCASTS ? + "B" : "."), + (stat_args.service_flags & SERVICE_DECAPSULATION_BY_MN ? + "D" : "."), + (stat_args.service_flags & SERVICE_MIN_ENCAP ? + "M" : "."), + (stat_args.service_flags & SERVICE_GRE_ENCAP ? + "G" : "."), + (stat_args.service_flags & SERVICE_VJ_COMPRESSION ? + "V" : "."), + (stat_args.service_flags & SERVICE_REVERSE_TUNNEL ? + "T" : "."), + (stat_args.service_flags & SERVICE_BIT_UNUSED ? + "?" : ".")); + /* When the last reg bit becomes defined, it *replaces* the ? entry. */ + + (void) printf("%-*.*s %-*.*s %-*lu %-*lu %*.*s\n", + /* Mobile Node */ + MN_ADDR_COL_WIDTH, MN_ADDR_COL_WIDTH, + addr2str(stat_args.node_af, + stat_args.node, + sizeof (stat_args.node), + node_str, + NI_MAXHOST, + flags), + /* Agent */ + MA_ADDR_COL_WIDTH, MA_ADDR_COL_WIDTH, + addr2str(stat_args.agent_af, + stat_args.agent, + sizeof (stat_args.agent), + agent_str, + NI_MAXHOST, + flags), + /* Time granted and expires */ + TIME_COL_WIDTH, expires - stat_args.granted, + TIME_COL_WIDTH, (expires < now.tv_sec ? + 0 : + expires - now.tv_sec), + /* Flags indicating services for the mn */ + FLAG_COL_WIDTH, FLAG_COL_WIDTH, service_str); +} + + +/* + * Displays a single agent-peer entry, formatting the fields + * according to the macros M*_ADDR_COL_WIDTH and PROT_TYPE_COL_WIDTH + * and using addr2str to conver the addresses in stat_args into + * printable strings depending on whether the '-n' flag was set. + * + * stat_args IN An entry returned from the stat door call + * flags IN Passed through to addr2str + */ +static void display_agent_entry(DoorStatArgs stat_args, int flags) { + char agent_str[MA_ADDR_COL_WIDTH]; + char request_str[PROT_TYPE_COL_WIDTH] = ""; + char reply_str[PROT_TYPE_COL_WIDTH] = ""; + char tunnel_str[PROT_TYPE_COL_WIDTH] = ""; + char reversetunnel_str[PROT_TYPE_COL_WIDTH] = ""; + + /* calculate what to print in the protection columns */ + if (stat_args.service_flags & IPSEC_REQUEST_AH) { + (void) strcat(request_str, "AH "); + } + if (stat_args.service_flags & IPSEC_REQUEST_ESP) { + (void) strcat(request_str, "ESP"); + } + + if (stat_args.service_flags & IPSEC_REPLY_AH) { + (void) strcat(reply_str, "AH "); + } + if (stat_args.service_flags & IPSEC_REPLY_ESP) { + (void) strcat(reply_str, "ESP"); + } + + if (stat_args.service_flags & IPSEC_TUNNEL_AH) { + (void) strcat(tunnel_str, "AH "); + } + if (stat_args.service_flags & IPSEC_TUNNEL_ESP) { + (void) strcat(tunnel_str, "ESP"); + } + + if (stat_args.service_flags & IPSEC_REVERSE_TUNNEL_AH) { + (void) strcat(reversetunnel_str, "AH "); + } + if (stat_args.service_flags & IPSEC_REVERSE_TUNNEL_ESP) { + (void) strcat(reversetunnel_str, "ESP"); + } + + (void) printf("%-*.*s %-*.*s %-*.*s %-*.*s %-*.*s\n", + /* agent-peer */ + MA_ADDR_COL_WIDTH, MA_ADDR_COL_WIDTH, + addr2str(stat_args.agent_af, + stat_args.agent, + sizeof (stat_args.agent), + agent_str, + MA_ADDR_COL_WIDTH, + flags), + /* protection info */ + PROT_TYPE_COL_WIDTH, PROT_TYPE_COL_WIDTH, request_str, + PROT_TYPE_COL_WIDTH, PROT_TYPE_COL_WIDTH, reply_str, + PROT_TYPE_COL_WIDTH, PROT_TYPE_COL_WIDTH, tunnel_str, + PROT_TYPE_COL_WIDTH, PROT_TYPE_COL_WIDTH, reversetunnel_str); +} + + +/* + * Enumerates through mipagent's entire table of foreign or home + * agent entries. We use a doors IPC to communicate with mipagent. + * Each door call retrieves a single entry, keeping memory usage + * low. Memory management is simplified by using the automatic + * variable stat_args to allocate all needed memory. Each entry + * is displayed based on the flags passed in. If flags indicate + * the user wants to see the protection in place (-p) with our + * agent peers, then display_agent_entry() is called, otherwise + * the user wants mobile nodes, and we call display_mn_entry(). + * + * type IN Foreign or Home Agent + * flags IN Passed through to display_*_entries() + */ +static void enumerate_stats(enum_stat_type type, int flags) { + int fd = open(MIPAGENTSTAT_DOOR, O_RDONLY); + door_arg_t arg; + DoorStatArgs stat_args; + + if (fd == -1) { + (void) fprintf(stderr, gettext("mipagent unavailable\n")); + exit(1); + } + + /* Set up door args */ + (void) memset(&stat_args, 0, sizeof (stat_args)); + stat_args.type = type; + stat_args.op = FIRST_ENT; + + (void) memset(&arg, 0, sizeof (arg)); + arg.data_ptr = (char *)&stat_args; + arg.data_size = sizeof (stat_args); + arg.rbuf = (char *)&stat_args; + arg.rsize = sizeof (stat_args); + + /* Do the first entry. If the server is down, we find out here. */ + if (door_call(fd, &arg) == -1) { + (void) fprintf(stderr, gettext("mipagent unavailable\n")); + exit(1); + } + + /* + * Now that we know the server is up, display the banner, + * then display information, or at least the fact that + * there's nothing to display! + */ + if (flags & PEER_PROTECTION) + /* display the mobility agent peer stat header */ + display_agent_header(type); + else + /* display the mn-stat header */ + display_mn_header(type); + + if (arg.data_size == 0) { + (void) fprintf(stdout, gettext("<none>\n\n")); + goto done; + } + + /* Switch to next entry mode for the rest of the enumeration */ + stat_args.op = NEXT_ENT; + + /* Enumerate */ + while (arg.data_size != 0) { + if (arg.data_size < sizeof (stat_args)) { + (void) fprintf(stderr, gettext("bad reply from mipagent\n")); + break; + } + + if (flags & PEER_PROTECTION) + display_agent_entry(stat_args, flags); + else + display_mn_entry(stat_args, flags); + + if (door_call(fd, &arg) == -1) { + perror("door_call"); + break; + } + } + +done: + (void) close(fd); +} + +static void usage(char **argv) { + (void) printf(gettext("Usage: %s [ -fhp ]\n"), *argv); +} + +/* + * Entry point for mipagentstat. main simply processes the command + * line arguments and uses them to dispatch foreign or home agent + * statistics enumerations. If no arguments are given, we retrieve + * both home and foreign agent stats. + */ +int +main(int argc, char **argv) { + int c; + int type = 0; + int flags = 0; + + (void) setlocale(LC_ALL, ""); +#if !defined(TEXT_DOMAIN) +#define TEXT_DOMAIN "SYS_TEST" +#endif + (void) textdomain(TEXT_DOMAIN); + + while ((c = getopt(argc, argv, "fhnp")) != EOF) { + switch (c) { + case 'f': + type |= DO_FA; + break; + case 'h': + type |= DO_HA; + break; + case 'n': + /* + * private flag: if true, we don't try to resolve + * addresses into host names. This can result in + * a significantly faster listing, and follows the + * tried and true behavior of utilities like netstat. + */ + flags |= NO_NAME_RESOLUTION; + break; + case 'p': + /* + * User wants to see the protection with our agent peers. + * This is set in type because doors doesn't see any flags. + */ + flags |= PEER_PROTECTION; + break; + default: + usage(argv); + exit(1); + } + } + + if ((!(type & DO_FA)) && (!(type & DO_HA))) + /* Neither is set, so user didn't specify, therefore do both. */ + type |= DO_BOTH; + + if (flags & PEER_PROTECTION) { + if (type & DO_FA) + /* user types -fp, wants peers of the FA = HA-peers */ + enumerate_stats(HOME_AGENT_PEER, flags); + + if (type & DO_HA) + /* user types -hp, wants peers of the HA = FA-peers */ + enumerate_stats(FOREIGN_AGENT_PEER, flags); + } else { + if (type & DO_FA) + enumerate_stats(FOREIGN_AGENT, flags); + + if (type & DO_HA) + enumerate_stats(HOME_AGENT, flags); + } + + return (0); +} diff --git a/deleted_files/usr/src/pkgdefs/SUNWmipr/Makefile b/deleted_files/usr/src/pkgdefs/SUNWmipr/Makefile new file mode 100644 index 0000000000..109f27ceb0 --- /dev/null +++ b/deleted_files/usr/src/pkgdefs/SUNWmipr/Makefile @@ -0,0 +1,39 @@ +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 +# +# +# ident "%Z%%M% %I% %E% SMI" +# +# Copyright 1999, 2002 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +include ../Makefile.com + +DATAFILES += i.initd +CHKINSTALLSRC=checkinstall.initd + +.KEEP_STATE: + +all: $(FILES) +install: all pkg + +include ../Makefile.targ diff --git a/deleted_files/usr/src/pkgdefs/SUNWmipr/depend b/deleted_files/usr/src/pkgdefs/SUNWmipr/depend new file mode 100644 index 0000000000..94e4c9c44b --- /dev/null +++ b/deleted_files/usr/src/pkgdefs/SUNWmipr/depend @@ -0,0 +1,53 @@ +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 +# +# ident "%Z%%M% %I% %E% SMI" +# +# This package information file defines software dependencies associated +# with the pkg. You can define three types of pkg dependencies with this file: +# P indicates a prerequisite for installation +# I indicates an incompatible package +# R indicates a reverse dependency +# <pkg.abbr> see pkginfo(4), PKG parameter +# <name> see pkginfo(4), NAME parameter +# <version> see pkginfo(4), VERSION parameter +# <arch> see pkginfo(4), ARCH parameter +# <type> <pkg.abbr> <name> +# (<arch>)<version> +# (<arch>)<version> +# ... +# <type> <pkg.abbr> <name> +# ... +# + +P SUNWcar Core Architecture, (Root) +P SUNWcakr Core Solaris Kernel Architecture (Root) +P SUNWkvm Core Architecture, (Kvm) +P SUNWcsr Core Solaris, (Root) +P SUNWckr Core Solaris Kernel (Root) +P SUNWcnetr Core Solaris Network Infrastructure (Root) +P SUNWcsu Core Solaris, (Usr) +P SUNWcsd Core Solaris Devices +P SUNWcsl Core Solaris Libraries +P SUNWsacom Solstice Enterprise Agents 1.0.3 files for root file system diff --git a/deleted_files/usr/src/pkgdefs/SUNWmipr/pkginfo.tmpl b/deleted_files/usr/src/pkgdefs/SUNWmipr/pkginfo.tmpl new file mode 100644 index 0000000000..ae469f1646 --- /dev/null +++ b/deleted_files/usr/src/pkgdefs/SUNWmipr/pkginfo.tmpl @@ -0,0 +1,59 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# 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 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# +# This required package information file describes characteristics of the +# package, such as package abbreviation, full package name, package version, +# and package architecture. +# +PKG="SUNWmipr" +NAME="Mobile-IP (Root)" +ARCH="ISA" +VERSION="ONVERS,REV=0.0.0" +SUNW_PRODNAME="SunOS" +SUNW_PRODVERS="RELEASE/VERSION" +SUNW_PKGTYPE="root" +MAXINST="1000" +CATEGORY="system" +DESC="Mobile-IP configuration and startup scripts" +VENDOR="Sun Microsystems, Inc." +HOTLINE="Please contact your local service provider" +EMAIL="" +CLASSES="none initd" +BASEDIR=/ +SUNW_PKGVERS="1.0" +SUNW_PKG_ALLZONES="true" +SUNW_PKG_HOLLOW="true" +SUNW_PKG_THISZONE="false" +#VSTOCK="<reserved by Release Engineering for package part #>" +#ISTATES="<developer defined>" +#RSTATES='<developer defined>' +#ULIMIT="<developer defined>" +#ORDER="<developer defined>" +#PSTAMP="<developer defined>" +#INTONLY="<developer defined>" diff --git a/deleted_files/usr/src/pkgdefs/SUNWmipr/prototype_com b/deleted_files/usr/src/pkgdefs/SUNWmipr/prototype_com new file mode 100644 index 0000000000..9399ad1a01 --- /dev/null +++ b/deleted_files/usr/src/pkgdefs/SUNWmipr/prototype_com @@ -0,0 +1,67 @@ +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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. +# +#ident "%Z%%M% %I% %E% SMI" +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. + +#!search <pathname pathname ...> # where to find pkg objects +#!include <filename> # include another 'prototype' file +#!default <mode> <owner> <group> # default used if not specified on entry +#!<param>=<value> # puts parameter in pkg environment + +# packaging files +i pkginfo +i copyright +i i.initd +i depend +i checkinstall +# +# source locations relative to the prototype file +# +d none etc 755 root sys +d none etc/inet 755 root sys +f none etc/inet/mipagent.conf-sample 600 root sys +f none etc/inet/mipagent.conf.fa-sample 600 root sys +f none etc/inet/mipagent.conf.ha-sample 600 root sys +d none etc/init.d 755 root sys +e initd etc/init.d/mipagent 744 root sys +d none etc/rc0.d 755 root sys +l initd etc/rc0.d/K06mipagent=../../etc/init.d/mipagent +d none etc/rc1.d 755 root sys +l initd etc/rc1.d/K06mipagent=../../etc/init.d/mipagent +d none etc/rc2.d 755 root sys +l initd etc/rc2.d/K06mipagent=../../etc/init.d/mipagent +d none etc/rc3.d 755 root sys +l initd etc/rc3.d/S80mipagent=../../etc/init.d/mipagent +d none etc/rcS.d 755 root sys +l initd etc/rcS.d/K06mipagent=../../etc/init.d/mipagent +d none etc/snmp 0755 root sys +d none etc/snmp/conf 0755 root sys +f none etc/snmp/conf/mipagent.acl 600 root sys +f none etc/snmp/conf/mipagent.reg 644 root sys diff --git a/deleted_files/usr/src/pkgdefs/SUNWmipr/prototype_i386 b/deleted_files/usr/src/pkgdefs/SUNWmipr/prototype_i386 new file mode 100644 index 0000000000..65f90f21fb --- /dev/null +++ b/deleted_files/usr/src/pkgdefs/SUNWmipr/prototype_i386 @@ -0,0 +1,51 @@ +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 +# +# +#pragma ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1999 by Sun Microsystems, Inc. +# All rights reserved. +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. + +#!search <pathname pathname ...> # where to find pkg objects +#!include <filename> # include another 'prototype' file +#!default <mode> <owner> <group> # default used if not specified on entry +#!<param>=<value> # puts parameter in pkg environment + +# +# Include ISA independent files (prototype_com) +# +!include prototype_com +# +# +# +# List files which are I386 specific here +# +# source locations relative to the prototype file +# +# +# SUNWmipr +# diff --git a/deleted_files/usr/src/pkgdefs/SUNWmipr/prototype_sparc b/deleted_files/usr/src/pkgdefs/SUNWmipr/prototype_sparc new file mode 100644 index 0000000000..95cc0a8311 --- /dev/null +++ b/deleted_files/usr/src/pkgdefs/SUNWmipr/prototype_sparc @@ -0,0 +1,51 @@ +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 +# +# +#pragma ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1999 by Sun Microsystems, Inc. +# All rights reserved. +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. + +#!search <pathname pathname ...> # where to find pkg objects +#!include <filename> # include another 'prototype' file +#!default <mode> <owner> <group> # default used if not specified on entry +#!<param>=<value> # puts parameter in pkg environment + +# +# Include ISA independent files (prototype_com) +# +!include prototype_com +# +# +# +# List files which are SPARC specific here +# +# source locations relative to the prototype file +# +# +# SUNWmipr +# diff --git a/deleted_files/usr/src/pkgdefs/SUNWmipu/Makefile b/deleted_files/usr/src/pkgdefs/SUNWmipu/Makefile new file mode 100644 index 0000000000..99746fee23 --- /dev/null +++ b/deleted_files/usr/src/pkgdefs/SUNWmipu/Makefile @@ -0,0 +1,36 @@ +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 +# +# +# ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1999 by Sun Microsystems, Inc. +# All rights reserved. +# + +include ../Makefile.com + +.KEEP_STATE: + +all: $(FILES) +install: all pkg + +include ../Makefile.targ diff --git a/deleted_files/usr/src/pkgdefs/SUNWmipu/depend b/deleted_files/usr/src/pkgdefs/SUNWmipu/depend new file mode 100644 index 0000000000..2dfd145bc0 --- /dev/null +++ b/deleted_files/usr/src/pkgdefs/SUNWmipu/depend @@ -0,0 +1,54 @@ +# +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 +# +# ident "%Z%%M% %I% %E% SMI" +# +# This package information file defines software dependencies associated +# with the pkg. You can define three types of pkg dependencies with this file: +# P indicates a prerequisite for installation +# I indicates an incompatible package +# R indicates a reverse dependency +# <pkg.abbr> see pkginfo(4), PKG parameter +# <name> see pkginfo(4), NAME parameter +# <version> see pkginfo(4), VERSION parameter +# <arch> see pkginfo(4), ARCH parameter +# <type> <pkg.abbr> <name> +# (<arch>)<version> +# (<arch>)<version> +# ... +# <type> <pkg.abbr> <name> +# ... +# + +P SUNWcar Core Architecture, (Root) +P SUNWcakr Core Solaris Kernel Architecture (Root) +P SUNWkvm Core Architecture, (Kvm) +P SUNWcsr Core Solaris, (Root) +P SUNWckr Core Solaris Kernel (Root) +P SUNWcnetr Core Solaris Network Infrastructure (Root) +P SUNWcsu Core Solaris, (Usr) +P SUNWcsl Core Solaris Libraries +P SUNWcsd Core Solaris Devices +P SUNWmipr Mobile-IP (Root) +P SUNWsasnm Solstice Enterprise Agents 1.0.3 Simple Network Management Protocol diff --git a/deleted_files/usr/src/pkgdefs/SUNWmipu/pkginfo.tmpl b/deleted_files/usr/src/pkgdefs/SUNWmipu/pkginfo.tmpl new file mode 100644 index 0000000000..8974c17fd6 --- /dev/null +++ b/deleted_files/usr/src/pkgdefs/SUNWmipu/pkginfo.tmpl @@ -0,0 +1,59 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# 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 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# +# This required package information file describes characteristics of the +# package, such as package abbreviation, full package name, package version, +# and package architecture. +# +PKG="SUNWmipu" +NAME="Mobile-IP (Usr)" +ARCH="ISA" +VERSION="ONVERS,REV=0.0.0" +SUNW_PRODNAME="SunOS" +SUNW_PRODVERS="RELEASE/VERSION" +SUNW_PKGTYPE="usr" +MAXINST="1000" +CATEGORY="system" +DESC="Mobile-IP daemon and utilities" +VENDOR="Sun Microsystems, Inc." +HOTLINE="Please contact your local service provider" +EMAIL="" +CLASSES="none" +BASEDIR=/ +SUNW_PKGVERS="1.0" +SUNW_PKG_ALLZONES="true" +SUNW_PKG_HOLLOW="false" +SUNW_PKG_THISZONE="false" +#VSTOCK="<reserved by Release Engineering for package part #>" +#ISTATES="<developer defined>" +#RSTATES='<developer defined>' +#ULIMIT="<developer defined>" +#ORDER="<developer defined>" +#PSTAMP="<developer defined>" +#INTONLY="<developer defined>" diff --git a/deleted_files/usr/src/pkgdefs/SUNWmipu/prototype_com b/deleted_files/usr/src/pkgdefs/SUNWmipu/prototype_com new file mode 100644 index 0000000000..2117635f1b --- /dev/null +++ b/deleted_files/usr/src/pkgdefs/SUNWmipu/prototype_com @@ -0,0 +1,51 @@ +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 (c) 1999 by Sun Microsystems, Inc. +# All rights reserved. +# +#pragma ident "%Z%%M% %I% %E% SMI" +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. + +#!search <pathname pathname ...> # where to find pkg objects +#!include <filename> # include another 'prototype' file +#!default <mode> <owner> <group> # default used if not specified on entry +#!<param>=<value> # puts parameter in pkg environment + +# packaging files +i pkginfo +i copyright +i depend +# +# source locations relative to the prototype file +# +d none usr 755 root sys +d none usr/lib 755 root bin +d none usr/lib/inet 755 root bin +f none usr/lib/inet/mipagent 555 root bin +d none usr/sbin 755 root bin +f none usr/sbin/mipagentconfig 500 root bin +f none usr/sbin/mipagentstat 555 root bin diff --git a/deleted_files/usr/src/pkgdefs/SUNWmipu/prototype_i386 b/deleted_files/usr/src/pkgdefs/SUNWmipu/prototype_i386 new file mode 100644 index 0000000000..334051a3c0 --- /dev/null +++ b/deleted_files/usr/src/pkgdefs/SUNWmipu/prototype_i386 @@ -0,0 +1,51 @@ +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 +# +# +#pragma ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1999 by Sun Microsystems, Inc. +# All rights reserved. +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. + +#!search <pathname pathname ...> # where to find pkg objects +#!include <filename> # include another 'prototype' file +#!default <mode> <owner> <group> # default used if not specified on entry +#!<param>=<value> # puts parameter in pkg environment + +# +# Include ISA independent files (prototype_com) +# +!include prototype_com +# +# +# +# List files which are I386 specific here +# +# source locations relative to the prototype file +# +# +# SUNWmipu +# diff --git a/deleted_files/usr/src/pkgdefs/SUNWmipu/prototype_sparc b/deleted_files/usr/src/pkgdefs/SUNWmipu/prototype_sparc new file mode 100644 index 0000000000..06068e73ff --- /dev/null +++ b/deleted_files/usr/src/pkgdefs/SUNWmipu/prototype_sparc @@ -0,0 +1,51 @@ +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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 +# +# +#pragma ident "%Z%%M% %I% %E% SMI" +# +# Copyright (c) 1999 by Sun Microsystems, Inc. +# All rights reserved. +# +# This required package information file contains a list of package contents. +# The 'pkgmk' command uses this file to identify the contents of a package +# and their location on the development machine when building the package. +# Can be created via a text editor or through use of the 'pkgproto' command. + +#!search <pathname pathname ...> # where to find pkg objects +#!include <filename> # include another 'prototype' file +#!default <mode> <owner> <group> # default used if not specified on entry +#!<param>=<value> # puts parameter in pkg environment + +# +# Include ISA independent files (prototype_com) +# +!include prototype_com +# +# +# +# List files which are SPARC specific here +# +# source locations relative to the prototype file +# +# +# SUNWmipu +# |