Important: The information in this document is obsolete and should not be used for new development.
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 theOTSndUData
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 optionOPT_SETRAWMODE
. Listing 10-3 shows the user functionDoNegotiateRawModeOption
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 theOTOptionMangement
function.Testing for Raw Mode Support
To use raw mode you need to determine whether the provider you are using supports it by examining theT_CAN_SUPPORT_MDATA
bit of the endpoint information structure for your endpoint. Listing 10-4 shows a functionCanDoRawMode
that you can call to determine whether your endpoint provider supports sending or receiving raw data. The function calls the OTGetEndpointInfo function and examines theinfo.flags
field to see if the T_CAN_SUPPORT_MDATA bit is set. If it is, the function returnstrue
.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 theTNetBuf
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
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
- Specify
0xffffffffUL
for theunitdata.addr.len
field of theTNetBuf
structure containing the address information. Set theopt.len
,opt.buf
, andaddr.buf
fields to 0.- Place DDP header information in the buffer referenced by the
udata.udata.buf
field of theTNetBuf
structure describing data being sent. The DDP header begins with the hop count byte. With raw mode enabled, the data in theunitdata.udata.bu
f field must be the complete DDP packet.
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
- Set the
opt.len
field and theudata.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.- 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.
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 theunitdata.addr.buf
fields set for anAF_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 supportsM_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