ARPSampleShell.c

/*
    File:       ARPSampleShell.c
 
    Contains:   Sample that shows how to talk to the ARP module.
 
    Written by: Quinn "The Eskimo!" 
 
    Copyright:  Copyright © 1997-1999 by Apple Computer, Inc., All Rights Reserved.
 
                You may incorporate this Apple sample source code into your program(s) without
                restriction. This Apple sample source code has been provided "AS IS" and the
                responsibility for its operation is yours. You are not permitted to redistribute
                this Apple sample source code as "Apple sample source code" after having made
                changes. If you're going to re-distribute the source, we require that you make
                it clear in the source that the code was descended from Apple sample source
                code, but that you've made changes.
 
    Change History (most recent first):
                7/21/1999   Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
                
 
*/
///////////////////////////////////////////////////////////////////
// Lots of standard OT constructs.
 
#include <OpenTptClient.h>
#include <OpenTptInternet.h>
#include <Memory.h>
 
///////////////////////////////////////////////////////////////////
// This sample makes heavy use of C's standard I/O package.
 
#include <stdio.h>
 
///////////////////////////////////////////////////////////////////
// Standard C string operations.
 
#include <string.h>
 
///////////////////////////////////////////////////////////////////
// Constants and types for ARP module messages.
 
#include "OTARPModule.h"
 
///////////////////////////////////////////////////////////////////
// Prototypes for our high-level interface to ARP.
 
#include "ARPerations.h"
 
///////////////////////////////////////////////////////////////////
 
// Define a structure for holding a standard hardware address,
// ie a 6 byte Ethernet address.
 
struct HardwareAddress {
    UInt8   fHardwareAddress[6];
};
typedef struct HardwareAddress HardwareAddress;
 
///////////////////////////////////////////////////////////////////
 
// Define constants for all the default address and such that we
// assume if you enter a blank field.
 
static char             kDefaultInterfaceName[] = "pci1011,140";
static HardwareAddress  kDefaultHardwareAddress = { 0x00, 0x05, 0x02, 0xBC, 0xC8, 0x4F };
static InetHost         kDefaultIPAddress = ( (17L << 24) || (203L << 16) || (21L << 8) || 98);
static char             kDefaultInterfaceConfig[] = "enet";
 
///////////////////////////////////////////////////////////////////
 
// Routines for reading and writing various address types.
 
static void GetHardwareAddress(HardwareAddress *hwAddr)
    // Prompt the user for a hardware address.
{
    unsigned int hw0, hw1, hw2, hw3, hw4, hw5;
    int result;
    char tmpStr[256];
    
    printf("Enter a hardware address:\n");
    tmpStr[0] = 0;
    gets(tmpStr);
    printf("Ò%sÓ\n", tmpStr);
    result = sscanf(tmpStr, "%x:%x:%x:%x:%x:%x", &hw0, &hw1, &hw2, &hw3, &hw4, &hw5);
    
    if (result != 6) {
        printf("Wrong answer. Using default hardware address.\n");
        *hwAddr = kDefaultHardwareAddress;
    } else {
        hwAddr->fHardwareAddress[0] = hw0;
        hwAddr->fHardwareAddress[1] = hw1;
        hwAddr->fHardwareAddress[2] = hw2;
        hwAddr->fHardwareAddress[3] = hw3;
        hwAddr->fHardwareAddress[4] = hw4;
        hwAddr->fHardwareAddress[5] = hw5;
    }
}
 
static void HardwareAddressToString(HardwareAddress hwAddr, char *outputString)
    // Convert a hardware address to a string suitable for printing.
{
    sprintf(outputString, "%02x:%02x:%02x:%02x:%02x:%02x", 
        hwAddr.fHardwareAddress[0],
        hwAddr.fHardwareAddress[1],
        hwAddr.fHardwareAddress[2],
        hwAddr.fHardwareAddress[3],
        hwAddr.fHardwareAddress[4],
        hwAddr.fHardwareAddress[5]
        );
}
 
static void GetInterfaceName(char *intfName)
    // Prompt the user for an interface name.
{
    printf("Enter an ARP interface name (press return for Ò%sÓ):\n", kDefaultInterfaceName);
    intfName[0] = 0;
    gets(intfName);
    if (intfName[0] == 0) {
        strcpy(intfName, kDefaultInterfaceName);
    }
}
 
static void GetIPAddress(InetHost *ipAddr)
    // Prompt the user for an IP address.
{
    char tmpStr[256];
    unsigned int ip0, ip1, ip2, ip3;
    int result;
    
    printf("Enter an IP address:\n");
    tmpStr[0] = 0;
    gets(tmpStr);
    result = sscanf(tmpStr, "%d.%d.%d.%d", &ip0, &ip1, &ip2, &ip3);
    
    if (result != 4) {
        printf("Wrong answer. Using default IP address.\n");
        *ipAddr = kDefaultIPAddress;
    } else {
        *ipAddr = (ip0 << 24) | (ip1 << 16) | (ip2 << 8) | ip3;
    }
}
 
static void IPAddressToString(InetHost ipAddr, char *outputString)
    // Convert an IP address to a string suitable for printing.
{
    sprintf(outputString, "%d.%d.%d.%d", 
        (ipAddr >> 24) & 0x0ff,
        (ipAddr >> 16) & 0x0ff,
        (ipAddr >> 8)  & 0x0ff,
        (ipAddr >> 0)  & 0x0ff
        );
}
 
static void GetFlag(char *flagName, UInt32 flagValue, UInt32 *flags)
    // Prompt the user for a flag.  The flagName is the user-visible
    // name of the flag.  If the user types anything other than
    // return or "n", flagVlaue is ORed into the flags variable.
{
    char tmpStr[256];
    
    printf("%s? (y/n)\n", flagName);
    gets(tmpStr);
    if ( tmpStr[0] != 0 && tmpStr[0] != 'n' && tmpStr[0] != 'N') {
        (*flags) |= flagValue;
    }
}
 
static void PrintFlag(char *flagName, UInt32 flagMask, UInt32 flags)
    // Print a flag.
{
    if ( (flags & flagMask) != 0 ) {
        printf("%s ", flagName);
    }
}
 
///////////////////////////////////////////////////////////////////
 
static OSStatus DoARPGetCacheReport(void)
    // Call through to the equivalent ARPerations routine
    // and then print the results.
{
    OSStatus err;
    Handle cacheReportHandle;
    char zero;
    
    printf("DoARPGetCacheReport\n");
    cacheReportHandle = NewHandle(0);
    err = MemError();
    if (err == noErr) {
        err = ARPGetCacheReport(cacheReportHandle);
        if (err == noErr) {
            zero = 0;
            err = PtrAndHand(&zero, cacheReportHandle, sizeof(zero));
            if (err == noErr) {
                HLock(cacheReportHandle);
                printf("%s\n\n", *cacheReportHandle);
            }
        }
        DisposeHandle(cacheReportHandle);
    }
    printf("\n");
    return (err);
}
 
///////////////////////////////////////////////////////////////////
 
static OSStatus DoARPAddEntry(void)
    // Prompt user for input and then call straight through
    // to the equivalent ARPerations routine.
{
    OSStatus err;
    char interfaceName[256];
    InetHost ipAddr;
    InetHost ipMask = 0xFFFFFFFF;
    HardwareAddress hwAddr;
    char ipAddrString[256];
    char hwAddrString[256];
    UInt32 flags;
    
    printf("DoARPAddEntry\n");
    GetInterfaceName(interfaceName);
    GetIPAddress(&ipAddr);
    IPAddressToString(ipAddr, ipAddrString);
    GetHardwareAddress(&hwAddr);
    HardwareAddressToString(hwAddr, hwAddrString);
    flags = 0;
    GetFlag("PERM   ", ACE_F_PERMANENT, &flags);
    GetFlag("PUBLISH", ACE_F_PUBLISH, &flags);
    GetFlag("MAPPING", ACE_F_MAPPING, &flags);
    
    printf("Adding ARP cache entry for %s -> %s on Ò%sÓ.\n", ipAddrString, hwAddrString, interfaceName);
    
    err = ARPAddEntry(interfaceName, IP_ARP_PROTO_TYPE, flags, 
                        &ipAddr, sizeof(InetHost), &ipMask, &hwAddr, sizeof(hwAddr));
 
    return (err);
}
 
///////////////////////////////////////////////////////////////////
 
static OSStatus DoARPDeleteEntry(void)
    // Prompt user for input and then call straight through
    // to the equivalent ARPerations routine.
{
    OSStatus err;
    InetHost ipAddr;
    char interfaceName[256];
    char ipAddrString[256];
    
    printf("DoARPDeleteEntry\n");
    GetInterfaceName(interfaceName);
    GetIPAddress(&ipAddr);
    IPAddressToString(ipAddr, ipAddrString);
    
    printf("Deleting ARP cache entry for %s on Ò%sÓ.\n", ipAddrString, interfaceName);
    
    err = ARPDeleteEntry(interfaceName, IP_ARP_PROTO_TYPE, &ipAddr, sizeof(InetHost));
 
    return (err);
}
 
///////////////////////////////////////////////////////////////////
 
static OSStatus DoARPCacheQuery(void)
    // Prompt user for input, call through to the equivalent
    // ARPerations routine, and then print the results.
{
    OSStatus err;
    char interfaceName[256];
    InetHost ipAddr;
    HardwareAddress hwAddr;
    char ipAddrString[256];
    char hwAddrString[256];
    UInt32 flags;
    
    printf("DoARPCacheQuery\n");
    GetInterfaceName(interfaceName);
    GetIPAddress(&ipAddr);
    IPAddressToString(ipAddr, ipAddrString);
    
    printf("Lookup ARP cache entry for %s on Ò%sÓ.\n", ipAddrString, interfaceName);
    
    err = ARPCacheQuery(interfaceName,
                        IP_ARP_PROTO_TYPE,
                        &ipAddr, sizeof(InetHost),
                        &hwAddr, sizeof(hwAddr), &flags);
 
    if (err == noErr) {
        HardwareAddressToString(hwAddr, hwAddrString);
        printf("Hardware address is %s.\n", hwAddrString);
        printf("Flags are ");
        PrintFlag("PERM", ACE_F_PERMANENT, flags);
        PrintFlag("PUBLISH", ACE_F_PUBLISH, flags);
        PrintFlag("DYING", ACE_F_DYING, flags);
        PrintFlag("RESOLVED", ACE_F_RESOLVED, flags);
        PrintFlag("MAPPING", ACE_F_MAPPING, flags);
        printf("\n");
    }
 
    return (err);
}
 
///////////////////////////////////////////////////////////////////
 
// This sample uses a big global array (gInterfacesWeBroughtUp) to store
// the list of interfaces that we have brought up.   The top of this
// array is defined by gMaxInterfaceIndex.  The array stores
// the configuration string used to create the interface (so that
// we can display it to the user) and the interfaceCookie returned
// by ARPInterfaceUp (so we can pass it back to ARPInterfaceDown
// to tear down the interface).
 
enum {
    kNumberOfOurARPInterfaces = 10          // Obviously an arbitrary limit.
};
 
struct InterfaceInfo {
    UInt32 cookie;
    char configString[256];
};
typedef struct InterfaceInfo InterfaceInfo;
 
static InterfaceInfo gInterfacesWeBroughtUp[kNumberOfOurARPInterfaces];
 
static SInt32 gMaxInterfaceIndex = -1;
 
static OSStatus DoARPPrintOurInterfaces(void)
    // Print the list of ARP interfaces we have brought up.
{
    SInt32 interfaceIndex;
    
    printf("DoARPPrintOurInterfaces\n");
    printf("Interfaces we brought up:\n");
    for (interfaceIndex = 0; interfaceIndex <= gMaxInterfaceIndex; interfaceIndex++) {
        printf("%2d -- %s\n",
            interfaceIndex,
            gInterfacesWeBroughtUp[interfaceIndex].configString
            );
    }
    printf("\n");
    return (noErr);
}
 
static OSStatus DoARPInterfaceUp(void)
    // Prompt user for input and then call through to ARPInterfaceUp
    // to bring up the interface.  If this succeeds, record the
    // interface in gInterfacesWeBroughtUp so we can tear it down
    // again.
{
    OSStatus err;
    
    printf("DoARPInterfaceUp\n");
    err = noErr;
    if ( gMaxInterfaceIndex == (kNumberOfOurARPInterfaces - 1) ) {
        err = -3;
    }
    if (err == noErr) {
        printf("Enter the configuration string of the interface you want to bring up:\n");
        gInterfacesWeBroughtUp[gMaxInterfaceIndex + 1].configString[0] = 0;
        gets(gInterfacesWeBroughtUp[gMaxInterfaceIndex + 1].configString);
        if ( gInterfacesWeBroughtUp[gMaxInterfaceIndex + 1].configString[0] == 0 ) {
            OTStrCopy(gInterfacesWeBroughtUp[gMaxInterfaceIndex + 1].configString, kDefaultInterfaceConfig);
        }
    }
    if (err == noErr) {
        err = ARPInterfaceUp(gInterfacesWeBroughtUp[gMaxInterfaceIndex + 1].configString,
                        &gInterfacesWeBroughtUp[gMaxInterfaceIndex + 1].cookie); 
    }
    if (err == noErr) {
        gMaxInterfaceIndex += 1;
    }
    
    return (err);
}
 
static OSStatus DoARPInterfaceDown(void)
    // Prompt user for the numeric index of the interface they 
    // want to tear down, and then call through to ARPInterfaceDown
    // to tear it down.  Afterwards, delete the torn down element from
    // the gInterfacesWeBroughtUp array
{
    OSStatus err;
    SInt32 interfaceIndex;
    char tmpStr[256];
    
    printf("DoARPInterfaceDown\n");
    (void) DoARPPrintOurInterfaces();
    printf("Enter an interface to take down:\n");
    tmpStr[0] = 0;
    gets(tmpStr);
    err = noErr;
    if ( sscanf(tmpStr, "%ld", &interfaceIndex) != 1 ) {
        err = -1;
    }
    if (err == noErr) {
        if ( (interfaceIndex < 0) || (interfaceIndex > gMaxInterfaceIndex) ) {
            err = -2;
        }
    }
    if (err == noErr) {
        err = ARPInterfaceDown(gInterfacesWeBroughtUp[interfaceIndex].cookie);
    }
    if (err == noErr) {
        gInterfacesWeBroughtUp[interfaceIndex] = gInterfacesWeBroughtUp[gMaxInterfaceIndex];
        gMaxInterfaceIndex -= 1;
    }
    
    return (err);
}
 
///////////////////////////////////////////////////////////////////
 
static OSStatus DoPrintCommandHelp(void)
    // Print the current list of commands.
{
    printf("DoPrintCommandHelp\n");
    printf("?) Prints this help.\n");
    printf("\n");
    printf("p) Print contents of ARP cache.\n");
    printf("a) Add an ARP cache entry.\n");
    printf("k) Delete an ARP cache entry.\n");
    printf("l) Lookup an ARP cache entry.\n");
    printf("\n");
    printf("i) See the ARP interfaces we have brought up.\n");
    printf("u) Bring up a new ARP interface.\n");
    printf("d) Tear down an ARP interface.\n");
    printf("\n");
    printf("q) Quit.\n");
    
    return (noErr);
}
 
///////////////////////////////////////////////////////////////////
 
void main(void)
{
    OSStatus err;
    char commandStr[256];
    Boolean quitNow;
        
    printf("ARPSample -- A poor man's ARPing tool.\n");
    
    err = InitOpenTransport();
    
    if (err == noErr) {
 
        quitNow = false;
        (void) DoPrintCommandHelp();
        
        // Welcome to the command loop.  Get a string from the user
        // and use the first letter to dispatch to the relevant
        // subroutine.
        
        do {
            printf("Enter a letter corresponding to a command.\n");
 
            err = noErr;
            gets(commandStr);
            switch (commandStr[0]) {
                case '?':
                    err = DoPrintCommandHelp();
                    break;
                case 'p':
                    err = DoARPGetCacheReport();
                    break;
                case 'a':
                    err = DoARPAddEntry();
                    break;
                case 'k':
                    err = DoARPDeleteEntry();
                    break;
                case 'l':
                    err = DoARPCacheQuery();
                    break;
                case 'i':
                    err = DoARPPrintOurInterfaces();
                    break;
                case 'u':
                    err = DoARPInterfaceUp();
                    break;
                case 'd':
                    err = DoARPInterfaceDown();
                    break;
                case 'q':
                    quitNow = true;
                    break;
                case '\n':
                    break;
                default:
                    printf("Huh? Ò%sÓ\n", commandStr);
                    break;
            }
            if (err != noErr) {
                printf("Error %ld.\n", err);
            }
        } while ( ! quitNow );  
 
        CloseOpenTransport();
    }
    
    if (err == noErr) {
        printf("Success.\n");
    } else {
        printf("Failed with error %d.\n", err);
    }
    printf("Done.  Press command-Q to Quit.\n");
}