4192 lines
105 KiB
C
4192 lines
105 KiB
C
/*
|
||
* $Id$
|
||
*
|
||
* :ts=4
|
||
*
|
||
* Copyright © 2001-2013 by Olaf Barthel. All Rights Reserved.
|
||
*/
|
||
|
||
/* There is a deliberate incompatibility in the 'struct AnchorPath'
|
||
definition between the AmigaOS 2.x/3.x and 4.x header files which
|
||
we will need to work around here. */
|
||
#if defined(__amigaos4__)
|
||
#define ap_Buf ap_Buffer
|
||
#else
|
||
#define USE_OLD_ANCHORPATH
|
||
#endif /* __amigaos4__ */
|
||
|
||
/****************************************************************************/
|
||
|
||
#include <libraries/bsdsocket.h>
|
||
|
||
#include <intuition/intuition.h>
|
||
|
||
#include <exec/execbase.h>
|
||
#include <exec/memory.h>
|
||
|
||
#include <dos/dosextens.h>
|
||
#include <dos/dostags.h>
|
||
#include <dos/anchorpath.h>
|
||
#include <dos/dosasl.h>
|
||
#include <dos/rdargs.h>
|
||
#include <dos/stdio.h>
|
||
|
||
#include <libraries/locale.h>
|
||
|
||
#include <workbench/startup.h>
|
||
#include <workbench/icon.h>
|
||
|
||
#include <clib/alib_protos.h>
|
||
|
||
/****************************************************************************/
|
||
|
||
#if defined(__amigaos4__)
|
||
#include <dos/obsolete.h>
|
||
#endif /* __amigaos4__ */
|
||
|
||
/****************************************************************************/
|
||
|
||
/* These are options relevant for the prototype header files
|
||
included below. */
|
||
#if !defined(__amigaos4__)
|
||
#define NO_INLINE_STDARG
|
||
#endif /* __amigaos4__ */
|
||
|
||
#define __NOLIBBASE__
|
||
#define __NOGLOBALIFACE__
|
||
#define __USE_INLINE__
|
||
|
||
/****************************************************************************/
|
||
|
||
#include <proto/bsdsocket.h>
|
||
#include <proto/intuition.h>
|
||
#include <proto/utility.h>
|
||
#include <proto/locale.h>
|
||
#include <proto/icon.h>
|
||
#include <proto/exec.h>
|
||
#include <proto/dos.h>
|
||
|
||
/****************************************************************************/
|
||
|
||
#include <stdarg.h>
|
||
#include <string.h>
|
||
|
||
/****************************************************************************/
|
||
|
||
#include "macros.h"
|
||
|
||
/****************************************************************************/
|
||
|
||
/* this macro lets us long-align structures on the stack */
|
||
#define D_S(type,name) \
|
||
char a_##name[sizeof(type)+3]; \
|
||
type *name = (type *)((ULONG)(a_##name+3) & ~3UL)
|
||
|
||
/****************************************************************************/
|
||
|
||
/* These two bits indicate the kind of address
|
||
represented by an IEEE 802.3 MAC address. These
|
||
are the two least significant bits of the first
|
||
address byte. */
|
||
#define MAC_Is_Group_Address 0x01
|
||
#define MAC_Is_Logical_Address 0x02
|
||
|
||
/****************************************************************************/
|
||
|
||
#include "AddNetInterface_rev.h"
|
||
|
||
/****************************************************************************/
|
||
|
||
#ifndef AbsExecBase
|
||
#define AbsExecBase (*(struct ExecBase **)4)
|
||
#endif /* AbsExecBase */
|
||
|
||
/* This is missing in the AmigaOS 2.x/3.x header files. */
|
||
#ifndef FORMAT_DEF
|
||
#define FORMAT_DEF 4
|
||
#endif /* FORMAT_DEF */
|
||
|
||
/****************************************************************************/
|
||
|
||
typedef LONG * NUMBER;
|
||
typedef LONG SWITCH;
|
||
typedef STRPTR KEY;
|
||
|
||
/****************************************************************************/
|
||
|
||
#define MAX_FILENAME_LEN 512
|
||
|
||
/****************************************************************************/
|
||
|
||
/* This context information is handed around for all the routines and
|
||
subroutines below. */
|
||
struct CommandContext
|
||
{
|
||
struct Library * cc_SysBase;
|
||
struct Library * cc_DOSBase;
|
||
struct Library * cc_UtilityBase;
|
||
struct Library * cc_SocketBase;
|
||
struct Library * cc_LocaleBase;
|
||
struct Library * cc_IconBase;
|
||
struct Library * cc_IntuitionBase;
|
||
|
||
#if defined(__amigaos4__)
|
||
|
||
/************************************************************************/
|
||
|
||
struct ExecIFace * cc_IExec;
|
||
struct DOSIFace * cc_IDOS;
|
||
struct UtilityIFace * cc_IUtility;
|
||
struct SocketIFace * cc_ISocket;
|
||
struct LocaleIFace * cc_ILocale;
|
||
struct IconIFace * cc_IIcon;
|
||
struct IntuitionIFace * cc_IIntuition;
|
||
|
||
/************************************************************************/
|
||
|
||
#endif /* __amigaos4__ */
|
||
|
||
struct Catalog * cc_Catalog;
|
||
UBYTE cc_ProgramName[256];
|
||
struct WBStartup * cc_StartupMessage;
|
||
struct RDArgs * cc_RDA;
|
||
BPTR cc_File;
|
||
struct AnchorPath * cc_AnchorPath;
|
||
BOOL cc_Quiet;
|
||
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;
|
||
};
|
||
|
||
/****************************************************************************/
|
||
|
||
/* The following set of DECLARE_... macros are used to load the library
|
||
bases in every routine that needs them. These are portable macros in
|
||
the sense that they allow the same code to be built both for AmigaOS 2.x/3.x
|
||
and 4.x. */
|
||
|
||
/****************************************************************************/
|
||
|
||
#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
|
||
|
||
#define DECLARE_ICONBASE(cc) \
|
||
struct IconIFace * IIcon = cc->cc_IIcon; \
|
||
struct Library * IconBase = cc->cc_IconBase
|
||
|
||
#define DECLARE_INTUITIONBASE(cc) \
|
||
struct IntuitionIFace * IIntuition = cc->cc_IIntuition; \
|
||
struct Library * IntuitionBase = cc->cc_IntuitionBase
|
||
|
||
/****************************************************************************/
|
||
|
||
#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
|
||
|
||
#define DECLARE_ICONBASE(cc) \
|
||
struct Library * IconBase = cc->cc_IconBase
|
||
|
||
#define DECLARE_INTUITIONBASE(cc) \
|
||
struct Library * IntuitionBase = cc->cc_IntuitionBase
|
||
|
||
/****************************************************************************/
|
||
|
||
#endif /* __amigaos4__ */
|
||
|
||
/****************************************************************************/
|
||
|
||
/* This program performs two passes on the interfaces it has to take
|
||
care of it. First it adds the interfaces, then it configures them.
|
||
Here is a definition of what each pass does. */
|
||
enum add_interface_mode_t
|
||
{
|
||
AIM_Add,
|
||
AIM_Configure
|
||
};
|
||
|
||
/****************************************************************************/
|
||
|
||
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 LONG match_key(struct CommandContext *cc, STRPTR what);
|
||
STATIC LONG add_tag(struct CommandContext *cc, Tag tag, ULONG data);
|
||
STATIC BOOL is_blank_space(UBYTE c);
|
||
STATIC STRPTR get_next_token(STRPTR input, STRPTR string, LONG string_len);
|
||
STATIC LONG get_hex_value(struct CommandContext *cc, STRPTR str);
|
||
STATIC VOID get_hex_string(LONG value, STRPTR str);
|
||
STATIC VOID strip_unprintable_characters(STRPTR s);
|
||
STATIC VOID strip_extra_blank_spaces(STRPTR s);
|
||
STATIC LONG add_interface(struct CommandContext *cc, STRPTR name, enum add_interface_mode_t operating_mode, LONG timeout);
|
||
STATIC BOOL validate_ip_address(struct CommandContext *cc, STRPTR key, STRPTR address, LONG line_number, STRPTR file);
|
||
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 VOID add_interface_node(struct CommandContext *cc, struct List *list, struct Node *new_node);
|
||
STATIC VOID VARARGS68K error_printf(struct CommandContext *cc, STRPTR format, ...);
|
||
STATIC VOID VARARGS68K warning_printf(struct CommandContext *cc, STRPTR format, ...);
|
||
STATIC VOID VARARGS68K info_printf(struct CommandContext *cc, STRPTR format, ...);
|
||
STATIC VOID info_print_fault(struct CommandContext *cc, LONG code);
|
||
STATIC VOID error_print_fault(struct CommandContext *cc, LONG code);
|
||
STATIC VOID error_print_fault_prefix(struct CommandContext *cc, LONG code, STRPTR prefix);
|
||
STATIC STRPTR get_builtin_str(LONG id);
|
||
STATIC STRPTR get_str(struct CommandContext *cc, LONG id);
|
||
STATIC LONG VARARGS68K Local_ConfigureInterfaceTags(struct CommandContext *cc, STRPTR interface_name, ...);
|
||
STATIC LONG VARARGS68K Local_SocketBaseTags(struct CommandContext *cc, ...);
|
||
STATIC LONG VARARGS68K Local_AddRouteTags(struct CommandContext *cc, ...);
|
||
|
||
/****************************************************************************/
|
||
|
||
/****** ROADSHOW/ADDNETINTERFACE **************************************************
|
||
*
|
||
* NAME
|
||
* AddNetInterface - Make network interfaces known to the protocol stack.
|
||
*
|
||
* FORMAT
|
||
* AddNetInterface [QUIET] [TIMEOUT=<n>] INTERFACE
|
||
*
|
||
* TEMPLATE
|
||
* INTERFACE/M,QUIET/S,TIMEOUT/K/N
|
||
*
|
||
* PATH
|
||
* C:ADDNETINTERFACE
|
||
*
|
||
* FUNCTION
|
||
* ADDNETINTERFACE starts the specified network interfaces, thus starting
|
||
* the connection.
|
||
*
|
||
* OPTIONS
|
||
* INTERFACE/M
|
||
* The name of the interface to add; this can be a plain interface
|
||
* name, such as "Ariadne", or the fully qualified file name which
|
||
* contains the interface configuration information. The tool
|
||
* expects the name of the file in question (without the prefixed
|
||
* path) to become the name of the interface. For historic reasons
|
||
* interface names cannot be longer than 15 characters.
|
||
*
|
||
* For your convenience, a wild card pattern can be specified in
|
||
* place of the file name to use.
|
||
*
|
||
* If several interface names are specified, they will be sorted in
|
||
* alphabetical order before they are added. If the interface
|
||
* files have icons attached, you can use tool types such as
|
||
* "PRI=5" or "PRIORITY=5" to select the order in which the interfaces
|
||
* will be sorted. Higher priority entries will appear before lower
|
||
* priority entries. If the priorities for two entries is identical,
|
||
* then the interface names will be compared. If no priority is
|
||
* given, the value 0 will be used.
|
||
*
|
||
* 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.
|
||
*
|
||
* 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.
|
||
*
|
||
* The 'AddNetInterface' command can be invoked from Workbench, too. It
|
||
* operates on the same configuration files with the same keywords, etc.
|
||
* To make it work, create an icon for your interface configuration file
|
||
* (it must be a project icon) and put 'AddNetInterface' into its default
|
||
* tool. Make sure that the project has enough stack space assigned (4000
|
||
* bytes minimum), then double-click on the icon. If things should go
|
||
* wrong, you will see an error requester pop up, and no further
|
||
* initialization will be done. You can configure two options in the
|
||
* project file's tool types: QUIET and TIMEOUT. These are identical to
|
||
* the two parameters of the same name you could pass on the command
|
||
* line; they define whether the command should print any error messages
|
||
* (the default is to print them) and how long the command should wait
|
||
* for DHCP configuration to conclude (default is a timeout of 60
|
||
* seconds).
|
||
*
|
||
* NOTES
|
||
* This command is similar to the Unix "ifconfig" command.
|
||
*
|
||
* The program makes two passes over the configuration files to be
|
||
* taken into account. In the first pass information is gathered
|
||
* on the interfaces to add, which is subsequently used to add those
|
||
* interfaces found. In the second pass interfaces are configured,
|
||
* setting their IP addresses, etc. If anything goes wrong in the
|
||
* first pass, processing will stop and no second pass will be
|
||
* done. If anything goes wrong in either the first or the second
|
||
* pass, that pass will not be completed.
|
||
*
|
||
* CONFIGURATION FILES
|
||
* Interfaces are configured through files stored in the
|
||
* "DEVS:NetInterfaces" or "SYS:Storage/NetInterfaces" directories.
|
||
* These are text files whose contents are described below.
|
||
*
|
||
* Each line of the file must correspond to an option; if a line is
|
||
* introduced by a '#' or ';' character it will be ignored (so are empty
|
||
* lines). The following options are supported:
|
||
*
|
||
* DEVICE/K
|
||
* Must be provided; the name of the SANA-II device driver. This
|
||
* should be the complete, fully qualified path to the driver. If
|
||
* no complete path is provided, the 'Devs:Networks' drawer will be
|
||
* checked. Thus, "DEVS:Networks/ariadne.device" is equivalent to
|
||
* "ariadne.device".
|
||
*
|
||
* UNIT/K/N
|
||
* Unit number of the device driver to open. The default is to
|
||
* use unit 0.
|
||
*
|
||
* IPTYPE/K/N
|
||
* You can use this parameter to override the packet type the
|
||
* stack uses when sending IP packets; default is 2048 (for
|
||
* Ethernet hardware).
|
||
*
|
||
* ARPTYPE/K/N
|
||
* You can use this parameter to override the packet type the
|
||
* stack uses when sending ARP packets. Default is 2054; this
|
||
* parameter only works with Ethernet hardware and should not be
|
||
* changed.
|
||
*
|
||
* IPREQUESTS/K/N
|
||
* The number of IP read requests to allocate and queue for the
|
||
* SANA-II device driver to use. The default value is 32, larger
|
||
* values can improve performance, especially with fast device
|
||
* drivers.
|
||
*
|
||
* WRITEREQUESTS/K/N
|
||
* The number of IP write requests to allocate and queue for the
|
||
* SANA-II device driver to use. The default value is 32, larger
|
||
* values can improve performance, especially with fast device
|
||
* drivers.
|
||
*
|
||
* ARPREQUESTS/K/N
|
||
* The number of ARP read requests to allocate and queue for the
|
||
* SANA-II device driver to use. The default value is 4.
|
||
*
|
||
* DEBUG/K (possible parameters: YES or NO)
|
||
* You can enable debug output for this interface (don't worry,
|
||
* you can always disable it later) 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.
|
||
*
|
||
* POINTTOPOINT/K (possible parameters: YES or NO)
|
||
* This indicates that the device is used for point to point
|
||
* connections. The stack automatically figures out whether the
|
||
* SANA-II device driver is of the point to point type, so you
|
||
* should not need to specify this option.
|
||
*
|
||
* MULTICAST/K (possible parameters: YES or NO)
|
||
* This tells the stack that this device can handle multicast
|
||
* packets. 'YES' only works with Ethernet hardware (where it's
|
||
* enabled by default anyway).
|
||
*
|
||
* DOWNGOESOFFLINE/K (possible parameters: YES or NO)
|
||
* This option is useful with point to point devices, like
|
||
* 'ppp.device'. When specified, bringing the interface 'down'
|
||
* (via the 'ConfigureNetInterface' program) or shutting down the
|
||
* stack will cause the associated SANA-II device driver to be
|
||
* switched offline (via the 'S2_OFFLINE' command).
|
||
*
|
||
* REPORTOFFLINE/K (possible parameters: YES or NO)
|
||
* When a device is switched offline, you may want to know about
|
||
* it. This is helpful with SLIP/PPP connections which run over a
|
||
* serial link which accumulates costs while it is open. When the
|
||
* connection is broken and the device goes offline, you will
|
||
* receive a brief notification of what happened. However, if you
|
||
* tell the library itself to shut down, no notification that a
|
||
* device was switched offline will be shown.
|
||
*
|
||
* REQUIRESINITDELAY/K (possible parameters: YES or NO)
|
||
* Some devices need a little time to settle after they have been
|
||
* opened or they will hickup and lose data after the first
|
||
* packet has been sent. The original 'Ariadne I' card is one
|
||
* such device. For these devices, the 'REQUIRESINITDELAY=YES'
|
||
* option will cause a delay of about a second before the first
|
||
* packet is sent.
|
||
*
|
||
* This option defaults to YES.
|
||
*
|
||
* COPYMODE/K (possible parameters: SLOW or FAST)
|
||
* This option is for chasing subtle bugs in the driver interface
|
||
* with cards like the original 'Ariadne I'. Cards like these do
|
||
* not support writing to the hardware transmit buffer in units
|
||
* other than 16 bits a piece. Default is 'SLOW', which is
|
||
* compatible with the Ariadne I. But if you're feeling
|
||
* adventurous, try the 'FAST' option (and don't complain if it
|
||
* doesn't work for you!).
|
||
*
|
||
* FILTER/K (possible parameters: OFF, LOCAL, IPANDARP or EVERYTHING)
|
||
* This option enables the use of the Berkeley packet filter for
|
||
* this particular interface. Possible choices for the key are:
|
||
*
|
||
* FILTER=OFF
|
||
* Disables the filter.
|
||
*
|
||
* FILTER=LOCAL
|
||
* Enables filtering on all IP and ARP packets that are
|
||
* intended for this particular interface. Packets
|
||
* intended for other interfaces or hosts are ignored.
|
||
*
|
||
* FILTER=IPANDARP
|
||
* Enables filtering on all IP and ARP packets that
|
||
* happen to fly by this interface, no matter whether the
|
||
* packets are intended for it or not. This requires that
|
||
* the underlying network device driver is opened for
|
||
* exclusive access in so-called 'promiscuous' mode. This
|
||
* may not work if other clients (Envoy, ACS) need to
|
||
* keep the driver opened.
|
||
*
|
||
* FILTER=EVERYTHING
|
||
* Identical to FILTER=IPANDARP, but will also filter all
|
||
* other kinds of packets that may show up.
|
||
*
|
||
* Default for this option is 'FILTER=LOCAL'. Note that by using
|
||
* this option you merely define what the filter mechanism can do
|
||
* and what it cannot do. The filter is not enabled when you add
|
||
* the interface.
|
||
*
|
||
* HARDWAREADDRESS/K
|
||
* You can specify the hardware address (layer 2 address, MAC
|
||
* address) this interface should respond to when it is first
|
||
* added and configured. This usually works only once for each
|
||
* interface, which means that once an address has been chosen
|
||
* you have to stick with it until the system is rebooted. And it
|
||
* also means that the first program to configure the address
|
||
* will manage to make its choice stick.
|
||
*
|
||
* The hardware address must be given as six bytes in hexadecimal
|
||
* notation, separated by colon characters, like this:
|
||
*
|
||
* HARDWAREADDRESS=00:60:30:00:11:22
|
||
*
|
||
* Take care, there are rules that apply to the choice of the
|
||
* hardware address, which means that you cannot simply pick a
|
||
* convenient number and get away with it. It is assumed that you
|
||
* will want to configure an IEEE 802.3 MAC address, which works for
|
||
* Ethernet hardware and is six bytes (48 bits) in size.
|
||
*
|
||
* In addition to the purely static interface configuration information you
|
||
* can also tell the configuration program to do something about the
|
||
* interfaces once they have all been added. That's when the following
|
||
* configuration file parameters will be taken into account:
|
||
*
|
||
* ADDRESS/K
|
||
* This configures the IP address of the interface. The parameter
|
||
* you supply should be an IP address in dotted-decimal notation
|
||
* ("192.168.0.1"). Don't pick a symbolic host name as the system
|
||
* may not yet be in a position to talk to name resolution server
|
||
* and translate the symbolic name.
|
||
*
|
||
* In place of the IP address you can also specify "DHCP"
|
||
* (Dynamic Host Configuration Protocol). 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.
|
||
*
|
||
* ALIAS/K/M
|
||
* In addition to the primary interface address you can assign
|
||
* several aliases to it. These must be specified in
|
||
* dotted-decimal notation ("192.168.0.1"). Alias addresses are
|
||
* added after the primary interface address has been configured.
|
||
*
|
||
* STATE/K
|
||
* By default, interfaces whose addresses are configured will
|
||
* switch automatically to 'up' state, making it possible for the
|
||
* TCP/IP stack to use them for network I/O. You can override
|
||
* this by using the 'STATE=DOWN' switch. The alternatives
|
||
* 'online' (implies 'up', but tells the underlying network
|
||
* interface driver to go online first) and 'offline' (implies
|
||
* 'down' but tells the driver to go offline first) are available
|
||
* as well.
|
||
*
|
||
* NETMASK/K
|
||
* This selects the subnet mask for the interface, which must be
|
||
* specified in dotted-decimal notation ("192.0.168.1").
|
||
*
|
||
* In place of the subnet mask you can also specify "DHCP"
|
||
* (Dynamic Host Configuration Protocol). 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.
|
||
*
|
||
* 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
|
||
* This configures the interface route metric value. Default
|
||
* is 0.
|
||
*
|
||
* 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.
|
||
*
|
||
* 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.
|
||
*
|
||
* LEASE/K
|
||
* This is a complex option which can be used to request how long
|
||
* an IP address should be bound to an interface, via the DHCP
|
||
* protocol. 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
|
||
* 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.
|
||
*
|
||
* Unsupported keywords in the configuration file (or typos) will be
|
||
* reported, along with the name of the file and the line number.
|
||
*
|
||
* The name of the configuration file defines the name of the respective
|
||
* interface. Interface names must be unique, and the case of the names
|
||
* does not matter. For historic reasons interface names cannot be longer
|
||
* than 15 characters. Beyond this no restrictions on naming conventions
|
||
* apply.
|
||
*
|
||
* DHCP PROTOCOL
|
||
* A few words on DHCP (Dynamic Host Configuration Protocol). First, it
|
||
* only works for Ethernet hardware, so please don't try it with PPP or
|
||
* SLIP. Now it gets a bit technical. Unless you request an address to be
|
||
* permanently assigned, DHCP will assign addresses only for a limited
|
||
* period of time. This is called a 'lease'. Once an IP address has been
|
||
* assigned through DHCP, the lease will be repeatedly extended. The DHCP
|
||
* server may over time decide not to extend the lease or assign a new IP
|
||
* address to the interface. To stop the lease from getting extended over
|
||
* and over again, you must either change the interface's primary IP
|
||
* address or mark it 'down'. The library will make a brave attempt to
|
||
* get a DHCPRELEASE datagram out to notify the server that the
|
||
* previously allocated IP address is no longer in use. Don't count on it
|
||
* to work, though. First, the protocol stack might be going down so fast
|
||
* that it cannot get the datagram out. Second, when you mark an
|
||
* interface 'down' you will effectively pull it out of circulation, it
|
||
* will not send any further datagrams. Third, DHCP rides on UDP whose
|
||
* second name is 'unreliable datagram protocol', meaning that any
|
||
* datagram may get lost or corrupted and nobody will hear about it; this
|
||
* is rather hard on DHCP since the release message is sent only once.
|
||
* Don't worry. Unless you request permanent leases, the leases will
|
||
* eventually time out and the now unused IP address will finally return
|
||
* to the pool of addresses available for allocation.
|
||
*
|
||
* EXAMPLES
|
||
* Start the interface called "DSL" and run quietly.
|
||
*
|
||
* 1> AddNetInterface DSL QUIET
|
||
*
|
||
* An example configuration file for the "Ariadne" interface, with
|
||
* some options commented out:
|
||
*
|
||
* 1> Type Devs:NetInterfaces/Ariadne
|
||
* device=ariadne.device
|
||
* unit=0
|
||
* #iprequests=64
|
||
* #writerequests=64
|
||
* copymode=fast
|
||
* #configure=dhcp
|
||
* address=192.168.0.1
|
||
* netmask=255.255.255.0
|
||
* #alias=192.168.0.9
|
||
* #hardwareaddress=00:60:30:00:11:22
|
||
* #id=a3000ux
|
||
* #debug=yes
|
||
* #filter=everything
|
||
*
|
||
* SEE ALSO
|
||
* ConfigureNetInterface
|
||
* NetShutdown
|
||
*
|
||
******************************************************************************
|
||
*/
|
||
|
||
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));
|
||
|
||
/* If launched from Workbench, pick up the startup message. */
|
||
pr = (struct Process *)FindTask(NULL);
|
||
if(pr->pr_CLI == ZERO)
|
||
{
|
||
struct MsgPort * mp = &pr->pr_MsgPort;
|
||
|
||
WaitPort(mp);
|
||
|
||
cc->cc_StartupMessage = (struct WBStartup *)GetMsg(mp);
|
||
}
|
||
|
||
/* Try to open the necessary libraries. */
|
||
error = open_libs(cc,SysBase);
|
||
if(error == OK)
|
||
{
|
||
DECLARE_LOCALEBASE(cc);
|
||
DECLARE_DOSBASE(cc);
|
||
|
||
/* If possible, open the catalog which contains the localized
|
||
program message. */
|
||
if(cc->cc_LocaleBase != NULL)
|
||
cc->cc_Catalog = OpenCatalogA(NULL,"roadshow.catalog",NULL);
|
||
|
||
/* Do what the program needs to do. */
|
||
result = cmd(cc);
|
||
|
||
/* Clean up... */
|
||
if(cc->cc_Catalog != NULL)
|
||
CloseCatalog(cc->cc_Catalog);
|
||
|
||
if(cc->cc_Tags != NULL)
|
||
FreeVec(cc->cc_Tags);
|
||
|
||
if(cc->cc_AnchorPath != NULL)
|
||
{
|
||
MatchEnd(cc->cc_AnchorPath);
|
||
|
||
#if defined(__amigaos4__)
|
||
{
|
||
FreeDosObject(DOS_ANCHORPATH,cc->cc_AnchorPath);
|
||
}
|
||
#else
|
||
{
|
||
FreeVec(cc->cc_AnchorPath);
|
||
}
|
||
#endif /* __amigaos4__ */
|
||
}
|
||
|
||
if(cc->cc_RDA != NULL)
|
||
{
|
||
FreeArgs(cc->cc_RDA);
|
||
FreeDosObject(DOS_RDARGS,cc->cc_RDA);
|
||
}
|
||
|
||
if(cc->cc_File != ZERO)
|
||
Close(cc->cc_File);
|
||
}
|
||
else
|
||
{
|
||
pr->pr_Result2 = error;
|
||
}
|
||
|
||
close_libs(cc);
|
||
|
||
/* Return the Workbench startup message. */
|
||
if(cc->cc_StartupMessage != NULL)
|
||
{
|
||
Forbid();
|
||
|
||
ReplyMsg((struct Message *)cc->cc_StartupMessage);
|
||
}
|
||
|
||
return(result);
|
||
}
|
||
|
||
/****************************************************************************/
|
||
|
||
/* Close all the libraries opened by open_libs(). */
|
||
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);
|
||
|
||
if(cc->cc_IIcon != NULL)
|
||
DropInterface((struct Interface *)cc->cc_IIcon);
|
||
|
||
if(cc->cc_IIntuition != NULL)
|
||
DropInterface((struct Interface *)cc->cc_IIntuition);
|
||
}
|
||
#endif /* __amigaos4__ */
|
||
|
||
if(cc->cc_IntuitionBase != NULL)
|
||
CloseLibrary(cc->cc_IntuitionBase);
|
||
|
||
if(cc->cc_IconBase != NULL)
|
||
CloseLibrary(cc->cc_IconBase);
|
||
|
||
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);
|
||
}
|
||
|
||
/****************************************************************************/
|
||
|
||
/* Open all the required libraries. */
|
||
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__ */
|
||
|
||
cc->cc_IconBase = OpenLibrary("icon.library",37);
|
||
|
||
#if defined(__amigaos4__)
|
||
{
|
||
if(cc->cc_IconBase != NULL)
|
||
{
|
||
cc->cc_IIcon = (struct IconIFace *)GetInterface(cc->cc_IconBase, "main", 1, 0);
|
||
if(cc->cc_IIcon == NULL)
|
||
{
|
||
CloseLibrary(cc->cc_IconBase);
|
||
cc->cc_IconBase = NULL;
|
||
}
|
||
}
|
||
}
|
||
#endif /* __amigaos4__ */
|
||
|
||
cc->cc_IntuitionBase = OpenLibrary("intuition.library",37);
|
||
|
||
#if defined(__amigaos4__)
|
||
{
|
||
if(cc->cc_IntuitionBase != NULL)
|
||
{
|
||
cc->cc_IIntuition = (struct IntuitionIFace *)GetInterface(cc->cc_IntuitionBase, "main", 1, 0);
|
||
if(cc->cc_IIntuition == NULL)
|
||
{
|
||
CloseLibrary(cc->cc_IntuitionBase);
|
||
cc->cc_IntuitionBase = 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 ADDNETINTERFACE_CATALOG_STRINGS
|
||
#include "roadshow.h"
|
||
|
||
/****************************************************************************/
|
||
|
||
/* This is the main() program, so to speak. */
|
||
STATIC LONG
|
||
cmd(struct CommandContext * cc)
|
||
{
|
||
STRPTR devs_prefix = "DEVS:NetInterfaces";
|
||
STRPTR storage_prefix = "SYS:Storage/NetInterfaces";
|
||
|
||
struct
|
||
{
|
||
KEY * Interface;
|
||
SWITCH Quiet;
|
||
NUMBER Timeout;
|
||
} args;
|
||
|
||
STRPTR args_template =
|
||
"INTERFACE/M,"
|
||
"QUIET/S,"
|
||
"TIMEOUT/K/N"
|
||
VERSTAG;
|
||
|
||
DECLARE_SYSBASE(cc);
|
||
DECLARE_DOSBASE(cc);
|
||
DECLARE_UTILITYBASE(cc);
|
||
DECLARE_ICONBASE(cc);
|
||
DECLARE_SOCKETBASE(cc);
|
||
|
||
struct List interface_list;
|
||
ULONG interface_list_size;
|
||
UBYTE * buf = NULL;
|
||
LONG result = RETURN_FAIL;
|
||
struct RDArgs * rda = NULL;
|
||
LONG timeout = 60;
|
||
BPTR old_cd = ZERO;
|
||
BOOL old_cd_valid = FALSE;
|
||
struct DiskObject * icon = NULL;
|
||
BOOL configuration_trouble = FALSE;
|
||
|
||
NewList(&interface_list);
|
||
interface_list_size = 0;
|
||
|
||
GetProgramName(cc->cc_ProgramName,sizeof(cc->cc_ProgramName));
|
||
|
||
memset(&args,0,sizeof(args));
|
||
|
||
/* If started from shell, read the command arguments. */
|
||
if(cc->cc_StartupMessage == NULL)
|
||
{
|
||
rda = ReadArgs(args_template,(LONG *)&args,NULL);
|
||
if(rda == NULL)
|
||
{
|
||
error_print_fault(cc,IoErr());
|
||
goto out;
|
||
}
|
||
|
||
cc->cc_Quiet = (BOOL)(args.Quiet != 0);
|
||
}
|
||
|
||
/* Did we manage to open utility.library? */
|
||
if(UtilityBase == NULL)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_NO_UTILITY_TXT));
|
||
|
||
goto out;
|
||
}
|
||
|
||
/* Did we manage to open bsdsocket.library? */
|
||
if(SocketBase == NULL)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_CANNOT_OPEN_BSDSOCKET_TXT));
|
||
|
||
goto out;
|
||
}
|
||
else
|
||
{
|
||
LONG have_interface_api = FALSE;
|
||
LONG have_routing_api = FALSE;
|
||
LONG have_address_conversion_api = FALSE;
|
||
|
||
/* Check if the bsdsocket.library we managed to open supports the
|
||
various APIs we expect below. */
|
||
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 cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_BSDSOCKET_HAS_NO_INTERFACE_API_TXT),
|
||
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 cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_BSDSOCKET_HAS_NO_ROUTE_API_TXT),
|
||
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 cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_HAS_NO_ADDRESS_CONVERSION_API_TXT),
|
||
SocketBase->lib_Node.ln_Name, SocketBase->lib_Version, SocketBase->lib_Revision);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
}
|
||
|
||
/* This is required by the code that reads the configuration
|
||
file. And we allocate this data here because if we had
|
||
allocated it before Intuition was opened, error display
|
||
would have been difficult. */
|
||
cc->cc_RDA = AllocDosObject(DOS_RDARGS,NULL);
|
||
if(cc->cc_RDA == NULL)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
error_print_fault(cc,IoErr());
|
||
|
||
goto out;
|
||
}
|
||
|
||
/* If started from shell, process the command line arguments. */
|
||
if(cc->cc_StartupMessage == NULL)
|
||
{
|
||
KEY * interface_table;
|
||
int operating_mode;
|
||
STRPTR interface;
|
||
struct Node * node;
|
||
|
||
/* This is to be used for pattern matching when trying to find
|
||
the interfaces to add. */
|
||
#if defined(__amigaos4__)
|
||
{
|
||
cc->cc_AnchorPath = AllocDosObjectTags(DOS_ANCHORPATH,
|
||
ADO_Strlen, MAX_FILENAME_LEN,
|
||
ADO_Mask, SIGBREAKF_CTRL_C,
|
||
TAG_END);
|
||
}
|
||
#else
|
||
{
|
||
cc->cc_AnchorPath = AllocVec(sizeof(*cc->cc_AnchorPath) + MAX_FILENAME_LEN,MEMF_ANY|MEMF_PUBLIC);
|
||
if(cc->cc_AnchorPath != NULL)
|
||
memset(cc->cc_AnchorPath,0,sizeof(*cc->cc_AnchorPath));
|
||
}
|
||
#endif /* __amigaos4__ */
|
||
|
||
if(cc->cc_AnchorPath == NULL)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
error_print_fault(cc,IoErr());
|
||
|
||
goto out;
|
||
}
|
||
|
||
if(args.Timeout != NULL && (*args.Timeout) > 0)
|
||
{
|
||
timeout = (*args.Timeout);
|
||
if(timeout < AAM_TIMEOUT_MIN)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
warning_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_TIMEOUT_TOO_SHORT_TXT),
|
||
timeout,AAM_TIMEOUT_MIN);
|
||
}
|
||
|
||
timeout = 10;
|
||
}
|
||
}
|
||
|
||
/* There has to be at least one interface name we can work with. */
|
||
if(args.Interface == NULL)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_NO_INTERFACE_NAME_GIVEN_TXT));
|
||
|
||
result = RETURN_ERROR;
|
||
|
||
goto out;
|
||
}
|
||
|
||
result = RETURN_OK;
|
||
|
||
/* Check each interface name given; if it's a wildcard pattern, expand it. */
|
||
interface_table = args.Interface;
|
||
|
||
while((interface = (*interface_table++)) != NULL)
|
||
{
|
||
/* Not an absolute path name? Look into DEVS: instead. */
|
||
if(FilePart(interface) == interface)
|
||
{
|
||
LONG len = strlen(interface);
|
||
LONG max_name_size = strlen(storage_prefix) + 1 + len + 1;
|
||
BPTR file_lock;
|
||
D_S(struct FileInfoBlock,fib);
|
||
BOOL have_name = FALSE;
|
||
LONG error = 0;
|
||
|
||
if(CheckSignal(SIGBREAKF_CTRL_C))
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
error_print_fault(cc,ERROR_BREAK);
|
||
|
||
goto out;
|
||
}
|
||
|
||
node = AllocVec(sizeof(*node) + max_name_size,MEMF_ANY|MEMF_PUBLIC);
|
||
if(node == NULL)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
error_print_fault(cc,IoErr());
|
||
|
||
result = RETURN_ERROR;
|
||
|
||
goto out;
|
||
}
|
||
|
||
node->ln_Name = (char *)(node + 1);
|
||
node->ln_Pri = 0;
|
||
|
||
/* Check if the interface file exists in the local directory.
|
||
Make sure that it's a file, too. */
|
||
file_lock = Lock(interface,SHARED_LOCK);
|
||
if(file_lock != ZERO && Examine(file_lock,fib))
|
||
{
|
||
if(fib->fib_DirEntryType < 0)
|
||
{
|
||
strcpy(node->ln_Name,interface);
|
||
have_name = TRUE;
|
||
}
|
||
else
|
||
{
|
||
error = ERROR_OBJECT_WRONG_TYPE;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
error = IoErr();
|
||
}
|
||
|
||
UnLock(file_lock);
|
||
|
||
/* If we still don't have a name, look into "DEVS:NetInterfaces". */
|
||
if(NOT have_name && (error == ERROR_OBJECT_WRONG_TYPE || error == ERROR_OBJECT_NOT_FOUND))
|
||
{
|
||
strcpy(node->ln_Name,devs_prefix);
|
||
AddPart(node->ln_Name,interface,max_name_size);
|
||
|
||
file_lock = Lock(node->ln_Name,SHARED_LOCK);
|
||
if(file_lock != ZERO && Examine(file_lock,fib))
|
||
{
|
||
if(fib->fib_DirEntryType < 0)
|
||
have_name = TRUE;
|
||
else
|
||
error = ERROR_OBJECT_WRONG_TYPE;
|
||
}
|
||
else
|
||
{
|
||
error = IoErr();
|
||
}
|
||
|
||
UnLock(file_lock);
|
||
}
|
||
|
||
/* If we still don't have a name, look into "SYS:Storage/NetInterfaces". */
|
||
if(NOT have_name && (error == ERROR_OBJECT_WRONG_TYPE || error == ERROR_OBJECT_NOT_FOUND))
|
||
{
|
||
strcpy(node->ln_Name,storage_prefix);
|
||
AddPart(node->ln_Name,interface,max_name_size);
|
||
|
||
file_lock = Lock(node->ln_Name,SHARED_LOCK);
|
||
if(file_lock != ZERO && Examine(file_lock,fib))
|
||
{
|
||
if(fib->fib_DirEntryType < 0)
|
||
have_name = TRUE;
|
||
else
|
||
error = ERROR_OBJECT_WRONG_TYPE;
|
||
}
|
||
else
|
||
{
|
||
error = IoErr();
|
||
}
|
||
|
||
UnLock(file_lock);
|
||
}
|
||
|
||
if(have_name)
|
||
{
|
||
/* Try to read the interface priority from the
|
||
icon attached to the file, if there is any. */
|
||
if(IconBase != NULL)
|
||
{
|
||
struct DiskObject * icon;
|
||
|
||
icon = GetDiskObject(node->ln_Name);
|
||
if(icon != NULL)
|
||
{
|
||
STRPTR priority;
|
||
|
||
priority = FindToolType(icon->do_ToolTypes,"PRI");
|
||
if(priority == NULL)
|
||
priority = FindToolType(icon->do_ToolTypes,"PRIORITY");
|
||
|
||
if(priority != NULL)
|
||
{
|
||
LONG value;
|
||
|
||
if(StrToLong(priority,&value) > 0)
|
||
{
|
||
if(-128 <= value && value <= 127)
|
||
node->ln_Pri = value;
|
||
}
|
||
}
|
||
|
||
FreeDiskObject(icon);
|
||
}
|
||
}
|
||
|
||
add_interface_node(cc,&interface_list,node);
|
||
interface_list_size++;
|
||
}
|
||
else
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
error_print_fault_prefix(cc,error,interface);
|
||
|
||
result = RETURN_ERROR;
|
||
|
||
goto out;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
static STRPTR info_suffix = ".info";
|
||
const int info_suffix_len = strlen(info_suffix);
|
||
LONG error;
|
||
|
||
/* We may have to check an icon or two, so icon.library better be open. */
|
||
if(IconBase == NULL)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_NO_ICON_TXT));
|
||
|
||
goto out;
|
||
}
|
||
|
||
MatchEnd(cc->cc_AnchorPath);
|
||
|
||
#ifndef __amigaos4__
|
||
{
|
||
memset(cc->cc_AnchorPath,0,sizeof(*cc->cc_AnchorPath));
|
||
|
||
cc->cc_AnchorPath->ap_Strlen = MAX_FILENAME_LEN;
|
||
cc->cc_AnchorPath->ap_BreakBits = SIGBREAKF_CTRL_C;
|
||
}
|
||
#endif /* __amigaos4__ */
|
||
|
||
/* Find all the files that match the pattern, if any. */
|
||
error = MatchFirst(interface,cc->cc_AnchorPath);
|
||
while(error == OK)
|
||
{
|
||
/* Careful there, only check files! */
|
||
if(cc->cc_AnchorPath->ap_Info.fib_DirEntryType < 0)
|
||
{
|
||
int len = strlen(cc->cc_AnchorPath->ap_Buf);
|
||
|
||
/* Files whose names end with ".info" are ignored. */
|
||
if(len < info_suffix_len || Stricmp(&cc->cc_AnchorPath->ap_Buf[len - info_suffix_len],info_suffix) != SAME)
|
||
{
|
||
struct DiskObject * icon;
|
||
|
||
node = AllocVec(sizeof(*node) + strlen(cc->cc_AnchorPath->ap_Buf)+1,MEMF_ANY);
|
||
if(node == NULL)
|
||
{
|
||
error = ERROR_NO_FREE_STORE;
|
||
break;
|
||
}
|
||
|
||
node->ln_Name = (char *)(node + 1);
|
||
node->ln_Pri = 0;
|
||
|
||
strcpy(node->ln_Name,cc->cc_AnchorPath->ap_Buf);
|
||
|
||
icon = GetDiskObject(node->ln_Name);
|
||
if(icon != NULL)
|
||
{
|
||
STRPTR priority;
|
||
|
||
priority = FindToolType(icon->do_ToolTypes,"PRI");
|
||
if(priority == NULL)
|
||
priority = FindToolType(icon->do_ToolTypes,"PRIORITY");
|
||
|
||
if(priority != NULL)
|
||
{
|
||
LONG value;
|
||
|
||
if(StrToLong(priority,&value) > 0)
|
||
{
|
||
if(-128 <= value && value <= 127)
|
||
node->ln_Pri = value;
|
||
}
|
||
}
|
||
|
||
FreeDiskObject(icon);
|
||
}
|
||
|
||
add_interface_node(cc,&interface_list,node);
|
||
interface_list_size++;
|
||
}
|
||
}
|
||
|
||
error = MatchNext(cc->cc_AnchorPath);
|
||
}
|
||
|
||
if(error != OK && error != ERROR_NO_MORE_ENTRIES)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
error_print_fault(cc,IoErr());
|
||
|
||
result = RETURN_ERROR;
|
||
|
||
goto out;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Now run through all the steps of the configuration process,
|
||
adding each interface in turn. */
|
||
for(operating_mode = AIM_Add ; operating_mode <= AIM_Configure ; operating_mode++)
|
||
{
|
||
for(node = interface_list.lh_Head ; node->ln_Succ != NULL ; node = node->ln_Succ)
|
||
{
|
||
result = add_interface(cc,node->ln_Name,operating_mode,timeout);
|
||
if(result != OK)
|
||
{
|
||
/* Fail only if there is one single interface involved. */
|
||
if(interface_list_size == 1)
|
||
goto out;
|
||
|
||
configuration_trouble = TRUE;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
result = RETURN_OK;
|
||
|
||
/* We may have to check an icon or two, so icon.library better be open. */
|
||
if(IconBase == NULL)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_NO_ICON_TXT));
|
||
|
||
goto out;
|
||
}
|
||
|
||
/* We need at least one project icon to be invoked with this command. */
|
||
if(cc->cc_StartupMessage->sm_NumArgs > 1)
|
||
{
|
||
D_S(struct FileInfoBlock,fib);
|
||
int operating_mode;
|
||
BOOL fib_valid;
|
||
BPTR lock;
|
||
LONG i;
|
||
|
||
memset(fib,0,sizeof(fib));
|
||
|
||
/* Run down the project icons. */
|
||
for(i = 1 ; i < cc->cc_StartupMessage->sm_NumArgs ; i++)
|
||
{
|
||
/* These are the default settings which can be
|
||
overridden through icon tool types. */
|
||
timeout = 60;
|
||
cc->cc_Quiet = FALSE;
|
||
|
||
/* Free the last icon we may have dealt with. */
|
||
if(icon != NULL)
|
||
{
|
||
FreeDiskObject(icon);
|
||
icon = NULL;
|
||
}
|
||
|
||
/* Remember the current directory we started with. It has
|
||
to be restored, eventually. */
|
||
if(NOT old_cd_valid)
|
||
{
|
||
old_cd = CurrentDir(cc->cc_StartupMessage->sm_ArgList[i].wa_Lock);
|
||
|
||
old_cd_valid = TRUE;
|
||
}
|
||
else
|
||
{
|
||
CurrentDir(cc->cc_StartupMessage->sm_ArgList[i].wa_Lock);
|
||
}
|
||
|
||
fib_valid = FALSE;
|
||
|
||
/* Try to figure out what kind of object we are dealing
|
||
with and, if it's a file, check the icon tool types. */
|
||
lock = Lock(cc->cc_StartupMessage->sm_ArgList[i].wa_Name,SHARED_LOCK);
|
||
if(lock != ZERO)
|
||
{
|
||
if(Examine(lock,fib))
|
||
{
|
||
fib_valid = TRUE;
|
||
|
||
if(icon == NULL)
|
||
{
|
||
icon = GetDiskObject(cc->cc_StartupMessage->sm_ArgList[i].wa_Name);
|
||
if(icon != NULL)
|
||
{
|
||
STRPTR str;
|
||
|
||
str = FindToolType(icon->do_ToolTypes,"QUIET");
|
||
if(str != NULL)
|
||
cc->cc_Quiet = TRUE;
|
||
|
||
str = FindToolType(icon->do_ToolTypes,"TIMEOUT");
|
||
if(str != NULL)
|
||
{
|
||
LONG val;
|
||
|
||
if((StrToLong(str,&val) > 0) && (val > 0))
|
||
{
|
||
if(val < 10)
|
||
val = 10;
|
||
|
||
timeout = val;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
UnLock(lock);
|
||
}
|
||
|
||
/* If we found a likely configuration file, take care of it. */
|
||
if(fib_valid && (fib->fib_DirEntryType < 0))
|
||
{
|
||
/* Run through the configuration steps for this icon. */
|
||
for(operating_mode = AIM_Add ; operating_mode <= AIM_Configure ; operating_mode++)
|
||
{
|
||
result = add_interface(cc,cc->cc_StartupMessage->sm_ArgList[i].wa_Name,operating_mode,timeout);
|
||
if(result != OK)
|
||
{
|
||
/* Fail only if there is one single interface involved. */
|
||
if(cc->cc_StartupMessage->sm_NumArgs == 1)
|
||
goto out;
|
||
|
||
configuration_trouble = TRUE;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if(configuration_trouble)
|
||
result = RETURN_WARN;
|
||
|
||
out:
|
||
|
||
if(NOT IsListEmpty(&interface_list))
|
||
{
|
||
struct Node * node;
|
||
|
||
while((node = RemHead(&interface_list)) != NULL)
|
||
FreeVec(node);
|
||
}
|
||
|
||
if(old_cd_valid)
|
||
CurrentDir(old_cd);
|
||
|
||
if(icon != NULL)
|
||
FreeDiskObject(icon);
|
||
|
||
DeleteMsgPort(cc->cc_ReplyPort);
|
||
|
||
if(cc->cc_Quiet && result != RETURN_OK)
|
||
result = RETURN_WARN;
|
||
|
||
FreeVec(buf);
|
||
|
||
if(rda != NULL)
|
||
FreeArgs(rda);
|
||
|
||
return(result);
|
||
}
|
||
|
||
/****************************************************************************/
|
||
|
||
/* Check if a string reads as YES/NO or ON/OFF. */
|
||
STATIC LONG
|
||
match_key(struct CommandContext * cc,STRPTR what)
|
||
{
|
||
DECLARE_UTILITYBASE(cc);
|
||
|
||
LONG result;
|
||
|
||
if(Stricmp(what,"YES") == SAME ||
|
||
Stricmp(what,"ON") == SAME)
|
||
{
|
||
result = TRUE;
|
||
}
|
||
else if (Stricmp(what,"NO") == SAME ||
|
||
Stricmp(what,"OFF") == SAME)
|
||
{
|
||
result = FALSE;
|
||
}
|
||
else
|
||
{
|
||
result = -1;
|
||
}
|
||
|
||
return(result);
|
||
}
|
||
|
||
/****************************************************************************/
|
||
|
||
/* Add a new tag item to a list being built. */
|
||
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);
|
||
}
|
||
|
||
/****************************************************************************/
|
||
|
||
/* Check if a character is considered a blank space. This includes
|
||
the ' ', '\t' and '\240' characters. */
|
||
STATIC BOOL
|
||
is_blank_space(UBYTE c)
|
||
{
|
||
BOOL result;
|
||
|
||
result = (BOOL)(c == ' ' || c == '\t' || c == (UBYTE)'\240');
|
||
|
||
return(result);
|
||
}
|
||
|
||
/****************************************************************************/
|
||
|
||
/* Get the next token from a string; tokens are separated by blank spaces
|
||
or the colon character. This is used for configuring the hardware
|
||
address of an Ethernet interface. */
|
||
STATIC STRPTR
|
||
get_next_token(
|
||
STRPTR input,
|
||
STRPTR string,
|
||
LONG string_len)
|
||
{
|
||
if((*input) == '\0')
|
||
{
|
||
input = NULL;
|
||
}
|
||
else
|
||
{
|
||
UBYTE c;
|
||
|
||
while(is_blank_space(*input) || (*input) == ':')
|
||
input++;
|
||
|
||
while(TRUE)
|
||
{
|
||
c = (*input++);
|
||
|
||
/* Stop at the end of the string or when a blank
|
||
space is found. */
|
||
if(c == '\0')
|
||
{
|
||
input--;
|
||
break;
|
||
}
|
||
else if (is_blank_space(c) || c == ':')
|
||
{
|
||
break;
|
||
}
|
||
|
||
if(string_len > 1)
|
||
{
|
||
(*string++) = c;
|
||
string_len--;
|
||
}
|
||
}
|
||
|
||
if(string_len > 0)
|
||
(*string) = '\0';
|
||
}
|
||
|
||
return(input);
|
||
}
|
||
|
||
/****************************************************************************/
|
||
|
||
/* Convert a hexadecimal number into a 32 bit integer. */
|
||
STATIC LONG
|
||
get_hex_value(struct CommandContext * cc,STRPTR str)
|
||
{
|
||
DECLARE_UTILITYBASE(cc);
|
||
|
||
LONG result = -1;
|
||
LONG value = 0;
|
||
LONG len = 0;
|
||
UBYTE c;
|
||
|
||
while((c = ToUpper(*str++)) != '\0')
|
||
{
|
||
len++;
|
||
if(len > 2)
|
||
goto out;
|
||
|
||
if('0' <= c && c <= '9')
|
||
c = c - '0';
|
||
else if ('A' <= c && c <= 'F')
|
||
c = c - 'A' + 10;
|
||
else
|
||
goto out;
|
||
|
||
value = (16 * value) + c;
|
||
}
|
||
|
||
result = value;
|
||
|
||
out:
|
||
|
||
return(result);
|
||
}
|
||
|
||
/****************************************************************************/
|
||
|
||
/* Turn an 8 bit integer into a hexadecimal string. */
|
||
STATIC VOID
|
||
get_hex_string(LONG value,STRPTR str)
|
||
{
|
||
STATIC UBYTE code[] = "0123456789ABCDEF";
|
||
|
||
str[0] = code[(value & 0xF0) >> 4];
|
||
str[1] = code[(value & 0x0F) ];
|
||
str[2] = '\0';
|
||
}
|
||
|
||
/****************************************************************************/
|
||
|
||
/* Remove all unprintable characters from a string. */
|
||
STATIC VOID
|
||
strip_unprintable_characters(STRPTR s)
|
||
{
|
||
STRPTR t = s;
|
||
UBYTE c;
|
||
|
||
while((c = (*s++)) != '\0')
|
||
{
|
||
if((c >= ' ' || c == '\t') && (c < '\177' || c >= (UBYTE)'\240'))
|
||
(*t++) = c;
|
||
}
|
||
|
||
(*t) = '\0';
|
||
}
|
||
|
||
/****************************************************************************/
|
||
|
||
/* Strip leading and trailing blank spaces from a string. */
|
||
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);
|
||
}
|
||
|
||
/****************************************************************************/
|
||
|
||
/* This is the big one. It reads the configuration file and acts upon what it finds. */
|
||
STATIC LONG
|
||
add_interface(struct CommandContext * cc,STRPTR name,enum add_interface_mode_t operating_mode,LONG timeout)
|
||
{
|
||
/* This is where the configuration file data will go. */
|
||
struct
|
||
{
|
||
KEY Device;
|
||
NUMBER Unit;
|
||
NUMBER IPType;
|
||
NUMBER ARPType;
|
||
NUMBER IPRequests;
|
||
NUMBER WriteRequests;
|
||
NUMBER ARPRequests;
|
||
KEY HardwareType; /* This is always ignored; it's only for the prefs editor to use! */
|
||
KEY Debug;
|
||
KEY Filter;
|
||
KEY PointToPoint;
|
||
KEY Multicast;
|
||
KEY DownGoesOffline;
|
||
KEY ReportOffline;
|
||
KEY RequiresInitDelay;
|
||
KEY CopyMode;
|
||
KEY Address;
|
||
KEY * Alias;
|
||
KEY NetMask;
|
||
KEY State;
|
||
KEY BroadcastAddress;
|
||
KEY DestinationAddress;
|
||
KEY HardwareAddress;
|
||
NUMBER Metric;
|
||
NUMBER MTU;
|
||
KEY Configure;
|
||
KEY Lease;
|
||
KEY ID;
|
||
KEY DHCPUnicast;
|
||
} args;
|
||
|
||
/* This command template corresponds to the parameter definitions above. */
|
||
STRPTR args_template =
|
||
"DEVICE/K,"
|
||
"UNIT/K/N,"
|
||
"IPTYPE/K/N,"
|
||
"ARPTYPE/K/N,"
|
||
"IPREQUESTS/K/N,"
|
||
"WRITEREQUESTS/K/N,"
|
||
"ARPREQUESTS/K/N,"
|
||
"HARDWARETYPE/K,"
|
||
"DEBUG/K,"
|
||
"FILTER/K,"
|
||
"POINTTOPOINT/K,"
|
||
"MULTICAST/K,"
|
||
"DOWNGOESOFFLINE/K,"
|
||
"REPORTOFFLINE/K,"
|
||
"REQUIRESINITDELAY/K,"
|
||
"COPYMODE/K,"
|
||
"ADDRESS/K,"
|
||
"ALIAS/K/M,"
|
||
"NETMASK/K,"
|
||
"STATE/K,"
|
||
"BROADCASTADDRESS/K,"
|
||
"DESTINATION=DESTINATIONADDRESS/K,"
|
||
"HARDWAREADDRESS/K,"
|
||
"METRIC/K/N,"
|
||
"MTU/K/N,"
|
||
"CONFIGURE/K,"
|
||
"LEASE/K,"
|
||
"ID/K,"
|
||
"DHCPUNICAST/K";
|
||
|
||
DECLARE_SYSBASE(cc);
|
||
DECLARE_DOSBASE(cc);
|
||
DECLARE_UTILITYBASE(cc);
|
||
DECLARE_SOCKETBASE(cc);
|
||
|
||
STRPTR hardware_address = NULL;
|
||
struct InterfaceHardwareAddress iha;
|
||
LONG interface_state = SM_Up;
|
||
STRPTR address = NULL;
|
||
STRPTR net_mask = NULL;
|
||
STRPTR broadcast_address = NULL;
|
||
STRPTR destination_address = NULL;
|
||
LONG metric = 0;
|
||
STRPTR device_name = NULL;
|
||
LONG device_unit = 0;
|
||
LONG result = RETURN_FAIL;
|
||
STRPTR interface_name = FilePart(name);
|
||
UBYTE default_domain_name[256];
|
||
UBYTE str[512];
|
||
UBYTE *s;
|
||
UBYTE *t;
|
||
UBYTE *v;
|
||
LONG line_number;
|
||
LONG error;
|
||
LONG len;
|
||
LONG i;
|
||
LONG separator_index;
|
||
UBYTE separator_char;
|
||
BOOL configure_dynamic = FALSE;
|
||
BOOL configure_auto = FALSE;
|
||
BOOL configure_slow_auto = FALSE;
|
||
ULONG lease_time = DHCP_DEFAULT_LEASE_TIME;
|
||
STRPTR client_id = NULL;
|
||
struct List alias_list;
|
||
struct Node * node;
|
||
LONG dhcp_unicast = FALSE;
|
||
|
||
NewList(&alias_list);
|
||
|
||
memset(&iha,0,sizeof(iha));
|
||
|
||
/* Try to open the configuration file. */
|
||
cc->cc_File = Open(name,MODE_OLDFILE);
|
||
if(cc->cc_File == ZERO)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error = IoErr();
|
||
|
||
Fault(error,NULL,str,sizeof(str));
|
||
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_CANNOT_OPEN_FILE_TXT),
|
||
name,str);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
/* Use a larger buffer to make reading from the configuration
|
||
file a little more efficient. */
|
||
SetVBuf(cc->cc_File,NULL,BUF_LINE,sizeof(str));
|
||
|
||
/* Free any configuration items allocated before. */
|
||
FreeVec(cc->cc_Tags);
|
||
cc->cc_Tags = NULL;
|
||
|
||
cc->cc_MaxTags = cc->cc_NumTags = 0;
|
||
|
||
line_number = 0;
|
||
|
||
/* Read the configuration file line by line. */
|
||
while(FGets(cc->cc_File,str,sizeof(str)-2) != NULL)
|
||
{
|
||
line_number++;
|
||
|
||
/* Drop anything from the line that we don't want. */
|
||
strip_unprintable_characters(str);
|
||
|
||
/* Skip leading blank spaces. */
|
||
s = str;
|
||
while(is_blank_space(*s))
|
||
s++;
|
||
|
||
/* A # or ; introduces a comment. We just ignore that. */
|
||
if((*s) == '#' || (*s) == ';')
|
||
continue;
|
||
|
||
/* Drop trailing blank spaces. */
|
||
len = strlen(s);
|
||
while(len > 0 && (is_blank_space(s[len-1]) || s[len-1] == '\r' || s[len-1] == '\n'))
|
||
len--;
|
||
|
||
if(len == 0)
|
||
continue;
|
||
|
||
s[len] = '\0';
|
||
|
||
/* There's a key and a value in this line. The key and the value
|
||
are separated by blank spaces or a '=' character. */
|
||
t = v = s;
|
||
|
||
/* Isolate the key; the key is everything that's not a blank
|
||
space or a '=' character. */
|
||
while(NOT is_blank_space(*t) && (*t) != '=' && (*t) != '\0')
|
||
{
|
||
v++;
|
||
t++;
|
||
}
|
||
|
||
/* Find the value. */
|
||
if((*t) != '\0')
|
||
{
|
||
(*v++) = ' ';
|
||
|
||
t++;
|
||
|
||
while(is_blank_space(*t) || (*t) == '=')
|
||
t++;
|
||
|
||
while((*t) != '\0')
|
||
(*v++) = (*t++);
|
||
}
|
||
|
||
(*v) = '\0';
|
||
|
||
/* Figure out where the separator character (blank space or '=') is. */
|
||
len = strlen(s);
|
||
|
||
separator_index = -1;
|
||
separator_char = '\0';
|
||
|
||
for(i = 0 ; i < len ; i++)
|
||
{
|
||
if(is_blank_space(s[i]) || s[i] == '=')
|
||
{
|
||
separator_index = i;
|
||
separator_char = s[i];
|
||
|
||
/* Chop off the string after the key. */
|
||
s[i] = '\0';
|
||
break;
|
||
}
|
||
}
|
||
|
||
/* Check if we know the key for this line. */
|
||
if(FindArg(args_template,s) == -1)
|
||
{
|
||
/* We don't know it, so we'll ignore it. */
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
warning_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_UNKNOWN_KEYWORD_TXT),
|
||
s,line_number,name);
|
||
}
|
||
|
||
continue;
|
||
}
|
||
|
||
/* Restore the character following the key. */
|
||
if(separator_index != -1)
|
||
s[separator_index] = separator_char;
|
||
|
||
s[len++] = '\n';
|
||
s[len] = '\0';
|
||
|
||
/* Process what's in this line. */
|
||
FreeArgs(cc->cc_RDA);
|
||
memset(&args,0,sizeof(args));
|
||
|
||
cc->cc_RDA->RDA_Source.CS_Buffer = s;
|
||
cc->cc_RDA->RDA_Source.CS_Length = len;
|
||
cc->cc_RDA->RDA_Source.CS_CurChr = 0;
|
||
cc->cc_RDA->RDA_Flags |= RDAF_NOPROMPT;
|
||
|
||
if(CANNOT ReadArgs((STRPTR)args_template,(LONG *)&args,cc->cc_RDA))
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error = IoErr();
|
||
|
||
Fault(error,NULL,str,sizeof(str));
|
||
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_PARSE_ERROR_TXT),
|
||
line_number,name,str);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
/* Did we get a device name? */
|
||
if(args.Device != NULL)
|
||
{
|
||
FreeVec(device_name);
|
||
|
||
device_name = AllocVec(strlen(args.Device)+1,MEMF_ANY|MEMF_PUBLIC);
|
||
if(device_name == NULL)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_NOT_ENOUGH_MEMORY_TO_PARSE_TXT),
|
||
line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
strcpy(device_name,args.Device);
|
||
}
|
||
|
||
/* Did we get a unit number? */
|
||
if(args.Unit != NULL)
|
||
device_unit = (*args.Unit);
|
||
|
||
/* Did we get an IP packet type? */
|
||
if(args.IPType != NULL)
|
||
{
|
||
error = add_tag(cc,IFA_IPType,(*args.IPType));
|
||
if(error != OK)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_NOT_ENOUGH_MEMORY_TO_PARSE_TXT),
|
||
line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
}
|
||
|
||
/* Did we get an ARP packet type? */
|
||
if(args.ARPType != NULL)
|
||
{
|
||
error = add_tag(cc,IFA_ARPType,(*args.ARPType));
|
||
if(error != OK)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_NOT_ENOUGH_MEMORY_TO_PARSE_TXT),
|
||
line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
}
|
||
|
||
/* Did we get a number for the total number of IP requests? */
|
||
if(args.IPRequests != NULL)
|
||
{
|
||
error = add_tag(cc,IFA_NumReadRequests,(*args.IPRequests));
|
||
if(error != OK)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_NOT_ENOUGH_MEMORY_TO_PARSE_TXT),
|
||
line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
}
|
||
|
||
/* Did we get a number for the total number of write requests? */
|
||
if(args.WriteRequests != NULL)
|
||
{
|
||
error = add_tag(cc,IFA_NumWriteRequests,(*args.WriteRequests));
|
||
if(error != OK)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_NOT_ENOUGH_MEMORY_TO_PARSE_TXT),
|
||
line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
}
|
||
|
||
/* Did we get a number for the total number of ARP requests? */
|
||
if(args.ARPRequests != NULL)
|
||
{
|
||
error = add_tag(cc,IFA_NumARPRequests,(*args.ARPRequests));
|
||
if(error != OK)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_NOT_ENOUGH_MEMORY_TO_PARSE_TXT),
|
||
line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
}
|
||
|
||
/* Did we get a filter mode? */
|
||
if(args.Filter != NULL)
|
||
{
|
||
LONG mode;
|
||
|
||
/* What is the filter set to? */
|
||
if(Stricmp(args.Filter,"OFF") == SAME)
|
||
mode = PFM_Nothing;
|
||
else if (Stricmp(args.Filter,"LOCAL") == SAME)
|
||
mode = PFM_Local;
|
||
else if (Stricmp(args.Filter,"IPANDARP") == SAME)
|
||
mode = PFM_IPandARP;
|
||
else if (Stricmp(args.Filter,"EVERYTHING") == SAME)
|
||
mode = PFM_Everything;
|
||
else
|
||
mode = -1;
|
||
|
||
if(mode < 0)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_UNKNOWN_PARAMETER_TXT),
|
||
args.Filter,line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
error = add_tag(cc,IFA_PacketFilterMode,mode);
|
||
if(error != OK)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_NOT_ENOUGH_MEMORY_TO_PARSE_TXT),
|
||
line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
}
|
||
|
||
/* Is this a point-to-point device? */
|
||
if(args.PointToPoint != NULL)
|
||
{
|
||
LONG mode;
|
||
|
||
mode = match_key(cc,args.PointToPoint);
|
||
if(mode < 0)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_UNKNOWN_PARAMETER_TXT),
|
||
args.PointToPoint,line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
error = add_tag(cc,IFA_PointToPoint,mode);
|
||
if(error != OK)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_NOT_ENOUGH_MEMORY_TO_PARSE_TXT),
|
||
line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
}
|
||
|
||
/* Enable or disable debug mode on this interface? */
|
||
if(args.Debug != NULL)
|
||
{
|
||
LONG mode;
|
||
|
||
mode = match_key(cc,args.Debug);
|
||
if(mode < 0)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_UNKNOWN_PARAMETER_TXT),
|
||
args.Debug,line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
error = add_tag(cc,IFA_SetDebugMode,mode);
|
||
if(error != OK)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_NOT_ENOUGH_MEMORY_TO_PARSE_TXT),
|
||
line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
}
|
||
|
||
/* Is this interface capable of multicasts? */
|
||
if(args.Multicast != NULL)
|
||
{
|
||
LONG mode;
|
||
|
||
mode = match_key(cc,args.Multicast);
|
||
if(mode < 0)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_UNKNOWN_PARAMETER_TXT),
|
||
args.Multicast,line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
error = add_tag(cc,IFA_Multicast,mode);
|
||
if(error != OK)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_NOT_ENOUGH_MEMORY_TO_PARSE_TXT),
|
||
line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
}
|
||
|
||
/* Should marking the interface "down" also take it offline? */
|
||
if(args.DownGoesOffline != NULL)
|
||
{
|
||
LONG mode;
|
||
|
||
mode = match_key(cc,args.DownGoesOffline);
|
||
if(mode < 0)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_UNKNOWN_PARAMETER_TXT),
|
||
args.DownGoesOffline,line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
error = add_tag(cc,IFA_DownGoesOffline,mode);
|
||
if(error != OK)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_NOT_ENOUGH_MEMORY_TO_PARSE_TXT),
|
||
line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
}
|
||
|
||
/* Report when the interface goes offline? */
|
||
if(args.ReportOffline != NULL)
|
||
{
|
||
LONG mode;
|
||
|
||
mode = match_key(cc,args.ReportOffline);
|
||
if(mode < 0)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_UNKNOWN_PARAMETER_TXT),
|
||
args.ReportOffline,line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
error = add_tag(cc,IFA_ReportOffline,mode);
|
||
if(error != OK)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_NOT_ENOUGH_MEMORY_TO_PARSE_TXT),
|
||
line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
}
|
||
|
||
/* Is a small delay required after initializing the interface? */
|
||
if(args.RequiresInitDelay != NULL)
|
||
{
|
||
LONG mode;
|
||
|
||
mode = match_key(cc,args.RequiresInitDelay);
|
||
if(mode < 0)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_UNKNOWN_PARAMETER_TXT),
|
||
args.RequiresInitDelay,line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
error = add_tag(cc,IFA_RequiresInitDelay,mode);
|
||
if(error != OK)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_NOT_ENOUGH_MEMORY_TO_PARSE_TXT),
|
||
line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
}
|
||
|
||
/* Use a particular copying mode? */
|
||
if(args.CopyMode != NULL)
|
||
{
|
||
LONG mode;
|
||
|
||
if(Stricmp(args.CopyMode,"SLOW") == SAME)
|
||
mode = CM_SlowWordCopy;
|
||
else if (Stricmp(args.CopyMode,"FAST") == SAME)
|
||
mode = CM_FastWordCopy;
|
||
else
|
||
mode = -1;
|
||
|
||
if(mode < 0)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_UNKNOWN_PARAMETER_TXT),
|
||
args.CopyMode,line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
error = add_tag(cc,IFA_CopyMode,mode);
|
||
if(error != OK)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_NOT_ENOUGH_MEMORY_TO_PARSE_TXT),
|
||
line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
}
|
||
|
||
/* Use a particular IP address, or DHCP? */
|
||
if(args.Address != NULL)
|
||
{
|
||
struct in_addr in;
|
||
|
||
/* Is this an IP address? */
|
||
if(Stricmp(args.Address,"DHCP") != SAME)
|
||
{
|
||
/* Is is a well-formed address? */
|
||
if(CANNOT validate_ip_address(cc,"ADDRESS",args.Address,line_number,name))
|
||
goto out;
|
||
}
|
||
|
||
/* If this is an IP address, have a closer look at it. */
|
||
if(inet_aton(args.Address,&in))
|
||
{
|
||
/* Neither 0 nor the broadcast address are permitted. */
|
||
if(in.s_addr == 0 || in.s_addr == ~0UL)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_INVALID_ADDRESS_TXT),
|
||
args.Address,line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
/* And no reserved range either. */
|
||
if(((in.s_addr >> 24) & 0xFF) == 169 &&
|
||
((in.s_addr >> 16) & 0xFF) == 254)
|
||
{
|
||
warning_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_DYNAMIC_ADDRESS_SHOULD_NOT_BE_BOUND_TXT),
|
||
args.Address,line_number,name);
|
||
}
|
||
}
|
||
|
||
FreeVec(address);
|
||
|
||
address = AllocVec(strlen(args.Address)+1,MEMF_ANY|MEMF_PUBLIC);
|
||
if(address == NULL)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_NOT_ENOUGH_MEMORY_TO_PARSE_TXT),
|
||
line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
strcpy(address,args.Address);
|
||
}
|
||
|
||
/* Set the interface to a particular state? */
|
||
if(args.State != NULL)
|
||
{
|
||
if(Stricmp(args.State,"UP") == SAME)
|
||
{
|
||
interface_state = SM_Up;
|
||
}
|
||
else if (Stricmp(args.State,"DOWN") == SAME)
|
||
{
|
||
interface_state = SM_Down;
|
||
}
|
||
else if (Stricmp(args.State,"ONLINE") == SAME)
|
||
{
|
||
interface_state = SM_Online;
|
||
}
|
||
else if (Stricmp(args.State,"OFFLINE") == SAME)
|
||
{
|
||
interface_state = SM_Offline;
|
||
}
|
||
else
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_UNKNOWN_STATE_PARAMETER_TXT),
|
||
args.State,line_number);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
}
|
||
|
||
/* Use a particular broadcast address? */
|
||
if(args.BroadcastAddress != NULL)
|
||
{
|
||
if(CANNOT validate_ip_address(cc,"BROADCASTADDRESS",args.BroadcastAddress,line_number,name))
|
||
goto out;
|
||
|
||
FreeVec(broadcast_address);
|
||
|
||
broadcast_address = AllocVec(strlen(args.BroadcastAddress)+1,MEMF_ANY|MEMF_PUBLIC);
|
||
if(broadcast_address == NULL)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_NOT_ENOUGH_MEMORY_TO_PARSE_TXT),
|
||
line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
strcpy(broadcast_address,args.BroadcastAddress);
|
||
}
|
||
|
||
/* For a point-to-point address, use a particular destination address for the peer? */
|
||
if(args.DestinationAddress != NULL)
|
||
{
|
||
if(CANNOT validate_ip_address(cc,"DESTINATIONADDRESS",args.DestinationAddress,line_number,name))
|
||
goto out;
|
||
|
||
FreeVec(destination_address);
|
||
|
||
destination_address = AllocVec(strlen(args.DestinationAddress)+1,MEMF_ANY|MEMF_PUBLIC);
|
||
if(destination_address == NULL)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_NOT_ENOUGH_MEMORY_TO_PARSE_TXT),
|
||
line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
strcpy(destination_address,args.DestinationAddress);
|
||
}
|
||
|
||
/* Use a particular hardware address? */
|
||
if(args.HardwareAddress != NULL)
|
||
{
|
||
UBYTE token[40];
|
||
UBYTE buf[10];
|
||
STRPTR arg;
|
||
LONG num_tokens;
|
||
LONG i;
|
||
|
||
/* Collect individual tokens; these are octet separated by
|
||
blank spaces or ':' characters. */
|
||
num_tokens = 0;
|
||
|
||
arg = args.HardwareAddress;
|
||
while((arg = get_next_token(arg,token,sizeof(token))) != NULL)
|
||
{
|
||
if(get_hex_value(cc,token) < 0)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_INVALID_HARDWARE_ADDRESS_TXT),
|
||
args.HardwareAddress,line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
num_tokens++;
|
||
}
|
||
|
||
/* Complain if we didn't get anything. */
|
||
if(num_tokens == 0)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_MISSING_HARDWARE_ADDRESS_TXT),
|
||
line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
FreeVec(iha.iha_Address);
|
||
FreeVec(hardware_address);
|
||
|
||
/* Allocate memory for the address. */
|
||
iha.iha_Length = num_tokens * 8;
|
||
iha.iha_Address = AllocVec(num_tokens,MEMF_ANY|MEMF_PUBLIC|MEMF_CLEAR);
|
||
if(iha.iha_Address == NULL)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_NOT_ENOUGH_MEMORY_FOR_HARDWARE_ADDRESS_TXT),
|
||
args.HardwareAddress);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
hardware_address = AllocVec(3 * num_tokens,MEMF_ANY|MEMF_PUBLIC|MEMF_CLEAR);
|
||
if(hardware_address == NULL)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_NOT_ENOUGH_MEMORY_FOR_HARDWARE_ADDRESS_TXT),
|
||
args.HardwareAddress);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
/* Now parse the individual octets. */
|
||
i = 0;
|
||
arg = args.HardwareAddress;
|
||
while((arg = get_next_token(arg,token,sizeof(token))) != NULL)
|
||
{
|
||
iha.iha_Address[i] = get_hex_value(cc,token);
|
||
|
||
get_hex_string(iha.iha_Address[i],buf);
|
||
if(i != 0)
|
||
strcat(hardware_address,":");
|
||
|
||
strcat(hardware_address,buf);
|
||
|
||
i++;
|
||
}
|
||
|
||
/* Assuming that this is probably an IEEE 802.3 family
|
||
address, we're going to check for a few likely
|
||
configuration errors due to poor choice of
|
||
address. */
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
if(num_tokens < 6)
|
||
{
|
||
warning_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_HARDWARE_ADDRESS_TOO_SHORT_TXT),
|
||
args.HardwareAddress,line_number,name);
|
||
}
|
||
else if (num_tokens > 6)
|
||
{
|
||
warning_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_HARDWARE_ADDRESS_TOO_LONG_TXT),
|
||
args.HardwareAddress,line_number,name);
|
||
}
|
||
|
||
if(FLAG_IS_SET(iha.iha_Address[0],MAC_Is_Group_Address))
|
||
{
|
||
BOOL is_broadcast_address = TRUE;
|
||
|
||
for(i = 0 ; i < num_tokens ; i++)
|
||
{
|
||
if(iha.iha_Address[i] != 0xFF)
|
||
{
|
||
is_broadcast_address = FALSE;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if(is_broadcast_address)
|
||
{
|
||
warning_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_HARDWARE_ADDRESS_IS_BROADCAST_TXT),
|
||
args.HardwareAddress,line_number,name);
|
||
}
|
||
else
|
||
{
|
||
warning_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_HARDWARE_ADDRESS_IS_GROUP_TXT),
|
||
args.HardwareAddress,line_number,name);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Use a particular netmask, or DHCP? */
|
||
if(args.NetMask != NULL)
|
||
{
|
||
/* Is this an IP address? */
|
||
if(Stricmp(args.NetMask,"DHCP") != SAME)
|
||
{
|
||
/* Is is a well-formed address? */
|
||
if(CANNOT validate_ip_address(cc,"NETMASK",args.NetMask,line_number,name))
|
||
goto out;
|
||
}
|
||
|
||
FreeVec(net_mask);
|
||
|
||
net_mask = AllocVec(strlen(args.NetMask)+1,MEMF_ANY|MEMF_PUBLIC);
|
||
if(net_mask == NULL)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_NOT_ENOUGH_MEMORY_TO_PARSE_TXT),
|
||
line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
strcpy(net_mask,args.NetMask);
|
||
}
|
||
|
||
/* Use a particular routing metric? */
|
||
if(args.Metric != NULL)
|
||
metric = (*args.Metric);
|
||
|
||
/* Use a particular MTU value? */
|
||
if(args.MTU != NULL && (*args.MTU) > 0)
|
||
{
|
||
error = add_tag(cc,IFA_LimitMTU,(*args.MTU));
|
||
if(error != OK)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_NOT_ENOUGH_MEMORY_TO_PARSE_TXT),
|
||
line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
}
|
||
|
||
/* Use a particular configuration method? */
|
||
if(args.Configure != NULL)
|
||
{
|
||
if(Stricmp(args.Configure,"DHCP") == SAME)
|
||
{
|
||
/* Dynamic Host Configuration Protocol */
|
||
configure_dynamic = TRUE;
|
||
configure_auto = FALSE;
|
||
}
|
||
else if (Stricmp(args.Configure,"SLOWAUTO") == SAME || Stricmp(args.Configure,"AUTO") == SAME)
|
||
{
|
||
/* ZeroConf; "slow" method for spanning tree routing. */
|
||
configure_dynamic = configure_auto = configure_slow_auto = TRUE;
|
||
}
|
||
else if (Stricmp(args.Configure,"FASTAUTO") == SAME)
|
||
{
|
||
/* ZeroConf; "fast" method for wireless applications, etc. */
|
||
configure_dynamic = configure_auto = TRUE;
|
||
configure_slow_auto = FALSE;
|
||
}
|
||
else
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_UNKNOWN_PARAMETER_TXT),
|
||
args.Configure,line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
}
|
||
|
||
/* Ask for a particular lease time? */
|
||
if(args.Lease != NULL)
|
||
{
|
||
STRPTR s = args.Lease;
|
||
STRPTR key = NULL;
|
||
LONG number;
|
||
LONG len;
|
||
|
||
/* Skip all leading blank spaces. */
|
||
while(is_blank_space(*s))
|
||
s++;
|
||
|
||
/* If it's a number, convert it now. */
|
||
len = 0;
|
||
number = 0;
|
||
while('0' <= (*s) && (*s) <= '9')
|
||
{
|
||
number = (10 * number) + (*s) - '0';
|
||
len++;
|
||
s++;
|
||
}
|
||
|
||
/* Skip all following blank spaces, if any. */
|
||
while(is_blank_space(*s))
|
||
s++;
|
||
|
||
if(s[0] != '\0')
|
||
key = s;
|
||
|
||
/* Check if there's a keyword instead. */
|
||
if(len == 0 && key != NULL)
|
||
{
|
||
/* This should be "infinite", "infinity" or
|
||
simply "inf". */
|
||
if(substring_matches(cc,"INF",key) == SAME)
|
||
{
|
||
lease_time = DHCP_INFINITE_LEASE_TIME;
|
||
}
|
||
else
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_UNKNOWN_LEASE_PARAMETER_TXT),
|
||
key,line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
}
|
||
else if (len > 0)
|
||
{
|
||
lease_time = number;
|
||
|
||
/* This could be qualifier, which stands for seconds,
|
||
minutes, hours, days or weeks. */
|
||
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 cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_UNKNOWN_LEASE_PARAMETER_TXT),
|
||
key,line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_INVALID_LEASE_PARAMETER_TXT),
|
||
args.Lease,line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
}
|
||
|
||
/* Use a particular client ID (for DHCP)? */
|
||
if(args.ID != NULL)
|
||
{
|
||
LONG len;
|
||
|
||
len = strlen(args.ID);
|
||
|
||
if(len > 255 && NOT cc->cc_Quiet)
|
||
{
|
||
warning_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_ID_TOO_LONG_TXT),
|
||
args.ID,line_number,name);
|
||
}
|
||
|
||
if(len < 2)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_ID_TOO_SHORT_TXT),
|
||
args.ID,line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
FreeVec(client_id);
|
||
|
||
client_id = AllocVec(len+1,MEMF_ANY|MEMF_PUBLIC);
|
||
if(client_id == NULL)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_INTERFACE_NOT_CONFIGURED_NO_MEMORY_TXT),
|
||
interface_name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
strncpy(client_id,args.ID,len);
|
||
client_id[len] = '\0';
|
||
}
|
||
|
||
/* Request that the DHCP server sends replies using
|
||
unicast instead of broadcast? */
|
||
if(args.DHCPUnicast != NULL)
|
||
{
|
||
LONG mode;
|
||
|
||
mode = match_key(cc,args.DHCPUnicast);
|
||
if(mode < 0)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_UNKNOWN_PARAMETER_TXT),
|
||
args.DHCPUnicast,line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
dhcp_unicast = mode;
|
||
}
|
||
|
||
/* Use an alias for this interface? */
|
||
if(args.Alias != NULL)
|
||
{
|
||
STRPTR * alias = (STRPTR *)args.Alias;
|
||
struct in_addr in;
|
||
STRPTR address;
|
||
|
||
while((address = (*alias++)) != NULL)
|
||
{
|
||
/* Check if the IP address is well-formed. */
|
||
if(CANNOT validate_ip_address(cc,"ALIAS",address,line_number,name))
|
||
goto out;
|
||
|
||
/* Have a closer look at the address. */
|
||
if(inet_aton(address,&in))
|
||
{
|
||
/* Don't permit 0 or the broadcast address. */
|
||
if(in.s_addr == 0 || in.s_addr == ~0UL)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_INVALID_ADDRESS_TXT),
|
||
address,line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
/* Don't use the reserved range. */
|
||
if(((in.s_addr >> 24) & 0xFF) == 169 &&
|
||
((in.s_addr >> 16) & 0xFF) == 254)
|
||
{
|
||
warning_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_DYNAMIC_ADDRESS_SHOULD_NOT_BE_BOUND_TXT),
|
||
address,line_number,name);
|
||
}
|
||
}
|
||
|
||
node = AllocVec(sizeof(*node) + strlen(address)+1,MEMF_ANY|MEMF_PUBLIC);
|
||
if(node == NULL)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_NOT_ENOUGH_MEMORY_TO_PARSE_TXT),
|
||
line_number,name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
node->ln_Name = (char *)(node + 1);
|
||
strcpy(node->ln_Name,address);
|
||
|
||
AddTail(&alias_list,node);
|
||
}
|
||
}
|
||
}
|
||
|
||
/* When adding the interface, use the provided hardware address. */
|
||
if(operating_mode == AIM_Add && iha.iha_Address != NULL)
|
||
{
|
||
error = add_tag(cc,IFA_HardwareAddress,(ULONG)&iha);
|
||
if(error != OK)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_NOT_ENOUGH_MEMORY_TO_CONFIGURE_HARDWARE_ADDRESS_TXT),
|
||
interface_name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
}
|
||
|
||
/* This concludes the parameter list. */
|
||
error = add_tag(cc,TAG_END,0);
|
||
if(error != OK)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_NOT_ENOUGH_MEMORY_TO_ADD_INTERFACE_TXT),
|
||
name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
/* Stop right here if no device name was given. */
|
||
if(device_name == NULL)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_NO_DEVICE_NAME_PROVIDED_TXT),
|
||
name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
/* In the "add" stage, add the interface with the parameters given. */
|
||
if(operating_mode == AIM_Add)
|
||
{
|
||
if(AddInterfaceTagList(interface_name,device_name,device_unit,cc->cc_Tags) != 0)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
LONG errno;
|
||
STRPTR code;
|
||
|
||
get_errno_and_code(cc,&errno,&code);
|
||
|
||
if(code != NULL && errno > 0)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_COULD_NOT_ADD_INTERFACE_ERROR_CODE_TXT),
|
||
interface_name,code);
|
||
}
|
||
else
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_COULD_NOT_ADD_INTERFACE_TXT),
|
||
interface_name);
|
||
}
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
info_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_INTERFACE_ADDED_TXT),
|
||
interface_name);
|
||
|
||
if(hardware_address != NULL)
|
||
{
|
||
info_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_INTERFACE_HARDWARE_ADDRESS_SET_TO_TXT),
|
||
interface_name,hardware_address);
|
||
}
|
||
}
|
||
}
|
||
else if (operating_mode == AIM_Configure)
|
||
{
|
||
/* In the configure state, set up the interface address and aliases. */
|
||
if(address != NULL || configure_dynamic)
|
||
{
|
||
struct AddressAllocationMessage * aam = &cc->cc_AllocationMessage;
|
||
BOOL want_address = (BOOL)(address != NULL && Stricmp(address,"DHCP") == SAME);
|
||
BOOL want_netmask = (BOOL)(net_mask != NULL && Stricmp(net_mask,"DHCP") == SAME);
|
||
|
||
/* Do we need to configure anything dynamically? */
|
||
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 cc->cc_Quiet)
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_NOT_ENOUGH_MEMORY_TO_CONFIGURE_INTERFACE_TXT),name);
|
||
|
||
goto out;
|
||
}
|
||
}
|
||
|
||
/* Before we begin, we will need to mark this
|
||
interface 'up' so that the protocol stack will
|
||
send messages through it. For some devices it
|
||
is not sufficient to mark the interface as up.
|
||
These also have to be switched online, too. */
|
||
if(Local_ConfigureInterfaceTags(cc,interface_name,
|
||
IFC_State,SM_Online,
|
||
TAG_DONE) != 0)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
LONG errno;
|
||
STRPTR code;
|
||
|
||
get_errno_and_code(cc,&errno,&code);
|
||
|
||
if(code != NULL && errno > 0)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_CANNOT_MARK_INTERFACE_UP_ERROR_CODE_TXT),
|
||
interface_name,code);
|
||
}
|
||
else
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_CANNOT_MARK_INTERFACE_UP_TXT),
|
||
interface_name);
|
||
}
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
if(cc->cc_StartupMessage == NULL)
|
||
{
|
||
info_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_TRYING_INTERFACE_CONFIGURATION_TXT),
|
||
interface_name);
|
||
|
||
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,interface_name,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));
|
||
|
||
/* ^C means "stop everything". */
|
||
if(signals & SIGBREAKF_CTRL_C)
|
||
{
|
||
AbortInterfaceConfig(aam);
|
||
WaitPort(cc->cc_ReplyPort);
|
||
GetMsg(cc->cc_ReplyPort);
|
||
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
info_printf(cc,"\n");
|
||
|
||
info_print_fault(cc,ERROR_BREAK);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
else if (signals & SIGBREAKF_CTRL_F)
|
||
{
|
||
/* ^F means "stop configuring this interface". */
|
||
AbortInterfaceConfig(aam);
|
||
WaitPort(cc->cc_ReplyPort);
|
||
GetMsg(cc->cc_ReplyPort);
|
||
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
info_printf(cc,"\n");
|
||
|
||
warning_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_INTERFACE_CONFIGURATION_ABORTED_TXT),
|
||
interface_name);
|
||
}
|
||
|
||
result = RETURN_OK;
|
||
goto out;
|
||
}
|
||
else
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
info_printf(cc,"\n");
|
||
|
||
WaitPort(cc->cc_ReplyPort);
|
||
GetMsg(cc->cc_ReplyPort);
|
||
|
||
/* If that didn't work out, print an error message. */
|
||
if(aam->aam_Result != AAMR_Success && NOT cc->cc_Quiet)
|
||
{
|
||
STATIC CONST error_map_table[][2] =
|
||
{
|
||
{ AAMR_Aborted, MSG_ADDNETINTERFACE_INTERFACE_CONFIGURATION_ABORTED_TXT },
|
||
{ AAMR_Timeout, MSG_ADDNETINTERFACE_INTERFACE_CONFIGURATION_ATTEMPT_TIMED_OUT_TXT },
|
||
{ AAMR_InterfaceNotKnown, MSG_ADDNETINTERFACE_INTERFACE_NOT_CONFIGURED_TXT },
|
||
{ AAMR_InterfaceWrongType, MSG_ADDNETINTERFACE_INTERFACE_WRONG_TYPE_TXT },
|
||
{ AAMR_AddressKnown, MSG_ADDNETINTERFACE_INTERFACE_ALREADY_CONFIGURED_TXT },
|
||
{ AAMR_VersionUnknown, MSG_ADDNETINTERFACE_INTERFACE_CONFIGURATION_VERSION_CONFLICT_TXT },
|
||
{ AAMR_NoMemory, MSG_ADDNETINTERFACE_INTERFACE_NOT_CONFIGURED_NO_MEMORY_TXT },
|
||
{ AAMR_AddressInUse, MSG_ADDNETINTERFACE_INTERFACE_NOT_CONFIGURED_ADDRESS_IN_USE_TXT },
|
||
{ AAMR_AddrChangeFailed, MSG_ADDNETINTERFACE_INTERFACE_NOT_CONFIGURED_ADDRESS_CHANGE_FAILED_TXT },
|
||
{ AAMR_MaskChangeFailed, MSG_ADDNETINTERFACE_INTERFACE_NOT_CONFIGURED_MASK_CHANGE_FAILED_TXT },
|
||
{ AAMR_Busy, MSG_ADDNETINTERFACE_INTERFACE_IS_BUSY_TXT },
|
||
{ -1, -1}
|
||
};
|
||
|
||
LONG message_code;
|
||
size_t i;
|
||
|
||
message_code = MSG_ADDNETINTERFACE_INTERFACE_NOT_CONFIGURED_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;
|
||
}
|
||
}
|
||
|
||
error_printf(cc,get_str(cc,message_code),
|
||
interface_name,aam->aam_Result);
|
||
}
|
||
|
||
/* Even if an error occured, don't stop the show. */
|
||
if(aam->aam_Result != AAMR_Success)
|
||
{
|
||
result = RETURN_OK;
|
||
goto out;
|
||
}
|
||
|
||
/* Check if we got the required IP address. */
|
||
if(configure_dynamic || want_address)
|
||
{
|
||
UBYTE str[20];
|
||
|
||
/* Did we really get something? */
|
||
if(aam->aam_Address == 0)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_INTERFACE_NOT_CONFIGURED_INVALID_ADDRESS_TXT),
|
||
interface_name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
/* Remember the address. */
|
||
strcpy(str,Inet_NtoA(aam->aam_Address));
|
||
|
||
FreeVec(address);
|
||
address = AllocVec(strlen(str)+1,MEMF_ANY|MEMF_PUBLIC);
|
||
if(address == NULL)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_INTERFACE_NOT_CONFIGURED_NO_MEMORY_TXT),
|
||
interface_name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
strcpy(address,str);
|
||
}
|
||
|
||
/* Check if we got the required subnet mask. */
|
||
if(configure_dynamic || want_netmask)
|
||
{
|
||
/* Did we really get something? */
|
||
if(aam->aam_SubnetMask == 0x00000000 ||
|
||
aam->aam_SubnetMask == 0xFFFFFFFF)
|
||
{
|
||
FreeVec(net_mask);
|
||
net_mask = NULL;
|
||
}
|
||
else
|
||
{
|
||
UBYTE str[20];
|
||
|
||
/* Remember the subnet mask. */
|
||
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 cc->cc_Quiet)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_INTERFACE_NOT_CONFIGURED_NO_MEMORY_TXT),
|
||
interface_name);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
strcpy(net_mask,str);
|
||
}
|
||
}
|
||
|
||
/* Validate the router and DNS address tables. */
|
||
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;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Finally, configure the interface using the information obtained above. */
|
||
if(Local_ConfigureInterfaceTags(cc,interface_name,
|
||
(NOT (configure_dynamic || want_address) && address != NULL) ? IFC_Address : TAG_IGNORE, address,
|
||
(NOT (configure_dynamic || want_netmask) && net_mask != NULL) ? IFC_NetMask : TAG_IGNORE, net_mask,
|
||
|
||
(broadcast_address != NULL) ? IFC_BroadcastAddress : TAG_IGNORE, broadcast_address,
|
||
(destination_address != NULL) ? IFC_DestinationAddress : TAG_IGNORE, destination_address,
|
||
(metric != 0) ? IFC_Metric : TAG_IGNORE, metric,
|
||
IFC_State, interface_state,
|
||
IFC_Complete, TRUE,
|
||
TAG_DONE) != 0)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
LONG errno;
|
||
STRPTR code;
|
||
|
||
get_errno_and_code(cc,&errno,&code);
|
||
|
||
if(code != NULL && errno > 0)
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_COULD_NOT_CONFIGURE_INTERFACE_ERROR_CODE_TXT),
|
||
interface_name,code);
|
||
}
|
||
else
|
||
{
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_COULD_NOT_CONFIGURE_INTERFACE_TXT),
|
||
interface_name);
|
||
}
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
/* Unless we shouldn't do so, say what we did above. */
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
info_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_INTERFACE_CONFIGURED_TXT),
|
||
interface_name);
|
||
|
||
if(address != NULL)
|
||
info_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_INTERFACE_CONFIGURED_ADDRESS_TXT),address);
|
||
|
||
if(net_mask != NULL)
|
||
info_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_INTERFACE_CONFIGURED_MASK_TXT),net_mask);
|
||
|
||
if(broadcast_address != NULL)
|
||
info_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_INTERFACE_CONFIGURED_BROADCAST_ADDRESS_TXT),broadcast_address);
|
||
|
||
if(destination_address != NULL)
|
||
info_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_INTERFACE_CONFIGURED_DESTINATION_ADDRESS_TXT),destination_address);
|
||
|
||
if(metric != 0)
|
||
info_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_INTERFACE_CONFIGURED_METRIC_TXT),metric);
|
||
|
||
info_printf(cc,".\n");
|
||
}
|
||
|
||
/* Check if we got any router information from the server. */
|
||
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;
|
||
|
||
/* Use this router address. */
|
||
strcpy(str,Inet_NtoA(aam->aam_RouterTable[i]));
|
||
|
||
/* The first is the default gateway address. */
|
||
if(n == 0)
|
||
{
|
||
if(Local_AddRouteTags(cc,
|
||
RTA_DefaultGateway,str,
|
||
TAG_DONE) != OK)
|
||
{
|
||
get_errno_and_code(cc,&error,&code);
|
||
}
|
||
|
||
/* Say what we did. */
|
||
if(error == OK && NOT cc->cc_Quiet)
|
||
info_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_DEFAULT_ROUTE_TXT),str);
|
||
}
|
||
else
|
||
{
|
||
/* The second is a destination address. */
|
||
if(Local_AddRouteTags(cc,
|
||
RTA_Destination,str,
|
||
TAG_DONE) != OK)
|
||
{
|
||
get_errno_and_code(cc,&error,&code);
|
||
}
|
||
|
||
/* Say what we did. */
|
||
if(error == OK && NOT cc->cc_Quiet)
|
||
info_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_ROUTE_TXT),str);
|
||
}
|
||
|
||
/* Print an error message if that didn't work. */
|
||
if(error != OK)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
LONG message_code;
|
||
|
||
if(code != NULL && error > 0)
|
||
message_code = MSG_ADDNETINTERFACE_COULD_NOT_ADD_ROUTE_ERROR_CODE_TXT;
|
||
else
|
||
message_code = MSG_ADDNETINTERFACE_COULD_NOT_ADD_ROUTE_TXT;
|
||
|
||
error_printf(cc,get_str(cc,message_code),str,code);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
n++;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Check if we got a default domain name to use for DNS lookups. */
|
||
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 cc->cc_Quiet)
|
||
{
|
||
info_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_DEFAULT_DOMAIN_NAME_TXT),
|
||
domain_name);
|
||
}
|
||
}
|
||
|
||
/* Check if we got a DNS server table to use. */
|
||
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);
|
||
|
||
/* Say what we did. */
|
||
if(error == OK && NOT cc->cc_Quiet)
|
||
info_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_DNS_TXT),str);
|
||
|
||
if(error != OK)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
LONG message_code;
|
||
|
||
if(code != NULL && error > 0)
|
||
message_code = MSG_ADDNETINTERFACE_COULD_NOT_ADD_DNS_ERROR_CODE_TXT;
|
||
else
|
||
message_code = MSG_ADDNETINTERFACE_COULD_NOT_ADD_DNS_TXT;
|
||
|
||
error_printf(cc,get_str(cc,message_code),str,code);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/* If we received a lease from a DHCP server, say how long it will last. */
|
||
if((configure_dynamic || want_address) && aam->aam_Protocol == AAMP_DHCP && NOT cc->cc_Quiet)
|
||
{
|
||
info_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_ADDRESS_TXT),
|
||
interface_name,address);
|
||
|
||
if(cc->cc_LeaseExpires.ds_Days == 0 &&
|
||
cc->cc_LeaseExpires.ds_Minute == 0 &&
|
||
cc->cc_LeaseExpires.ds_Tick == 0)
|
||
{
|
||
info_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_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);
|
||
|
||
info_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_LEASED_UNTIL_TXT),
|
||
date,time);
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Finally, try to add alias addresses for this interface. */
|
||
if(NOT IsListEmpty(&alias_list))
|
||
{
|
||
for(node = alias_list.lh_Head ;
|
||
node->ln_Succ != NULL ;
|
||
node = node->ln_Succ)
|
||
{
|
||
if(Local_ConfigureInterfaceTags(cc,interface_name,
|
||
IFC_AddAliasAddress,node->ln_Name,
|
||
TAG_DONE) != 0)
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
{
|
||
LONG message_code;
|
||
LONG errno;
|
||
STRPTR code;
|
||
|
||
get_errno_and_code(cc,&errno,&code);
|
||
|
||
if(code != NULL && errno > 0)
|
||
message_code = MSG_ADDNETINTERFACE_COULD_NOT_ADD_ALIAS_ERROR_CODE_TXT;
|
||
else
|
||
message_code = MSG_ADDNETINTERFACE_COULD_NOT_ADD_ALIAS_TXT;
|
||
|
||
error_printf(cc,get_str(cc,message_code),interface_name,node->ln_Name,code);
|
||
}
|
||
|
||
goto out;
|
||
}
|
||
|
||
/* Say what we did. */
|
||
if(NOT cc->cc_Quiet)
|
||
info_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_ALIAS_TXT),node->ln_Name);
|
||
}
|
||
}
|
||
}
|
||
|
||
result = RETURN_OK;
|
||
|
||
out:
|
||
|
||
/* Clean up the lot... */
|
||
while((node = RemHead(&alias_list)) != NULL)
|
||
FreeVec(node);
|
||
|
||
FreeVec(client_id);
|
||
FreeVec(address);
|
||
FreeVec(net_mask);
|
||
FreeVec(broadcast_address);
|
||
FreeVec(destination_address);
|
||
|
||
FreeVec(device_name);
|
||
|
||
FreeVec(hardware_address);
|
||
FreeVec(iha.iha_Address);
|
||
|
||
if(cc->cc_File != ZERO)
|
||
{
|
||
Close(cc->cc_File);
|
||
cc->cc_File = ZERO;
|
||
}
|
||
|
||
return(result);
|
||
}
|
||
|
||
/****************************************************************************/
|
||
|
||
/* Try to convert an IP address specification into a number an complain
|
||
if that doesn't work. */
|
||
STATIC BOOL
|
||
validate_ip_address(struct CommandContext * cc,STRPTR key,STRPTR address,LONG line_number,STRPTR file)
|
||
{
|
||
DECLARE_SOCKETBASE(cc);
|
||
|
||
struct in_addr in;
|
||
BOOL result;
|
||
|
||
if(inet_aton(address,&in))
|
||
{
|
||
result = TRUE;
|
||
}
|
||
else
|
||
{
|
||
if(NOT cc->cc_Quiet)
|
||
error_printf(cc,get_str(cc,MSG_ADDNETINTERFACE_INVALID_IP_ADDRESS_AT_TXT),key,address,line_number,file);
|
||
|
||
result = FALSE;
|
||
}
|
||
|
||
return(result);
|
||
}
|
||
|
||
/****************************************************************************/
|
||
|
||
/* Get the error message text corresponding to an error number. */
|
||
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;
|
||
}
|
||
|
||
/****************************************************************************/
|
||
|
||
/* Check if part of a string matches a shorter string. */
|
||
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);
|
||
}
|
||
|
||
/****************************************************************************/
|
||
|
||
/* Add a new interface node to the list, sorting its contents by priority
|
||
and name. The list is sorted by descending priority, and where the priority
|
||
is identical, by name (in lexical order). */
|
||
STATIC VOID
|
||
add_interface_node(struct CommandContext * cc,struct List * list,struct Node * new_node)
|
||
{
|
||
DECLARE_UTILITYBASE(cc);
|
||
DECLARE_DOSBASE(cc);
|
||
|
||
struct Node * list_node;
|
||
|
||
/* Find a node on the list that's "larger" than the node
|
||
we are about to add. */
|
||
for(list_node = list->lh_Head ;
|
||
list_node->ln_Succ != NULL ;
|
||
list_node = list_node->ln_Succ)
|
||
{
|
||
if((list_node->ln_Pri < new_node->ln_Pri) || (list_node->ln_Pri == new_node->ln_Pri && Stricmp(FilePart(list_node->ln_Name),FilePart(new_node->ln_Name)) > 0))
|
||
break;
|
||
}
|
||
|
||
/* Now insert the new node in the right position,
|
||
in front of the list node found above. */
|
||
new_node->ln_Succ = (struct Node *)list_node;
|
||
new_node->ln_Pred = (struct Node *)list_node->ln_Pred;
|
||
|
||
list_node->ln_Pred = (struct Node *)new_node;
|
||
new_node->ln_Pred->ln_Succ = (struct Node *)new_node;
|
||
}
|
||
|
||
/****************************************************************************/
|
||
|
||
/* Print an error message or show an error requester instead. */
|
||
STATIC VOID VARARGS68K
|
||
error_printf(struct CommandContext * cc,STRPTR format,...)
|
||
{
|
||
DECLARE_DOSBASE(cc);
|
||
DECLARE_SYSBASE(cc);
|
||
DECLARE_INTUITIONBASE(cc);
|
||
|
||
va_list args;
|
||
|
||
if(cc->cc_StartupMessage == NULL)
|
||
{
|
||
STRPTR program_name = cc->cc_ProgramName;
|
||
BPTR fh;
|
||
|
||
/* Try to use the error output stream associated with the shell. */
|
||
#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();
|
||
|
||
VFPrintf(fh,"%s: ",&program_name);
|
||
|
||
#if defined(__amigaos4__)
|
||
{
|
||
va_startlinear(args,format);
|
||
VFPrintf(fh,format,va_getlinearva(args,APTR));
|
||
va_end(args);
|
||
}
|
||
#else
|
||
{
|
||
va_start(args,format);
|
||
VFPrintf(fh,format,args);
|
||
va_end(args);
|
||
}
|
||
#endif /* __amigaos4__ */
|
||
|
||
VFPrintf(fh,"\n",NULL);
|
||
}
|
||
else
|
||
{
|
||
if(IntuitionBase != NULL)
|
||
{
|
||
struct EasyStruct es;
|
||
|
||
memset(&es,0,sizeof(es));
|
||
|
||
es.es_StructSize = sizeof(es);
|
||
es.es_Title = get_str(cc,MSG_ADDNETINTERFACE_ERROR_MESSAGE_TITLE_TXT);
|
||
es.es_TextFormat = format;
|
||
es.es_GadgetFormat = get_str(cc,MSG_ADDNETINTERFACE_ERROR_MESSAGE_BUTTON_LABEL_TXT);
|
||
|
||
#if defined(__amigaos4__)
|
||
{
|
||
va_startlinear(args,format);
|
||
EasyRequestArgs(NULL,&es,NULL,va_getlinearva(args,APTR));
|
||
va_end(args);
|
||
}
|
||
#else
|
||
{
|
||
va_start(args,format);
|
||
EasyRequestArgs(NULL,&es,NULL,args);
|
||
va_end(args);
|
||
}
|
||
#endif /* __amigaos4__ */
|
||
}
|
||
}
|
||
}
|
||
|
||
/****************************************************************************/
|
||
|
||
/* Print a warning message in the shell window. */
|
||
STATIC VOID VARARGS68K
|
||
warning_printf(struct CommandContext * cc,STRPTR format,...)
|
||
{
|
||
DECLARE_DOSBASE(cc);
|
||
|
||
if(cc->cc_StartupMessage == NULL)
|
||
{
|
||
STRPTR program_name = cc->cc_ProgramName;
|
||
va_list args;
|
||
|
||
VPrintf("%s: ",&program_name);
|
||
|
||
#if defined(__amigaos4__)
|
||
{
|
||
va_startlinear(args,format);
|
||
VPrintf(format,va_getlinearva(args,APTR));
|
||
va_end(args);
|
||
}
|
||
#else
|
||
{
|
||
va_start(args,format);
|
||
VPrintf(format,args);
|
||
va_end(args);
|
||
}
|
||
#endif /* __amigaos4__ */
|
||
|
||
VPrintf("\n",NULL);
|
||
}
|
||
}
|
||
|
||
/****************************************************************************/
|
||
|
||
/* Print an informational message in the shell window. */
|
||
STATIC VOID VARARGS68K
|
||
info_printf(struct CommandContext * cc,STRPTR format,...)
|
||
{
|
||
DECLARE_DOSBASE(cc);
|
||
|
||
if(cc->cc_StartupMessage == NULL)
|
||
{
|
||
va_list args;
|
||
|
||
#if defined(__amigaos4__)
|
||
{
|
||
va_startlinear(args,format);
|
||
VPrintf(format,va_getlinearva(args,APTR));
|
||
va_end(args);
|
||
}
|
||
#else
|
||
{
|
||
va_start(args,format);
|
||
VPrintf(format,args);
|
||
va_end(args);
|
||
}
|
||
#endif /* __amigaos4__ */
|
||
}
|
||
}
|
||
|
||
/****************************************************************************/
|
||
|
||
/* Print an error string in the shell window; this is supposed to be
|
||
an informational message only. */
|
||
STATIC VOID
|
||
info_print_fault(struct CommandContext * cc,LONG code)
|
||
{
|
||
DECLARE_DOSBASE(cc);
|
||
|
||
if(cc->cc_StartupMessage == NULL)
|
||
{
|
||
UBYTE str[100];
|
||
|
||
Fault(code,NULL,str,sizeof(str));
|
||
|
||
info_printf(cc,"%s: %s\n",cc->cc_ProgramName,str);
|
||
}
|
||
}
|
||
|
||
/****************************************************************************/
|
||
|
||
/* Print an error string in the shell window, corresponding to a code. */
|
||
STATIC VOID
|
||
error_print_fault(struct CommandContext * cc,LONG code)
|
||
{
|
||
DECLARE_DOSBASE(cc);
|
||
|
||
if(cc->cc_StartupMessage == NULL)
|
||
{
|
||
PrintFault(code,cc->cc_ProgramName);
|
||
}
|
||
else
|
||
{
|
||
UBYTE str[100];
|
||
|
||
Fault(code,NULL,str,sizeof(str));
|
||
|
||
error_printf(cc,"%s",str);
|
||
}
|
||
}
|
||
|
||
/****************************************************************************/
|
||
|
||
/* Print an error string in the shell window, corresponding to a code, using
|
||
a special prefix. */
|
||
STATIC VOID
|
||
error_print_fault_prefix(struct CommandContext * cc,LONG code,STRPTR prefix)
|
||
{
|
||
DECLARE_DOSBASE(cc);
|
||
|
||
if(cc->cc_StartupMessage == NULL)
|
||
{
|
||
PrintFault(code,prefix);
|
||
}
|
||
else
|
||
{
|
||
UBYTE str[100];
|
||
|
||
Fault(code,NULL,str,sizeof(str));
|
||
|
||
error_printf(cc,"%s: %s",prefix,str);
|
||
}
|
||
}
|
||
|
||
/****************************************************************************/
|
||
|
||
/* 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)
|
||
{
|
||
DECLARE_LOCALEBASE(cc);
|
||
|
||
STRPTR builtin_string;
|
||
STRPTR result;
|
||
|
||
builtin_string = get_builtin_str(id);
|
||
|
||
if(cc->cc_Catalog != NULL)
|
||
result = (STRPTR)GetCatalogStr(cc->cc_Catalog,id,builtin_string);
|
||
else
|
||
result = builtin_string;
|
||
|
||
return(result);
|
||
}
|
||
|
||
/****************************************************************************/
|
||
|
||
/* The following are varargs stubs for several bsdsocket.library routines
|
||
which are necessary for the 68k GCC build. */
|
||
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);
|
||
}
|
||
|
||
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);
|
||
}
|