Legacy Documentclose button

Important: The information in this document is obsolete and should not be used for new development.

Previous Book Contents Book Index Next

Inside Macintosh: Networking With Open Transport / Part 1 - Open Transport Essentials
Chapter 10 - Advanced Topics


Using Raw Mode

Raw mode refers to the ability of some connectionless providers to pass packet header information, which would normally be stripped at the appropriate protocol level, up to a higher level. For example, if you open a DDP endpoint, you can send and receive data in raw mode in order to determine how many routers a packet had passed through before you receive it. Normally, hop count information is stored in the DDP packet header; by using raw mode you can access this information, which would otherwise be stripped off before you received the packet.

There are two methods for anabling raw mode packet handling. At the link layer (Ethernet and TokenRing), use the OTOptionManagement function to enable raw mode packet processing. Above the link layer, the AppleTalk DDP protocol supports raw mode in a different manner. For more information, see the description of the OTSndUData function in "Using General Open Transport Functions With DDP". Your protocol might support specific options; for example RawIP supports the IP header include option.

Using Option Management to Set Raw Mode

If you want to use raw mode at the link layer level, you should use the option OPT_SETRAWMODE. Listing 10-3 shows the user function DoNegotiateRawModeOption as an example of how you negotiate raw mode using options.

Listing 10-3 Negotiating raw mode using options

#include <OpenTransport.h>
#include <OpenTptLinks.h>

OSStatus DoNegotiateRawModeOption(EndpointRef ep, UInt32 rawModeOption);

/* use the options as defined in the OpenTptLinks.h header
   when setting the rawModeOption parameter. */

OSStatus DoNegotiateRawModeOption(EndpointRef ep, UInt32 rawModeOption)

{
   UInt8 buf[kOTFourByteOptionSize];
                  /* buffer for fourByte Option size */
   TOption* opt;  /* option ptr to make items easier to access */
   TOptMgmt req;
   TOptMgmt ret;
   OSStatus err;
   
   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;
   

   opt->level= LNK_TPI; /* dealing with tpi */
   opt->name= OPT_SETRAWMODE;/* specify raw mode */
   opt->len= kOTFourByteOptionSize;
   opt->status = 0;
   *(UInt32*)opt->value = rawModeOption;
            /* set the desired option level, true or false */
            
   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
         err = kOTNoError;
   }
      
   return err;
}
The function assumes the endpoint is in synchronous mode. It defines buffers that contain option negotiation information and then calls the OTOptionMangement function.

Testing for Raw Mode Support

To use raw mode you need to determine whether the provider you are using supports it by examining the T_CAN_SUPPORT_MDATA bit of the endpoint information structure for your endpoint. Listing 10-4 shows a function CanDoRawMode that you can call to determine whether your endpoint provider supports sending or receiving raw data. The function calls the OTGetEndpointInfo function and examines the info.flags field to see if the T_CAN_SUPPORT_MDATA bit is set. If it is, the function returns true.

Listing 10-4 Testing for raw data support

Boolean CanDoRawMode(EndpointRef ep)
{
   TEndpointInfoinfo;
   OSStatus    err;
   Boolean     result;
   
   err = OTGetEndpointInfo(ep, &info);
   if (err != kOTNoError)
      result = false;
   else if (info.flags & T_CAN_SUPPORT_MDATA)
      result = true;/* this also means that the src addr info is
                     in the info record */
   else
      result = false;

   return result;
}

Sending and Receiving in Raw Mode at the Protocol Level

Currently raw mode is supported only for DDP endpoints. To enable or disable raw mode packet processing of data under DDP, you modify the TNetBuf addr field that is sent in the OTSendUdata function. Once raw mode processing is enabled with the OTSndUData call, it stays in effect until you explicitly disable it.

To enable raw mode, you must

  1. Specify 0xffffffffUL for the unitdata.addr.len field of the TNetBuf structure containing the address information. Set the opt.len, opt.buf, and addr.buf fields to 0.

  2. Place DDP header information in the buffer referenced by the udata.udata.buf field of the TNetBuf structure describing data being sent. The DDP header begins with the hop count byte. With raw mode enabled, the data in the unitdata.udata.buf field must be the complete DDP packet.

Once you have sent a raw mode pocket, the protocol will deliver incoming packets in raw mode as well. When using raw mode on receives, you should

  1. Set the opt.len field and the udata.addr.maxlen field to 0. However it is set, Open Transport does not fill this field with address information. Instead it returns the complete DDP packet (including the header) in the data buffer described in step 2.

  2. Allocate a buffer (into which the data is stored when the function returns) that is large enough to hold header information as well as the data being received.

Be careful when using raw mode packets because you can no longer tell a full incoming packet from a partial read without remembering that the T_MORE flag was set on the previous read.

To disable raw mode packet processing, send a normal DDP packet with the unitdata.addr.len and the unitdata.addr.buf fields set for an AF_ATALK_DDP or similar structure.

Listing 10-5 shows how you send an echo packet using a DDP endpoint. The sample code includes a call to CanDoMDataMode, a function that looks at the flags associated with creating the endpoint to determine whether the endpoint supports M_DATA mode. It is assumed that the endpoint is bound and that it is in synchronous mode.

Listing 10-5 Testing for raw mode support for a DDP endpoint

#include <OpenTransport.h>
#include <OpenTptAppleTalk.h>
#include <Types.h>
#include <Events.h>
#include <stdio.h>

void doOpenTptEcho(EndpointRef ep, UInt16 destNet, UInt8 destNode);
extern Boolean CanDoMDataMode(EndpointRef ep);

enum {
   kddpMaxNormData = 586,
   kddpMaxRawData= 599
};
enum {
   kEchoSocketID= 4
};
enum {
   kEchoRequest= 1,
   kEchoType= 4
};

void doOpenTptEcho(EndpointRef ep, UInt16 destNet, UInt8 destNode)
{
   TBind       boundAddr;
   DDPAddressd dpAddr, destAddr;
   TUnitData   unitdata;
   OSStatus    err = kOTNoError;
   OTResult    result;
   OTFlags     flags;
   
   UInt8    buf[kddpMaxRawData];
   UInt8    buf1[64] = "This is a sample string for the first part
                                       of the buffer";
   Boolean  done = false;
   Boolean  useMDataMode;
      
   if (!OTIsSynchronous(ep))
   {
      fprintf(stderr, "endpoint must be synchronous for this sample");
      return;
   }

   /* verify that the endpoint is bound first. */
   result = OTGetEndpointState(ep);
   if (result != T_IDLE)
   {
      fprintf(stderr, "endpoint must be bound for this sample");
      return;
   }
   
      /* check for support of M_DATA mode so that we get the */
      /* header info along with the datagram */
   useMDataMode = CanDoMDataMode(ep);
      
   if (useMDataMode == true)
   {
/* set up data buffer to send Echo Request as a DDP M_DATA packet */
/* get our protocol address to fill into the M_DATA packet */
      
      boundAddr.addr.buf = (UInt8*)&ddpAddr;
      boundAddr.addr.maxlen = sizeof(ddpAddr);
      err = OTGetProtAddress(ep, &boundAddr, nil);
      
      if (err != kOTNoError)
      {
         fprintf(stderr, "error occurred calling OTGetProtAddress 
                              - %ld\n", err);
         return;
      }
      else
      {
         /* packet length */

         /* clear hopcount, but set the upper 2 bits of the length */
         buf[0] = (UInt8)(kddpMaxRawData >> 8) & 0x0003;
         /* set the lower byte of the length field */
         buf[1] = (UInt8)(kddpMaxRawData & 0x00FF);

         /* packet checksum */
         
         buf[2] = 0;// no checksum
         buf[3] = 0;// no checksum

         /* dest network */
         
         buf[4] = (UInt8)(destNet >> 8);
         buf[5] = (UInt8)(destNet & 0x00FF);

         
         /* src network */
         
         buf[6] = (UInt8)(ddpAddr.fNetwork >> 8);
         buf[7] = (UInt8)(ddpAddr.fNetwork & 0x00FF);

         buf[8] = (UInt8)destNode;/* dest node */
         buf[9] = (UInt8)ddpAddr.fNodeID;/* src node */
         
         buf[10] = kEchoSocketID;/* set dest socket to echo socket */
         buf[11] = (UInt8)ddpAddr.fSocket;/* src socket */
         
         buf[12] = kEchoType;/* set packet type to echo packet */
         buf[13] = kEchoRequest; /* packet is echo request packet */
         BlockMove((Ptr)&buf1, (Ptr)&buf[14], sizeof(buf1));
         
            /* set up the unitdata structure */
         unitdata.udata.buf = (UInt8*)buf;/* data area */
         unitdata.udata.len = kddpMaxRawData;
         unitdata.addr.buf = nil;/* address area*/

/* by sending the packet with the addr.len field set to 0xFFFFFFFFUL,*/
/* one enables M_DATA mode with DDP.  Once you send a packet in this */
/* manner, all packet deliveries will also be in M_DATA mode.  This */
/* continues until a packet is sent with the addr.len field set to a */ 
/* value other than 0xFFFFFFFFUL. */
         unitdata.addr.len = (size_t)0xffffffffUL;
         unitdata.opt.buf = nil;
         unitdata.opt.len = 0; /* no options being sent */
      }     
   }
   else
   {
      /* Set up DDP Address field with the destination address */
      /* for the Echo request */
      
      destAddr.fAddressType = AF_ATALK_DDP;
      destAddr.fNetwork = destNet;
      destAddr.fNodeID = destNode;
      destAddr.fSocket = kEchoSocketID;
      destAddr.fDDPType = kEchoType;
      
      /* Set up data buffer for the Echo Request */

      /* indicate packet is an echo request packet */
      buf[0] = kEchoRequest;
      
         /* fill in the buffer with the string */
      BlockMove((Ptr)&buf1, (Ptr)&buf[1], sizeof(buf1));

      /* set up unitdata fields */
      //
      unitdata.udata.buf = (UInt8*)buf;// data area
      unitdata.udata.len = kddpMaxNormData;
      unitdata.addr.buf = (UInt8*)&destAddr;// address area
      unitdata.addr.len = kDDPAddressLength;
      unitdata.opt.len = 0; // no options being sent
   }
   
   /* Send the data */
   err = OTSndUData(ep, &unitdata);
   
   /* If no error occured sending the data, then process */
   /* expected the Echo Response.*/
   if (err == kOTNoError)
   {
      while (done == false)
      {
         result = OTLook(ep);
         if ( result == T_DATA )
         {
            while (done == false)
            {
      /* Set up the UnitData structure to recieve response packet */
      /* Set up the udata and address area to accomodate either an */
      /* M_DATA response or the typical response where the data */
      /* and addr fields are filled in. */
               
               unitdata.udata.buf = (UInt8*)buf;/* data area */
               unitdata.udata.len = 0;
               unitdata.udata.maxlen = kddpMaxRawData;
               unitdata.addr.buf = (UInt8*)&destAddr;/* address area 
               unitdata.addr.maxlen = kDDPAddressLength;
               unitdata.opt.maxlen = 0; /* no options are expected */
               
      /* note that we reuse the buffer we used to send the echo */
      /* request packet with.  After the OTSnd completes in */
      /* synchronous mode successfully, the buffer has been released */
      /* for use by the program. */
                result = OTRcvUData(ep, &unitdata, &flags);
               
                if (result == kOTNoDataErr)
                {
                  done = true;
   /* whenever there is a data indication, it's best to read the data */
   /* until the kOTNoDataErr since this releases memory that OT has */
   /* reserved for the data. In this case, we've consumed all */
   /* available data and are ready to exit this function. */
                }
                else if (result < 0)
                {
                  fprintf(stderr, "unknown error occurred reading
                                 data - %ld\n", result);
                  done = true;
                }
                else if (result == kOTNoError)
                {
                  /* read echo reply successfully */
                  /* continue to read until kOTNoDataErr occurs. */
                  fprintf(stderr, "%ld bytes read.\n",
                                    unitdata.udata.len);
                }
            }
            
         }
         else
         {
         /* an event other than T_DATA occurred */
            
         }
         /* another way to escape this routine. */
         if (Button())
            done = true;
      }
   }
}


Subtopics
Using Option Management to Set Raw Mode
Testing for Raw Mode Support
Sending and Receiving in Raw Mode at the Protocol Level

Previous Book Contents Book Index Next

© Apple Computer, Inc.
15 JAN 1998