amiga-roadshow/examples/ConfigureNetInterface.c

2375 lines
55 KiB
C

/*
* $Id: ConfigureNetInterface.c,v 1.17 2007-08-26 12:30:15 obarthel Exp $
*
* :ts=4
*
* Copyright © 2001-2007 by Olaf Barthel. All Rights Reserved.
*/
#include <libraries/bsdsocket.h>
#include <exec/execbase.h>
#include <exec/memory.h>
#include <dos/dosextens.h>
#include <dos/dostags.h>
#include <dos/dosasl.h>
#include <dos/rdargs.h>
#include <dos/stdio.h>
#include <libraries/locale.h>
/****************************************************************************/
#if defined(__amigaos4__)
#include <dos/obsolete.h>
#endif /* __amigaos4__ */
/****************************************************************************/
#if !defined(__amigaos4__)
#define NO_INLINE_STDARG
#endif /* __amigaos4__ */
#define __NOLIBBASE__
#define __NOGLOBALIFACE__
#define __USE_INLINE__
/****************************************************************************/
#include <proto/bsdsocket.h>
#include <proto/utility.h>
#include <proto/locale.h>
#include <proto/exec.h>
#include <proto/dos.h>
/****************************************************************************/
#if defined(__amigaos4__) && !defined(Flush)
#define Flush(fh) FFlush(fh)
#endif /* __amigaos4__ */
/****************************************************************************/
#include <string.h>
#include <stdarg.h>
/****************************************************************************/
#include "macros.h"
/****************************************************************************/
#include "ConfigureNetInterface_rev.h"
/****************************************************************************/
#ifndef AbsExecBase
#define AbsExecBase (*(struct ExecBase **)4)
#endif /* AbsExecBase */
/****************************************************************************/
#ifndef FORMAT_DEF
#define FORMAT_DEF 4
#endif /* FORMAT_DEF */
/****************************************************************************/
typedef LONG * NUMBER;
typedef LONG SWITCH;
typedef STRPTR KEY;
/****************************************************************************/
struct CommandContext
{
struct Library * cc_SysBase;
struct Library * cc_DOSBase;
struct Library * cc_UtilityBase;
struct Library * cc_LocaleBase;
struct Library * cc_SocketBase;
#if defined(__amigaos4__)
/************************************************************************/
struct ExecIFace * cc_IExec;
struct DOSIFace * cc_IDOS;
struct UtilityIFace * cc_IUtility;
struct LocaleIFace * cc_ILocale;
struct SocketIFace * cc_ISocket;
/************************************************************************/
#endif /* __amigaos4__ */
struct Catalog * cc_Catalog;
UBYTE cc_ProgramName[256];
struct TagItem * cc_Tags;
LONG cc_NumTags;
LONG cc_MaxTags;
struct MsgPort * cc_ReplyPort;
struct AddressAllocationMessage
cc_AllocationMessage;
ULONG cc_RouterTable[16];
ULONG cc_DNSTable[16];
struct DateStamp cc_LeaseExpires;
};
/****************************************************************************/
#if defined(__amigaos4__)
/****************************************************************************/
#define DECLARE_SYSBASE(cc) \
struct ExecIFace * IExec = cc->cc_IExec; \
struct Library * SysBase = cc->cc_SysBase
#define DECLARE_DOSBASE(cc) \
struct DOSIFace * IDOS = cc->cc_IDOS; \
struct Library * DOSBase = cc->cc_DOSBase
#define DECLARE_UTILITYBASE(cc) \
struct UtilityIFace * IUtility = cc->cc_IUtility; \
struct Library * UtilityBase = cc->cc_UtilityBase
#define DECLARE_LOCALEBASE(cc) \
struct LocaleIFace * ILocale = cc->cc_ILocale; \
struct Library * LocaleBase = cc->cc_LocaleBase
#define DECLARE_SOCKETBASE(cc) \
struct SocketIFace * ISocket = cc->cc_ISocket; \
struct Library * SocketBase = cc->cc_SocketBase
/****************************************************************************/
#else
/****************************************************************************/
#define DECLARE_SYSBASE(cc) \
struct Library * SysBase = cc->cc_SysBase
#define DECLARE_DOSBASE(cc) \
struct Library * DOSBase = cc->cc_DOSBase
#define DECLARE_UTILITYBASE(cc) \
struct Library * UtilityBase = cc->cc_UtilityBase
#define DECLARE_LOCALEBASE(cc) \
struct Library * LocaleBase = cc->cc_LocaleBase
#define DECLARE_SOCKETBASE(cc) \
struct Library * SocketBase = cc->cc_SocketBase
/****************************************************************************/
#endif /* __amigaos4__ */
/****************************************************************************/
LONG _start(VOID);
/****************************************************************************/
STATIC VOID close_libs(struct CommandContext *cc);
STATIC LONG open_libs(struct CommandContext *cc, struct Library *SysBase);
STATIC LONG cmd(struct CommandContext *cc);
STATIC BOOL validate_ip_address(struct CommandContext *cc, BOOL quiet, STRPTR key, STRPTR address);
STATIC LONG add_tag(struct CommandContext *cc, Tag tag, ULONG data);
STATIC VOID get_errno_and_code(struct CommandContext *cc, LONG *errno_ptr, STRPTR *code_ptr);
STATIC BOOL substring_matches(struct CommandContext *cc, STRPTR pattern, STRPTR string);
STATIC BOOL is_blank_space(UBYTE c);
STATIC VOID strip_extra_blank_spaces(STRPTR s);
STATIC LONG VARARGS68K Local_Printf(struct CommandContext *cc, STRPTR format, ...);
STATIC VOID Local_PrintFault(struct CommandContext *cc, LONG error, STRPTR prefix);
STATIC LONG VARARGS68K Local_ErrorPrintf(struct CommandContext *cc, STRPTR format, ...);
STATIC STRPTR get_builtin_str(LONG id);
STATIC STRPTR get_str(struct CommandContext *cc, LONG id);
STATIC LONG VARARGS68K Local_AddRouteTags(struct CommandContext *cc, ...);
STATIC LONG VARARGS68K Local_ConfigureInterfaceTags(struct CommandContext *cc, STRPTR interface_name, ...);
STATIC LONG VARARGS68K Local_SocketBaseTags(struct CommandContext *cc, ...);
/****************************************************************************/
/****** ROADSHOW/CONFIGURENETINTERFACE ****************************************
*
* NAME
* ConfigureNetInterface - Configure network interface parameters.
*
* FORMAT
* ConfigureNetInterface [QUIET] [TIMEOUT=<n>] INTERFACE
*
* TEMPLATE
* INTERFACE/A,QUIET/S,ADDRESS/K,NETMASK/K,BROADCASTADDR/K,
* DESTINATION=DESTINATIONADDR/K,METRIC/K/N,MTU/K/N,ALIASADDR/K,
* DELETEADDR/K,ONLINE/S,OFFLINE/S,UP/S,DOWN/S,DEBUG/K,COMPLETE/K,
* CONFIGURE/K,LEASE/K,RELEASE=RELEASEADDRESS/S,ID/K,TIMEOUT/K/N,
* DHCPUNICAST/K
*
* PATH
* C:CONFIGURENETINTERFACE
*
* FUNCTION
* CONFIGURENETINTERFACE is used to define how a network interface will
* react and how it will interact with your network.
*
* OPTIONS
* INTERFACE/A
* The name of the interface to be configured. This is a required
* parameter.
*
* QUIET/S
* This option causes the program not to emit any error messages
* or progress reports. Also, if the program encounters an error
* it will flag this as failure code 5 which can be looked at
* using the 'if warn' shell script command. If this option is
* not in effect, failure codes will be more severe and all sorts
* of progress information will be displayed.
*
* ADDRESS/K
* The IP address to assign to this interface. This should be
* specified in dotted-decimal notation ("192.168.0.1") and not as
* symbolic name since the system may not be in a state to perform a
* name resolution.
*
* In place of the IP address you can also specify "DHCP". As the
* name suggests, this will start a configuration process involving
* the DHCP protocol which should eventually yield the right IP
* address for this host. Note that this configuration procedure only
* works for Ethernet hardware.
*
* NETMASK/K
* The subnet mask to assign to this interface. This must be
* specified in dotted-decimal notation ("192.168.0.1").
*
* In place of the subnet mask you can also specify "DHCP". As the
* name suggests, this will start a configuration process involving
* the DHCP protocol which should eventually yield the right
* subnet mask for this host. Note that this configuration procedure
* only works for Ethernet hardware.
*
* BROADCASTADDR/K
* The broadcast address to be used by this interface; must be
* specified in dotted-decimal notation ("192.168.0.1") and only
* works with interfaces that support broadcasts in the first place
* (i.e. Ethernet hardware).
*
* DESTINATION=DESTINATIONADDR/K
* The address of the point-to-point partner for this interface; must
* be specified in dotted-decimal notation ("192.168.0.1"). Only
* works for point-to-point connections, such as PPP.
*
* METRIC/K/N
* Route metric value for this interface.
*
* MTU/K/N
* You can limit the maximum transmission size used by the TCP/IP
* stack to push data through the interface. The interface driver
* will have its own ideas about the maximum transmission size.
* You can therefore only suggest a smaller value than the
* driver's preferred hardware MTU size.
*
* ALIASADDR/K
* This adds another address to this interface to respond to. You
* can add as many aliases as you like, provided you don't run out
* of memory.
*
* DELETEADDR/K
* This removes an alias address from the list the interface is to
* respond to.
*
* UP
* DOWN
* ONLINE
* OFFLINE
* This configures the 'line state' of the interface; four states
* are supported:
*
* UP
* The protocol stack will attempt to transmit messages
* through this interface (even though it might not be
* online yet).
*
* DOWN
* The protocol stack will no longer attempt to transmit
* messages through this interface (even though it might
* still be online).
*
* OFFLINE
* The underlying networking device driver is put offline
* and the protocol stack will no longer try to send
* messages through the interface either.
*
* ONLINE
* An attempt is made to put the underlying networking
* driver online. If that works, then the protocol stack
* will attempt to transmit messages through this
* interface.
*
* DEBUG/K (possible parameters: YES or NO)
* You can enable debug output for this interface to help in tracking
* down configuration problems. At this time of writing, the debug
* mode will, if enabled, produce information on the progress of the
* DHCP configuration process.
*
* COMPLETE/K (possible parameters: YES or NO)
* If you configure an interface in several steps, use this parameter
* in the final invocation of the program. It will tell the TCP/IP
* stack that the configuration for this interface is complete. This
* has the effect of causing the static route definition file to be
* reread, if necessary.
*
* RELEASEADDRESS
* If an IP address was dynamically assigned to an interface, this
* switch will tell ConfigureNetInterface to release it. Note that
* you can only release what was previously allocated.
*
* CONFIGURE/K (possible parameters: DHCP, AUTO or FASTAUTO)
* You can use DHCP configuration for this interface and protocol
* stack internals, namely the list of routers (and the default
* gateway) to use and the domain name servers. This option allows
* you to bring up the complete network configuration in one
* single step.
*
* You can request that a particular IP address is assigned to this
* interface by the DHCP process by specifying CONFIGURE=DHCP and
* your choice of ADDRESS=xxx.xxx.xxx.xxx.
*
* If your network has no DHCP server, you may choose
* CONFIGURE=AUTO to use automatic IPv4 address selection,
* based upon a protocol called ZeroConf. This protocol will
* select a currently unused address from a specially
* designated address range.
*
* If you choose automatic configuration in a wireless network,
* you might want to use CONFIGURE=FASTAUTO instead of
* CONFIGURE=AUTO.
*
* Note that only the CONFIGURE=DHCP option will attempt to
* set up a default route and a set of DNS servers for you to
* use. The alternatives of CONFIGURE=FASTAUTO and
* CONFIGURE=AUTO are restricted to selecting the network
* interface IPv4 addresses.
*
* TIMEOUT/K/N
* If you're going to use DHCP configuration for any of the
* interfaces, a default timeout value of 60 seconds will
* limit the time an interface can take to be configured.
* This parameter allows you to use a different timeout value.
* Note that due to how the configuration protocol works,
* the timeout cannot be shorter than ten seconds.
*
* LEASE/K
* This is a complex option which can be used to request how long an
* IP address should be bound to an interface. Several combinations
* of options are possible. Here is a short list:
*
* LEASE=300
* LEASE=300seconds
*
* This requests a lease of exactly 300 seconds, or
* five minutes.
*
* LEASE=30min
*
* This requests a lease of 30 minutes.
*
* LEASE=2hours
*
* This requests a lease of 2 hours.
*
* LEASE=1day
*
* This requests a lease of 1 day.
*
* LEASE=4weeks
*
* This requests a lease of 4 weeks.
*
* LEASE=infinite
*
* This requests that the IP address should be
* permanently bound.
*
* Blank spaces between the numbers and the qualifiers are supported.
* The qualifiers are tested using substring matching, which means
* for example that "30 minutes" is the same as "30 min" and "30 m".
*
* Note that the requested lease time may be ignored by the DHCP
* server. After all, it is just a suggestion and not an order.
*
* ID/K
* This option works along with the CONFIGURE=DHCP process. It can be
* used to tell the DHCP server by which name the local host should be
* referred to. Some DHCP servers are on good terms with their local name
* resolution services and will add the name and the associated IP
* address to the local host database. The name you can supply here
* cannot be longer than 255 characters and must be at least 2 characters
* long. Keep it brief: not all DHCP servers have room for the whole 255
* characters.
*
* DHCPUNICAST/K (possible parameters: YES or NO)
* Some DHCP servers may not be able to respond to requests for
* assigning IP addresses unless the responses are sent directly
* to the computer which sent the requests. In such cases you
* might want to use DHCPUNICAST=YES option.
*
* NOTES
* The command is similar to the Unix "ifconfig" command.
*
* If you tell an interface to go online then the program's return
* code will tell you if the command succeeded: a return value of 0
* indicates success (the interface is now online), and a value
* of 5 indicates that it didn't quite work.
*
* Configuring the address of an interface has two effects: first,
* the interface will be marked as 'up', meaning that the protocol
* stack will attempt to send messages through it when appropriate.
* Second, a direct route to the interface will be established.
*
* SEE ALSO
* AddNetInterface
*
******************************************************************************
*/
LONG
_start(VOID)
{
struct Library *SysBase = (struct Library *)AbsExecBase;
#if defined(__amigaos4__)
struct ExecIFace * IExec = (struct ExecIFace *)((struct ExecBase *)SysBase)->MainInterface;
#endif /* __amigaos4__ */
struct CommandContext _cc,*cc = &_cc;
LONG result = RETURN_FAIL;
struct Process * pr;
LONG error;
memset(cc,0,sizeof(*cc));
pr = (struct Process *)FindTask(NULL);
if(pr->pr_CLI == ZERO)
{
struct MsgPort * mp = &pr->pr_MsgPort;
struct Message * mn;
WaitPort(mp);
mn = GetMsg(mp);
Forbid();
ReplyMsg(mn);
goto out;
}
error = open_libs(cc,SysBase);
if(error == OK)
{
DECLARE_LOCALEBASE(cc);
if(cc->cc_LocaleBase != NULL)
cc->cc_Catalog = OpenCatalogA(NULL,"roadshow.catalog",NULL);
result = cmd(cc);
if(cc->cc_Tags != NULL)
FreeVec(cc->cc_Tags);
if(cc->cc_Catalog != NULL)
CloseCatalog(cc->cc_Catalog);
}
else
{
pr->pr_Result2 = error;
}
close_libs(cc);
out:
return(result);
}
/****************************************************************************/
STATIC VOID
close_libs(struct CommandContext * cc)
{
DECLARE_SYSBASE(cc);
#if defined(__amigaos4__)
{
if(cc->cc_IDOS != NULL)
DropInterface((struct Interface *)cc->cc_IDOS);
if(cc->cc_ILocale != NULL)
DropInterface((struct Interface *)cc->cc_ILocale);
if(cc->cc_ISocket != NULL)
DropInterface((struct Interface *)cc->cc_ISocket);
if(cc->cc_IUtility != NULL)
DropInterface((struct Interface *)cc->cc_IUtility);
}
#endif /* __amigaos4__ */
if(cc->cc_UtilityBase != NULL)
CloseLibrary(cc->cc_UtilityBase);
if(cc->cc_SocketBase != NULL)
CloseLibrary(cc->cc_SocketBase);
if(cc->cc_LocaleBase != NULL)
CloseLibrary(cc->cc_LocaleBase);
if(cc->cc_DOSBase != NULL)
CloseLibrary(cc->cc_DOSBase);
}
/****************************************************************************/
STATIC LONG
open_libs(struct CommandContext * cc,struct Library *SysBase)
{
#if defined(__amigaos4__)
struct ExecIFace * IExec = (struct ExecIFace *)((struct ExecBase *)SysBase)->MainInterface;
#endif /* __amigaos4__ */
LONG error;
cc->cc_SysBase = SysBase;
#if defined(__amigaos4__)
{
cc->cc_IExec = IExec;
}
#endif /* __amigaos4__ */
cc->cc_DOSBase = OpenLibrary("dos.library",36);
#if defined(__amigaos4__)
{
if(cc->cc_DOSBase != NULL)
{
cc->cc_IDOS = (struct DOSIFace *)GetInterface(cc->cc_DOSBase, "main", 1, 0);
if(cc->cc_IDOS == NULL)
{
CloseLibrary(cc->cc_DOSBase);
cc->cc_DOSBase = NULL;
}
}
}
#endif /* __amigaos4__ */
if(cc->cc_DOSBase == NULL)
{
error = ERROR_INVALID_RESIDENT_LIBRARY;
goto out;
}
cc->cc_LocaleBase = OpenLibrary("locale.library",38);
#if defined(__amigaos4__)
{
if(cc->cc_LocaleBase != NULL)
{
cc->cc_ILocale = (struct LocaleIFace *)GetInterface(cc->cc_LocaleBase, "main", 1, 0);
if(cc->cc_ILocale == NULL)
{
CloseLibrary(cc->cc_LocaleBase);
cc->cc_LocaleBase = NULL;
}
}
}
#endif /* __amigaos4__ */
cc->cc_UtilityBase = OpenLibrary("utility.library",37);
#if defined(__amigaos4__)
{
if(cc->cc_UtilityBase != NULL)
{
cc->cc_IUtility = (struct UtilityIFace *)GetInterface(cc->cc_UtilityBase, "main", 1, 0);
if(cc->cc_IUtility == NULL)
{
CloseLibrary(cc->cc_UtilityBase);
cc->cc_UtilityBase = NULL;
}
}
}
#endif /* __amigaos4__ */
/* The following may be necessary to flush out an inoperable
bsdsocket.library which reached the end of the shutdown
process. */
#if 1
{
struct ExecBase * ex = (struct ExecBase *)SysBase;
struct Library * lib;
Forbid();
lib = (struct Library *)FindName(&ex->LibList,"bsdsocket.library");
if(lib != NULL)
RemLibrary(lib);
Permit();
}
#endif
cc->cc_SocketBase = OpenLibrary("bsdsocket.library",4);
#if defined(__amigaos4__)
{
if(cc->cc_SocketBase != NULL)
{
cc->cc_ISocket = (struct SocketIFace *)GetInterface(cc->cc_SocketBase, "main", 1, 0);
if(cc->cc_ISocket == NULL)
{
CloseLibrary(cc->cc_SocketBase);
cc->cc_SocketBase = NULL;
}
}
}
#endif /* __amigaos4__ */
error = OK;
out:
return(error);
}
/****************************************************************************/
#define CATCOMP_ARRAY
#define CONFIGURENETINTERFACE_CATALOG_STRINGS
#include "roadshow.h"
/****************************************************************************/
STATIC LONG
cmd(struct CommandContext * cc)
{
struct
{
KEY Interface;
SWITCH Quiet;
KEY Address;
KEY NetMask;
KEY BroadcastAddress;
KEY DestinationAddress;
NUMBER Metric;
NUMBER MTU;
KEY AddAddress;
KEY DeleteAddress;
SWITCH Online;
SWITCH Offline;
SWITCH Up;
SWITCH Down;
KEY Debug;
KEY Complete;
KEY Configure;
KEY Lease;
SWITCH ReleaseAddress;
KEY ID;
NUMBER Timeout;
KEY DHCPUnicast;
} args;
STRPTR args_template =
"INTERFACE/A,"
"QUIET/S,"
"ADDRESS/K,"
"NETMASK/K,"
"BROADCASTADDR/K,"
"DESTINATION=DESTINATIONADDR/K,"
"METRIC/K/N,"
"MTU/K/N,"
"ALIASADDR/K,"
"DELETEADDR/K,"
"ONLINE/S,"
"OFFLINE/S,"
"UP/S,"
"DOWN/S,"
"DEBUG/K,"
"COMPLETE/K,"
"CONFIGURE/K,"
"LEASE/K,"
"RELEASE=RELEASEADDRESS/S,"
"ID/K,"
"TIMEOUT/K/N,"
"DHCPUNICAST/K"
VERSTAG;
DECLARE_SYSBASE(cc);
DECLARE_DOSBASE(cc);
DECLARE_UTILITYBASE(cc);
DECLARE_SOCKETBASE(cc);
struct AddressAllocationMessage * aam = &cc->cc_AllocationMessage;
LONG result = RETURN_FAIL;
LONG have_interface_api = FALSE;
LONG have_routing_api = FALSE;
LONG have_address_conversion_api = FALSE;
struct RDArgs * rda;
STRPTR state_name = NULL;
int state = -1;
LONG error;
BOOL quiet = FALSE;
STRPTR address = NULL;
STRPTR net_mask = NULL;
BOOL configure_dynamic = FALSE;
BOOL configure_auto = FALSE;
BOOL configure_slow_auto = FALSE;
LONG timeout;
UBYTE default_domain_name[256];
ULONG lease_time = DHCP_DEFAULT_LEASE_TIME;
STRPTR client_id = NULL;
LONG dhcp_unicast = FALSE;
GetProgramName(cc->cc_ProgramName,sizeof(cc->cc_ProgramName));
memset(&args,0,sizeof(args));
rda = ReadArgs(args_template,(LONG *)&args,NULL);
if(rda == NULL)
{
PrintFault(IoErr(),cc->cc_ProgramName);
goto out;
}
quiet = (BOOL)(args.Quiet != 0);
if(UtilityBase == NULL)
{
if(NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_NO_UTILITY_TXT),
cc->cc_ProgramName);
}
goto out;
}
if(SocketBase == NULL)
{
if(NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_CANNOT_OPEN_BSDSOCKET_TXT),
cc->cc_ProgramName);
}
goto out;
}
if(Local_SocketBaseTags(cc,
SBTM_GETREF(SBTC_HAVE_INTERFACE_API),&have_interface_api,
TAG_END) != 0)
{
have_interface_api = FALSE;
}
if(NOT have_interface_api)
{
if(NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_BSDSOCKET_HAS_NO_INTERFACE_API_TXT),
cc->cc_ProgramName, SocketBase->lib_Node.ln_Name, SocketBase->lib_Version, SocketBase->lib_Revision);
}
goto out;
}
if(Local_SocketBaseTags(cc,
SBTM_GETREF(SBTC_HAVE_ROUTING_API),&have_routing_api,
TAG_END) != 0)
{
have_routing_api = FALSE;
}
if(NOT have_routing_api)
{
if(NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_BSDSOCKET_HAS_NO_ROUTE_API_TXT),
cc->cc_ProgramName, SocketBase->lib_Node.ln_Name, SocketBase->lib_Version, SocketBase->lib_Revision);
}
goto out;
}
if(Local_SocketBaseTags(cc,
SBTM_GETREF(SBTC_HAVE_ADDRESS_CONVERSION_API),&have_address_conversion_api,
TAG_END) != 0)
{
have_address_conversion_api = FALSE;
}
if(NOT have_address_conversion_api)
{
if(NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_HAS_NO_ADDRESS_CONVERSION_API_TXT),
cc->cc_ProgramName, SocketBase->lib_Node.ln_Name, SocketBase->lib_Version, SocketBase->lib_Revision);
}
goto out;
}
if(args.Address != NULL)
{
struct in_addr in;
if(Stricmp(args.Address,"DHCP") != SAME)
{
if(CANNOT validate_ip_address(cc,quiet,"ADDRESS",args.Address))
goto out;
}
if(inet_aton(args.Address,&in))
{
if(in.s_addr == 0 || in.s_addr == ~0UL)
{
if(NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_INVALID_ADDRESS_TXT),
cc->cc_ProgramName,args.Address);
}
goto out;
}
if(((in.s_addr >> 24) & 0xFF) == 169 &&
((in.s_addr >> 16) & 0xFF) == 254)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_DYNAMIC_ADDRESS_SHOULD_NOT_BE_BOUND_TXT),
cc->cc_ProgramName,args.Address);
}
}
FreeVec(address);
address = AllocVec(strlen(args.Address) + 1,MEMF_ANY|MEMF_PUBLIC);
if(address != NULL)
{
strcpy(address,args.Address);
}
else
{
if(NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_NOT_ENOUGH_MEMORY_TO_CONFIGURE_INTERFACE_ADDRESS_TXT),
cc->cc_ProgramName,args.Interface);
}
goto out;
}
}
if(args.NetMask != NULL)
{
if(Stricmp(args.NetMask,"DHCP") != SAME)
{
if(CANNOT validate_ip_address(cc,quiet,"NETMASK",args.NetMask))
goto out;
}
FreeVec(net_mask);
net_mask = AllocVec(strlen(args.NetMask) + 1,MEMF_ANY|MEMF_PUBLIC);
if(net_mask != NULL)
{
strcpy(net_mask,args.NetMask);
}
else
{
if(NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_NOT_ENOUGH_MEMORY_TO_CONFIGURE_INTERFACE_MASK_TXT),
cc->cc_ProgramName,args.Interface);
}
goto out;
}
}
if(args.DestinationAddress != NULL)
{
if(CANNOT validate_ip_address(cc,quiet,"DESTINATIONADDR",args.DestinationAddress))
goto out;
error = add_tag(cc,IFC_DestinationAddress,(ULONG)args.DestinationAddress);
if(error != OK)
{
if(NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_NOT_ENOUGH_MEMORY_TO_CONFIGURE_INTERFACE_DESTINATION_ADDRESS_TXT),
cc->cc_ProgramName,args.Interface,args.DestinationAddress);
}
goto out;
}
}
if(args.BroadcastAddress != NULL)
{
if(CANNOT validate_ip_address(cc,quiet,"BROADCASTADDR",args.BroadcastAddress))
goto out;
error = add_tag(cc,IFC_BroadcastAddress,(ULONG)args.BroadcastAddress);
if(error != OK)
{
if(NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_NOT_ENOUGH_MEMORY_TO_CONFIGURE_INTERFACE_BROADCAST_ADDRESS_TXT),
cc->cc_ProgramName,args.Interface,args.BroadcastAddress);
}
goto out;
}
}
if(args.Metric != NULL)
{
error = add_tag(cc,IFC_Metric,(*args.Metric));
if(error != OK)
{
if(NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_NOT_ENOUGH_MEMORY_TO_CONFIGURE_INTERFACE_METRIC_TXT),
cc->cc_ProgramName,args.Interface,(*args.Metric));
}
goto out;
}
}
if(args.MTU != NULL && (*args.MTU) > 0)
{
error = add_tag(cc,IFC_LimitMTU,(*args.MTU));
if(error != OK)
{
if(NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_NOT_ENOUGH_MEMORY_TO_CONFIGURE_INTERFACE_MTU_TXT),
cc->cc_ProgramName,args.Interface,(*args.MTU));
}
goto out;
}
}
if(args.Timeout != NULL && (*args.Timeout) > 0)
{
timeout = (*args.Timeout);
if(timeout < AAM_TIMEOUT_MIN)
{
if(NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_TIMEOUT_TOO_SHORT_TXT),
cc->cc_ProgramName,timeout);
}
timeout = AAM_TIMEOUT_MIN;
}
}
else
{
timeout = 60;
}
if(args.AddAddress != NULL)
{
if(CANNOT validate_ip_address(cc,quiet,"ALIASADDR",args.AddAddress))
goto out;
error = add_tag(cc,IFC_AddAliasAddress,(ULONG)args.AddAddress);
if(error != OK)
{
if(NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_NOT_ENOUGH_MEMORY_TO_ADD_ALIAS_ADDRESS_TXT),
cc->cc_ProgramName,args.Interface,args.AddAddress);
}
goto out;
}
}
if(args.DeleteAddress != NULL)
{
if(CANNOT validate_ip_address(cc,quiet,"DELETEADDR",args.DeleteAddress))
goto out;
error = add_tag(cc,IFC_DeleteAliasAddress,(ULONG)args.DeleteAddress);
if(error != OK)
{
if(NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_NOT_ENOUGH_MEMORY_TO_DELETE_ALIAS_ADDRESS_TXT),
cc->cc_ProgramName,args.Interface,args.DeleteAddress);
}
goto out;
}
}
if(args.Debug != NULL)
{
BOOL mode = FALSE;
if(Stricmp(args.Debug,"ON") == SAME || Stricmp(args.Debug,"YES") == SAME)
{
mode = TRUE;
}
else if (Stricmp(args.Debug,"OFF") != SAME && Stricmp(args.Debug,"NO") != SAME)
{
if(NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_UNKNOWN_DEBUG_PARAMETER_TXT),
cc->cc_ProgramName,args.Debug);
}
goto out;
}
error = add_tag(cc,IFC_SetDebugMode,(ULONG)mode);
if(error != OK)
{
if(NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_NOT_ENOUGH_MEMORY_TO_CONFIGURE_TXT),
cc->cc_ProgramName,args.Interface);
}
goto out;
}
}
if(args.Complete != NULL)
{
BOOL complete = FALSE;
if(Stricmp(args.Complete,"ON") == SAME || Stricmp(args.Complete,"YES") == SAME)
{
complete = TRUE;
}
else if (Stricmp(args.Complete,"OFF") != SAME && Stricmp(args.Complete,"NO") != SAME)
{
if(NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_UNKNOWN_COMPLETE_PARAMETER_TXT),
cc->cc_ProgramName,args.Complete);
}
goto out;
}
error = add_tag(cc,IFC_Complete,(ULONG)complete);
if(error != OK)
{
if(NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_NOT_ENOUGH_MEMORY_TO_CONFIGURE_TXT),
cc->cc_ProgramName,args.Interface);
}
goto out;
}
}
if(args.Configure != NULL)
{
if(Stricmp(args.Configure,"DHCP") == SAME)
{
configure_dynamic = TRUE;
configure_auto = FALSE;
}
else if (Stricmp(args.Configure,"SLOWAUTO") == SAME || Stricmp(args.Configure,"AUTO") == SAME)
{
configure_dynamic = configure_auto = configure_slow_auto = TRUE;
}
else if (Stricmp(args.Configure,"FASTAUTO") == SAME)
{
configure_dynamic = configure_auto = TRUE;
configure_slow_auto = FALSE;
}
else
{
if(NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_UNKNOWN_CONFIGURE_PARAMETER_TXT),
cc->cc_ProgramName,args.Configure);
}
goto out;
}
}
if(args.Online || args.Offline || args.Up || args.Down)
{
STRPTR switches[4];
LONG count;
memset(switches,0,sizeof(switches));
count = 0;
if(args.Online)
{
state_name = "ONLINE";
state = SM_Online;
switches[count++] = state_name;
}
if(args.Offline)
{
state_name = "OFFLINE";
state = SM_Offline;
switches[count++] = state_name;
}
if(args.Up)
{
state_name = "UP";
state = SM_Up;
switches[count++] = state_name;
}
if(args.Down)
{
state_name = "DOWN";
state = SM_Down;
switches[count++] = state_name;
}
if(count > 1)
{
if(NOT quiet)
{
LONG i;
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_PICK_ONLY_ONE_STATE_TXT),cc->cc_ProgramName);
for(i = 0 ; i < count ; i++)
{
if(i > 0)
Local_ErrorPrintf(cc,",");
Local_ErrorPrintf(cc," %s",switches[i]);
}
Local_ErrorPrintf(cc,".\n");
}
goto out;
}
}
if(args.Lease != NULL)
{
STRPTR s = args.Lease;
STRPTR key = NULL;
LONG number;
LONG len;
while(is_blank_space(*s))
s++;
len = 0;
number = 0;
while('0' <= (*s) && (*s) <= '9')
{
number = (10 * number) + (*s) - '0';
len++;
s++;
}
while(is_blank_space(*s))
s++;
if(s[0] != '\0')
key = s;
if(len == 0 && key != NULL)
{
if(substring_matches(cc,"INF",key) == SAME)
{
lease_time = DHCP_INFINITE_LEASE_TIME;
}
else
{
if(NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_UNKNOWN_LEASE_PARAMETER_TXT),
cc->cc_ProgramName,key);
}
goto out;
}
}
else if (len > 0)
{
lease_time = number;
if(key != NULL)
{
if(substring_matches(cc,"SECOND",key) == SAME)
{
/* This is the default unit */
}
else if (substring_matches(cc,"MINUTE",key) == SAME)
{
lease_time *= 60;
}
else if (substring_matches(cc,"HOUR",key) == SAME)
{
lease_time *= 60 * 60;
}
else if (substring_matches(cc,"DAY",key) == SAME)
{
lease_time *= 24 * 60 * 60;
}
else if (substring_matches(cc,"WEEK",key) == SAME)
{
lease_time *= 7 * 24 * 60 * 60;
}
else
{
if(NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_UNKNOWN_LEASE_PARAMETER_TXT),
cc->cc_ProgramName,key);
}
goto out;
}
}
}
else
{
if(NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_INVALID_LEASE_PARAMETER_TXT),
cc->cc_ProgramName,args.Lease);
}
goto out;
}
}
if(args.ID != NULL)
{
if(strlen(args.ID) > 255 && NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_ID_TOO_LONG_TXT),
args.ID);
}
if(strlen(args.ID) < 2)
{
if(NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_ID_TOO_SHORT_TXT),
args.ID);
}
goto out;
}
client_id = args.ID;
}
/* Request that the DHCP server sends replies using
unicast instead of broadcast? */
if(args.DHCPUnicast != NULL)
{
LONG mode = FALSE;
if(Stricmp(args.DHCPUnicast,"ON") == SAME || Stricmp(args.DHCPUnicast,"YES") == SAME)
{
mode = TRUE;
}
else if (Stricmp(args.DHCPUnicast,"OFF") != SAME && Stricmp(args.DHCPUnicast,"NO") != SAME)
{
if(NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_UNKNOWN_UNICAST_PARAMETER_TXT),
cc->cc_ProgramName,args.DHCPUnicast);
}
goto out;
}
dhcp_unicast = mode;
}
if(args.ReleaseAddress)
{
if(Local_ConfigureInterfaceTags(cc,args.Interface,
IFC_ReleaseAddress,TRUE,
TAG_DONE) != 0)
{
if(NOT quiet)
{
LONG errno;
STRPTR code;
get_errno_and_code(cc,&errno,&code);
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_COULD_NOT_RELEASE_INTERFACE_ADDRESS_TXT),
cc->cc_ProgramName,args.Interface);
if(code != NULL && errno > 0)
Local_ErrorPrintf(cc," (%s)",code);
Local_ErrorPrintf(cc,".\n");
}
goto out;
}
if(NOT quiet)
{
Local_Printf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_INTERFACE_ADDRESS_WAS_RELEASED_TXT),
args.Interface);
}
}
if(address != NULL || configure_dynamic)
{
BOOL want_address = (BOOL)(address != NULL && Stricmp(address,"DHCP") == SAME);
BOOL want_netmask = (BOOL)(net_mask != NULL && Stricmp(net_mask,"DHCP") == SAME);
if(configure_dynamic || want_address || want_netmask)
{
LONG signals;
/* Remember the client identifier. */
aam->aam_ClientIdentifier = client_id;
/* We have to have the reply port ready. */
if(cc->cc_ReplyPort == NULL)
{
cc->cc_ReplyPort = CreateMsgPort();
if(cc->cc_ReplyPort == NULL)
{
if(NOT quiet)
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_NOT_ENOUGH_MEMORY_TO_CONFIGURE_TXT),cc->cc_ProgramName,args.Interface);
goto out;
}
}
/* Before we begin, we will need to mark this
interface 'up' so that the protocol stack will
send messages through it. */
if(Local_ConfigureInterfaceTags(cc,args.Interface,
IFC_State,SM_Up,
TAG_DONE) != 0)
{
if(NOT quiet)
{
LONG errno;
STRPTR code;
get_errno_and_code(cc,&errno,&code);
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_COULD_NOT_MARK_INTERFACE_UP_TXT),
cc->cc_ProgramName,args.Interface);
if(code != NULL && errno > 0)
Local_ErrorPrintf(cc," (%s)",code);
Local_ErrorPrintf(cc,".\n");
}
goto out;
}
if(NOT quiet)
{
Local_Printf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_TRYING_INTERFACE_CONFIGURATION_TXT),
cc->cc_ProgramName,args.Interface);
Flush(Output());
}
/* Initialize the message, then send it. */
aam->aam_Message.mn_Node.ln_Type = NT_REPLYMSG;
aam->aam_Message.mn_ReplyPort = cc->cc_ReplyPort;
aam->aam_Message.mn_Length = sizeof(*aam);
memcpy(aam->aam_InterfaceName,args.Interface,sizeof(aam->aam_InterfaceName)-1);
aam->aam_InterfaceName[sizeof(aam->aam_InterfaceName)-1] = '\0';
if(configure_auto)
{
if(configure_slow_auto)
aam->aam_Protocol = AAMP_SLOWAUTO;
else
aam->aam_Protocol = AAMP_FASTAUTO;
}
else
{
aam->aam_Protocol = AAMP_DHCP;
}
aam->aam_Version = AAM_VERSION;
aam->aam_Timeout = timeout;
aam->aam_LeaseTime = lease_time;
aam->aam_RouterTable = cc->cc_RouterTable;
aam->aam_RouterTableSize = NUM_ENTRIES(cc->cc_RouterTable);
aam->aam_DNSTable = cc->cc_DNSTable;
aam->aam_DNSTableSize = NUM_ENTRIES(cc->cc_DNSTable);
aam->aam_LeaseExpires = &cc->cc_LeaseExpires;
aam->aam_DomainName = default_domain_name;
aam->aam_DomainNameSize = sizeof(default_domain_name);
aam->aam_Unicast = dhcp_unicast; /* Note: this field only exists in version 2 and above */
strcpy(default_domain_name,"");
if(address != NULL && Stricmp(address,"DHCP") != SAME)
aam->aam_RequestedAddress = inet_addr(address);
BeginInterfaceConfig(aam);
/* Wait for something to happen. */
signals = Wait(SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_F | (1UL << cc->cc_ReplyPort->mp_SigBit));
if(signals & SIGBREAKF_CTRL_C)
{
AbortInterfaceConfig(aam);
WaitPort(cc->cc_ReplyPort);
GetMsg(cc->cc_ReplyPort);
if(NOT quiet)
{
Local_Printf(cc,"\n");
Local_PrintFault(cc,ERROR_BREAK,cc->cc_ProgramName);
}
goto out;
}
else if (signals & SIGBREAKF_CTRL_F)
{
AbortInterfaceConfig(aam);
WaitPort(cc->cc_ReplyPort);
GetMsg(cc->cc_ReplyPort);
if(NOT quiet)
{
Local_Printf(cc,"\n");
Local_Printf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_INTERFACE_CONFIGURATION_ABORTED_TXT),
cc->cc_ProgramName,args.Interface);
}
result = RETURN_OK;
goto out;
}
else
{
if(NOT quiet)
Local_Printf(cc,"\n");
WaitPort(cc->cc_ReplyPort);
GetMsg(cc->cc_ReplyPort);
if(aam->aam_Result != AAMR_Success && NOT quiet)
{
STATIC CONST error_map_table[][2] =
{
{ AAMR_Aborted, MSG_CONFIGURENETINTERFACE_INTERFACE_CONFIGURATION_ABORTED_TXT },
{ AAMR_Timeout, MSG_CONFIGURENETINTERFACE_INTERFACE_CONFIGURATION_TIMED_OUT_TXT },
{ AAMR_InterfaceNotKnown, MSG_CONFIGURENETINTERFACE_INTERFACE_CONFIGURATION_NAME_UNKNOWN_TXT },
{ AAMR_InterfaceWrongType, MSG_CONFIGURENETINTERFACE_INTERFACE_CONFIGURATION_WRONG_TYPE_TXT },
{ AAMR_AddressKnown, MSG_CONFIGURENETINTERFACE_INTERFACE_CONFIGURATION_ALREADY_CONFIGURED_TXT },
{ AAMR_VersionUnknown, MSG_CONFIGURENETINTERFACE_INTERFACE_CONFIGURATION_NOT_COMPATIBLE_TXT },
{ AAMR_NoMemory, MSG_CONFIGURENETINTERFACE_INTERFACE_CONFIGURATION_NOT_ENOUGH_MEMORY_TXT },
{ AAMR_AddressInUse, MSG_CONFIGURENETINTERFACE_INTERFACE_CONFIGURATION_ADDRESS_IN_USE_TXT },
{ AAMR_AddrChangeFailed, MSG_CONFIGURENETINTERFACE_INTERFACE_CONFIGURATION_ADDRESS_NOT_CHANGED_TXT },
{ AAMR_MaskChangeFailed, MSG_CONFIGURENETINTERFACE_INTERFACE_CONFIGURATION_MASK_NOT_CHANGED_TXT },
{ AAMR_Busy, MSG_CONFIGURENETINTERFACE_INTERFACE_IS_BUSY_TXT },
{ -1, -1}
};
LONG message_code;
size_t i;
message_code = MSG_CONFIGURENETINTERFACE_INTERFACE_CONFIGURATION_UNKNOWN_ERROR_TXT ;
for(i = 0 ; error_map_table[i][0] != -1 ; i++)
{
if(aam->aam_Result == error_map_table[i][0])
{
message_code = error_map_table[i][1];
break;
}
}
Local_ErrorPrintf(cc,get_str(cc,message_code),
cc->cc_ProgramName,args.Interface,aam->aam_Result);
}
if(aam->aam_Result != AAMR_Success)
{
result = RETURN_OK;
goto out;
}
if(configure_dynamic || want_address)
{
UBYTE str[20];
if(aam->aam_Address == 0)
{
if(NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_INTERFACE_NOT_CONFIGURED_ADDRESS_INVALID_TXT),
cc->cc_ProgramName,args.Interface);
}
goto out;
}
strcpy(str,Inet_NtoA(aam->aam_Address));
FreeVec(address);
address = AllocVec(strlen(str)+1,MEMF_ANY|MEMF_PUBLIC);
if(address == NULL)
{
if(NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_INTERFACE_CONFIGURATION_NOT_ENOUGH_MEMORY_TXT),
cc->cc_ProgramName,args.Interface);
}
goto out;
}
strcpy(address,str);
}
if(configure_dynamic || want_netmask)
{
if(aam->aam_SubnetMask == 0x00000000 ||
aam->aam_SubnetMask == 0xFFFFFFFF)
{
FreeVec(net_mask);
net_mask = NULL;
}
else
{
UBYTE str[20];
strcpy(str,Inet_NtoA(aam->aam_SubnetMask));
FreeVec(net_mask);
net_mask = AllocVec(strlen(str)+1,MEMF_ANY|MEMF_PUBLIC);
if(net_mask == NULL)
{
if(NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_INTERFACE_CONFIGURATION_NOT_ENOUGH_MEMORY_TXT),
cc->cc_ProgramName,args.Interface);
}
goto out;
}
strcpy(net_mask,str);
}
}
if(configure_dynamic)
{
LONG i,n;
n = 0;
for(i = 0 ; i < aam->aam_RouterTableSize ; i++)
{
if(aam->aam_RouterTable[i] != 0)
n++;
}
if(n == 0)
aam->aam_RouterTable = NULL;
n = 0;
for(i = 0 ; i < aam->aam_DNSTableSize ; i++)
{
if(aam->aam_DNSTable[i] != 0)
n++;
}
if(n == 0)
aam->aam_DNSTable = NULL;
}
/* If we are about to set the interface address, we will also
have to take care of the interface state, which defaults to
'up'. */
if(state == -1)
state = SM_Up;
}
}
}
if(address != NULL)
{
error = add_tag(cc,IFC_Address,(ULONG)address);
if(error != OK)
{
if(NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_NOT_ENOUGH_MEMORY_TO_CONFIGURE_ADDRESS_TXT),
cc->cc_ProgramName,args.Interface,address);
}
goto out;
}
}
if(net_mask != NULL)
{
error = add_tag(cc,IFC_NetMask,(ULONG)net_mask);
if(error != OK)
{
if(NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_NOT_ENOUGH_MEMORY_TO_CONFIGURE_NETMASK_TXT),
cc->cc_ProgramName,args.Interface,net_mask);
}
goto out;
}
}
if(cc->cc_NumTags > 0)
{
if(state == SM_Online || state == SM_Up)
{
error = add_tag(cc,IFC_State,state);
if(error != OK)
{
if(NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_NOT_ENOUGH_MEMORY_TO_CONFIGURE_STATE_TXT),
cc->cc_ProgramName,args.Interface);
}
goto out;
}
state = -1;
}
error = add_tag(cc,TAG_END,0);
if(error != OK)
{
if(NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_NOT_ENOUGH_MEMORY_TO_CONFIGURE_INTERFACE_TXT),
cc->cc_ProgramName,args.Interface);
}
goto out;
}
if(ConfigureInterfaceTagList(args.Interface,cc->cc_Tags) != OK)
{
if(NOT quiet)
{
LONG error = OK;
STRPTR code = NULL;
get_errno_and_code(cc,&error,&code);
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_COULD_NOT_CONFIGURE_INTERFACE_TXT),
cc->cc_ProgramName,args.Interface);
if(code != NULL && error > 0)
Local_ErrorPrintf(cc," (%s)",code);
Local_ErrorPrintf(cc,".\n");
}
goto out;
}
if(NOT quiet)
{
STRPTR prefix = "";
Local_Printf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_INTERFACE_CONFIGURED_TXT),
cc->cc_ProgramName,args.Interface);
if(args.Address != NULL)
{
Local_Printf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_INTERFACE_ADDRESS_IS_TXT),prefix,args.Address);
prefix = ", ";
}
if(args.NetMask != NULL)
{
Local_Printf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_INTERFACE_MASK_TXT),prefix,args.NetMask);
prefix = ", ";
}
if(args.DestinationAddress != NULL)
{
Local_Printf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_INTERFACE_DESTINATION_ADDRESS_TXT),prefix,args.DestinationAddress);
prefix = ", ";
}
if(args.BroadcastAddress != NULL)
{
Local_Printf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_INTERFACE_BROADCAST_ADDRESS_TXT),prefix,args.BroadcastAddress);
prefix = ", ";
}
if(args.Metric != NULL)
{
Local_Printf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_INTERFACE_METRIC_TXT),prefix,(*args.Metric));
prefix = ", ";
}
if(args.AddAddress != NULL)
{
Local_Printf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_INTERFACE_ADD_ADDRESS_TXT),prefix,args.AddAddress);
prefix = ", ";
}
if(args.DeleteAddress != NULL)
{
Local_Printf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_INTERFACE_DELETE_ADDRESS_TXT),prefix,args.DeleteAddress);
}
Local_Printf(cc,").\n");
}
}
if(configure_dynamic)
{
STRPTR domain_name;
if(aam->aam_DomainName != NULL && aam->aam_DomainName[0] != '\0')
domain_name = aam->aam_DomainName;
else
domain_name = "";
SetDefaultDomainName(domain_name);
if(domain_name[0] != '\0' && NOT quiet)
{
Local_Printf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_DEFAULT_DOMAIN_NAME_TXT),
cc->cc_ProgramName,domain_name);
}
}
if(configure_dynamic && aam->aam_RouterTable != NULL)
{
LONG i,n;
n = 0;
for(i = 0 ; i < aam->aam_RouterTableSize ; i++)
{
if(aam->aam_RouterTable[i] != 0)
{
UBYTE str[20];
LONG error = OK;
STRPTR code = NULL;
strcpy(str,Inet_NtoA(aam->aam_RouterTable[i]));
if(n == 0)
{
if(Local_AddRouteTags(cc,
RTA_DefaultGateway,str,
TAG_DONE) != OK)
{
get_errno_and_code(cc,&error,&code);
}
if(error == OK && NOT quiet)
{
Local_Printf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_ADDED_DEFAULT_ROUTE_TXT),
cc->cc_ProgramName,str);
}
}
else
{
if(Local_AddRouteTags(cc,
RTA_Destination,str,
TAG_DONE) != OK)
{
get_errno_and_code(cc,&error,&code);
}
if(error == OK && NOT quiet)
{
Local_Printf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_ADDED_ROUTE_TXT),
cc->cc_ProgramName,str);
}
}
if(error != OK)
{
if(NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_COULD_NOT_ADD_ROUTE_TO_TXT),
cc->cc_ProgramName,str);
if(code != NULL && error > 0)
Local_ErrorPrintf(cc," (%s)",code);
Local_ErrorPrintf(cc,".\n");
}
goto out;
}
n++;
}
}
}
if(configure_dynamic && aam->aam_DNSTable != NULL)
{
LONG i;
for(i = 0 ; i < aam->aam_DNSTableSize ; i++)
{
if(aam->aam_DNSTable[i] != 0)
{
UBYTE str[20];
LONG error = OK;
STRPTR code = NULL;
strcpy(str,Inet_NtoA(aam->aam_DNSTable[i]));
if(AddDomainNameServer(str) != OK)
get_errno_and_code(cc,&error,&code);
if(error != OK)
{
if(NOT quiet)
{
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_COULD_NOT_ADD_DNS_TXT),
cc->cc_ProgramName,str);
if(code != NULL && error > 0)
Local_ErrorPrintf(cc," (%s)",code);
Local_ErrorPrintf(cc,".\n");
}
goto out;
}
if(NOT quiet)
{
Local_Printf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_ADDED_DNS_TXT),
cc->cc_ProgramName,str);
}
}
}
}
if(configure_dynamic && aam->aam_Protocol == AAMP_DHCP && NOT quiet)
{
Local_Printf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_INTERFACE_ADDRESS_TXT),
cc->cc_ProgramName,args.Interface,address);
if(cc->cc_LeaseExpires.ds_Days == 0 &&
cc->cc_LeaseExpires.ds_Minute == 0 &&
cc->cc_LeaseExpires.ds_Tick == 0)
{
Local_Printf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_LEASED_PERMANENTLY_TXT));
}
else
{
struct DateTime dat;
UBYTE date[LEN_DATSTRING+1];
UBYTE time[LEN_DATSTRING+1];
memset(&dat,0,sizeof(dat));
dat.dat_Stamp = cc->cc_LeaseExpires;
dat.dat_Format = FORMAT_DEF;
dat.dat_StrDate = date;
dat.dat_StrTime = time;
DateToStr(&dat);
strip_extra_blank_spaces(date);
strip_extra_blank_spaces(time);
Local_Printf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_LEASED_UNTIL_TXT),
date,time);
}
}
if(state != -1)
{
if(Local_ConfigureInterfaceTags(cc,args.Interface,
IFC_State,state,
TAG_END) != OK)
{
if(NOT quiet)
{
LONG error = OK;
STRPTR code = NULL;
get_errno_and_code(cc,&error,&code);
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_COULD_NOT_SET_STATE_TXT),
cc->cc_ProgramName,args.Interface,state_name);
if(code != NULL && error > 0)
Local_ErrorPrintf(cc," (%s)",code);
Local_ErrorPrintf(cc,".\n");
}
if(state == SM_Online)
result = RETURN_WARN;
goto out;
}
if(NOT quiet)
{
Local_Printf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_STATE_CHANGED_TXT),
cc->cc_ProgramName,args.Interface,state_name);
}
}
result = RETURN_OK;
out:
DeleteMsgPort(cc->cc_ReplyPort);
FreeVec(address);
FreeVec(net_mask);
if(quiet && result != RETURN_OK)
result = RETURN_WARN;
if(rda != NULL)
FreeArgs(rda);
return(result);
}
/****************************************************************************/
STATIC BOOL
validate_ip_address(struct CommandContext * cc,BOOL quiet,STRPTR key,STRPTR address)
{
DECLARE_SOCKETBASE(cc);
struct in_addr in;
BOOL result;
if(inet_aton(address,&in))
{
result = TRUE;
}
else
{
if(NOT quiet)
Local_ErrorPrintf(cc,get_str(cc,MSG_CONFIGURENETINTERFACE_INVALID_IP_ADDRESS_AT_TXT),cc->cc_ProgramName,key,address);
result = FALSE;
}
return(result);
}
/****************************************************************************/
STATIC LONG
add_tag(struct CommandContext * cc,Tag tag,ULONG data)
{
DECLARE_SYSBASE(cc);
LONG error = OK;
LONG which = -1;
LONG i;
for(i = 0 ; i < cc->cc_NumTags ; i++)
{
if(cc->cc_Tags[i].ti_Tag == tag)
{
which = i;
break;
}
}
if(which == -1 && cc->cc_NumTags + 1 >= cc->cc_MaxTags)
{
struct TagItem * new_tags;
new_tags = AllocVec(sizeof(*new_tags) * (cc->cc_MaxTags+10),MEMF_ANY|MEMF_PUBLIC);
if(new_tags == NULL)
{
error = ERROR_NO_FREE_STORE;
goto out;
}
if(cc->cc_Tags != NULL)
CopyMem(cc->cc_Tags,new_tags,sizeof(*new_tags) * cc->cc_NumTags);
FreeVec(cc->cc_Tags);
cc->cc_Tags = new_tags;
cc->cc_MaxTags += 10;
}
if(which == -1)
which = cc->cc_NumTags++;
cc->cc_Tags[which].ti_Tag = tag;
cc->cc_Tags[which].ti_Data = data;
out:
return(error);
}
/****************************************************************************/
STATIC VOID
get_errno_and_code(struct CommandContext * cc,LONG * errno_ptr,STRPTR * code_ptr)
{
LONG errno = 0;
LONG code;
Local_SocketBaseTags(cc,
SBTM_GETREF(SBTC_ERRNO),&errno,
TAG_END);
code = errno;
if(Local_SocketBaseTags(cc,
SBTM_GETREF(SBTC_ERRNOSTRPTR),&code,
TAG_END) != 0)
{
code = 0;
}
(*errno_ptr) = errno;
(*code_ptr) = (STRPTR)code;
}
/****************************************************************************/
STATIC BOOL
substring_matches(struct CommandContext * cc,STRPTR pattern,STRPTR string)
{
DECLARE_UTILITYBASE(cc);
BOOL result = FALSE;
LONG i,len,pattern_len;
len = strlen(string);
pattern_len = strlen(pattern);
for(i = 0 ; i <= len - pattern_len ; i++)
{
if(Strnicmp(&string[len],pattern,pattern_len) == SAME)
{
result = TRUE;
break;
}
}
return(result);
}
/****************************************************************************/
STATIC BOOL
is_blank_space(UBYTE c)
{
BOOL result;
result = (BOOL)(c == ' ' || c == '\t' || c == (UBYTE)'\240');
return(result);
}
/****************************************************************************/
STATIC VOID
strip_extra_blank_spaces(STRPTR s)
{
LONG num_leading_spaces;
LONG num_trailing_spaces;
LONG len,i;
len = strlen(s);
num_leading_spaces = 0;
for(i = 0 ; i < len ; i++)
{
if(NOT is_blank_space(s[i]))
break;
num_leading_spaces++;
}
num_trailing_spaces = 0;
for(i = len-1 ; i >= 0 ; i--)
{
if(NOT is_blank_space(s[i]))
break;
num_trailing_spaces++;
}
if(num_trailing_spaces > 0)
{
len -= num_trailing_spaces;
s[len] = '\0';
}
if(num_leading_spaces > 0)
memmove(s,&s[num_leading_spaces],len+1);
}
/****************************************************************************/
STATIC LONG VARARGS68K
Local_Printf(struct CommandContext * cc,STRPTR format,...)
{
DECLARE_DOSBASE(cc);
va_list args;
LONG result;
#if defined(__amigaos4__)
{
va_startlinear(args,format);
result = VPrintf(format,va_getlinearva(args,APTR));
va_end(args);
}
#else
{
va_start(args,format);
result = VPrintf(format,args);
va_end(args);
}
#endif /* __amigaos4__ */
return(result);
}
/****************************************************************************/
STATIC VOID
Local_PrintFault(struct CommandContext * cc,LONG error,STRPTR prefix)
{
DECLARE_DOSBASE(cc);
UBYTE str[100];
Fault(error,NULL,str,sizeof(str));
Local_Printf(cc,"%s: %s\n",prefix,str);
}
/****************************************************************************/
STATIC LONG VARARGS68K
Local_ErrorPrintf(struct CommandContext * cc,STRPTR format,...)
{
DECLARE_DOSBASE(cc);
DECLARE_SYSBASE(cc);
va_list args;
LONG result;
BPTR fh;
#if defined(__amigaos4__)
{
fh = ErrorOutput();
}
#else
{
struct Process * this_process = (struct Process *)FindTask(NULL);
fh = this_process->pr_CES;
}
#endif /* __amigaos4__ */
if(fh == ZERO)
fh = Output();
#if defined(__amigaos4__)
{
va_startlinear(args,format);
result = VFPrintf(fh,format,va_getlinearva(args,APTR));
va_end(args);
}
#else
{
va_start(args,format);
result = VFPrintf(fh,format,args);
va_end(args);
}
#endif /* __amigaos4__ */
return(result);
}
/****************************************************************************/
/* This looks up a locale string ID in the builtin database; adapted
from CygnusEd because I couldn't find my own implementation for this
application... */
STATIC STRPTR
get_builtin_str(LONG id)
{
LONG top,middle,bottom;
STRPTR builtin_string;
/* The search area is all those message between bottom and top, inclusive. */
bottom = 0;
top = NUM_ENTRIES(CatCompArray) - 1;
/* Binary search through the CatCompArray to find the requested string.
Note that this assumes that the strings are sorted. Catcomp defaults
to creating sorted arrays, but it does _not_ force it. If in the .cd
file you specify out of order string numbers this routine will fail. */
while(bottom != top)
{
middle = (bottom + top) / 2;
if(CatCompArray[middle].cca_ID >= id)
top = middle;
else
bottom = middle + 1;
}
/* The only time this error message should occur is if you've passed
a garbage number OR if the CatCompArray is not sorted. */
if(CatCompArray[bottom].cca_ID == id)
builtin_string = (STRPTR)CatCompArray[bottom].cca_Str;
else
builtin_string = "";
return(builtin_string);
}
STATIC STRPTR
get_str(struct CommandContext * cc, LONG id)
{
STRPTR builtin_string;
STRPTR result;
builtin_string = get_builtin_str(id);
if(cc->cc_Catalog != NULL)
{
DECLARE_LOCALEBASE(cc);
result = (STRPTR)GetCatalogStr(cc->cc_Catalog,id,builtin_string);
}
else
{
result = builtin_string;
}
return(result);
}
/****************************************************************************/
STATIC LONG VARARGS68K
Local_AddRouteTags(struct CommandContext * cc,...)
{
DECLARE_SOCKETBASE(cc);
va_list args;
LONG result;
#if defined(__amigaos4__)
{
va_startlinear(args,cc);
result = AddRouteTagList(va_getlinearva(args,struct TagItem *));
va_end(args);
}
#else
{
va_start(args,cc);
result = AddRouteTagList((struct TagItem *)args);
va_end(args);
}
#endif /* __amigaos4__ */
return(result);
}
STATIC LONG VARARGS68K
Local_ConfigureInterfaceTags(struct CommandContext * cc,STRPTR interface_name,...)
{
DECLARE_SOCKETBASE(cc);
va_list args;
LONG result;
#if defined(__amigaos4__)
{
va_startlinear(args,interface_name);
result = ConfigureInterfaceTagList(interface_name,va_getlinearva(args,struct TagItem *));
va_end(args);
}
#else
{
va_start(args,interface_name);
result = ConfigureInterfaceTagList(interface_name,(struct TagItem *)args);
va_end(args);
}
#endif /* __amigaos4__ */
return(result);
}
STATIC LONG VARARGS68K
Local_SocketBaseTags(struct CommandContext * cc,...)
{
DECLARE_SOCKETBASE(cc);
va_list args;
LONG result;
#if defined(__amigaos4__)
{
va_startlinear(args,cc);
result = SocketBaseTagList(va_getlinearva(args,struct TagItem *));
va_end(args);
}
#else
{
va_start(args,cc);
result = SocketBaseTagList((struct TagItem *)args);
va_end(args);
}
#endif /* __amigaos4__ */
return(result);
}