OTGetDefaultEthernetAddress.c

/*
    File:       OTGetDefaultEthernetAddress.c
 
    Contains:   Demo of accessing OT from CodeWarrior 68K and
                Symantec for MPW 68K code resource.
 
    Written by: Quinn "The Eskimo!"
 
    Copyright:  © 1996-8 by Apple Computer, Inc., all rights reserved.
 
    Change History (most recent first):
 
*/
 
#define qDebug 1
 
/////////////////////////////////////////////////////////////////////
// Standard OT Interfaces
 
#include <OpenTransport.h>
#include <OpenTptLinks.h>
 
/////////////////////////////////////////////////////////////////////
// Low-Level OT Interfaces
 
#include <OTDebug.h>
 
// OTDebugStr is not defined in any OT header files, but it is
// exported by the libraries, so we define the prototype here.
 
extern pascal void OTDebugStr(const char* str);
 
/////////////////////////////////////////////////////////////////////
// Other Toolbox Interfaces
 
#include <HyperXCMD.h>
#include <TextUtils.h>
#include <Strings.h>
 
/////////////////////////////////////////////////////////////////////
// Specical Envirnoment Dependent Stuff
 
#if defined(__MWERKS__)
    #include <A4Stuff.h>
 
    extern UInt32 ZZZApplParamsHack[8];
 
    // Evil pseudo-LibraryManager stuff
 
    typedef long GlobalWorld;
 
    GlobalWorld GetCurrentGlobalWorld(void):__D0
        = {0x200D};                                 /* move.l   A5,D0       */
 
    void SynchGlobalWorldFromA4(void)
        = {0x2A4C};                                 /* move.l   A4,A5       */
 
    void SynchA4FromGlobalWorld(void)
        = {0x284D};                                 /* move.l   A5,A4       */
 
    GlobalWorld SetCurrentGlobalWorld(GlobalWorld:__A0):__D0
        = {0x200D,                                  /* move.l   A5,D0       */
           0x2A48};                                 /* move.l   A0,A5       */
 
#else
    #include <LibraryManagerUtilities.h>
    #include <LibraryManager.h>
#endif
 
/////////////////////////////////////////////////////////////////////
 
// Forward definition for TrueMain
 
static void TrueMain(XCmdPtr xpb);
 
/////////////////////////////////////////////////////////////////////
// Standard XCMD main entry point, one for each environment.
 
#if defined(__MWERKS__)
 
    pascal void main(XCmdPtr xpb);
 
    pascal void main(XCmdPtr xpb)
        // Metrowerks main line.
    {
        long oldA4;
        GlobalWorld oldWorld;
        UInt32 *junk;
    
        Debugger();
        
        // Create a reference to our dummy AppParams globals and
        // assign it to a pointer.  This prevents the linker
        // from dead-stripper the variable.
        
        junk = &ZZZApplParamsHack[1];
        
        // Now save A5, setup A4, and then setup A4 from A5.
        
        oldWorld = GetCurrentGlobalWorld();
        
        oldA4 = SetCurrentA4();
        SynchGlobalWorldFromA4();
    
        // Call the real code.
        
        TrueMain(xpb);
        
        // Clean up.
        
        (void) SetCurrentGlobalWorld(oldWorld);
        (void) SetA4(oldA4);
    
        // Debugger();
    }
    
#else
    
    pascal void MAIN(XCmdPtr xpb)
        // Symantec main line.
    {
        OSStatus err;
        GlobalWorld oldWorld;
    
        Debugger();
        
        // Save A5 and then init our code resource's A5 world.
        
        oldWorld = GetCurrentGlobalWorld();
        err = InitCodeResource();
        if (err != noErr) {
            // No point using a DebugStr because the string would A5 relative
            //  and this failure indicates that A5 could not be setup!
            Debugger();
        } else {
 
            // Call the real code.
 
            TrueMain(xpb);
            
            // Clean up.
            
            (void) SetCurrentGlobalWorld(oldWorld);
            FreeGlobalWorld();
        }
        // Debugger();
    }
    
#endif
 
/////////////////////////////////////////////////////////////////////
// Generic OT Stuff
 
struct EnetAddress {
    unsigned char bytes[6];
};
typedef struct EnetAddress EnetAddress, *EnetAddressPtr;
 
typedef struct T8022Address T8022Address;
 
static T8022Address gSimpleAddr = {
    AF_8022,                                // OTAddressType for 802 provider
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00},   // hardware address, use zeros for bind requests
    0x8888,                                 // SAP / protocol type, value > 1500 implies ethernet protocol with no SNAP
    {0x00,0x00,0x00,0x00,0x00}
};
 
static OSStatus GetDefaultEthernetAddress(EnetAddressPtr defEnetAddr)
    // This routine returns the default Ethernet address of the machine
    // in the (6 byte) buffer pointed to by defEnetAddr.
{
    OSStatus        err;
    OSStatus        junk;
    EndpointRef     ep;
    TBind           bindRequest;
    TBind           bindResult;
    T8022Address    resultAddr;
 
 
    ep = OTOpenEndpoint(OTCreateConfiguration(kEnetName), 0, 0, &err);
    if (err == kOTNoError) {
 
        // Setup bind request
 
        OTMemzero(&bindRequest, sizeof(TBind));
        bindRequest.addr.buf = (UInt8 *) &gSimpleAddr;
        bindRequest.addr.len = k8022BasicAddressLength;  // family type + Ethernet + type field
 
        // Setup bind result
 
        OTMemzero(&bindResult, sizeof(TBind));
        bindResult.addr.buf = (UInt8 *) &resultAddr;
        bindResult.addr.maxlen = sizeof(resultAddr);
 
        // Call bind, which will return the MAC address
        // to which we're bound.
 
        err = OTBind(ep, &bindRequest, &bindResult);
        if (err == noErr) {
            BlockMoveData( resultAddr.fHWAddr, defEnetAddr->bytes, 6);
        }
        
        // Clean up.
        
        junk = OTCloseProvider(ep);
        OTAssert("GetDefaultEthernetAddress: Could not close endpoint", junk == noErr);
    }
    return err;
}
 
static char gHexDigits[16] = "0123456789ABCDEF";
 
static void HexB(UInt8 b, char *buffer)
{
    buffer[0] = gHexDigits[b >> 4];
    buffer[1] = gHexDigits[b & 0x0F];
}
 
static void TrueMain(XCmdPtr xpb)
    // Extra procedure wrapper to avoid horrible register caching problem
    //  whereby the value of result was held in register A3 which was
    //  setup from an A5 relative offset before our A5 had been set up
    //  by InitCodeResource.  Urgh!
{
    OSStatus err;
    EnetAddress defEnetAddr;
    char result[256];
    short i;
 
    err = InitOpenTransport();
    if (err == noErr) {
    
        // Call OT to get the Ethernet address.
        
        err = GetDefaultEthernetAddress(&defEnetAddr);
        
        // Construct a formatted string from the Ethernet address.
        
        if (err == noErr) {
            OTStrCopy(result, "xx:xx:xx:xx:xx:xx");
            for (i = 0; i < 6; i++) {
                HexB(defEnetAddr.bytes[i], result + (3 * i));
            }
        }
        
        if (err != noErr) {
            OTStrCopy(result, "Error");
        }
        
        // Copy that string out to the returnValue handle.
 
        (void) PtrToHand((Ptr) result, &xpb->returnValue, OTStrLength(result) + 1);
 
        CloseOpenTransport();
    }
}