Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
GetEnetAddrDirect.c
/* |
File: GetEnetAddrDirect.c |
Contains: This is a sample program to obtain the ethernet address from a Power Mac using |
1. direct access to the ROM for the 61/71/8100 Power Macs, or by accessing the |
Name Registry for PCI based systems. This means that the the address can be |
accessed without Open Transport being available, or without having to open the |
Ethernet device driver. |
2. use OpenTransport to display the ethernet address for all ethernet devices |
that are detected. For this method to work, the program opens a connection over |
the found ethernet port. If the openConnection call works, then we can use the |
OT APIs to obtain the ethernet address. |
For the earlier Power Macs, 6100/ 7100/8100, the Burned In Address is found in |
ROM at address 0x50f08000. One must read every 16 bytes for each of the 6 |
bytes that make up the address. That is you'll need to |
read address 50f08000, 50f08010, 50f08020, 50f08030, 50f08040, |
and 50f08050. The found address is byte swapped. which means |
10 00 E0 2B 06 AF, which if you bit invert each byte becomes |
08 00 07 D4 60 F5. |
For PCI Power Macs, the burned in address is generally in |
the Name Registry, however, the name of the entry is vendor |
specified. For the 72/73/75/76/85/86/95/9600 Power Macs, look at the |
"local-mac-address" entry. For the PCI Power Macs which use the Comm Slot2 |
card, look at the "ASNT,ethernet-address" entry for a pointer to where the |
ethernet address is stored. |
The one set of Power Macs, that this program does not demonstrate how to access |
using the direct means are the 52/53/62/6300 systems which use the original |
CommSlot Ethernet card and which can also use the PDS slot LC style ethernet |
card |
Written by: Rich Kubota |
Copyright: Copyright © 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/22/1999 Karl Groethe Updated for Metrowerks Codewarror Pro 2.1 |
*/ |
#include <MacTypes.h> |
#include <Gestalt.h> |
#include <Errors.h> |
#include <NameRegistry.h> |
#include <stdio.h> |
#include <Strings.h> |
#include <OpenTransport.h> |
#include <OpenTptLinks.h> |
#include <OpenTptConfig.h> |
enum { |
kUnsupported = 0, |
kPDMMachine = 1, |
kPCIMachine = 2, |
kCommSlotMachine = 3, |
kPCIComm2Machine = 4 |
}; |
enum { |
kPDMEnetROMBase = 0x50f08000 |
}; |
enum { |
gestaltPowerBookG3SeriesFSTN = 314, |
gestaltiMac = 406 |
}; |
struct Address8022 |
{ |
OTAddressType fAddrFamily; |
UInt8 fHWAddr[k48BitAddrLength]; |
UInt16 fSAP; |
UInt8 fSNAP[k8022SNAPLength]; |
}; |
typedef struct Address8022 Address8022; |
UInt32 DoesCPUHaveBuiltInEthernet(void); |
UInt8 ByteSwapValue(UInt8 val); |
OSStatus GetPDMBuiltInEnetAddr(UInt8 *enetaddr); |
OSStatus GetPCIBuiltInEnetAddr(UInt8 *enetaddr); |
OSStatus GetPCIComm2EnetAddr(UInt8 *enetaddr); |
void DisplayEnetAddr(UInt8 *enetaddr); |
void DisplayBurnedInAddress(void); |
void DisplayOTEthernetAddresses(void); |
UInt32 DoesCPUHaveBuiltInEthernet(void) |
{ |
long response; |
OSStatus err; |
UInt32 result = kUnsupported; |
err = Gestalt(gestaltMachineType, &response); |
switch (response) |
{ |
case gestaltPowerMac8100_120: |
case gestaltAWS9150_80: |
case gestaltPowerMac8100_110: |
case gestaltPowerMac7100_80: |
case gestaltPowerMac8100_100: |
case gestaltAWS9150_120: |
case gestaltPowerMac8100_80: |
case gestaltPowerMac6100_60: |
case gestaltPowerMac6100_66: |
case gestaltPowerMac7100_66: |
result = kPDMMachine; |
break; |
case gestaltPowerMac9500: |
case gestaltPowerMac7500: |
case gestaltPowerMac8500: |
case gestaltPowerBook3400: |
case gestaltPowerBookG3: |
case gestaltPowerMac7200: |
case gestaltPowerMac7300: |
case gestaltPowerBookG3Series: |
case gestaltPowerBookG3SeriesFSTN: |
case gestaltPowerMacG3: |
case gestaltiMac: |
result = kPCIMachine; |
break; |
case gestaltPowerMac5200: |
case gestaltPowerMac6200: |
result = kCommSlotMachine; |
break; |
case gestaltPowerMac6400: |
case gestaltPowerMac5400: |
case gestaltPowerMac5500: |
case gestaltPowerMac6500: |
case gestaltPowerMac4400_160: |
case gestaltPowerMac4400: |
result = kPCIComm2Machine; |
} |
if (response == kUnsupported) |
{ |
err = Gestalt(gestaltNameRegistryVersion, (long*) &response); |
if (err == noErr) |
result = kPCIMachine; |
} |
return result; |
} |
UInt8 ByteSwapValue(UInt8 val) |
{ |
UInt8 result = 0; |
if (val & 0x01) |
result |= 0x80; |
if (val & 0x02) |
result |= 0x40; |
if (val & 0x04) |
result |= 0x20; |
if (val & 0x08) |
result |= 0x10; |
if (val & 0x10) |
result |= 0x08; |
if (val & 0x20) |
result |= 0x04; |
if (val & 0x40) |
result |= 0x02; |
if (val & 0x80) |
result |= 0x01; |
return result; |
} |
OSStatus GetPDMBuiltInEnetAddr(UInt8 *enetaddr) |
{ |
UInt32 i; |
UInt8 *val; |
for (i = 0; i < 6; i++) |
{ |
val = (UInt8 *)(kPDMEnetROMBase + i * 0x10); |
enetaddr[i] = ByteSwapValue(*val); |
} |
return noErr; |
} |
OSStatus GetPCIBuiltInEnetAddr(UInt8 *enetaddr) |
{ |
OSStatus err = noErr; |
RegEntryIter cookie; |
RegEntryID theFoundEntry; |
unsigned char enetAddrStr[32] = "\plocal-mac-address"; |
RegCStrEntryNamePtr enetAddrCStr = p2cstr( enetAddrStr ); |
RegEntryIterationOp iterOp; |
UInt8 enetAddr[6]; |
Boolean done = false; |
RegPropertyValueSize theSize; |
err = RegistryEntryIDInit( &theFoundEntry ); |
if (err != noErr) |
{ |
fprintf(stdout, "RegistryEntryIDInit failed\n"); |
return err; |
} |
err = RegistryEntryIterateCreate( &cookie ); |
if (err != noErr) |
{ |
fprintf(stdout, "RegistryEntryIterateCreate failed\n"); |
return err; |
} |
iterOp = kRegIterDescendants; |
err = RegistryEntrySearch( &cookie, iterOp, &theFoundEntry, &done, |
enetAddrCStr, nil, 0); |
if (err == noErr) |
{ |
theSize = sizeof(enetAddr);; |
err = RegistryPropertyGet(&theFoundEntry, enetAddrCStr, &enetAddr, &theSize ); |
if (err == noErr) |
BlockMove(enetAddr, enetaddr, sizeof(enetAddr)); |
} |
RegistryEntryIterateDispose( &cookie ); |
return noErr; |
} |
OSStatus GetPCIComm2EnetAddr(UInt8 *enetaddr) |
{ |
OSStatus err = noErr; |
RegEntryIter cookie; |
RegEntryID theFoundEntry; |
unsigned char enetAddrStr[32] = "\pASNT,ethernet-address"; |
RegCStrEntryNamePtr enetAddrCStr = p2cstr( enetAddrStr ); |
RegEntryIterationOp iterOp; |
UInt8 *enetAddr; |
Boolean done = false; |
RegPropertyValueSize theSize; |
err = RegistryEntryIDInit( &theFoundEntry ); |
if (err != noErr) |
{ |
fprintf(stdout, "RegistryEntryIDInit failed\n"); |
return err; |
} |
err = RegistryEntryIterateCreate( &cookie ); |
if (err != noErr) |
{ |
fprintf(stdout, "RegistryEntryIterateCreate failed\n"); |
return err; |
} |
iterOp = kRegIterDescendants; |
err = RegistryEntrySearch( &cookie, iterOp, &theFoundEntry, &done, |
enetAddrCStr, nil, 0); |
if (err == noErr) |
{ |
theSize = sizeof(enetAddr);; |
err = RegistryPropertyGet(&theFoundEntry, enetAddrCStr, &enetAddr, &theSize ); |
if (err == noErr) |
BlockMove(enetAddr, enetaddr, 6); |
} |
RegistryEntryIterateDispose( &cookie ); |
return noErr; |
} |
void DisplayEnetAddr(UInt8 *enetaddr) |
{ |
fprintf(stdout, "%02X.",(int )enetaddr[0]); |
fprintf(stdout, "%02X.",(int )enetaddr[1]); |
fprintf(stdout, "%02X.",(int )enetaddr[2]); |
fprintf(stdout, "%02X.",(int )enetaddr[3]); |
fprintf(stdout, "%02X.",(int )enetaddr[4]); |
fprintf(stdout, "%02X",(int )enetaddr[5]); |
} |
void DisplayBurnedInAddress(void) |
{ |
OSStatus err; |
UInt32 cputype; |
UInt8 enetaddr[6]; |
fprintf(stdout, "First, get the burned-in ethernet address directly from ROM or NameRegistry\n"); |
cputype = DoesCPUHaveBuiltInEthernet(); |
switch (cputype) |
{ |
case kPDMMachine: |
err = GetPDMBuiltInEnetAddr((UInt8*)enetaddr); |
if (err == noErr) |
{ |
fprintf(stdout, "\nBurned-In address for Ethernet Built-In => "); |
DisplayEnetAddr((UInt8*)&enetaddr); |
} |
break; |
case kPCIMachine: |
err = GetPCIBuiltInEnetAddr((UInt8*)enetaddr); |
if (err == noErr) |
{ |
fprintf(stdout, "\nBurned-In address for Ethernet Built-In => "); |
DisplayEnetAddr((UInt8*)&enetaddr); |
} |
break; |
case kCommSlotMachine: |
fprintf(stdout, "\n\nThis is a NuBus based Power Mac which may have a CommSlot Ethernet card"); |
fprintf(stdout, "\nmust use Open Transport to obtain the ethernet address"); |
break; |
case kPCIComm2Machine: |
fprintf(stdout, "\n\nThis is a PCI system which may have a CommSlot2 Ethernet card"); |
fprintf(stdout, "\nmust use Open Transport to obtain the ethernet address"); |
break; |
default: |
fprintf(stdout, "\n It appears that this CPU does not have built-in ethernet\n"); |
break; |
} |
} |
void DisplayOTEthernetAddresses(void) |
{ |
OSStatus status; |
EndpointRef ep; |
OTPortRecord devicePortRecord; |
UInt32 index; |
TBind returnInfo; |
TBind requestInfo; |
Address8022 theReturnAddr = {AF_8022, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0x0000, |
{0x00,0x00,0x00,0x00,0x00}}; |
Address8022 theAddr = {AF_8022, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0x8888, |
{0x00,0x00,0x00,0x00,0x00}}; |
Boolean foundAPort; |
Str255 userFriendlyName; |
if (status = InitOpenTransport()) |
{ |
fprintf(stdout, "\n\nOpen Transport is not installed or is inactive\n"); |
return; |
} |
else |
{ |
fprintf(stdout, "\n\nNow checking for Ethernet addresses using Open Transport\n"); |
fprintf(stdout, "There will be a slight delay as I try to open a connection\n"); |
fprintf(stdout, "over each card.\n"); |
} |
index = 0; |
// iterate thru each OT port record for ethernet ports. |
while (foundAPort = OTGetIndexedPort(&devicePortRecord,index)) |
{ |
if ((devicePortRecord.fCapabilities & kOTPortIsDLPI) && |
(devicePortRecord.fCapabilities & kOTPortIsTPI) && |
(kOTEthernetDevice == OTGetDeviceTypeFromPortRef(devicePortRecord.fRef))) |
{ |
ep = OTOpenEndpoint(OTCreateConfiguration(devicePortRecord.fPortName), (OTOpenFlags)NULL, NULL,&status); |
if (status == kOTNoError) |
{ |
// we have to bind the endpoint before we can get it's address info |
requestInfo.addr.buf = (UInt8 *)&theAddr; |
requestInfo.addr.len = 10; // family type + Ethernet + type field |
// don't use sizeof(theAddr) since we are binding to type 1 Ethernet |
// address, not to an 802.2 address. |
requestInfo.addr.maxlen = 0; |
requestInfo.qlen = 0; |
status = OTBind(ep, &requestInfo, NULL); |
if (status == kOTNoError) |
{ |
returnInfo.addr.buf = (UInt8 *)&theReturnAddr; |
returnInfo.addr.maxlen = 10; // family type + 6 bytes for Ethernet + type |
returnInfo.qlen = 0; |
status = OTGetProtAddress(ep,&returnInfo,NULL); |
if (status == kOTNoError) |
{ |
OTGetUserPortNameFromPortRef(devicePortRecord.fRef, userFriendlyName); |
fprintf(stdout, "\n The Ethernet address for %#s is => ", userFriendlyName); |
DisplayEnetAddr((UInt8*)&theReturnAddr.fHWAddr); |
} |
OTUnbind(ep); |
} |
OTCloseProvider(ep); |
} |
} |
index++; |
} |
// closing down |
CloseOpenTransport(); |
} |
main (void) |
{ |
fprintf(stdout, "Sample program to obtain the available ethernet addresses"); |
DisplayBurnedInAddress(); |
DisplayOTEthernetAddresses(); |
return 0; |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-07-22