// ********************************************************************************************************************************** // ********************************************************************************************************************************** // ******************************************* Coding Style - V0.30 dated: 2002Jun05 ************************************************ // ********************************************************************************************************************************** // ********************************************************************************************************************************** // 1 1 1 1 // 1 2 3 4 5 6 7 8 9 0 1 2 3 // 3456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012 // // ********************************************************************************************************************************** // ********************************************************** COMMENTING ************************************************************ // ********************************************************************************************************************************** // The "//" commenting convention shall be used. // An in-line comment shall be properly indented. // comment may follow the statement line: // // Sample code is preceeded by "| " , as shown below // | // Checking for exception conditions // | if (x > 0) // Warning processing code // | goto Label; // // ********************************************************************************************************************************** // ****************************************************** NAMING CONVENTIONS ******************************************************** // ********************************************************************************************************************************** // The code shall use these conventions for symbol name formats: // MY_DEFINE - All caps and underscores between words // Used when naming defines and enum values // // MyType - First letter is upper case; each run-together word is capitalized // MyRoutine() - Used when naming typedefs and subroutine names // // myData - First letter is lower case; each run-together word is capitalized // myField - Used when naming variable names, and data-structure fields. // // Don't use abbreviations that are unclear to others and save only a few keystrokes. // Examples follow: // // | #define MY_DEFINES // | enum values { // | STATUS_GOOD, // | STATUS_POOR, // | STATUS_FATAL // | }; // // | typedef struct { // | int hiPart; // | int loPart; // | } PairOfInts; // // | uInt4 myData; // | sInt4 MyRoutine(); // ********************************************************************************************************************************** // ****************************************************** INDENTATION STYLE ********************************************************* // ********************************************************************************************************************************** // Each level of code uses a 4-space indentation. // Initial "{" braces shall appear at end of line. Final "}" braces shall appear at start of line. // // If only a single statement is enclosed, then curly braces should not be used. In "if/else" sequences, curly braches // should be used unless both both blocks are single statements. Indentation for common structures is illustrated below. // | if (condition) // | statement1; // | // | if (condition) // | statement1; // | else // | statement2; // | // | if (condition) { // | statement1; // | statement2; // | } // | // | if (condition) { // | statement1; // | statement2; // | } else { // | statement3; // | } // | // | if (condition) { // | statement1; // | } else { // | statement2; // | statement3; // | } // | switch (variable) { // | case VAL2: // | statement1; // | break; // | default: // | statement2; // | } // | while (condition) // | statement1; // | // | while (condition) { // | statement1; // | statement2; // | } // | for (n= 0; n < N; n += 1) // | statement1; // | // | for (n= 0; n < N; n += 1) { // | statement1; // | statement2; // | } // ********************************************************************************************************************************** // *********************************************** C-code programming constraints *************************************************** // ********************************************************************************************************************************** // 1) For clarity, avoid using the following C constructs: // x++, y--, --x, and ++y. // Post increment or decrement are phrased as x+= 1 or y-= 1. // 2) For correct ness, never suppress compilation warnings. Following guidelines help eliminate spurious lint warnings // // ********************************************************************************************************************************** // ************************************************ Inhibiting warning messages ***************************************************** // ********************************************************************************************************************************** // To minimize the number of false lint messages (on a Sun compiler), lint directives were used. It's assumed that a preprocessor // can change these directives to work with other compilers. The lint directives (which are included as comments before the // offending line) include CONSTCOND and FALLTHRU which are used as illustrated below: // // | // CONSTCOND // | lineWhichUses(!CONSTANT); // | // | case X: // | initialCode(); // | // FALLTHRU // | case Y: // | commonSwitchCode(); // | break; // // Special DEFAULT_ONLY and DEFAULT_LAST macros are used within switch statements, when all of the enumerated values are intended // to be used. The DEFAULT_ONLY is used when all enumerated values are used. It is typically followed by an ERROR() statement, or // an ERROR1(arg) statement, to catch run-time errors. The "arg" expression inside of the ERROR1(arg) macro is used to inhibit gcc // warnings, but ensuring that variables are set before being used, as illustrated below: // // | switch(value) { // | case X: // | add = 4; // | break; // | case Y: // | add = 5; // | break; // | DEFAULT_ONLY // | ERROR1(add = 4); // | } // | sum += add; // The DEAFULT_LAST macro is used when some of the enumerated value are not used. Like DEFAULT_ONLY, this macro is either // defaulted to a null statements (for compile-time checking of enumerated value usage) or to a "default:" statement, // for run-time checking of enumerated values. An example is shown below" // // | switch(value) { // | case X: // | ProcessX(); // | break; // | case Y: // | ProcessY(); // | break; // | case Z: // | DEFAULT_LAST // | ERROR(); // | } // Depending on the option which is selected, null routines are sometimes included in the compilation, but never called. // To eliminate lint/gcc warnings, the null routine includes a EXECUTE_ERROR2(a1,a2) macro which uses all of the calling // arguments, as illustrated below: // // | #if DOP_XXXX_NONE // | uInt2 // | StubRoutine(CommonParameters *a1, int a2) // | { // | EXECUTE_ERROR2(a1, a2); // | return((uInt2)0); // | } // | #endif // Sample routines are included to illustrate how vendor-dependent routines may be constructed. In some cases, the sample routine // does not use all of its arguments. For such routines, the IS_USED(a) macro is used to eliminate "argument not used" warnings, // as illustrated below: // // | int // | AddressMatchSample(MemParameters *memPtr, uInt2 this, uInt2 that) // | { // | assert(memPtr != NULL); // | IS_USED(that); // | return(memPtr->common.nodeId == this); // | } // // ********************************************************************************************************************************** // ************************************************** indent argument values *************(****************************************** // ********************************************************************************************************************************** // The code is formatted using indent (GNU version 1.2) with the following flags set: // indent -l132 -c47 -cd35 -i2 -ci1 -di1 -nbad -nbap -ncs -npcs -nfc1 -br -sc -ce -ncdb -nlp // // -l132 maximum length of a line is 132 characters // -c47 code comments start at line position 47 // -cd35 declaration comments start at line position 35 // -i2 indentation level is 2 spaces // -ci1 continuation lines are indented 1 space // -di1 put identifiers in first available position after type // -nbad no blank line is forced after a declaration // -nbap no blank line is forced after a procedure body // -ncs no space after a cast operator // -npcs no space after a procedure name and '(' // -nfc1 do not format comments in the first column // -br put '{' on line with if // -sc put '*' at left of comments // -ce put else on same line as '}' // -ncdb no comment delimiters on blank lines // -nlp do not line up continued lines at parentheses // // *********************************************************************************************************************************** // ****************************************************** compiler tolerance ********************************************************* // *********************************************************************************************************************************** // // The code is designed to support compilers that are "almost" ANSI compliant, by avoiding features that have been found to cause // problems: // // 1) assert(). ANSI C defines this to behave like a function, returning the void 0 value. Since many compilers use a different // convention in their assert.h file, this C code provides its own assert() definition // (unless the GNU compiler is being used, which gets this right). // // 2) External function declarations. When declaring a function, either within the header or the routine itself, use the // typedef names, as illustrated below: // // | void // | DoLocks(Quads2(*LockCompute) (Quads2, Quads2, Quads2), int sub, // | int size, Byte * valPtr, Byte * argPtr, Byte * oldPtr, Byte * memPtr) // | { // | // Other DoLocks() code would be located here // | } // // 3) When the function prototype is used to specify the format // within a data structure, then the typedef name should be avoided, // as illustrated below: // // | typedef struct _ChipInitInfo { // | // | // Other structure entry definitions // | // | void (*VdSetup) (struct _ChipInitInfo *); // | // | } ChipInitInfo; // ********************************************************************************************************************************** // **************************************************** Compile-time warnings ******************************************************* // ********************************************************************************************************************************** // Testing for compile-time errors is performed using gcc, using the command // string given below. Note that -O2 option is required to find the // "uninitialized" warnings. // // gcc -O2 -Wall -Wshadow -Wpointer-arith -Wcast-qual -Wcast-align -Wmissing-prototypes -c code.c // // Symbol length limitations: // To test that only 31 significant characters are required for // internal identifiers, gcc is used with the following options: // // gcc -fsyntax-only -Wid-clash-31 ourCode.c // // // ********************************************************************************************************************************** // ********************************************************************************************************************************** // **************************************************** Compiler dependencies ******************************************************* // ********************************************************************************************************************************** // ********************************************************************************************************************************** // The GNU C compiler defines assert() properly, most C compilers do not. // This assert() definitions are provided for non GNU C compilers. #include #include #ifdef __GNUC__ #include #else #ifdef NDEBUG #define assert(ex) ((void)0) #else #define assert(ex) ((void)((ex) ? 0 : ((void)fprintf(stderr, \ "Assertion failed: file \"%s\",line %d\n",__FILE__,__LINE__), \ ((void)abort(), 0)))) #endif #endif // A null definition for gcc checks; all enum values must be used #ifdef GCC_CHECK #define DEFAULT_ONLY // NOTREACHED #define DEFAULT_LAST #else #define DEFAULT_ONLY default: #define DEFAULT_LAST default: #endif #ifdef PURE_ANSI int rand(void); // ANSI standard random function #define RAND16() (uInt2)(((rand()>>4)&0xff)|((rand()<<4)&0xff00)) #define RAND32() (uInt4)(RAND16()<<16 | RAND16()) #else int random(void); // Unix random() function #define RAND16() (uInt2)random() #define RAND32() (uInt4)random() #endif // This line should never be executed, print message and abort #define ERROR() ((void)((void)fprintf(stderr, "ERROR() executed: file \"%s\",line %d\n",__FILE__,__LINE__), (void)abort(), 0)) // ********************************************************************************************************************************** // ************************************************** User Modifiable Constants ***************************************************** // ********************************************************************************************************************************** // This constant allows the user to test whether reserved fields are really ignored. // If DEBUG is 1, use random-valued reserved fields, to validate they are properly ignored. // If DEBUG is 0, use zero-valued reserved fields, to conform to the specification. #define DEBUG 0 // Tests ignored fields // ********************************************************************************************************************************** // ************************************************** Other header definitions ****************************************************** // ********************************************************************************************************************************** // The IS_USED() macros eliminates lint/gcc warnings within uncalled stub routines #define IS_USED1(a) ((a)=(a)) #define IS_USED2(a,b) (IS_USED1(a), IS_USED1(b)) #define IS_USED3(a,b,c) (IS_USED2(a, b), IS_USED1(c)) #define IS_USED4(a,b,c,d) (IS_USED2(a, b), IS_USED2(c, d)) #define IS_USED5(a,b,c,d,e) (IS_USED4(a,b,c,d), IS_USED1(e)) #define IS_USED6(a,b,c,d,e,f) (IS_USED4(a,b,c,d), IS_USED2(e,f)) #define IS_USED7(a,b,c,d,e,f,g) (IS_USED4(a,b,c,d), IS_USED3(e,f,g)) #define IS_USED8(a,b,c,d,e,f,g,h) (IS_USED4(a,b,c,d), IS_USED4(e,f,g,h)) #define IS_USED9(a,b,c,d,e,f,g,h,i) (IS_USED8(a,b,c,d,e,f,g,h), IS_USED1(i)) #define IS_USED10(a,b,c,d,e,f,g,h,i,j) (IS_USED8(a,b,c,d,e,f,g,h), IS_USED2(i,j)) #define IS_USED11(a,b,c,d,e,f,g,h,i,j,k) (IS_USED8(a,b,c,d,e,f,g,h), IS_USED3(i,j,k)) #define IS_USED12(a,b,c,d,e,f,g,h,i,j,k,l) (IS_USED8(a,b,c,d,e,f,g,h), IS_USED4(i,j,k,l)) #define IS_USED13(a,b,c,d,e,f,g,h,i,j,k,l,m) (IS_USED8(a,b,c,d,e,f,g,h), IS_USED5(i,j,k,l,m)) #define IS_USED14(a,b,c,d,e,f,g,h,i,j,k,l,m,n) (IS_USED8(a,b,c,d,e,f,g,h), IS_USED6(i,j,k,l,m,n)) #define IS_USED15(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o) (IS_USED8(a,b,c,d,e,f,g,h), IS_USED7(i,j,k,l,m,n,o)) #define EXECUTE_ERROR1(a1) ( IS_USED1(a1), ERROR() ) #define EXECUTE_ERROR2(a1,a2) ( IS_USED2(a1,a2), ERROR() ) #define EXECUTE_ERROR3(a1,a2,a3) ( IS_USED3(a1,a2,a3), ERROR() ) #define EXECUTE_ERROR4(a1,a2,a3,a4) ( IS_USED4(a1,a2,a3,a4), ERROR() ) #define EXECUTE_ERROR5(a1,a2,a3,a4,a5) ( IS_USED5(a1,a2,a3,a4,a5), ERROR() ) #define EXECUTE_ERROR6(a1,a2,a3,a4,a5,a6) ( IS_USED6(a1,a2,a3,a4,a5,a6), ERROR() ) #define EXECUTE_ERROR7(a1,a2,a3,a4,a5,a6,a77) ( IS_USED7(a1,a2,a3,a4,a5,a6,a7), ERROR() ) #define EXECUTE_ERROR8(a1,a2,a3,a4,a5,a6,a7,a8) ( IS_USED8(a1,a2,a3,a4,a5,a6,a7,a8), ERROR() ) #define EXECUTE_ERROR9(a1,a2,a3,a4,a5,a6,a7,a8,a99) ( IS_USED9(a1,a2,a3,a4,a5,a6,a7,a8,a9), ERROR() ) #define EXECUTE_ERROR10(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) ( IS_USED10(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10), ERROR() ) #define EXECUTE_ERROR11(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11) ( IS_USED11(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11), ERROR() ) // RESERVED_SET() is used to keep lint quiet #define RESERVED_SET() ((int)(DEBUG ? RAND16() : 0)) typedef unsigned char uInt1; // assuming 'char' is an 8-bit value typedef unsigned short uInt2; // assuming 'short' is a 16-bit value typedef unsigned long uInt4; // assuming 'long' is a 32-bit value typedef unsigned long long uInt8; // assuming 'long long' is a 64-bit value typedef signed char sInt1; // assuming 'char' is an 8-bit value typedef signed long sInt2; // assuming 'short' is a 16-bit value typedef signed long sInt4; // assuming 'long' is a 32-bit value typedef signed long long sInt8; // assuming 'long long' is a 64-bit value typedef uInt4 uIntA; // Assuming address pointers are 32-bit values // ******************************************************************************************************************************** // *************************************************** Old Darwin code reference ************************************************** // **** This old code has extensive problems, but is being maintained (as a reference) during replacement code construction. ****** // ******************************************************************************************************************************** #define OLD_CODE 0 #if OLD_CODE #define FALSE 0 #define TRUE 1 #define LP_MU_ 1 // Added by the editor to suppress gcc errors #define HOPS 1 // Added by the editor to suppress gcc errors #define HUH 1 // Added by the editor to suppress gcc errors typedef uInt1 Boolean; typedef struct { uInt4 loTbDepth; // Low priority transit buffer depth uInt4 addRate; // Count of low priority (LP) and excess medium priority eMP octets transmitted by client uInt4 addRateCongestion; // Count of LP and eMP octets transmitted by client and destined beyond the congestion point uInt4 lpAddRate; // addRate run through a low pass filter uInt4 nlpAddRate; // lpAddRate/WEIGHT uInt4 lpAddRateContestion; // addRateCongestion run through a low pass filter uInt4 nlpAddRateContestion; // lpAddRateContestion / WEIGHT Boolean addRateOk; // flag indicating that client is allowed to transmit uInt4 allowRateCongestion; // The fair amount each node is allowed to transmit beyond the congestion point uInt4 fwdRate; // Count of LP+eMP octets forwarded from the LP transit buffer uInt4 lpFwdRate; // fwdRate run through low pass filter uInt4 rate_iMP; // Count of iMP octets forwarded and added uInt4 lp_rate_iMP; // Rate_iMP run through low pass filter uInt4 lpAllowCongestion; // allowRateCongestion run through low pass filter Boolean congested; // Station congestion: transit buffer occupancy, link utilization or HoL timer expration uInt4 accessDelay; uInt2 rcvdAdvertisedRate; // The fair rate(# of bytes in a decay interval)received from the downstream neighbor uInt2 advertisedRate; // The fair rate (# of bytes in a decay interval) passed along to the upstream neighbor sInt2 tokenOctets; // Bytes in RPR-fa dynamic shaper/policer for eMP&LP traffic beyond congestion point sInt2 tokenOctetsLow; // Bytes in RPR-fa shaper/policer for low priority sInt2 tokenOctetsMed; // Bytes in RPR-fa shaper/policer for medium (iMP+eMP) priority sInt2 tokenOctetsHigh; // Bytes in RPR-fa shaper/policer for high priority uInt2 numberActiveSources; // Number of active sources Boolean addPacketEnqueuedHigh; Boolean addPacketEnqueued_low; int fairnessOn; // Added by the editor to eliminate gcc errors int mode; // Added by the editor to eliminate gcc errors int initial; // Added by the editor to eliminate gcc errors int nextState; // Added by the editor to eliminate gcc errors int currentState; // Added by the editor to eliminate gcc errors int reservedRate; // Added by the editor to eliminate gcc errors int aboveHighThreshold; // Added by the editor to eliminate gcc errors int aboveLowThreshold; // Added by the editor to eliminate gcc errors int belowHighThreshold; // Added by the editor to eliminate gcc errors int belowLowThreshold; // Added by the editor to eliminate gcc errors int hysteresis; // Added by the editor to eliminate gcc errors int loAllow; // Added by the editor to eliminate gcc errors int lpAllow; // Added by the editor to eliminate gcc errors int nodeState; // Added by the editor to eliminate gcc errors int wrapped; // Added by the editor to eliminate gcc errors int addPacketEnqueued; // Added by the editor to eliminate gcc errors int my_SA; // Added by the editor to eliminate gcc errors int my_RI; // Added by the editor to eliminate gcc errors } Station; typedef struct { uInt1 SA[6]; Boolean RI; uInt2 rate; } FairnessPacket; FairnessPacket fairnessPacket; //received fairness packet typedef enum { FAIRNESS_OFF, FAIRNESS_ON, RAMP_UP, RAMP_DOWN, DOWNSTREAM_CONGESTED } States; States currentState, nextState; Boolean initial; // Constants (Tunable, provisioned LME objects): uInt2 WEIGHT; // Configured weight for this station an integer between 1 and 63 uInt2 w[HOPS]; // weight vector for all stations on the ring uInt2 BUCKET_SIZE; // provisioned RPR-fa dynamic shaper leaky bucket size in octets uInt4 MAX_ALLOWANCE; // Configured value for max allowed rate for this node uInt4 DECAY_INTERVAL; // 8,000 octet times @ OC-12, // 32,000 octet times @ OC-48, // 128,000 octet times @ OC-192 uInt4 ADVERTISEMENT_INTERVAL; // Between 1 MTU time and DECAY_INTERVAL uInt2 AGECOEFF = 4; // Aging coeff for addRate and fwdRate uInt2 LP_FWD = 64; // Low pass filter for fwdRate uInt2 LP_MU = 512; // Low pass filter for my fair rate uInt2 LP_MUHistory = 511; // Low pass filter for history rate uInt2 LP_ALLOW = 64; // LP filter for allow rate auto increment uInt2 LP_ALLOW_COEF = 128; // low-pass filter for lpAllow uInt2 NULL_RATE = 0xFFFF; // All 1's in rcvdAdvertisedRate field. uInt2 TB_LO_THRESHOLD; // TB depth at which no more LP client traffic can be sent uInt4 MAX_LRATE; // AGECOEFF * DECAY_INTERVAL = // 512,000 for OC-192 // 128,000 for OC-48 // 32,000 for OC-12 uInt4 AD_THRESHOLD; // Default value 1ms //Each station should have knowledge of reserved rate uInt4 reservedRate; // High priority reserved rate (# of bytes in a decay interval Boolean mode; // Advertising mode: 1 conservative, 0 (default) aggressive void UpdatedEveryClockCycle(Station *); void UpdatedWhenFairnessPacketReceived(Station *, FairnessPacket *); void CalculatedEveryDecayInterval(Station *); void CalculatedEveryAdvertisementInterval(Station *); void Advertise(Station *); uInt2 F1(Station *, int); // THESE ARE UPDATED EVERY CLOCK CYCLE: // addRate is increment by 1 for every LP/eMP octet that is // Transmitted by the client (does not include data // Transmitted from the Transit Buffer). // addRateCongestion is increment by 1 for every LP/eMP octet that is // Transmitted by the client (does not include data // Transmitted from the Transit Buffer) and destined beyond congestion // point (i.e., TTL > TTL_to_congestion). // fwdRate is increment by 1 for every LP/eMP octet that exits the LP Transit Buffer void UpdatedEveryClockCycle(Station * sPtr) { // tokenOctets is decremented by 1 for every LP/eMP octet that is transmitted by the client. // A packet is sent to completion, why is the below check here? if ((sPtr->addRateCongestion < sPtr->allowRateCongestion) && (sPtr->fwdRate + sPtr->addRate + sPtr->rate_iMP < MAX_LRATE - sPtr->reservedRate) && (sPtr->tokenOctets > 0) && !((sPtr->loTbDepth > 0) && (WEIGHT * sPtr->fwdRate < sPtr->addRate)) && (sPtr->addRate < MAX_ALLOWANCE)) sPtr->addRateOk = TRUE; // true means OK to send client packets // Access delay is: // started when an SOP arrives // reset when packet is transmitted // not increased when a packet is enqueued if (sPtr->addPacketEnqueued) sPtr->accessDelay += 1; // Any packet being added except high priority if (sPtr->accessDelay >= AD_THRESHOLD) // Access delay expires sPtr->congested = TRUE; } // UPDATED WHEN FAIRNESS_PKT IS RECEIVED: void UpdatedWhenFairnessPacketReceived(Station * sPtr, FairnessPacket * fPtr) { if ((fPtr->SA[0] == sPtr->my_SA) && // Change by editor to suppress GCC errors ((sPtr->nodeState == sPtr->wrapped || fPtr->RI == sPtr->my_RI))) { sPtr->rcvdAdvertisedRate = NULL_RATE; } else { sPtr->rcvdAdvertisedRate = fPtr->rate; } } //steering case: // do not forward on, // for wrapping case pass set //treat single link as segment failure. // THE FOLLOWING IS CALCULATED EVERY DECAY_INTERVAL: void CalculatedEveryDecayInterval(Station * sPtr) { if ((sPtr->loTbDepth > TB_LO_THRESHOLD / 2) || // LPTB crosses threshold ((sPtr->addRate + sPtr->fwdRate) > (MAX_LRATE - sPtr->reservedRate)) || // Link utilization cross high threshold (sPtr->accessDelay >= AD_THRESHOLD)) { // access delay sPtr->congested = TRUE; } else { sPtr->congested = FALSE; } sPtr->lpAddRate = (sPtr->lpAddRate / (LP_MU_ - 1 / LP_MU) + (sPtr->addRate / LP_MU)); // More generic weights than LP_MU-1 sPtr->nlpAddRate = sPtr->lpAddRate / WEIGHT; // modified weight function //addRate is decremented by min(allow_rate/AGECOEFF, addRate/AGECOEFF) sPtr->lpFwdRate = ((LP_FWD - 1) * sPtr->lpFwdRate + sPtr->fwdRate) / LP_FWD; // fwdRate is decremented by fwdRate/AGECOEFF //(Note: lp values calculated prior to decrement of non-lp values). // tokenOctets is incremented at a rate which equals to // lpAllow /(AGECOEFF * DECAY_INTERVAL) sPtr->lpAllow = ((LP_ALLOW_COEF - 1) * sPtr->lpAllow + sPtr->allowRateCongestion) / LP_ALLOW_COEF; if (sPtr->rcvdAdvertisedRate != NULL_RATE) sPtr->allowRateCongestion = (sPtr->rcvdAdvertisedRate * WEIGHT); else sPtr->allowRateCongestion += (MAX_LRATE - sPtr->reservedRate - sPtr->allowRateCongestion) / LP_ALLOW; if (sPtr->fairnessOn && sPtr->mode == 1) sPtr->allowRateCongestion = sPtr->advertisedRate * WEIGHT; // fwd_rate_iMP is increment by 1 for every iMP octet that // exits the LP Transit Buffer } // THE FOLLOWING IS CALCULATED EVERY ADVERTISEMENT_INTERVAL: void CalculatedEveryAdvertisementInterval(Station * sPtr) { Advertise(sPtr); if ((sPtr->addRate + sPtr->fwdRate) < (MAX_LRATE - sPtr->reservedRate - sPtr->hysteresis)) { sPtr->belowLowThreshold = TRUE; sPtr->aboveLowThreshold = FALSE; } else { sPtr->belowLowThreshold = FALSE; sPtr->aboveLowThreshold = TRUE; } if ((sPtr->addRate + sPtr->fwdRate) >= (MAX_LRATE - reservedRate)) { sPtr->aboveHighThreshold = TRUE; sPtr->belowHighThreshold = FALSE; } else { sPtr->belowHighThreshold = TRUE; sPtr->aboveHighThreshold = FALSE; } } void // rate advertisement machine Advertise(Station * sPtr) { int I = 1, J = 1; // Added by editor to eliminate gcc errors sPtr->nextState = sPtr->currentState; // No change switch (sPtr->currentState) { case FAIRNESS_OFF: if (sPtr->rcvdAdvertisedRate != NULL_RATE) //downstream_congested sPtr->nextState = DOWNSTREAM_CONGESTED; //next state is downstream congested if (sPtr->congested) sPtr->nextState = FAIRNESS_ON; // next state is congested sPtr->advertisedRate = NULL_RATE; // advertises is still maximum bw // allowRateCongestion += (MAX_LRATE-allowRateCongestion)/LP_ALLOW; sPtr->initial = TRUE; case FAIRNESS_ON: if (sPtr->initial) { sPtr->advertisedRate = sPtr->mode ? sPtr->nlpAddRate : (MAX_LRATE - sPtr->reservedRate) / F1(sPtr, HUH); // calculated initial rate:fair rate per unit weight sPtr->initial = FALSE; } // advertise min(low pass add rate, received advertise rate) sPtr->advertisedRate = (sPtr->nlpAddRate < sPtr->rcvdAdvertisedRate) ? sPtr->nlpAddRate : sPtr->rcvdAdvertisedRate; if (sPtr->rcvdAdvertisedRate != NULL_RATE) sPtr->nextState = DOWNSTREAM_CONGESTED; // next state is downstream congested if (sPtr->belowLowThreshold) sPtr->nextState = RAMP_UP; //allowRateCongestion case RAMP_UP: sPtr->advertisedRate = sPtr->mode ? NULL_RATE : sPtr->lpAddRate + sPtr->lpAddRate * I / J; if (sPtr->advertisedRate > (MAX_LRATE - sPtr->reservedRate)) sPtr->advertisedRate = NULL_RATE; if (sPtr->aboveHighThreshold) sPtr->nextState = RAMP_DOWN; if (sPtr->aboveLowThreshold) sPtr->nextState = FAIRNESS_ON; if (sPtr->advertisedRate == NULL_RATE) sPtr->nextState = FAIRNESS_OFF; //allowRateCongestion case RAMP_DOWN: sPtr->advertisedRate = sPtr->mode ? sPtr->lpAddRate : sPtr->lpAddRate - sPtr->lpAddRate * I / J; if (sPtr->belowHighThreshold) sPtr->nextState = FAIRNESS_ON; if (sPtr->belowLowThreshold) sPtr->nextState = RAMP_UP; //allowRateCongestion case DOWNSTREAM_CONGESTED: if (sPtr->lpFwdRate > (sPtr->allowRateCongestion / WEIGHT)) sPtr->advertisedRate = sPtr->rcvdAdvertisedRate; else sPtr->advertisedRate = NULL_RATE; sPtr->allowRateCongestion = (sPtr->rcvdAdvertisedRate * WEIGHT); // WEIGHT is local weight * received control message if (sPtr->rcvdAdvertisedRate == NULL_RATE) sPtr->nextState = FAIRNESS_OFF; sPtr->currentState = sPtr->nextState; } } uInt2 F1(Station * sPtr, int weightStation) { int i; uInt2 weightTotalActive = 0; // Local variable weightTotalActive // input weightStation; // mode 1: weight == stationWeight; // for (i = 1; sPtr->numberActiveSources; i += 1) weightTotalActive += w[i]; // Add all active weight global variable weightTotalActive += weightStation; // Add local station weight return (weightTotalActive); } #endif // OLD_CODE // ******************************************************************************************************************************** // ************************************************** IEEE C-code illustrations ************************************************** // ************************* This new code is preliminary and is being updated to track RPR developments ************************** // ******************************************************************************************************************************** // TBDs: // Libraries // Client interface completion // CRC bug check // Specific frame types (idles, for now) // Cable lengths and clock rates // // Memory alignment structures: // void *memalign(size_t align, size_t nbytes); // void free(void *aPtr); // #define NEW_CODE 1 #if NEW_CODE #define HOPS 64 // Worst-case number of hops #define MTU 9216 // Worst-case frame length #define FTU (MTU+8) // Fifo occupancy size #define MINIMUM(x,y) (((x)-(y))>0 ? (x):(y)) // Modulo-arithmetic-compatible maximum #define MAXIMUM(x,y) (((x)-(y))<0 ? (x):(y)) // Modulo-arithmetic-compatible minimum #define MINIMUM3(x,y,z) MINIMUM(MINIMUM(x,y),z) // Minimum of three values #define MIN_MAX(x,min,max) MAXIMUM(MINIMUM(x,max),min) // Min/Max bounding function #define ONE (((uInt8)1)<<32) // Scalar for {integer:32, fraction:32} values #define MCAST_BIT (((uInt8)1)<<48) // Multicast bit with MAC addresses #define UCAST 0 // Distinquishing unicast of unicast/multicast states #define MCAST 8 // Distinquishing multicast of unicast/multicast states #define LEAD_SIZE ((uInt4)&(frame.timeToLive)-(uInt4)&(frame)) #define HEAD_SIZE ((uInt4)&(frame.payload)-(uInt4)&(frame.timeToLive)) #define FAIR_SIZE 16 #define FULL_SIZE(size) (LEAD_SIZE+HEAD_SIZE+((size+3)/4)*4) #define LOAD_SIZE(fPtr) (fPtr->frameTypeframeSize-HEAD_SIZE) #define INIT_FIFO(qPtr) (((Frame *)qPtr)->forwPtr= ((Frame *)qPtr)->backPtr= ((Frame *)qPtr)) #define TWO32 ((uInt8)0X100000000) #define TEN09 ((uInt8)1000000000) #define COMMON_TIME(xPtr) ((xPtr->common.corePtr)->common.nextTime) #define MOP_STB ((sPtr->options&(1<options&(1<limit-(qPtr)->depth) #define FOREVER 1 #define BLOCK_SIZE(xPtr) (((Common *)xPtr)->corePtr->common.blockSize) typedef enum { EOP_STB, // Secondary transmit buffer EOP_SPATIAL_AB // Spatial class-A and class-B provisions } Options; typedef enum { CLASS_A, // Lowest jitter provisioned bandwidth CLASS_B, // Higher jitter provisioned bandwidth CLASS_C // Unprovisioned or unused provisioned bandwidth } BaseClasses; typedef enum { CLASS_A0, // Class-A temporal-unrecoverable bandwidth CLASS_A1, // Class-A temporal-recoverable bandwidth CLASS_B0, // Class-B committed bandwidth CLASS_B1, // Class-B excess bandwidth CLASS_Cx // Class-C opportunistic bandwidth } SubClasses; typedef enum { SC_Ca0, // Client sourced class-A0 SC_Ca1, // Client sourced class-A1 SC_Cb0, // Client sourced class-B0 SC_Cb1, // Client sourced class-B1 SC_Cc, // Client sourced class-C SC_Ma0=8, // MAC sourced class-A0 SC_Ta0=16, // Transit sourced class-A0 SC_Ta1, // Transit sourced class-A1 SC_Tb0, // Transit sourced class-B0 SC_Tb1, // Transit sourced class-B1 SC_Tc, // Transit sourced class-C SC_Not=24 // Default sourced idle } SrcClasses; typedef enum { ST_NOTHING, // The null entry indication ST_STATION, // Lower level MAC station ST_TOPPING // Ringlet selection adaptation layer } SimType; typedef enum { FT_IDLE, // Idle frame type FT_FAIR, // Fairness frame FT_CONTROL, // Control frame for the MAC FT_DATA // Data frame } FrameTypes; typedef struct { sInt8 dataHi; sInt8 dataLo; } Timer; typedef struct _Frame { // Internal 20-byte header for accounting struct _Frame *forwPtr; // Within queue, pointer to next entry struct _Frame *backPtr; // Within queue, pointer to previous entry Timer timeStamp; // Time stamp, for FIFO delay timing unsigned sourceTag:2; // Sourced location (client, MAC, or transit) unsigned frameSize:14; // Frame-size specifier unsigned noPayload:1; unsigned available:15; // Additional padding bytes ensures payload alignment uInt2 padding; // Header field values as per the current definition uInt1 timeToLive; // One-byte aging field unsigned runId:1; // Run identifier unsigned subClass:1; // Subclass identifier unsigned frameType:2; // Frame identifier unsigned serviceClass:2; // Base class specifier unsigned wrapping:1; // Wrapping is allowed unsigned flooding:1; // Flooding to remote MAC addresses unsigned destinationMacAddressHi:32; // Destination MAC addresses (MSBs) unsigned destinationMacAddressLo:16; // Destination MAC addresses (LSBs) unsigned sourceMacAddressHi:16; // Destination MAC addresses (LSBs) unsigned sourceMacAddressLo:32; // Destination MAC addresses (LSBs) unsigned etherType:16; // Payload type field unsigned headerCrc:16; // HeaderCRC // Following quadlet-aligned payload values uInt4 payload; // Payload start address } Frame; Frame frame; // The array entries support spatial provisioning; for uniform provisioning, only first entry is used. typedef struct { uInt8 credits[HOPS]; // Transmission credits uInt4 rate[HOPS]; // Transmission rate uInt4 hiLimit; // High credit limit uInt4 loLimit; // Low credit limit uInt1 pass; // Allowed transmission indication } Shaper; typedef struct { uInt8 rprRingRxUcastClassA0Frames; uInt8 rprRingRxUcastClassA0Bytes; uInt8 rprRingRxUcastClassA1Frames; uInt8 rprRingRxUcastClassA1Bytes; uInt8 rprRingRxUcastClassB0Frames; uInt8 rprRingRxUcastClassB0Bytes; uInt8 rprRingRxUcastClassB1Frames; uInt8 rprRingRxUcastClassB1Bytes; uInt8 rprRingRxUcastClassCxFrames; uInt8 rprRingRxUcastClassCxBytes; uInt8 rprRingRxMcastClassA0Frames; uInt8 rprRingRxMcastClassA0Bytes; uInt8 rprRingRxMcastClassA1Frames; uInt8 rprRingRxMcastClassA1Bytes; uInt8 rprRingRxMcastClassB0Frames; uInt8 rprRingRxMcastClassB0Bytes; uInt8 rprRingRxMcastClassB1Frames; uInt8 rprRingRxMcastClassB1Bytes; uInt8 rprRingRxMcastClassCxFrames; uInt8 rprRingRxMcastClassCxBytes; uInt8 rprRingTxUcastClassA0Frames; uInt8 rprRingTxUcastClassA0Bytes; uInt8 rprRingTxUcastClassA1Frames; uInt8 rprRingTxUcastClassA1Bytes; uInt8 rprRingTxUcastClassB0Frames; uInt8 rprRingTxUcastClassB0Bytes; uInt8 rprRingTxUcastClassB1Frames; uInt8 rprRingTxUcastClassB1Bytes; uInt8 rprRingTxUcastClassCxFrames; uInt8 rprRingTxUcastClassCxBytes; uInt8 rprRingTxMcastClassA0Frames; uInt8 rprRingTxMcastClassA0Bytes; uInt8 rprRingTxMcastClassA1Frames; uInt8 rprRingTxMcastClassA1Bytes; uInt8 rprRingTxMcastClassB0Frames; uInt8 rprRingTxMcastClassB0Bytes; uInt8 rprRingTxMcastClassB1Frames; uInt8 rprRingTxMcastClassB1Bytes; uInt8 rprRingTxMcastClassCxFrames; uInt8 rprRingTxMcastClassCxBytes; uInt8 rprClientRxUcastClassA0Frames; uInt8 rprClientRxUcastClassA0Bytes; uInt8 rprClientRxUcastClassA1Frames; uInt8 rprClientRxUcastClassA1Bytes; uInt8 rprClientRxUcastClassB0Frames; uInt8 rprClientRxUcastClassB0Bytes; uInt8 rprClientRxUcastClassB1Frames; uInt8 rprClientRxUcastClassB1Bytes; uInt8 rprClientRxUcastClassCxFrames; uInt8 rprClientRxUcastClassCxBytes; uInt8 rprClientRxMcastClassA0Frames; uInt8 rprClientRxMcastClassA0Bytes; uInt8 rprClientRxMcastClassA1Frames; uInt8 rprClientRxMcastClassA1Bytes; uInt8 rprClientRxMcastClassB0Frames; uInt8 rprClientRxMcastClassB0Bytes; uInt8 rprClientRxMcastClassB1Frames; uInt8 rprClientRxMcastClassB1Bytes; uInt8 rprClientRxMcastClassCxFrames; uInt8 rprClientRxMcastClassCxBytes; uInt8 rprClientTxUcastClassA0Frames; uInt8 rprClientTxUcastClassA0Bytes; uInt8 rprClientTxUcastClassA1Frames; uInt8 rprClientTxUcastClassA1Bytes; uInt8 rprClientTxUcastClassB0Frames; uInt8 rprClientTxUcastClassB0Bytes; uInt8 rprClientTxUcastClassB1Frames; uInt8 rprClientTxUcastClassB1Bytes; uInt8 rprClientTxUcastClassCxFrames; uInt8 rprClientTxUcastClassCxBytes; uInt8 rprClientTxMcastClassA0Frames; uInt8 rprClientTxMcastClassA0Bytes; uInt8 rprClientTxMcastClassA1Frames; uInt8 rprClientTxMcastClassA1Bytes; uInt8 rprClientTxMcastClassB0Frames; uInt8 rprClientTxMcastClassB0Bytes; uInt8 rprClientTxMcastClassB1Frames; uInt8 rprClientTxMcastClassB1Bytes; uInt8 rprClientTxMcastClassCxFrames; uInt8 rprClientTxMcastClassCxBytes; uInt8 rprRingRxErrorHeaderCrcFrames; uInt8 rprRingRxErrorPayloadCrcFrames; uInt8 rprRingRxErrorTimeToLive0Frames; uInt8 rprRingRxErrorTimeToLive1Frames; uInt8 rprRingRxErrorMcastSourceFrames; uInt8 rprRingRxErrorWrongRunFrames; } Counters; // ******************************************************************************************************************************** // ***************************** Editor note (DVJ): To be removed prior to final publication. ************************************* // ********************************** Functional FifoQueue parameters to be supplied ********************************************** // ******************************************************************************************************************************** typedef struct { Frame *headPtr; // First queue entry Frame *tailPtr; // Last queue entry uInt4 depth; // Current FIFO depth, in bytes uInt4 limit; // Maximum FIFO size, in bytes uInt8 delay; // Fixed FIFO delay (fractions-of-second) Timer enqueueTime; // Time of next allowed enqueue uInt8 enqueueRate; // Rate of allowed enqueues (fractions-of-second per byte) } FifoQueue; typedef struct { uInt1 runId; // Run identifier Counters counters; // Performance and error-logging counters Shaper shaperM; // MAC control-message shaper (scalar always) Shaper shaperS; // Sustaining STB shaper (scalar always) Shaper shaperA; // Class-A shaper (scalar or vector) Shaper shaperB; // Class-B shaper (scalar or vector) Shaper shaperC; // Class-C shaper (scalar or vector) Shaper shaperD; // Downstream shaper (scalar or vector) FifoQueue ptq; // Primary transit queue FifoQueue stq; // Secondary transit queue (when applicable) FifoQueue stage; // Staging buffer FifoQueue macControl; // MAC control frame uInt1 sendA, sendB, sendC; // Control indications for the client uInt1 sentA[4], sentB[4], sentC[4]; // Past history for client consistency check uInt1 sentIndex; } Attachment; typedef struct { unsigned permiscous:1; // Permiscous mode unsigned reserved:31; // Reserved } Modes; typedef struct { FifoQueue fifoQueue; // Transmit fifo storage (head and tail pointers) FifoQueue *fifoPtr; // Receive fifo pointer to transmit-fifo storage uInt4 stateInfo; // Available out-of-band control information } DualPort; typedef struct _Common { struct _Common *forwPtr; // Forward double-link schedule-list pointer struct _Common *backPtr; // Backward double-link schedule-list pointer struct _Core *corePtr; // Pointer to controlling hum char *name; // Human readable component-identifier name uInt1 type; // ST_STATION or ST_TOPPING Timer nextTime; // Time for next thread activation Timer tickTime; // Time for next thread execution uInt8 tickSize; // Size of a time tick, in fractions of second DualPort north; // North port (attachment 0 client connection) DualPort south; // South port (attachment 1 client connection) DualPort east; // East port (attachment0 out, attachment1 in) DualPort west; // West port (attachment0 in, attachment1 out) uInt4 blockSize; // Block-alignment size of common block } Common; // ^ | | ^ // | north | | south | // +--------------|----------|----------|--------|----------------. // | .---------. | | | | // | |FifoQueue| v | | | // | +---------'---------. | | .---------| // ---->|--------->| Attachment0 |-----|--------|----->|FifoQueue|----> // | '-------------------' | | '---------| // west | | .---------. | east // | v |FifoQueue| | // |---------+ .---------'---------. | // <----|FifoQueue|<--------------------| Attachment1 |<---------|<---- // '---------' '-------------------' | // '--------------------------------------------------------------' // // // frames frames sendA // ^ | ^ sendB // | | | ^ sendC // | | | | ^ // +----------------|-----------------|----| | |----------------. // | | .----------. | | | | | // | | |MacControl| | | | | | // | | '----+-----' | | | | | // | . . . . . . . .|. . . . | . . . .|. . | | | . . . . . . . .| // | | | | | | | .-----. | // | | | | ++-+-++ | | | // | | | +-->|stage|-->| | | // | . . . . . . . .|. . . . | . . . . . .'-----' | | . . | // | | +--------------------->| | | // | | .-----. | MUX |->+ | // RingRx | .--------+---+----+--------. +-->| PTQ |-->| | | | RingTx // ---->|-->|Validate|CondCopy|Removals|-->+ +-----+ | | +->|----> // | '--------+--------+--------' +-->| STQ |-->| | | // | '-----' '-----' | // '------------------------------------------------------------' // typedef struct { Common common; // Common component-control information Modes modes; // Operational modes sInt4 options; // Options uInt8 macAddress; // Unique MAC address Attachment attachment[2]; // Attachment point states } Station; typedef struct { Common common; // Common component-control information } Topping; typedef struct _Core { Common common; // Common component-control information Frame idleFrame; // Idle frame unsigned debug:1; unsigned other:31; } Core; // ******************************************************************************************************************************** // ***************************** Editor note (DVJ): To be removed prior to final publication. ************************************* // ***************** Station-to-station FIFO depth (cable lengths), nominal clock, and PPM drift to be specified ****************** // ******************************************************************************************************************************** typedef struct { SimType type; // Type of component char *name; // Name of component uInt4 depth; // Secondary transit queue depth in bytes uInt4 options; // Options for component uInt4 tickBytes; // Bytes per clock tick uInt4 tickDelta; // Clock difference in PPM uInt4 linkDelay; // Cable length in meters (5ns/meter) uInt4 linkDelta; // Cable difference in PPM } InitialData; InitialData initialData[5] = { {ST_STATION, "Station0", 0, 0, 16, 100, 10000, -100}, {ST_TOPPING, "Topping0", 0, 0, 16, 0, 0, 0}, {ST_STATION, "Station1", 0, 0, 16, -100, 10000, 100}, {ST_TOPPING, "Topping1", 0, 0, 16, 0, 0, 0}, {NULL, NULL} }; Core core; // ******************************************************************************************************************************** // ***************************** Editor note (DVJ): To be removed prior to final publication. ************************************* // ***************************** Functional idle-frame template to be provided, part of core ************************************** // ******************************************************************************************************************************** int Execute(Core *, InitialData *); void ReceiveRingFrame(Station *, Attachment *, DualPort *); uInt8 *ReceivedFrame(Station *, Attachment *, Frame *); uInt4 HeadCrcCheck(Frame *); uInt4 HeadCrcDelta(Frame *, uInt1); void DataCrcStomp(Station *, Attachment *, Frame *); Frame *Enqueue(Station *, DualPort *, FifoQueue *, Frame *); void AddressExtract(Frame *, uInt8 *, uInt8 *); int CorruptCheck(Station *, Attachment *, Frame *, uInt8); int CopyClass(Station *, Attachment *, Frame *, uInt8, uInt8); int UpdateTimeToLive(Station *, Attachment *, Frame *); int StripCheck(Station *, Attachment *, Frame *, uInt8, uInt8); void SelectTransmit(Station *, Attachment *); Frame *SelectMonoTransmit(Station *, Attachment *); Frame *SelectDualTransmit(Station *, Attachment *); void UpdateSends(Station *, Attachment *); void TransmitRingFrame(Station *, Attachment *, DualPort *); void StagingFrame(Station *, Attachment *, Frame *); void CreditUpdate(Station *, Shaper *, uInt1, uInt1, uInt4, int, int); void TransmitCredits(Station *, Attachment *, Frame *); uInt4 DepthToRateBC(uInt4); Frame *Dequeue(Common *, FifoQueue *); void CopyToClient(Station *, Attachment *, Frame *); uInt4 FifoSized(FifoQueue *); uInt4 DepthToRateBC(uInt4); void UpdateCounters(Station *, Attachment *, Frame *, uInt8 *(*)( Station *, Attachment *, Frame *, uInt8)); uInt8 *SelectRingRxCounters(Station *, Attachment *, Frame *, uInt8); uInt8 *SelectRingTxCounters(Station *, Attachment *, Frame *, uInt8); uInt8 *SelectClientRxCounters(Station *, Attachment *, Frame *, uInt8); uInt8 *SelectClientTxCounters(Station *, Attachment *, Frame *, uInt8); void StationUpdate(Station *); void AttachUpdate(Station *, Attachment *, Attachment *, DualPort *, DualPort *, DualPort *); void StageClientFrame(Station *, Attachment *, DualPort *); void ToppingUpdate(Topping *); void Insert(Common *, Frame *, Frame *, Frame *); void Delete(Common *, Frame *); void Wakeup(Common *, void *, Timer); Frame *IdleFrame(); Common *Linkup(Core *, InitialData *); void Setup(Core *, InitialData *, Common *, uInt8); Timer NextTickTime(Timer, uInt8); Frame *FrameMake(uInt4 size); Frame *FrameCopy(Frame *); int FullQueue(Common *, FifoQueue *); Timer DiffTime(Timer, Timer); Timer BumpTime(Timer, uInt8); char *MemAlign(int, int); char *bcopy(char *, char *, uInt4); #define MSB32 ((unsigned)1<<31) #define ONES32 0XFFFFFFFF #define CRC_COMPUTE ((uInt4)0X04C11DB7) #define CRC_RESULTS ((uInt4)0XC704DD7B) void PrintTable(int, int); int ValidateCrc(int, uInt4 *, int); uInt4 GenerateCrc(int, uInt4 *, int); uInt4 CalculateCrc(int, uInt4 *, int); uInt4 CrcBits(uInt4, uInt4, int); uInt4 BitReverse(uInt4); void Error(char *); #define TESTING 1 // Execute simulation // corePtr - pointer to core context // initPtr - pointer to initialization data int Execute(Core *corePtr, InitialData *initPtr) { Common *lastPtr, *cPtr, *bestPtr, *comPtr= (Common *)corePtr; Timer tickTime, delta; int above, upper, lower; lastPtr= Linkup(corePtr, initPtr); assert(lastPtr!=0); Setup(corePtr, initPtr, lastPtr, (uInt8)10000000000); for (;FOREVER;) { for (cPtr= bestPtr= comPtr->forwPtr; cPtr!=comPtr; cPtr= cPtr->forwPtr) { if (cPtr->tickTime.dataHi==0&&cPtr->tickTime.dataLo==0) { tickTime= NextTickTime(cPtr->nextTime, cPtr->tickSize); cPtr->tickTime= tickTime; } delta= DiffTime(cPtr->tickTime,bestPtr->tickTime); if (delta.dataHi<0) bestPtr= cPtr; } if (TESTING) { above= (int)(bestPtr->tickTime.dataHi&0XFFFFFFFF); upper= (int)(bestPtr->tickTime.dataLo>>32); lower= (int)(bestPtr->tickTime.dataLo&0XFFFFFFFF); printf("Running=%s at time=%d:%d.%d\n",bestPtr->name, above, upper, lower); } comPtr->nextTime= bestPtr->tickTime; bestPtr->nextTime= BumpTime(comPtr->nextTime,(uInt8)0X100000000); bestPtr->tickTime.dataHi= bestPtr->tickTime.dataLo= 0; switch(bestPtr->type) { case ST_STATION: StationUpdate((Station *)bestPtr); break; case ST_TOPPING: ToppingUpdate((Topping *)bestPtr); break; } } } Common * Linkup(Core *corePtr, InitialData *initPtr) { Common *cPtr, *comPtr= (Common *)corePtr, *lastPtr=NULL; InitialData *iPtr; uInt4 align; comPtr->forwPtr= comPtr->backPtr= comPtr; comPtr->name= "Core"; for (align=1; alignblockSize= align; for (iPtr= initPtr; iPtr->type!=ST_NOTHING; iPtr+= 1) { switch(iPtr->type) { case ST_STATION: cPtr= (Common *)MemAlign(align, sizeof(Station)); assert(cPtr!=NULL); lastPtr= cPtr; break; case ST_TOPPING: cPtr= (Common *)MemAlign(align, sizeof(Topping)); break; case ST_NOTHING: ERROR(); break; } Insert(comPtr, (Frame *)comPtr->backPtr, (Frame *)comPtr, (Frame *)cPtr); } assert(lastPtr!=NULL); return(lastPtr); } void Setup(Core *corePtr, InitialData *initPtr, Common *lastPtr, uInt8 bitsPerSecond) { Common *cPtr, *csPtr, *ctPtr; Common *comPtr= (Common *)corePtr, *pastPtr= lastPtr; Station *sPtr; Attachment *aPtr; InitialData *iPtr; sInt8 tickDiff, delays; uInt1 i; comPtr->tickSize= (((uInt8)1<<63)/bitsPerSecond)*2; corePtr->idleFrame.frameType= FT_IDLE; corePtr->idleFrame.frameSize= 16; for (cPtr= comPtr->forwPtr, iPtr= initPtr; cPtr!=comPtr; cPtr= cPtr->forwPtr, iPtr+= 1) { assert(cPtr!=NULL); cPtr->type= iPtr->type; cPtr->name= iPtr->name; INIT_FIFO(&(cPtr->north.fifoQueue)); INIT_FIFO(&(cPtr->south.fifoQueue)); INIT_FIFO(&(cPtr->east.fifoQueue)); INIT_FIFO(&(cPtr->west.fifoQueue)); tickDiff= (iPtr->tickDelta*comPtr->tickSize)/1000000; cPtr->tickSize= iPtr->tickBytes*(comPtr->tickSize+tickDiff); switch(iPtr->type) { case ST_STATION: sPtr= (Station *)(csPtr= cPtr); aPtr= &(sPtr->attachment[0]); if (iPtr->depth!=0) { sPtr->options|= (1<depth; aPtr[1].stq.depth= iPtr->depth; } for (i=0; i<2; i+= 1) { INIT_FIFO(&(aPtr[i].ptq)); INIT_FIFO(&(aPtr[i].stq)); INIT_FIFO(&(aPtr[i].stage)); INIT_FIFO(&(aPtr[i].macControl)); } pastPtr->east.fifoPtr= &(csPtr->west.fifoQueue); csPtr->west.fifoPtr= &(pastPtr->east.fifoQueue); csPtr->west.fifoQueue.delay= delays= (iPtr->linkDelay*5*TWO32)/TEN09; pastPtr->east.fifoQueue.delay= delays+(delays*iPtr->linkDelta)/1000000; pastPtr= csPtr; break; case ST_TOPPING: ctPtr= cPtr; csPtr->north.fifoPtr= &(ctPtr->east.fifoQueue); ctPtr->east.fifoPtr= &(csPtr->north.fifoQueue); csPtr->north.fifoPtr= &(ctPtr->west.fifoQueue); ctPtr->west.fifoPtr= &(csPtr->south.fifoQueue); cPtr= ctPtr; break; case ST_NOTHING: ERROR(); break; } cPtr->corePtr= corePtr; } } // Determine the next tickSize-synchronous timer value // nextTime - The unsynchronized timer value // tickSize - The time-tick interval Timer NextTickTime(Timer nextTime, uInt8 tickSize) { Timer tickTime; uInt8 topSide, lowSide, delta, remain; assert(tickSize!=0); topSide= (nextTime.dataHi<<32)|(nextTime.dataLo>>32); // Time is seconds and fractions lowSide= nextTime.dataLo&0XFFFFFFFF; // Residual subfractions of second remain= (((((topSide%tickSize)<<16)%tickSize)<<16)+lowSide)%tickSize; // Remainder after tickSize divide tickTime= delta==0 ? nextTime : BumpTime(nextTime, (tickSize-remain)); // Next tickSize-synchronized period return(tickTime); } // Updating the station involves updating both attachments // sPtr - pointer to station context void StationUpdate(Station *sPtr) { Common *cPtr; Attachment *a0Ptr, *a1Ptr; assert(sPtr != NULL); cPtr= (Common *)(&(sPtr->common)); a0Ptr= &(sPtr->attachment[0]); a1Ptr= &(sPtr->attachment[1]); AttachUpdate(sPtr, a0Ptr, a1Ptr, &(cPtr->east), &(cPtr->west), &(cPtr->north)); AttachUpdate(sPtr, a1Ptr, a0Ptr, &(cPtr->west), &(cPtr->east), &(cPtr->south)); } // Topping portion of the MAC (almost the client) // tPtr - pointer to topping context void ToppingUpdate(Topping *tPtr) { Common *comPtr; Frame *fPtr; comPtr= (Common *)(&(tPtr->common)); if ((fPtr=Dequeue(comPtr, comPtr->west.fifoPtr))!=NULL) free(fPtr); if ((fPtr=Dequeue(comPtr, comPtr->east.fifoPtr))!=NULL) free(fPtr); } // Attachment point updates // sPtr - pointer to station context // thisPtr - applicable attachment pointer // thatPtr - other attachment pointer // sinkPtr - ring receive queue // sendPtr - ring transmit queue // northPtr - client interface queue void AttachUpdate(Station *sPtr, Attachment *thisPtr, Attachment *thatPtr, DualPort *sinkPtr, DualPort *sendPtr, DualPort *northPtr) { assert(sPtr != NULL && thisPtr!=NULL && thatPtr != NULL); assert(sinkPtr!=NULL && sendPtr!=NULL && northPtr!=NULL); ReceiveRingFrame(sPtr, thisPtr, sinkPtr); StageClientFrame(sPtr, thisPtr, northPtr); TransmitRingFrame(sPtr, thisPtr, sendPtr); } // ******************************************************************************************************************************** // ***************************** Editor note (DVJ): To be removed prior to final publication. ************************************* // ************************************** StageClientFrame() routine to be supplied *********************************************** // ******************************************************************************************************************************** void StageClientFrame(Station *sPtr, Attachment *thisPtr, DualPort *northPtr) { IS_USED3(sPtr, thisPtr, northPtr); } // Receive frame processing // sPtr - pointer to station context // aPtr - pointer to attachment context // dPtr - pointer to duplex cable connection void ReceiveRingFrame(Station *sPtr, Attachment *aPtr, DualPort *dPtr) { FifoQueue *qPtr; Frame *fPtr, *rPtr; uInt8 destinMac, sourceMac; assert(sPtr != NULL && aPtr != NULL && dPtr!=NULL && dPtr->fifoPtr!=NULL); qPtr= dPtr->fifoPtr; if ((fPtr= Dequeue((Common *)sPtr, qPtr))==NULL) // Check for the next receive-queue frame return; // or wait for the next available frame AddressExtract(fPtr, &destinMac, &sourceMac); // Extract the destination & source MAC addresses if (CorruptCheck(sPtr, aPtr, fPtr, sourceMac)) // Check and discard corrupted frames return; DataCrcStomp(sPtr, aPtr, fPtr); // Stomp frames with incorrect data CRCs UpdateCounters(sPtr, aPtr, fPtr, SelectRingRxCounters); // Update ringRx receiver MIB statistics if (UpdateTimeToLive(sPtr, aPtr, fPtr)) // Decrement the timeToLive value, discard aged return; // frames, and update the header CRC check if (StripCheck(sPtr, aPtr, fPtr, destinMac, sourceMac)) // Decrement the timeToLive value, discard aged return; // frames, and update the header CRC check if (MOP_STB==0 || fPtr->serviceClass==CLASS_A) // All class-A frames are saved in the PTQ rPtr= Enqueue(sPtr, NULL, &(aPtr->ptq), fPtr); // For the mono-queue option, save all in PTQ else // For the dual-queue option, rPtr= Enqueue(sPtr, NULL, &(aPtr->stq), fPtr); // save the non class-A traffic in the STQ assert(rPtr==NULL); } // Reject illegal frames and provide MIBs pointer for accounting // sPtr - pointer to station context // aPtr - attachment pointer // fPtr - frame pointer // sourceMac - convenient sourceMacAddress int CorruptCheck(Station *sPtr, Attachment *aPtr, Frame *fPtr, uInt8 sourceMac) { uInt8 *cntPtr= NULL; assert(sPtr != NULL && aPtr != NULL && fPtr!=NULL); if (HeadCrcCheck(fPtr)!=0) // Discard frames if the header CRC is bad cntPtr= &(aPtr->counters.rprRingRxErrorHeaderCrcFrames); if (cntPtr==NULL && fPtr->timeToLive==0) // Frames with a zero-valued timeToLive cntPtr= &(aPtr->counters.rprRingRxErrorTimeToLive0Frames); // are discarded before passing-onward if (cntPtr==NULL && (sourceMac&MCAST_BIT)!=0) // The sourceMacAddress never identifies cntPtr= &(aPtr->counters.rprRingRxErrorMcastSourceFrames); // a multicast source location if (cntPtr==NULL && fPtr->wrapping==0 && fPtr->runId!=aPtr->runId) // Frames that don't support wrapping cntPtr= &(aPtr->counters.rprRingRxErrorWrongRunFrames); // never appear on the opposing run if (cntPtr==NULL) return(0); cntPtr[0]+= 1; // Log the erroneous error contition free(fPtr); // before discarding the corrupted frame return(1); } #define REVERSE 1 // Identify frames that are copied to the client // sPtr - pointer to station context // aPtr - attachment pointer // fPtr - frame pointer void DataCrcStomp(Station *sPtr, Attachment *aPtr, Frame *fPtr) { uInt4 compute, present, stomps, size; uInt1 *crcPtr; assert(sPtr != NULL && aPtr != NULL && fPtr!=NULL); // Check for invalid pointers if ((size= LOAD_SIZE(fPtr))==0) // Payload is sometimes not present return; // and is therefore not checked assert(size>=4); compute= GenerateCrc(REVERSE, &(fPtr->payload), size); // Compute the valid CRC value crcPtr= (uInt1 *)(&(fPtr->payload))+(size-4); // Determine CRC location bcopy(crcPtr, (uInt1 *)&present, 4); // Fetch the actual CRC value stomps= compute^0XFFFFFFFF; // Stomped value is complemented CRC if (present==compute||present==stomps) // Ignore validated or stomped CRC return; bcopy((uInt1 *)&present, crcPtr, 4); // Stomp all bad payload CRC values aPtr->counters.rprRingRxErrorPayloadCrcFrames+= 1; } // Identify frames that are copied to the client // sPtr - pointer to station context // aPtr - attachment pointer // fPtr - frame pointer // destinMac - convenient destinationMacAddress // sourceMac - convenient sourceMacAddress int // Check whether frame is copied to client CopyClass(Station *sPtr, Attachment *aPtr, Frame *fPtr, uInt8 destinMac, uInt8 sourceMac) { assert(sPtr != NULL && aPtr != NULL && fPtr!=NULL); if (sPtr->modes.permiscous!=0) // While in the permiscous mode, return(1); // the client gets everything if (fPtr->runId!=aPtr->runId) // While wrapping on the opposing run return(0); // frames are not copied to the client if (destinMac==sPtr->macAddress) // Matching destinationMacAddress frames return(1); // are copied to the client if (sourceMac==sPtr->macAddress) // Matching sourceMacAddress frames return(0); // are ignored by the client if (fPtr->flooding!=0) // Flooding frames on bridge-featured stations return(1); // are copied to the client return(0); // By default, pass-through frames are ignored } // Update headerCrc based on updated timeToLive value // sPtr - pointer to station context // aPtr - attachment pointer // fPtr - frame pointer int UpdateTimeToLive(Station *sPtr, Attachment *aPtr, Frame *fPtr) { uInt1 oldTime, newTime; assert(sPtr != NULL && aPtr != NULL && fPtr!=NULL); // Detect invalid pointers fPtr->timeToLive= newTime= (oldTime=fPtr->timeToLive)-1; // Decrement timeToLive in pass-through frames if (newTime==0) { free(fPtr); aPtr->counters.rprRingRxErrorTimeToLive0Frames+= 1; // Aged frames are are logged as an error and return(1); // are discarded rather than queued in transit } HeadCrcDelta(fPtr, (oldTime^newTime)); return(0); } // Strip received frame, based on address comparisons // sPtr - pointer to station context // aPtr - attachment pointer // fPtr - frame pointer // destinMac - convenient destinationMacAddress // sourceMac - convenient sourceMacAddress int // Strip frames after allowing copy-to-client StripCheck(Station *sPtr, Attachment *aPtr, Frame *fPtr, uInt8 destinMac, uInt8 sourceMac) { int strip; assert(sPtr != NULL && aPtr != NULL && fPtr!=NULL); if (fPtr->runId!=aPtr->runId) // While wrapping on the opposing run, return(0); // frames are ignored and pass through strip= (destinMac==sPtr->macAddress); if (strip||sourceMac==sPtr->macAddress) { // Matching sourceMacAddress frames or free(fPtr); // matching destinationMacAddress frames return(1); // are removed before passing through } return(0); // By default, frame pass-through stations } // ******************************************************************************************************************************** // ***************************** Editor note (DVJ): To be removed prior to final publication. ************************************* // *********************************** Functional CRC check routine to be supplied ************************************************ // ******************************************************************************************************************************** uInt4 HeadCrcCheck(Frame *fPtr) { assert(fPtr!=NULL); IS_USED1(fPtr); return(0); } // ******************************************************************************************************************************** // ***************************** Editor note (DVJ): To be removed prior to final publication. ************************************* // **************************************** HeadCrcDelta() routine to be supplied ************************************************* // ******************************************************************************************************************************** uInt4 HeadCrcDelta(Frame *fPtr, uInt1 diff) { assert(fPtr!=NULL); IS_USED2(fPtr, diff); return(0); } // Copy frame to client // sPtr - station pointer // aPtr - attachment pointer // fPtr - frame pointer void CopyToClient(Station *sPtr, Attachment *aPtr, Frame *fPtr) { Common *cPtr= (Common *)sPtr; DualPort *dPtr; Frame *newPtr; assert(sPtr != NULL && aPtr != NULL && fPtr!=NULL); // Pointer validity check UpdateCounters(sPtr, aPtr, fPtr, SelectClientTxCounters); // Update MIB counters newPtr= FrameCopy(fPtr); // Make duplicate copy of frame dPtr= aPtr->runId ? &(cPtr->north) : &(cPtr->south); // Select proper attachment point Enqueue(sPtr, dPtr, &(dPtr->fifoQueue), fPtr); // Enqueue for client servicing } // Extract destination and source MAC addresses // fPtr - frame pointer // destin - destination MAC address // source - source MAC address void // Extract destination and source MAC addresses AddressExtract(Frame *fPtr, uInt8 *destin, uInt8 *source) { uInt8 sourceMac, destinMac; assert(fPtr != NULL && destin != NULL && destin!= NULL); // Argument-pointer validation check destinMac= fPtr->destinationMacAddressHi; // Capture the most-significant bits destin[0]= (destinMac<<16)|fPtr->destinationMacAddressLo; // and include the least-significant bits sourceMac= fPtr->sourceMacAddressHi; // Capture the most-significant bits source[0]= (sourceMac<<32)|fPtr->sourceMacAddressLo; // and include the least-significant bits } // Called after each transmission to select next-frame transmission // sPtr - pointer to station context // aPtr - attachment pointer // dPtr - external DualPort pointer void TransmitRingFrame(Station *sPtr, Attachment *aPtr, DualPort *portPtr) { Frame *fPtr; FifoQueue *qPtr= &(portPtr->fifoQueue); assert(sPtr != NULL && aPtr != NULL && qPtr != NULL); // Argument-pointer validation check if (FullQueue((Common *)sPtr, qPtr)) // The line rate limits transmissions return; if (MOP_STB==0) // Different selection protocols for fPtr= SelectMonoTransmit(sPtr, aPtr); // single primary transit queue (PTQ) else // and the dual transit queue, with fPtr= SelectDualTransmit(sPtr, aPtr); // also secondary transit queue (STQ) if (fPtr==NULL) // If no transmission is available, fPtr= FrameCopy(&(((Core *)(sPtr->common.corePtr))->idleFrame)); // then idle frames are sent assert(fPtr!=NULL); TransmitCredits(sPtr, aPtr, fPtr); // Update the shaper credits UpdateSends(sPtr, aPtr); // and send indications for client UpdateCounters(sPtr, aPtr, fPtr, SelectRingTxCounters); // Update MIB counters and then Enqueue(sPtr, portPtr, portPtr->fifoPtr, fPtr); // transmit the selected frame } // Pick next transmit selection, for mono-queue option // sPtr - pointer to station context // aPtr - attachment pointer Frame * SelectMonoTransmit(Station *sPtr, Attachment *aPtr) { Frame *fPtr= NULL; uInt4 spaceP; assert(sPtr != NULL && aPtr != NULL); // Argument-pointer validation check spaceP= FIFO_SPACE(&(aPtr->ptq)); // If PTQ space exceeds and MTU if (spaceP > MTU && aPtr->shaperM.pass!=0) // and the shaperM rate is validated, fPtr= Dequeue((Common *)sPtr, &(aPtr->macControl)); // control frames are queued. if (fPtr==NULL) // Otherwise, check for and send fPtr= Dequeue((Common *)sPtr, &(aPtr->ptq)); // queued frames within the PTQ if (fPtr==NULL) // Otherwise, check for and send fPtr= Dequeue((Common *)sPtr, &(aPtr->stage)); // queued frames within the stage return(fPtr); } // Pick next transmit selection, for dual-queue option // sPtr - pointer to station context // aPtr - attachment pointer Frame * SelectDualTransmit(Station *sPtr, Attachment *aPtr) { Frame *fPtr= NULL; uInt4 spaceP, spaceS; uInt1 passM, passD; assert(sPtr != NULL && aPtr != NULL); // Argument-pointer validation check spaceP= FIFO_SPACE(&(aPtr->ptq)); // For any transmissions, sufficient PTQ spaceS= FIFO_SPACE(&(aPtr->stq)); // and STQ space must be available. passM= aPtr->shaperS.pass!=0; passD= aPtr->shaperD.pass!=0; if (spaceP > MTU && spaceS > MTU && passM) // If space is available and shaperM fPtr= Dequeue((Common *)sPtr, &(aPtr->macControl)); // is validated, send MAC-control frames if (fPtr==NULL && spaceS <= MTU) // If STQ fifo storage-limit is threatened fPtr= Dequeue((Common *)sPtr, &(aPtr->stq)); // select an entry to avoid overflow loss. if (fPtr==NULL) // Otherwise, obey precedence by selecting fPtr= Dequeue((Common *)sPtr, &(aPtr->ptq)); // primary transit-queue frames. if (fPtr==NULL) // Otherwise, check for insert-limited fPtr= Dequeue((Common *)sPtr, &(aPtr->stage)); // frames queued within the stage if (fPtr==NULL && passD) // Otherwise, select from the fPtr= Dequeue((Common *)sPtr, &(aPtr->stq)); // secondary transit-queue frames. return(fPtr); } // Update {sendA,sendB,sendC} status information for client // sPtr - pointer to station context // aPtr - attachment pointer void // Update client's send indications based UpdateSends(Station *sPtr, Attachment *aPtr) // on shaper-supplied pass indications { FifoQueue *fifoPtr= &(aPtr->stage); uInt4 fifoSpace; uInt1 passS, passA, passB, passD, passC, sendA, sendB, sendC, index; assert(sPtr != NULL && aPtr != NULL); fifoSpace= fifoPtr->limit-fifoPtr->depth; if (fifoSpace < FTU) { // When the stage buffer is effectively full, aPtr->sendA= aPtr->sendB= aPtr->sendC= 0; // all send indications are withdrawn return; } passS= aPtr->shaperS.pass; passA= aPtr->shaperA.pass; passB= aPtr->shaperB.pass; passC= aPtr->shaperC.pass; passD= aPtr->shaperD.pass; aPtr->sendA= sendA= passA; // The class-A send depends on no others if (MOP_STB==0) { aPtr->sendB= sendB= MINIMUM(passB, passD); // The class-B/C sends are also inhibited aPtr->sendC= sendC= MINIMUM(passC, passD); // to support downstream class-A traffic } else { aPtr->sendB= sendB= MINIMUM3(passB, passD, passS); // Client shaping avoids STQ starvation aPtr->sendC= sendC= MINIMUM3(passC, passD, passS); // with weighted classB&class-C transmissions } index= aPtr->sentIndex; // Update minimum-over interval accounts assert(indexsentA)/sizeof(aPtr->sentA[0])); // that can later be used to detect the aPtr->sentA[index]= MINIMUM(aPtr->sentA[index], sendA); // overly long (interface timing dependent) aPtr->sentB[index]= MINIMUM(aPtr->sentB[index], sendB); // class-A, class-B, or class-C aPtr->sentC[index]= MINIMUM(aPtr->sentC[index], sendC); // flow-control violations } // Update credits based on transmitted frame size // sPtr - pointer to station context // aPtr - attachment pointer // fPtr - frame pointer void TransmitCredits(Station *sPtr, Attachment *aPtr, Frame *fPtr) { uInt4 typed, types; uInt2 size= fPtr->frameSize; uInt1 hops; assert(sPtr != NULL && aPtr != NULL && fPtr!=NULL); typed= (fPtr->sourceTag<<3)|((1<<(fPtr->serviceClass))|fPtr->subClass); // The MAC control traffic is rate-limited CreditUpdate(sPtr, &(aPtr->shaperM), 1, 1, size, typed&(SC_Ma0), 1); // based on recovery time between sends types= SC_Ca0|SC_Ca1|SC_Ta0|SC_Ta1|SC_Ma0|SC_Not; // The downstream shaper... if (EOP_SPATIAL_AB==0) CreditUpdate(sPtr, &(aPtr->shaperD), 1, 1, size, typed&types, 1); else CreditUpdate(sPtr, &(aPtr->shaperD), hops, HOPS, size, typed&types, 1); } // Update credits based on staged frame size // sPtr - pointer to station context // aPtr - attachment pointer // fPtr - frame pointer void StagingFrame(Station *sPtr, Attachment *aPtr, Frame *fPtr) { FifoQueue *fifoPtr; uInt4 typed, depth; uInt2 size= fPtr->frameSize; uInt1 types1, types2, typesA, typesB, hops; assert(sPtr != NULL && aPtr != NULL && fPtr!=NULL); typed= (fPtr->sourceTag<<3)|((1<<(fPtr->serviceClass))|fPtr->subClass); if (MOP_STB!=0) { fifoPtr= &(aPtr->stq); depth= (fifoPtr->depth*ONE)/fifoPtr->limit ; // The shaper rate depends on the aPtr->shaperS.rate[0]= DepthToRateBC(depth); // normalized depth of the STQ types1= (typed&(SC_Cb0|SC_Cb1|SC_Cc))!=0; // For dual-queue designs, rate-limiting types2= (typed&(SC_Tb0|SC_Tb1|SC_Tc))!=0; // applies to the ratio of non-class-A CreditUpdate(sPtr, &(aPtr->shaperS), 1, 1, size, types1, types2); // traffic from the client and transit } typesA= (typed&(SC_Ca0|SC_Ca1))!=0; typesB= (typed&(SC_Cb0))!=0; if (EOP_SPATIAL_AB==0) { CreditUpdate(sPtr, &(aPtr->shaperA), 1, 1, size, typesA, 1); // The class-A traffic is rate limited CreditUpdate(sPtr, &(aPtr->shaperB), 1, 1, size, typesB, 1); // The class-B traffic is rate limited } else { CreditUpdate(sPtr, &(aPtr->shaperA), hops, HOPS, size, typesA, 1); // The class-A traffic is rate limited CreditUpdate(sPtr, &(aPtr->shaperB), hops, HOPS, size, typesB, 1); // The class-B traffic is rate limited } } // Called by TransmitRingFrame() or StagingFrame(), for spatial-shaper adjustments: // sPtr - pointer to station context // shPtr - spatial shaper context // local - distance over which frame is sent // total - distance over which frame could be sent // size - transmission size // sending - transmission credit reduction // bumping - weighted credit accumulations void CreditUpdate(Station *sPtr, Shaper *shPtr, uInt1 local, uInt1 total, uInt4 size, int sending, int bumping) { uInt8 credits, hiLevel, loLevel; uInt4 sendSize, bumpSize; int i, hops; assert(sPtr != NULL && shPtr != NULL); sendSize= sending!=0 ? size:0; bumpSize= bumping!=0 ? size:0; hiLevel = shPtr->hiLimit * ONE; loLevel = shPtr->loLimit * ONE; for (i=0, hops= HOPS; i=local) sendSize= 0; credits = shPtr->credits[i] + (bumpSize * shPtr->rate[0]) - (sendSize * ONE); shPtr->credits[0]= credits = MIN_MAX(credits, loLevel, hiLevel); if ((creditspass= hops; } // Convert secondary-FIFO depth indication to rate for shaperS // depth - normalized STQ depth (2**32 corresponds to unity) uInt4 // Compute depth-dependent shaper-S rate DepthToRateBC(uInt4 depth) { uInt4 rate; rate = ONE - (2 * depth); rate = MIN_MAX(rate, 0, (ONE*7)/8); return(rate); } // Called to update MIB performance counters // sPtr - pointer to station context // aPtr - attachment pointer // fPtr - frame pointer // destinMac - destination MAC address // Selection - routine that selects MIB pairs // Returns pointer to frame-count MIB void UpdateCounters(Station *sPtr, Attachment *aPtr, Frame *fPtr, uInt8 *(*Selection) (Station *, Attachment *, Frame *, uInt8)) { uInt8 *cntPtr, destinMac, sourceMac; assert(sPtr != NULL && aPtr != NULL && fPtr!=NULL && Selection!=NULL); // Argument-pointer validation AddressExtract(fPtr, &destinMac, &sourceMac); // Extract the sourc-MAC address if ((cntPtr= (*(Selection))(sPtr, aPtr, fPtr, destinMac))==NULL) // Detemine statistics-pair address return; // or return if no pair is found cntPtr[0]+= 1; // Update frame counter cntPtr[1]+= fPtr->frameSize; // Update following byte counter } // Called to update receive MIB counters // sPtr - pointer to station context // aPtr - attachment pointer // fPtr - frame pointer // destinMac - destination MAC address // Returns pointer to frame-count MIB uInt8 * SelectRingRxCounters(Station *sPtr, Attachment *aPtr, Frame *fPtr, uInt8 destinMac) { int class= (fPtr->serviceClass<<1)|fPtr->subClass; int multi= (destinMac&MCAST_BIT)!=0 ? MCAST : UCAST; assert(sPtr != NULL && aPtr != NULL && fPtr!=NULL); switch(multi|class) { case UCAST|CLASS_A0: return(&(aPtr->counters.rprRingRxUcastClassA0Frames)); case UCAST|CLASS_A1: return(&(aPtr->counters.rprRingRxUcastClassA1Frames)); case UCAST|CLASS_B0: return(&(aPtr->counters.rprRingRxUcastClassB0Frames)); case UCAST|CLASS_B1: return(&(aPtr->counters.rprRingRxUcastClassB1Frames)); case UCAST|CLASS_Cx: return(&(aPtr->counters.rprRingRxUcastClassCxFrames)); case MCAST|CLASS_A0: return(&(aPtr->counters.rprRingRxMcastClassA0Frames)); case MCAST|CLASS_A1: return(&(aPtr->counters.rprRingRxMcastClassA1Frames)); case MCAST|CLASS_B0: return(&(aPtr->counters.rprRingRxMcastClassB0Frames)); case MCAST|CLASS_B1: return(&(aPtr->counters.rprRingRxMcastClassB1Frames)); case MCAST|CLASS_Cx: return(&(aPtr->counters.rprRingRxMcastClassCxFrames)); } return(NULL); } // Called to update transmit MIB counters // sPtr - pointer to station context // aPtr - attachment pointer // fPtr - frame pointer // destinMac - destination MAC address // Returns pointer to frame-count MIB uInt8 * SelectRingTxCounters(Station *sPtr, Attachment *aPtr, Frame *fPtr, uInt8 destinMac) { int class= (fPtr->serviceClass<<1)|fPtr->subClass; int multi= (destinMac&MCAST_BIT)!=0 ? MCAST : UCAST; assert(sPtr != NULL && aPtr != NULL && fPtr!=NULL); switch(multi|class) { case UCAST|CLASS_A0: return(&(aPtr->counters.rprRingTxUcastClassA0Frames)); case UCAST|CLASS_A1: return(&(aPtr->counters.rprRingTxUcastClassA1Frames)); case UCAST|CLASS_B0: return(&(aPtr->counters.rprRingTxUcastClassB0Frames)); case UCAST|CLASS_B1: return(&(aPtr->counters.rprRingTxUcastClassB1Frames)); case UCAST|CLASS_Cx: return(&(aPtr->counters.rprRingTxUcastClassCxFrames)); case MCAST|CLASS_A0: return(&(aPtr->counters.rprRingTxMcastClassA0Frames)); case MCAST|CLASS_A1: return(&(aPtr->counters.rprRingTxMcastClassA1Frames)); case MCAST|CLASS_B0: return(&(aPtr->counters.rprRingTxMcastClassB0Frames)); case MCAST|CLASS_B1: return(&(aPtr->counters.rprRingTxMcastClassB1Frames)); case MCAST|CLASS_Cx: return(&(aPtr->counters.rprRingTxMcastClassCxFrames)); } return(NULL); } // Called to update receive MIB counters // sPtr - pointer to station context // aPtr - attachment pointer // fPtr - frame pointer // destinMac - destination MAC address // Returns pointer to frame-count MIB uInt8 * SelectClientRxCounters(Station *sPtr, Attachment *aPtr, Frame *fPtr, uInt8 destinMac) { int class= (fPtr->serviceClass<<1)|fPtr->subClass; int multi= (destinMac&MCAST_BIT)!=0 ? MCAST : UCAST; assert(sPtr != NULL && aPtr != NULL && fPtr!=NULL); switch(multi|class) { case UCAST|CLASS_A0: return(&(aPtr->counters.rprClientRxUcastClassA0Frames)); case UCAST|CLASS_A1: return(&(aPtr->counters.rprClientRxUcastClassA1Frames)); case UCAST|CLASS_B0: return(&(aPtr->counters.rprClientRxUcastClassB0Frames)); case UCAST|CLASS_B1: return(&(aPtr->counters.rprClientRxUcastClassB1Frames)); case UCAST|CLASS_Cx: return(&(aPtr->counters.rprClientRxUcastClassCxFrames)); case MCAST|CLASS_A0: return(&(aPtr->counters.rprClientRxMcastClassA0Frames)); case MCAST|CLASS_A1: return(&(aPtr->counters.rprClientRxMcastClassA1Frames)); case MCAST|CLASS_B0: return(&(aPtr->counters.rprClientRxMcastClassB0Frames)); case MCAST|CLASS_B1: return(&(aPtr->counters.rprClientRxMcastClassB1Frames)); case MCAST|CLASS_Cx: return(&(aPtr->counters.rprClientRxMcastClassCxFrames)); } return(NULL); } // Called to update transmit MIB counters // sPtr - pointer to station context // aPtr - attachment pointer // fPtr - frame pointer // destinMac - destination MAC address // Returns pointer to frame-count MIB uInt8 * SelectClientTxCounters(Station *sPtr, Attachment *aPtr, Frame *fPtr, uInt8 destinMac) { int class= (fPtr->serviceClass<<1)|fPtr->subClass; int multi= (destinMac&MCAST_BIT)!=0 ? MCAST : UCAST; assert(sPtr != NULL && aPtr != NULL && fPtr!=NULL); switch(multi|class) { case UCAST|CLASS_A0: return(&(aPtr->counters.rprClientTxUcastClassA0Frames)); case UCAST|CLASS_A1: return(&(aPtr->counters.rprClientTxUcastClassA1Frames)); case UCAST|CLASS_B0: return(&(aPtr->counters.rprClientTxUcastClassB0Frames)); case UCAST|CLASS_B1: return(&(aPtr->counters.rprClientTxUcastClassB1Frames)); case UCAST|CLASS_Cx: return(&(aPtr->counters.rprClientTxUcastClassCxFrames)); case MCAST|CLASS_A0: return(&(aPtr->counters.rprClientTxMcastClassA0Frames)); case MCAST|CLASS_A1: return(&(aPtr->counters.rprClientTxMcastClassA1Frames)); case MCAST|CLASS_B0: return(&(aPtr->counters.rprClientTxMcastClassB0Frames)); case MCAST|CLASS_B1: return(&(aPtr->counters.rprClientTxMcastClassB1Frames)); case MCAST|CLASS_Cx: return(&(aPtr->counters.rprClientTxMcastClassCxFrames)); } return(NULL); } // ******************************************************************************************************************************** // ***************************** Editor note (DVJ): To be removed prior to final publication. ************************************* // ********************* blank payloads to be incorporated into Enqueue() and Dequeue() for efficiency **************************** // ******************************************************************************************************************************** // Called to insert tail-of-FIFO entry // sPtr - pointer to station context // qPtr - FIFO pointer structures // fPtr - FIFO data pointer Frame * Enqueue(Station *sPtr, DualPort *portPtr, FifoQueue *qPtr, Frame *fPtr) { Common *comPtr= (Common *)sPtr, *sigPtr; Timer delta, alarmTime; uInt8 bump; assert(sPtr != NULL && qPtr != NULL && fPtr!=NULL); // Valid pointers are supplied assert(qPtr->headPtr!=NULL && qPtr->tailPtr!=NULL); // Queue has been initialized if (qPtr->enqueueRate!=0) { delta= DiffTime(qPtr->enqueueTime,COMMON_TIME(sPtr)); if (delta.dataHi>0) { Wakeup((Common *)sPtr, (void *)sPtr, qPtr->enqueueTime); // A limited enqueue rate may force return(NULL); // the current enqueue to be delayed } bump= qPtr->enqueueRate*fPtr->frameSize; qPtr->enqueueTime= BumpTime(COMMON_TIME(sPtr),bump); // Schedule the enqueue completion Wakeup((Common *)sPtr, (void *)sPtr, qPtr->enqueueTime); // and wakeup the thread afterwards } fPtr->timeStamp= alarmTime= BumpTime(COMMON_TIME(sPtr),qPtr->delay); // Set timeStamp for enforced delays qPtr->depth+= fPtr->frameSize; Insert(comPtr, qPtr->tailPtr, (Frame *)qPtr, fPtr); // Insert at the tail of the queue sigPtr= portPtr==NULL ? (void *)sPtr : (void *)(portPtr->fifoPtr); Wakeup(comPtr, sigPtr, alarmTime); return(0); } // Called to detect full-FIFO-queue condition on transmit output // comPtr - pointer to caller context // qPtr - FIFO pointer structures int FullQueue(Common *comPtr, FifoQueue *qPtr) { Timer delta; assert(comPtr!= NULL && qPtr != NULL); // Argument-pointer validation check assert(qPtr->headPtr!= NULL && qPtr->tailPtr != NULL); // Queue-pointer validation check if (qPtr->headPtr==(Frame *)qPtr&&qPtr->tailPtr==(Frame *)qPtr) // Can always add to an empty queue return(0); assert(qPtr->headPtr!=(Frame *)qPtr&&qPtr->tailPtr!=(Frame *)qPtr); delta= DiffTime(qPtr->enqueueTime,comPtr->corePtr->common.nextTime); if (delta.dataHi>0) // Permature data is never delivered return(1); return(0); } // Called to remove head-of-FIFO entry // comPtr - pointer to caller context // qPtr - FIFO pointer structures Frame * Dequeue(Common *comPtr, FifoQueue *qPtr) { Frame *fPtr; Timer delta; assert(comPtr!= NULL && qPtr!=NULL); // Argument-pointer validation check assert(qPtr->headPtr!= NULL&&qPtr->tailPtr!=NULL); // Queue-pointer validation check if (qPtr->headPtr==(Frame *)qPtr&&qPtr->tailPtr==(Frame *)qPtr) // Cannot dequeue from an empty list return(NULL); assert(qPtr->headPtr!=(Frame *)qPtr&&qPtr->tailPtr!=(Frame *)qPtr); // Queue-pointer validation check fPtr= qPtr->headPtr; delta= DiffTime(fPtr->timeStamp,comPtr->corePtr->common.nextTime); if (delta.dataHi>0) // Permature data is never delivered return(NULL); fPtr= qPtr->headPtr; // The head identifies the entry Delete(comPtr, fPtr); // that is deleted from the queue qPtr->depth-= fPtr->frameSize; // The FIFO depth is decreased return(fPtr); // The dequeued entry is returned } // Double-link list insertion // comPtr - common context pointer // leadPtr - leading entry pointer // nextPtr - following entry pointer // fPtr - inserted entry pointer void Insert(Common *comPtr, Frame *leadPtr, Frame *nextPtr, Frame *fPtr) { assert(comPtr != NULL && leadPtr!=NULL && nextPtr!=NULL && fPtr!=NULL); // Argument-pointer validation check assert(fPtr->forwPtr==NULL && fPtr->backPtr==NULL); // Queue-pointer validation check fPtr->backPtr= leadPtr; fPtr->forwPtr= nextPtr; // Set inserted-entry pointers leadPtr->forwPtr= nextPtr->backPtr= fPtr; // Set adjacent-entry pointers } // Double-link list deletion // comPtr - common context pointer // fPtr - inserted entry pointer void Delete(Common *comPtr, Frame *fPtr) { Frame *headPtr, *tailPtr; assert(comPtr != NULL && fPtr!=NULL); // Argument-pointer validation check headPtr= fPtr->backPtr; // Determine the adjacent tailPtr= fPtr->forwPtr; // head and tail entries assert(headPtr != NULL && tailPtr != NULL); // Adjacent-pointer validation check headPtr->forwPtr= fPtr->forwPtr; // Set head to skip-over deleted entry tailPtr->backPtr= fPtr->backPtr; // Set tail to skip-over deleted entry fPtr->forwPtr= fPtr->backPtr= NULL; // Delete entry pointers themselves } // Scheduling wakeup adjustment // comPtr - common context pointer // delta - time until next activation void Wakeup(Common *comPtr, void *pokePtr, Timer alarm) { Common *sigPtr; Timer delta; uIntA address; assert(comPtr != NULL && pokePtr!=NULL); // Argument-pointer validation check address= ((uIntA)pokePtr); // The wakeup is directed to the sigPtr= (Common *)(address-(address%BLOCK_SIZE(comPtr))); // associated Common structure delta= DiffTime(sigPtr->nextTime, alarm); if (delta.dataHi>0) { // If alarm precedes other alarms, sigPtr->nextTime= alarm; // set the earlier alarm time and sigPtr->tickTime.dataHi= sigPtr->tickTime.dataLo= 0; // force tickTime recalculation } } // Making of a frame // fPtr - frame pointer: NULL==>zero, valid==>copy Frame * FrameMake(uInt4 size) { Frame *fPtr; uInt4 mSize; mSize= LEAD_SIZE+HEAD_SIZE+size+3; // Size of needed storage fPtr= (Frame *)malloc(mSize); // with extra to force alignment assert(fPtr!=NULL); fPtr->frameSize= size; // Set the frame size and initialize fPtr->forwPtr= fPtr->backPtr= NULL; // the forward and backward pointers return(fPtr); } // Making of a frame // fPtr - frame pointer: NULL==>zero, valid==>copy Frame * FrameCopy(Frame *fPtr) { Frame *newPtr; uInt4 mSize; assert(fPtr!=NULL); mSize= LEAD_SIZE+HEAD_SIZE+fPtr->frameSize+3; // Size of needed storage newPtr= (Frame *)malloc(mSize); // with extra to force alignment assert(newPtr!=NULL); bcopy((char *)fPtr, (char *)newPtr, mSize); // Copy the frame contents & initialize newPtr->forwPtr= newPtr->backPtr= NULL; // the forward and backward pointers return(newPtr); } // Return aligned storage // align - align requirements (next power of two) // fPtr - size of aligned data structure char * MemAlign(int align, int size) { uInt4 base; char *cPtr, *newPtr; int align2, size2, delta; for (align2=1; align2first.dataLo) ? 1 : 0;; // borrows from the more-significant half delta.dataHi= first.dataHi-final.dataHi-borrow; // Addition fo the more-significant half return(delta); } // Return difference of 16-byte timer values // first - first data value // final - final data value Timer BumpTime(Timer first, uInt8 final) { Timer delta; uInt8 sumLo; delta.dataLo= sumLo= first.dataLo+final; // Update least-significant octlet delta.dataHi+= (sumLo= 1); // Packet size including CRC crcSum = CalculateCrc(reverse, inputs, sizeInBytes - 4); // Compute the CRC on just the data return (~crcSum); // Complement the final value } int // Validate CRC, where sizeInBytes includes the CRC ValidateCrc(int reverse, uInt4 * inputs, int sizeInBytes) { uInt4 crcSum, check; assert(sizeInBytes >= 1); // Packet size including CRC crcSum = CalculateCrc(reverse, inputs, sizeInBytes); // Computation continues through through the CRC check = reverse ? BitReverse(crcSum) : crcSum; // Conditional bit-reverse of generated output return (check != CRC_RESULTS); // ?? Is this right ?? } // The GenerateCrc() function points to protected values, // it checks these values and return a final 32 - bit result uInt4 CalculateCrc(int reverse, uInt4 * inputs, int sizeInBytes) { uInt4 inQuad, crcSum, sum; int i; assert(sizeInBytes >= 1); // Packet size including CRC crcSum = (uInt4) 0XFFFFFFFF; // crcSum is initialized to all ones for (i = 0; i < sizeInBytes; i += 1) { // Process bytes covered by the CRC if ((i%4)==0) inQuad = reverse ? inputs[i] : BitReverse(inputs[i]); crcSum = CrcBits(crcSum, inQuad, 8); inQuad<<= 8; } sum = reverse ? BitReverse(crcSum) : crcSum; return (sum); } uInt4 CrcBits(uInt4 last, uInt4 input, int size) { uInt4 crcSum, newMask; int i, oldBit, newBit, sumBit; crcSum = last; // Process each bit within the input uInt4 value for (newMask = MSB32, i = 0; i < size; newMask >>= 1, i += 1) { newBit = ((input & newMask) != 0); // The next input bit oldBit = ((crcSum & MSB32) != 0); // and MSB of crcSum sumBit = oldBit ^ newBit; // are EXOR'd together // Shift the old crcSum left and exclusive - OR the new newBit values crcSum = ((crcSum << 1) & ONES32) ^ (sumBit ? CRC_COMPUTE : 0); } return (crcSum); } // Reverse the order of bits within bytes uInt4 BitReverse(uInt4 old) { uInt4 new, oldMask, newMask; int i, j; for (i = new = 0; i < 4; i += 1) { for (j = 0; j < 8; j += 1) { oldMask = 1 << (8 * i + 7 - j); newMask = 1 << (8 * i + j); new |= (old & oldMask) ? newMask : 0; } } return (new); } // ********************************************************************************************************************************** // ***************************************************** CRC_32_EXCHANGED_BY_32 ***************************************************** // ********************************************************************************************************************************** #ifdef CRC_32_EXCHANGED_BY_32 // C00-through-c31 are the most- through least-significant bits of check. // d00-through-d31 are the most- through least-significant bits of input. // "a".."t""A".." " are intermediate bit values. a= c00^d00; b= c01^d01; c= c02^d02; d= c03^d03; e= c04^d04; f= c05^d05; g= c06^d06; h= c07^d07; j= c08^d08; k= c09^d09; m= c10^d10; n= c11^d11; p= c12^d12; r= c13^d13; s= c14^d14; t= c15^d15; A= c16^d16; B= c17^d17; C= c18^d18; D= c19^d19; E= c20^d20; F= c21^d21; G= c22^d22; H= c23^d23; J= c24^d24; K= c25^d25; M= c26^d26; N= c27^d27; P= c28^d28; R= c29^d29; S= c30^d30; T= c31^d31; // 00 10 20 30 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 // a b c d e f g h j k m n p r s t A B C D E F G H J K M N P R S T c00= d^e^ g^ j^k^m^ p^r^ C^ G^ K^M^ T; c01= e^f^ h^ k^m^n^ r^s^ A^ D^ H^ M^N ; c02= a^b^c^ e^ h^ m^n^p^ s^t^ C^ J^ N^P^ S ; c03= a^b^c^d^ f^ n^p^r^ t^ D^ K^ P^R^ T; c04= a^b^c^d^e^ g^ p^r^s^ A^ E^ M^ R^S ; c05= b^c^d^e^f^ h^ r^s^t^ B^ F^ N^ S^T; c06= a^ c^d^e^f^g^ s^t^A^ C^ G^ P^ T; c07= a^b^ d^e^f^g^h^ t^A^B^ D^ H^ R ; c08= a^ c^ f^g^ k^ n^ r^s^ A^ E^F^ J^ P^R ; c09= b^ d^ g^h^ m^ p^ s^t^ B^ F^G^ K^ R^S ; c10= a^ c^ e^ h^ n^ r^ t^ C^ G^H^ M^ S^T; c11= a^b^ d^ f^ j^ p^ s^ A^ D^ H^ N^ T; c12= b^c^ e^ g^ j^k^ r^ t^A^B^ E^ P ; c13= a^ c^d^ f^ h^ k^m^ s^ B^C^ F^ R ; c14= a^ c^d^ f^ h^j^ m^n^ t^ B^ D^E^ G^ J ; c15= c^d^ f^ h^j^k^ n^p^ B^ F^ H^J^K^ S ; c16= e^ h^ k^ s^t^A^ C^D^E^ J^K^ N^P ; c17= a^ f^ m^ t^ B^ D^E^F^ K^M^ P^R ; c18= c^ e^f^ h^j^ n^ B^ F^G^ J^ M^N^ R ; c19= a^b^c^d^e^ h^j^k^ p^ B^ E^ G^H^J^K^ N^P ; c20= a^ d^ g^h^ k^m^ r^ B^ E^F^ H^J^K^M^ P^R^S ; c21= b^ e^ h^j^ m^n^ s^ C^ F^G^ K^M^N^ R^S^T; c22= c^ f^ k^ n^p^ t^A^ D^ G^H^ M^N^P^ S^T; c23= a^ d^ g^ j^ m^ p^r^ A^B^ E^ H^ N^P^R^ T; c24= a^b^c^ e^f^g^h^j^ B^C^ E^ J^ S ; c25= a^ d^e^ j^k^ B^ D^E^F^ J^K^ S^T; c26= a^ c^ g^h^j^k^m^ A^B^ F^G^ J^K^M^ S^T; c27= b^ d^ h^ k^m^n^ A^B^C^ G^H^ K^M^N^ T; c28= a^b^ f^g^h^ m^n^p^ A^ D^E^ H^J^ M^N^P^ S ; c29= a^ e^f^ n^p^r^ C^ F^ J^K^ N^P^R^S^T; c30= b^ f^g^ p^r^s^ A^ D^ G^ K^M^ P^R^S^T; c31= a^b^ e^f^ j^ r^s^t^A^ C^ H^J^ M^N^ R^ T; #endif // CRC_32_EXCHANGED_BY_32 // ********************************************************************************************************************************* // ***************************************************** CRC_32_EXCHANGED_BY_16 **************************************************** // ********************************************************************************************************************************* #ifdef CRC_32_EXCHANGED_BY_16 // C00-through-c31 are the most- through least-significant bits of check. // d00-through-d15 are the most- through least-significant bits of input. // "a".."t""A".." " are intermediate bit values. a= c00^d00; b= c01^d01; c= c02^d02; d= c03^d03; e= c04^d04; f= c05^d05; g= c06^d06; h= c07^d07; j= c08^d08; k= c09^d09; m= c10^d10; n= c11^d11; p= c12^d12; r= c13^d13; s= c14^d14; t= c15^d15; A= c16; B= c17; C= c18; D= c19; E= c20; F= c21; G= c22; H= c23; J= c24; K= c25; M= c26; N= c27; P= c28; R= c29; S= c30; T= c31; // 00 10 20 30 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 // a b c d e f g h j k m n p r s t A B C D E F G H J K M N P R S T c00= c^ g^ k^m^ t^A ; c01= a^ d^ h^ m^n^ B ; c02= c^ j^ n^p^ s^ C ; c03= d^ k^ p^r^ t^ D ; c04= a^ e^ m^ r^s^ E ; c05= b^ f^ n^ s^t^ F ; c06= a^ c^ g^ p^ t^ G ; c07= a^b^ d^ h^ r^ H ; c08= a^ e^f^ j^ p^r^ J ; c09= b^ f^g^ k^ r^s^ K ; c10= c^ g^h^ m^ s^t^ M ; c11= a^ d^ h^ n^ t^ N ; c12= a^b^ e^ p^ P ; c13= b^c^ f^ r^ R ; c14= b^ d^e^ g^ j^ S ; c15= b^ f^ h^j^k^ s^ T; c16= a^ c^d^e^ j^k^ n^p ; c17= b^ d^e^f^ k^m^ p^r ; c18= b^ f^g^ j^ m^n^ r ; c19= b^ e^ g^h^j^k^ n^p ; c20= b^ e^f^ h^j^k^m^ p^r^s ; c21= c^ f^g^ k^m^n^ r^s^t ; c22= a^ d^ g^h^ m^n^p^ s^t ; c23= a^b^ e^ h^ n^p^r^ t ; c24= b^c^ e^ j^ s ; c25= b^ d^e^f^ j^k^ s^t ; c26= a^b^ f^g^ j^k^m^ s^t ; c27= a^b^c^ g^h^ k^m^n^ t ; c28= a^ d^e^ h^j^ m^n^p^ s ; c29= c^ f^ j^k^ n^p^r^s^t ; c30= a^ d^ g^ k^m^ p^r^s^t ; c31= a^ c^ h^j^ m^n^ r^ t ; #endif // CRC_32_EXCHANGED_BY_16 // ********************************************************************************************************************************* // ***************************************************** CRC_32_EXCHANGED_BY_8 ***************************************************** // ********************************************************************************************************************************* #ifdef CRC_32_EXCHANGED_BY_8 // c00-through-c31 are the most- through least-significant bits of check. // d00-through-d07 are the most- through least-significant bits of input. // "a".."t""A".." " are intermediate bit values. a= c00^d00; b= c01^d01; c= c02^d02; d= c03^d03; e= c04^d04; f= c05^d05; g= c06^d06; h= c07^d07; j= c08; k= c09; m= c10; n= c11; p= c12; r= c13; s= c14; t= c15; A= c16; B= c17; C= c18; D= c19; E= c20; F= c21; G= c22; H= c23; J= c24; K= c25; M= c26; N= c27; P= c28; R= c29; S= c30; T= c31; // 00 10 20 30 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 // a b c d e f g h j k m n p r s t A B C D E F G H J K M N P R S T c00= b^c^ h^j ; c01= c^d^ k ; c02= a^ d^e^ g^ m ; c03= b^ e^f^ h^ n ; c04= c^ f^g^ p ; c05= d^ g^h^ r ; c06= e^ h^ s ; c07= f^ t ; c08= a^ e^f^ A ; c09= b^ f^g^ B ; c10= c^ g^h^ C ; c11= d^ h^ D ; c12= e^ E ; c13= f^ F ; c14= a^ G ; c15= a^b^ g^ H ; c16= a^b^ d^e^ J ; c17= b^c^ e^f^ K ; c18= a^ c^d^ f^ M ; c19= a^b^ d^e^ N ; c20= a^b^c^ e^f^g^ P ; c21= b^c^d^ f^g^h^ R ; c22= c^d^e^ g^h^ S ; c23= d^e^f^ h^ T; c24= a^ g ; c25= a^b^ g^h ; c26= a^b^c^ g^h ; c27= b^c^d^ h ; c28= a^ c^d^e^ g ; c29= a^b^ d^e^f^g^h ; c30= b^c^ e^f^g^h ; c31= a^ c^d^ f^ h ; #endif // CRC_32_EXCHANGED_BY_8