NegotiateRawModeSample.c

/*
    File:       NegotiateRawModeSample.c
 
    Contains:   This sample demonstrates the use of Option Management to place an Ethernet
                endpoint into raw mode.  In addition, the sample distinguishes whether the
                ethernet driver is based on the original Ethernet template that was used on
                the Power Mac 72/73/75/76/85/86/95/9600 systems. Under SSW 8.5, the ethernet
                driver will be based on the Apple Ethernet template which is a modification 
                of the Mentat template customized to the Mac OS. For the purposes of
                enabling and using raw mode, the Apple Ethernet template can be considered
                the same as the mentat template.
    
                BACKGROUND
                As of the release of OpenTransport 1.1.1, a new driver template, provided
                by Mentat, was released.  This new driver template is simpler to use and
                provides a standard mechanism for handling promiscuous mode.
    
                There are 2 important differences between these two templates.  The mechanism
                by which an Ethernet endpoint is placed into raw mode is different.  In addition,
                the raw mode packet that the mentat based driver passes, must be handled
                differently from packets passed up by the original ethernet drivers.
    
                OBJECTIVE:
                This code snippet has been modified to do 2 things
                1. demonstrate a method for placing an ethernet endpoint into raw mode regardless
                of the template type that the underlying driver is based on, and,
                2. to return the template type so that the caller will know how to correctly
                handle the raw mode packets.
    
                FOR USERS OF PREVIOUS VERSIONS OF THIS CODE
    
                IMPORTANT Note: This sample does not support asynchronous endpoints. The technique
                of checking whether the endpoint is async on entry to this function and changing
                it to sync, can work under some cases, however, this is not always true.
                If an async endpoint must be used, then modify the following code as appropriate
                to work with a handler routine that handles the T_OPTMGMTCOMPLETE event.  The cookie
                will be a pointer to the returned TOptMgmt structure so that you can check the 
                negotiation result.
    
                Input parameters:
                EndpointRef - ethernet endpoint that you want to place into raw mode.
                rawModeOption - one of the following values
                                kOTRawRcvOn - enable raw mode
                                kOTRawRcvOff - disable raw mode
                    
                                    // where the mentat template is present
                                kOTRawRcvOnWithTimeStamp - enable raw mode and return timestamp
    
                return paramters:
                result - kOTNoError if the raw mode option was successfully negotiated
                         < 0 OptionManagement call failed with the returned error
                         > 0 OptionManagement call completed with no error, but the negotiation
                                returned a result other than T_SUCCESS
                templateType - type of ethernet template that was detected.
                                kUnknownTemplate
                                kOrigTemplate,
                                kMentatTemplate
 
                raw mode data -
                An ethernet driver based on the original template will return the ethernet packet
                in the OTRcvUData buffer such that the destination address begins at offset 0 in
                the buffer.  A Mentat based driver will prepend the ethernet packet with the 
                following structure so that the destination packet begins at offset 0x18.
    
                struct dl_recv_status_t {
                unsigned long   dl_overall_length;
                unsigned long   dl_flags;
                unsigned long   dl_packet_length_before_truncation;
                unsigned long   dl_pad;
                OTTimeStamp     dl_timestamp;
                };
    
                This structure is defined in the file dlpiuser.h.  This header is found in the 
                OT Modules Development samples folder of the OT SDK.
 
    Written by: Rich Kubota 
 
    Copyright:  Copyright © 1998-1999 by Apple Computer, Inc., All Rights Reserved.
 
                You may incorporate this Apple sample source code into your program(s) without
                restriction. This Apple sample source code has been provided "AS IS" and the
                responsibility for its operation is yours. You are not permitted to redistribute
                this Apple sample source code as "Apple sample source code" after having made
                changes. If you're going to re-distribute the source, we require that you make
                it clear in the source that the code was descended from Apple sample source
                code, but that you've made changes.
 
    Change History (most recent first):
                7/22/1999   Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
                
 
*/
 
#include <Gestalt.h>
#include "NegotiateRawModeSample.h"
#include "OpenTptLinks.h"
 
static Boolean  IsDesiredOTVersionPresent(UInt32 desVers);
 
// important note - use the options as defined in the OpenTptLinks.h header
// when setting the rawModeOption parameter.
pascal OSStatus DoNegotiateRawModeOption(EndpointRef ep, 
                                        UInt32 rawModeOption, 
                                        UInt32 *templateType)
 
{
    UInt8       twelveByteOptionBuf[kOTOptionHeaderSize+12];
    dl_recv_control_t *rawModePtr;
    UInt8       buf[kOTFourByteOptionSize]; // define buffer for fourByte Option size
    TOption*    opt;                        // option ptr to make items easier to access
    TOptMgmt    req;
    TOptMgmt    ret;
    OSStatus    err;
    
    
    *templateType = kUnknownTemplate;       // intialize the template type return value
    
    opt = (TOption*)buf;                    // set option ptr to buffer
    req.opt.buf = buf;
    req.opt.len = sizeof(buf);
    req.flags   = T_NEGOTIATE;              // negotiate for rawmode option
 
    ret.opt.buf = buf;
    ret.opt.maxlen = kOTFourByteOptionSize; // first try the four-byte option request
    
 
    opt->level  = LNK_TPI;                  // dealing with tpi
    opt->name   = OPT_SETRAWMODE;
    opt->len    = kOTFourByteOptionSize;
    opt->status = 0;
    *(UInt32*)opt->value = rawModeOption;       // set the desired option level, true or false
 
    if (OTIsSynchronous(ep) == false)           // check whether ep sync or not
    {
        DebugStr("\p DoNegotiateRawModeOption does not support async endpoints");
        return (-1);
    }
                
    err = OTOptionManagement(ep, &req, &ret);
        
        // if no error then return the option status value
    if (err == kOTNoError)
    {
        if (opt->status != T_SUCCESS)
            err = opt->status;
        else
            *templateType = kOrigTemplate;  // the negotiation succeeded so we are dealing
                                            // with a driver based on orig template
    }
    
    if (err != kOTNoError)
    {
            // check if OT 1.2 or greater is present
            // there is a bug in the tpi8022 module in OT <= v1.1.x, such that 12 byte raw modes
            // options are not passed to the dlpi module and an IONACK result is returned.
        if (IsDesiredOTVersionPresent(kOTVers12))
        {
                // let's try the 12 byte option
            opt = (TOption*)twelveByteOptionBuf;    // set option ptr to buffer
            req.opt.buf = twelveByteOptionBuf;
            req.opt.len = sizeof(twelveByteOptionBuf);
            req.flags   = T_NEGOTIATE;              // negotiate for rawmode option
 
            ret.opt.buf = twelveByteOptionBuf;
            ret.opt.maxlen = sizeof(twelveByteOptionBuf);
 
            opt->level  = LNK_TPI;                  // dealing with tpi
            opt->name   = OPT_SETRAWMODE;
            opt->len    = sizeof(twelveByteOptionBuf);
            opt->status = 0;
            
            rawModePtr = (dl_recv_control_t*)&opt->value;
            rawModePtr->dl_primitive = kOTSetRecvMode;
            rawModePtr->dl_flags = DL_NORMAL_STATUS;
            rawModePtr->dl_truncation_length = 0;
            
            err = OTOptionManagement(ep, &req, &ret);
 
                // if no error then return the option status value
            if (err == kOTNoError)
            {
                if (opt->status != T_SUCCESS)
                    err = opt->status;
                else
                    *templateType = kMentatTemplate;
            }
            
        }
        
    }
 
    return err;
}
 
/*
*/
 
Boolean IsDesiredOTVersionPresent(UInt32 desVers)
{
    OSErr   err;
    UInt32  otVersion;
    
    err = Gestalt(gestaltOpenTptVersions, (long*) &otVersion);
    if (err)
        return false;
    else
        return (otVersion >= desVers);
}