/* bootEthMacHandler.c - Bootrom loader application ethernet MAC set support */ /* * Copyright (c) 2006-2009, 2012, 2013 Wind River Systems, Inc. * * The right to copy, distribute, modify or otherwise make use * of this software may be licensed only pursuant to the terms * of an applicable Wind River license agreement. */ /* modification history -------------------- 01j,10jan13,wyt replace maxMacDevices with maxMacAddresses in the for statement 01i,06nov12,h_k increased MAX_MAC_ADRS to 20 for the board that supports more than 10 devices. 01h,12aug12,mpc Remove building warnings. (WIND00354175) 01g,11jan12,pgh Fix sprintf() usage, and replace sscanf() calls. 01f,11dec09,pgh 64-bit conversion 01e,12jun09,pgh Fix call to sysMacOffsetGet() 01d,27apr09,pgh Update documentation. 01c,23apr08,pgh Fix endian problems with MAC address. 01b,06feb07,jmt Add bootAppPrintf to optimize size 01a,24oct06,jmt written */ /* DESCRIPTION This module contain support routines for the VxWorks boot loader application ethernet MAC component. This module is added to the boot loader application when the INCLUDE_BOOT_ETH_MAC_HANDLER component is included. This module contains an initialization routine, which adds a command to the boot shell to allow the ethernet MAC address to be modified. This component uses the bootCommandHandlerAdd() to add the 'M' command, which allows all six bytes of the MAC address to be set. The 'M' command does allow the vendor specific bytes of the MAC address to be modified; unlike the bootEthAdrSet.c component, which adds the 'N' command to the boot shell. Some BSPs use the 'M' command, and others use the 'N' command. Therefore, the usage of the 'M' versus 'N' commands is BSP specific. The 'M' command has optional arguments, and this results in the following five different command line examples: \is \i M \i M motfcc \i M motfcc1 \i M motfcc1 00:01:00 \i M motfcc0 00:A0:1E:00:01:00 \ie The first example, 'M', will invoke a dialog with the user to display the current devices and prompt for which device address to change as below: \cs 0 quit 1 motfcc0 00:A0:1E:00:01:1A 2 motscc0 00:A0:1E:00:01:1B Selection : \ce If selection '0' is made, the dialog will quit. If the selection is for one of the MAC devices, then the dialog will prompt for the MAC address of the selected device as shown below: \cs 00- 00 A0- A0 1E- 1E 00- \ce The first three bytes of the MAC address are fixed and can't be changed using this method. The remaining three subsequent values will be displayed for modification. If no entry is made, the previous value remains unchanged. If the MAC address read from configuration memory does not include the three byte vendor code, it is assumed that the address read is invalid. In this case, a pseudo-random address is generated before the dialog commences. The address generation algorithm uses a hashing method to generate the address based on the sum of various fixed parameters such as the contents of the boot configuration. This method generates an address that is reproducible, given the same build and boot parameters. If the boot record is not valid, a random address is generated that is not reproducible. The second example, 'M motfcc', shows a method used to avoid the first part of the user dialog. In this case, the device is specified on the command line. Since the unit number is not included, unit zero is assumed. The third example, 'M motfcc1', shows the command format that should be used to select a device other than unit zero. The fourth example, 'M motfcc1 00:01:00', shows a syntax that avoids the user dialog. In this example, the first three bytes of the MAC address will be the WR vendor code. The remaining three bytes will be as specified on the command line. This method requires that exactly three bytes of the address be supplied. The fifth example, 'M motfcc0 00:A0:1E:00:01:00', shows a method that can be used to set all six bytes of the MAC address, including the vendor code. This syntax is used to override the default WR vendor code. Care must be taken when using this syntax as the vendor code will be replaced with the values specified on the command line. NOTE: When upgrading the boot loader from VxWorks version 6.6 or older, you will need to reprogram the MAC addresses. The byte order of how the MAC address is stored changed beginning with VxWorks version 6.7. Prior to updating a VxWorks 6.6, or older, boot loader, display and save the current MAC values for the target board. Once the new VxWorks boot loader has been installed, reprogram the MAC addresses of the target board using the values saved from the older boot load MAC address display. INCLUDE FILES: vxWorks.h */ /* includes */ #include #include #include #include #include #include #include #include /* defines */ /* maximum line length for cmd input to 'M' and 'sEnet' routine */ #define MAX_LINE 160 #define MAX_MAC_ADRS 20 /* must not go above this value */ #define MAX_ADR_SIZE 6 #define MAX_MAC_SHOW_BUF_SIZE 40 #define IFG_MAC_SUPPLIED 1 /* remaining boot line identifies new MAC address */ #define IFG_DEV_SUPPLIED 2 /* operator elects to quit the dialog */ #define IFG_OPR_QUIT 3 /* device is selected, but no MAC address */ #define NOTEOS(arg) (*arg!=0 && (*arg!= (char)EOF)) #define SKIPSPACE(arg) while( NOTEOS(arg) && \ (isspace ((int) *arg))) arg++ /* typedefs */ /* globals */ extern const char *sysNetDevName[]; extern int sysMacIndex2Dev (int index); extern int sysMacIndex2Unit (int index); extern STATUS sysMacOffsetGet (char *ifName, int ifUnit, char **ppEnet, int * pOffset); extern STATUS sysNetMacNVRamAddrGet (char *ifName, int ifUnit, UINT8 *ifMacAddr, int ifMacAddrLen); extern STATUS sysNetMacAddrGet (char *ifName, int ifUnit, UINT8 *ifMacAddr, int ifMacAddrLen); extern STATUS sysNetMacAddrSet (char *ifName, int ifUnit, UINT8 *ifMacAddr, int ifMacAddrLen); /* local vars */ static int maxMacAddresses; static int maxMacDevices; static UINT8 defaultEnetAddress[3]; static int macAddressLength; static char macShowStr[MAX_MAC_ADRS] [MAX_MAC_SHOW_BUF_SIZE]; static const char macErrStr[] = "** invalid device id\n"; /* forward declarations */ void bootEthMacHandlerInit(int, int, UINT8, UINT8, UINT8, int); LOCAL int bootAppSEnet (char * cmd); /******************************************************************************* * * bootEthMacHandlerInit - Initialize the Ethernet MAC Component * * This routine initializes the boot loader application ethernet MAC component. * This routine adds a command to the boot shell to allow the ethernet MAC * address to be modified. * * RETURNS: N/A * * ERRNO: N/A * * \NOMANUAL */ void bootEthMacHandlerInit ( int maxMacAdrs, /* Number of MAC Addresses to store */ int maxMacDevs, /* Number of MAC Devices */ UINT8 defEnetAdrs0, /* Default 1st byte of vendor code */ UINT8 defEnetAdrs1, /* Default 2nd byte of vendor code */ UINT8 defEnetAdrs2, /* Default 3rd byte of vendor code */ int macAdrsLen /* MAC Address length */ ) { /* setup local vars */ if (maxMacAdrs > MAX_MAC_ADRS) maxMacAddresses = MAX_MAC_ADRS; else maxMacAddresses = maxMacAdrs; maxMacDevices = maxMacDevs; defaultEnetAddress[0] = defEnetAdrs0; defaultEnetAddress[1] = defEnetAdrs1; defaultEnetAddress[2] = defEnetAdrs2; macAddressLength = macAdrsLen; /* setup command handlers */ bootCommandHandlerAdd("M", bootAppSEnet, BOOT_CMD_MATCH_STRICT, "M [dev][unitNo] [MAC]", "- set/display ethernet address"); } /* Local functions */ /******************************************************************************* * * macAddressShow - Display the device and MAC address in string form. * * This routine returns a pointer to a string of the form: * * id device unit address * * where: * id is an integer 1..maxMacAddresses * device is a string (e.g. motfcc) * unit is unit number * address is a six byte hex mac address * example: * "01 motfcc0 00:A0:1E:00:10:0A * * This routine takes an index as an argument, where the index is in the * range 00..(maxMacAddresses-1). * * If the passed index is out of range, this routine returns a pointer to an * error message. * * RETURNS: A pointer to a string. * * ERRNO: N/A * * \NOMANUAL */ LOCAL void * macAddressShow ( int index /* MAC device index */ ) { int devNameIndex; int unit; UINT8 macAddr[MAX_ADR_SIZE]; /* range check passed index */ if ((index < 0) || (index >= maxMacAddresses)) { return ((char *) macErrStr); /* if error, return error string */ } /* convert MAC index to device index and unit number */ devNameIndex = sysMacIndex2Dev (index); unit = sysMacIndex2Unit(index); /* get a copy of the current device address */ if (sysNetMacNVRamAddrGet ((char *)sysNetDevName[devNameIndex], unit, macAddr, macAddressLength) != OK) { /* macAddr is filled with all f's if ERROR */ memset (macAddr, 0xff, MAX_ADR_SIZE); } /* convert to string */ (void)snprintf (macShowStr[index], MAX_MAC_SHOW_BUF_SIZE, "%2d %6s%d %02x:%02x:%02x:%02x:%02x:%02x\n", index+1, sysNetDevName[devNameIndex], unit, macAddr[0], macAddr[1], macAddr[2], macAddr[3], macAddr[4], macAddr[5]); return (macShowStr[index]); } /******************************************************************************* * * ifGet - Get network interface name * * This routine parses the remaining command line (after the command character * has been removed) and attempts to identify the requested device and unit * number using this string. If the command line does not provide the device * name, a dialog is initiated to identify the device. * * RETURNS: * IFG_MAC_SUPPLIED - if remaining boot line identifies new MAC address. * IFG_OPR_QUIT - if the operator elects to quit the dialog * IFG_DEV_SUPPLIED - if a device is selected, but no MAC address * * ERRNO: N/A * * \NOMANUAL */ LOCAL int ifGet ( char ** ifName, /* interface name */ int * unit, /* interface unit */ char * pNum, /* Command line */ uchar_t * curArr /* current MAC address */ ) { char line [MAX_LINE + 1]; uchar_t passedMac [MAX_ADR_SIZE]; int numMacDigiRead = 0; char *pLine; /* ptr to current position in line */ int nameLen = 0; int index; int macAddressPassed = 0; int macDevPassed = 0; void * showStr; pLine = pNum; SKIPSPACE(pLine); /* advance past any leading whitespaces */ *ifName = pLine; /* determine if the bootline passed includes ifName, unit, and MAC */ while (NOTEOS(pLine) && isalpha((int)*pLine)) { nameLen++; /* count device length */ pLine++; } /* if device name found */ if (nameLen != 0) { for (index = 0; index < maxMacAddresses; index++) { /* if indexed device matches passed device name */ if (strncmp (sysNetDevName[sysMacIndex2Dev(index)], *ifName, strlen((char *)sysNetDevName[sysMacIndex2Dev(index)])) == 0) { /* save return dev name */ *ifName = (char *)sysNetDevName[sysMacIndex2Dev(index)]; macDevPassed = 1; /* set flag */ /* was unit number supplied? */ if (isdigit((int)*pLine)) { *unit = (int)strtol(pLine, &pLine, 0); /* extract unit number */ } else { *unit = 0; /* if not supplied, assume unit 0 */ } /* look for MAC address */ while (NOTEOS(pLine)) { SKIPSPACE(pLine); /* advance to next field */ if (!NOTEOS(pLine)) { break; /* end of string */ } if (isxdigit((int)*pLine)) { passedMac[numMacDigiRead++] = (uchar_t) strtol(pLine, &pLine, 16); } else /* some illegal character read */ { break; } if (*pLine == ':') pLine++; } /* if we were able to read the MAC address */ if (numMacDigiRead == 6) /* if full MAC address */ { macAddressPassed = 1; for (index = 0; index < 6; index++) { curArr[index] = passedMac[index]; } } else if (numMacDigiRead == 3) /* if half MAC address */ { macAddressPassed = 1; curArr[0] = defaultEnetAddress[0]; curArr[1] = defaultEnetAddress[1]; curArr[2] = defaultEnetAddress[2]; for (index = 3; index < 6; index++) /* 3 bytes only */ { curArr[index] = passedMac[index - 3]; } } break; /* matching device found. Look no further */ } /* end if indexed device matches passed device name */ } } /* end if no device name found */ if (macDevPassed == 0) /* if the command line lacks a device name */ { /* print known devices */ bootAppPrintf ("Set device MAC address\n\n",0,0,0,0,0,0); bootAppPrintf (" 0 quit\n",0,0,0,0,0,0); for (index = 0; index < maxMacAddresses; index++) { showStr = macAddressShow(index); bootAppPrintf (" %s", (_Vx_usr_arg_t)showStr,0,0,0,0,0); } index = -1; /* initialize to invalid index */ /* query for new network device (1..n) */ while ((index < 0) || ( index >= maxMacAddresses)) { bootAppPrintf (" Selection : ",0,0,0,0,0,0); if (fioRdString (STD_IN, line, MAX_LINE) == EOF) /* end of line */ { continue; } line [MAX_LINE] = EOS; /* make sure input line has EOS */ /* skip leading spaces*/ for (pLine = line; isspace ((int) *pLine); ++pLine) ; if (*pLine == EOS) /* if field is just CR */ { continue; } /* if not number */ if (bootScanNum (&pLine, (_Vx_usr_arg_t *)&index, FALSE) != OK) { bootAppPrintf("\ninvalid selection\n",0,0,0,0,0,0); index = -1; return (IFG_OPR_QUIT); /* quit */ } if (index == 0) { index = -1; return (IFG_OPR_QUIT); /* quit */ } index--; /* set to zero based index */ } /* end query for new network device (1..n) */ /* return device string and unit number */ *ifName = (char *)sysNetDevName[sysMacIndex2Dev(index)]; *unit = sysMacIndex2Unit(index); } if (macAddressPassed) return (IFG_MAC_SUPPLIED); return (IFG_DEV_SUPPLIED); } /******************************************************************************* * * dynamicMacAddrGen - Generate a dynamic MAC address * * This routine generates a 3-byte network interface MAC address. This should * be used as the last three bytes of the device address. This routine * attempts to make the address unique, but is not guaranteed to do so. * * This routine should only be called if both sysNetMacAddrGet() and * sysNVRamNetMacAddrGet() return ERROR, indicating that there is no other * suitable mechanism for generating a MAC address. * * RETURNS: * 1 for an address which will be reproducible across multiple runs * 0 if the address is likely to change between vxWorks and bootrom or * between two invocations within either vxWorks or bootrom. * * ERRNO: N/A * * \NOMANUAL */ LOCAL int dynamicMacAddrGen ( UINT8 * ifName, /* interface name */ int ifUnit, /* interface unit number */ UINT8 * ifMacAddr /* MAC address for the interface */ ) { BOOT_PARAMS params; int i = 0; UINT32 sum = 0; char adrs [BOOT_TARGET_ADDR_LEN]; /* hash sum of specified interface name */ while ( EOS != ifName[i] ) sum += ifName[i++]; /* check boot command */ if (usrBootLineCrack (sysBootLine, ¶ms) == OK) { if ( ( params.ead[0] != EOS ) && ( params.ead[1] != EOS ) && ( params.ead[2] != EOS ) && ( params.ead[3] != EOS ) && ( params.ead[4] != EOS ) && ( params.ead[5] != EOS ) ) { /* OK, use target address */ *ifMacAddr++ = (UINT8)((UINT32)params.ead[3] + sum + (UINT32)ifUnit); *ifMacAddr++ = (UINT8)params.ead[4]; *ifMacAddr++ = (UINT8)params.ead[5]; return(1); } adrs[0] = (char)(params.bad[0] + params.had[0] + params.gad[0]); adrs[1] = (char)(params.bad[1] + params.had[1] + params.gad[1]); adrs[2] = (char)(params.bad[2] + params.had[2] + params.gad[2]); adrs[3] = (char)(params.bad[3] + params.had[3] + params.gad[3]); adrs[4] = (char)(params.bad[4] + params.had[4] + params.gad[4]); adrs[5] = (char)(params.bad[5] + params.had[5] + params.gad[5]); if ( ( adrs[0] != EOS ) && ( adrs[1] != EOS ) && ( adrs[2] != EOS ) && ( adrs[3] != EOS ) && ( adrs[4] != EOS ) && ( adrs[5] != EOS ) ) { /* use host + gateway + backplane */ *ifMacAddr++ = (UINT8)((UINT32)(adrs[0] + adrs[3]) + sum + (UINT32)ifUnit); *ifMacAddr++ = (UINT8)(adrs[1] + adrs[4]); *ifMacAddr++ = (UINT8)(adrs[2] + adrs[5]); return(1); } /* hash some strings together */ for ( i = 0 ; i < BOOT_DEV_LEN ; i++ ) sum += (UINT8)params.bootDev[i]; for ( i = 0 ; i < BOOT_HOST_LEN ; i++ ) sum += (UINT8)params.hostName[i]; for ( i = 0 ; i < BOOT_HOST_LEN ; i++ ) sum += (UINT8)params.targetName[i]; for ( i = 0 ; i < BOOT_FILE_LEN ; i++ ) sum += (UINT8)params.bootFile[i]; for ( i = 0 ; i < BOOT_FILE_LEN ; i++ ) sum += (UINT8)params.startupScript[i]; for ( i = 0 ; i < BOOT_USR_LEN ; i++ ) sum += (UINT8)params.usr[i]; for ( i = 0 ; i < BOOT_PASSWORD_LEN ; i++ ) sum += (UINT8)params.passwd[i]; for ( i = 0 ; i < BOOT_OTHER_LEN ; i++ ) sum += (UINT8)params.other[i]; adrs[0] = 0; adrs[1] = 4; adrs[2] = (char)(( sum >> 24 ) & 0x00ff); adrs[3] = (char)(( sum >> 16 ) & 0x00ff); adrs[4] = (char)(( sum >> 8 ) & 0x00ff); adrs[5] = (char)(( sum >> 0 ) & 0x00ff); *ifMacAddr++ = (UINT8)((UINT32)(adrs[0] + adrs[3]) + sum + (UINT32)ifUnit); *ifMacAddr++ = (UINT8)(adrs[1] + adrs[4]); *ifMacAddr++ = (UINT8)(adrs[2] + adrs[5]); return(1); } /* * boot command not available, generate address * which is as close to random as we can make it. * If we get here, there isn't any reasonable way to * make a highly unique number, but we'll do the * best we reasonably can. * * NOTE: This is guaranteed to cause problems when * booting, unless rommable vxWorks image is used. * If we get here, the vxWorks and bootrom images * will use different MAC addresses. When the interface * changes, vxWorks will correctly send a gratuitous * ARP packet. However, some switches will ignore * the gratuitous ARP packet which came so quickly * after the vxWorks image download. In this case, * the target will be able to send traffic out, but * until it has done so, no other computer will be able * to contact it. To resolve this problem, the target * should initiate outbound IP traffic after a suitable * delay. This can be a simple ping, or it can be * a symbol table download, or whatever. */ sum += (UINT32)tickGet(); /* time component */ sum += (UINT32)((ptrdiff_t)¶ms); /* stack addr: runtime mem use component */ sum += (UINT32)((ptrdiff_t)ifMacAddr); /* data addr: compile-time component */ adrs[0] = 0; adrs[1] = 4; adrs[2] = (char)((sum >> 24) & 0x00ff); adrs[3] = (char)((sum >> 16) & 0x00ff); adrs[4] = (char)((sum >> 8) & 0x00ff); adrs[5] = (char)((sum >> 0) & 0x00ff); *ifMacAddr++ = (UINT8)(adrs[0] + adrs[3] + ifUnit); *ifMacAddr++ = (UINT8)(adrs[1] + adrs[4]); *ifMacAddr++ = (UINT8)(adrs[2] + adrs[5]); return(0); } /******************************************************************************* * * mEnet - Modify the last three bytes of the device ethernet address. * * This routine is called if the command line lacks a network address for the * selected device. It initiates a dialog with the user to obtain the address. * * RETURNS: N/A * * ERRNO: N/A * * \NOMANUAL */ LOCAL void mEnet ( char * pNum, /* returned MAC address */ int unitNum, /* interface unit number */ char * ifName /* interface name */ ) { uchar_t byte [MAX_ADR_SIZE]; /* array to hold new Enet addr */ uchar_t curArr [MAX_ADR_SIZE]; /* array to hold current Enet addr */ char line [MAX_LINE + 1]; char *pEnet; /* dummy variable */ int pOffset = 0; /* dummy variable */ char *pLine; /* ptr to current position in line */ int value; /* value found in line */ STATUS status; int ix; /* make sure device is valid */ if (sysMacOffsetGet (ifName, unitNum, &pEnet, &pOffset) != OK) { bootAppPrintf ("** invalid device\n",0,0,0,0,0,0); return; } /* read current value */ status = sysNetMacNVRamAddrGet (ifName, unitNum, curArr, macAddressLength); /* if at first we don't succeed, try second method */ if (status !=OK) sysNetMacAddrGet (ifName, unitNum, curArr, macAddressLength); /* if current MAC address is invalid */ if ((status != OK) || (curArr[0] != defaultEnetAddress[0]) || (curArr[1] != defaultEnetAddress[1]) || (curArr[2] != defaultEnetAddress[2])) { curArr[0] = defaultEnetAddress[0]; curArr[1] = defaultEnetAddress[1]; curArr[2] = defaultEnetAddress[2]; ix = dynamicMacAddrGen((UINT8 *) ifName, unitNum, (UINT8 *) &curArr[3]); bootAppPrintf ("Mac address for %s%d invalid. ", (_Vx_usr_arg_t)ifName, (_Vx_usr_arg_t)unitNum, 0,0,0,0); if (ix == 1) { bootAppPrintf ("Using a reproducible random address.\n", 0,0,0,0,0,0); } else { bootAppPrintf ("Using a non-reproducible random address.\n", 0,0,0,0,0,0); } } bootAppPrintf ("%s%d current Ethernet Address is: ", (_Vx_usr_arg_t)ifName, (_Vx_usr_arg_t)unitNum, 0,0,0,0); bootAppPrintf ("%02x:%02x:%02x:%02x:%02x:%02x\n", (_Vx_usr_arg_t)curArr[0], (_Vx_usr_arg_t)curArr[1], (_Vx_usr_arg_t)curArr[2], (_Vx_usr_arg_t)curArr[3], (_Vx_usr_arg_t)curArr[4], (_Vx_usr_arg_t)curArr[5]); byte[5] = curArr[5]; byte[4] = curArr[4]; byte[3] = curArr[3]; byte[2] = curArr[2]; byte[1] = curArr[1]; byte[0] = curArr[0]; bootAppPrintf ("Modify only the last 3 bytes (board unique portion) of" " Ethernet Address.\nThe first 3 bytes are fixed at " "manufacturer's default address block.\n",0,0,0,0,0,0); for (ix = 0; ix < MAX_ADR_SIZE / 2; ix++) bootAppPrintf ("%02x- %02x\n", (_Vx_usr_arg_t)byte[ix], (_Vx_usr_arg_t)byte[ix], 0,0,0,0); /* start on fourth byte of enet addr */ for (ix = MAX_ADR_SIZE / 2; ix < MAX_ADR_SIZE; ix++) { /* prompt for substitution */ bootAppPrintf ("%02x- ", (_Vx_usr_arg_t)byte[ix], 0,0,0,0,0); /* * get substitution value: * skip empty lines (CR only); * quit on end of file or invalid input; * otherwise put specified value at address */ if (fioRdString (STD_IN, line, MAX_LINE) == EOF) break; line [MAX_ADR_SIZE] = EOS; /* make sure input line has EOS */ for (pLine = line; isspace ((int) *pLine); ++pLine) /* skip leading spaces*/ ; if (*pLine == EOS) /* skip field if just CR */ continue; if (bootScanNum (&pLine, (_Vx_usr_arg_t *)&value, TRUE) != OK) break; /* quit if not number */ byte[ix] = (uchar_t)value; /* assign new value */ } bootAppPrintf ("\n",0,0,0,0,0,0); if (sysNetMacAddrSet (ifName, unitNum, byte, macAddressLength) != OK) { bootAppPrintf ("** error setting address for %s%d\n", (_Vx_usr_arg_t)ifName, (_Vx_usr_arg_t)unitNum, 0,0,0,0); return; } if (sysNetMacNVRamAddrGet (ifName, unitNum, byte, macAddressLength) == OK) { bootAppPrintf ("New Ethernet Address is: ",0,0,0,0,0,0); for (ix = 0; ix < 5; ix++) bootAppPrintf ("%02x:", (_Vx_usr_arg_t)byte[ix],0,0,0,0,0); bootAppPrintf ("%02x\n", (_Vx_usr_arg_t)byte[5],0,0,0,0,0); } else { bootAppPrintf ("error getting Mac address from NVRAM \n",0,0,0,0,0,0); } } /******************************************************************************* * * sEnet - Set the device ethernet address * * This routine checks the command line to see if the MAC address can be set * for the requested device. The command line is parsed to extract the device * name, unit name, and MAC address. All three items are optional. Example * command lines are as follows: * * M * M motfcc * M motfcc1 * M motfcc1 00:01:00 * M motfcc0 00:A0:1E:00:01:00 * * The first example will invoke a dialog with the user to display the current * devices and prompt for which device address to change as below: * * 0 quit * 1 motfcc0 00:A0:1E:00:01:1A * 2 motscc0 00:A0:1E:00:01:1B * Selection : * * If selection '0' is made, the dialog will quit. If the selection is for one * of the MAC devices, then the dialog will prompt for the MAC address of the * selected device as shown below: * * 00- 00 * A0- A0 * 1E- 1E * 00- * * The first three bytes of the MAC address are fixed and can't be changed * using this method. The remaining three subsequent values will be displayed * for modification. If no entry is made, the previous value remains unchanged. * * If the MAC address read from configuration memory does not include the three * byte vendor code, it is assumed that the address read is invalid. In this * case, a pseudo-random address is generated before the dialog commences. The * address generation algorithm uses a hashing method to generate the address * based on the sum of various fixed parameters such as the contents of the * boot configuration. This method generates an address that is reproducible, * given the same build and boot parameters. If the boot record is not valid, * a random address is generated that is not reproducible. * * The second example 'M motfcc' shows a method used to avoid the first part of * the user dialog. In this case, the device is specified on the command line. * Since the unit number is not included, so unit zero is assumed. * * The third example 'M motfcc1' shows the command format that should be used * to select a device other than unit zero. * * The fourth example 'M motfcc1 00:01:00' shows a syntax that avoids the user * dialog. In this example, the first three bytes of the MAC address will be * the WR vendor code. The remaining three bytes will be as specified on the * command line. This method requires that exactly three bytes of the address * be supplied. * * The last example 'M motfcc0 00:A0:1E:00:01:00' shows a method that can be * used to set all six bytes of the MAC address, including the vendor code. * This syntax is used to override the default WR vendor code. Care must be * taken when using this syntax as the vendor code will be replaced with the * values specified on the command line. * * RETURNS: N/A * * ERRNO: N/A * * \NOMANUAL */ LOCAL void sEnet ( char * pNum /* Boot line, including unit number. */ ) { uchar_t curArr [MAX_ADR_SIZE]; /* array to hold current Enet addr */ int unitNum; char * ifName ="\n"; int ifGetStatus; /* identify the network device */ ifGetStatus = ifGet (&ifName, &unitNum, pNum, curArr); if (ifGetStatus == IFG_OPR_QUIT) return; /* operator abort */ if (ifGetStatus == IFG_MAC_SUPPLIED) { if (sysNetMacAddrSet (ifName, unitNum, curArr, macAddressLength) != OK) { bootAppPrintf ("** error setting address for %s%d\n", (_Vx_usr_arg_t)ifName, (_Vx_usr_arg_t)unitNum, 0,0,0,0); return; } } else { mEnet (pNum, unitNum, ifName); } } /******************************************************************************* * * bootAppSEnet - Set Ethernet MAC Address * * This routine is the boot shell command handler routine for the modify * ethernet MAC address command. This routine sets the Ethernet MAC address * for a network device. * * RETURNS: BOOT_STATUS_COMPLETE * * ERRNO: N/A * * \NOMANUAL */ LOCAL int bootAppSEnet ( char * cmd ) { /* skip the command name and point to first parameter */ bootCmdNameSkip (&cmd, 1); sEnet(cmd); return BOOT_STATUS_COMPLETE; }