Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

422 lines
22 KiB

/* buffdesc.h, /atalk-ii/ins, Garth Conboy, 03/29/92 */
/* Copyright (c) 1992 by Pacer Software Inc., La Jolla, CA */
/* GC - Initial coding.
GC - (05/20/92): Added support for opaque data descriptors.
GC - (06/24/92): More major changes: a single BufferDescriptor chunk
may now contain both out-board and on-board data.
GC - (06/30/92): Added holders for transmit completion info in the
BufferDescriptor.
GC - (12/04/92): Added some commentary and defined for Xyplex buffer
management.
*** Make the PVCS source control system happy:
$Header$
$Log$
***
Data structure and routine declarations for transmit buffer lists.
In order to avoid buffer copies when prepending protocol and data
link headers to outgoing datagrams we use a buffer chaining
technique. The most all send routines take "BufferDescriptor"s
rather than "data buffer"s as arguments; this allows these routines to
logically prepend headers without moving the buffers around. These
BufferDescriptors are then passed down to actual packet out rotuines
in Depend.c.
Each buffer chunk in a BufferDescriptor chain is capable of holding,
describing or pointing-to two types of data: an out-board buffer
of some type (either "char *" or opaque, as described later) and an
on-board data buffer. A single "chunk" can contain both, in which
case the on-board data is prepended to the out-board data; that is,
the on-board data is treated as a header for the out-board data.
One core assumption is that there is some sort of "gather send"
capability is provided by the underlying hardware. If no such "gather
send" capability exists, multiple-chunk-buffer-descriptors will
need to be coalesced into a single chunk before being passed down to
the actual hardware send routines.
This, above mentioned, coalescing, could be a real performance problem
in a router that does not support gather send. For this reason there
is a "prependInPlace" flag kept in the BufferDescriptor. If this flag
is set, requests to AllocateHeader will NOT create a new link in the
buffer chain, but WILL simply move the exisitng pointer BACKWARDS in
memory and increment the known size of the existing chunk! Thus, it is
assumed that there exists preceding space sufficient to hold the
requested header(s). WATCH OUT FOR THIS!
It is likely that the router will set the "prependInPlace" flag, because
there is a slight performance win even if gather send is supported (less
allocating and freeing, only a single chunk to transmit). If this is
being done, incoming packets MUST have sufficient space allocated
preceding the Ddp datagram for the incoming header to be replaced with
a new (and possibly longer) Ddp, 802.2 and data link headers. Keep in
mind Token Ring source routing... that can take alot of header space!
One other note on "prependInPlace": each BufferDescriptor has a certain
amount of on-board buffer space, if a new header (a call to
AllocateHeader) can be fit into this space we will do it regardeless of
the setting of the "prependInPlace" flag.
#if defined(Xyplex)
In Xyplex's port, there is a standard "packet" structure, this is a
"header" containing flags and a pointer to a separate data buffer
(this data buffer is big enough to hold a complete max-link-sized
buffer). They don't want to transmit (or have at all) "chunked"
expressions. So, in this environment, AllocateHeader has been
modified to, when allocating a completely new chain (no existing
header to prepend to) to set "outBoardBuffer" to point to a newly
allocated "packet" structure and to set "outBoardData" to the start
of the separate data buffer plus "MaximumHeaderLength +
LongDdpHeaderLength." "OutBoardAllocatedSize" will be set to
the requested header size plus "MaximumHeaderLength +
LongDdpHeaderLength" while "outBoardSize" will be set to the
requested size. This will allow subsequent calls to AllocateHeader
(that are really attempting to pre-pend a header) to just "back
up" and use more space in the separate data buffer. The result
being always a single outBoard chunk of contiguous data, just what
they want.
If the above strategy is going to be used from higher levels of the
protocol stack that do not directly call Ddp (e.g. Asp and Pap),
additional header space will need to be reserved. Rather than using
"MaximumHeaderLength + LongDdpHeaderLength," "MaximumHeaderLength +
LongDdpHeaderLength + AtpHeaderSize" would need to be used.
When transmitting, the "packet" structure wants to be updated to
cause the transmit to start at the current "outBoardData" pointer's
value and to transmit "outBoardSize" bytes from there.
On freeing, this "packet" and separate data buffer is always
returned to the "system" -- we set MaxKeptBufferBytes to zero, so we
just retain the BufferDescriptor itself.
Note that this breaks the implied rule that "outBoardBuffer" is always
less than or equal to "outBoardData," but we won't (or at least
shouldn't) get into any trouble.
#endif
*/
/* We allow small buffers to be stored internal to the buffer descriptor
to reduce memory thrashing for things such as Atp header & user bytes.
This functionality can be disabled by defining MaxOnBoardBytes to be
zero (0). */
#if Iam a WindowsNT
#define MaxOnBoardBytes (MaximumHeaderLength + LongDdpHeaderLength + 4 + 4)
/* Max link hdr + long Ddp hdr +
Atp hdr + Atp user bytes */
#elif defined(Xyplex)
#define MaxOnBoardBytes 0 /* See above comments. */
#else
#define MaxOnBoardBytes (4 + 4) /* ATP header & user bytes */
#endif
/* The out-board data buffer described by each chunk in a BufferDescriptor
chain can be of one of two types: either an actual data buffer (char *)
or an opaque "data descriptor" in some system dependent format (void *).
In the first case, the data may be a data buffer dynamically
allocated by the BufferDescriptor routines, or it may be a "user buffer"
that a BufferDescriptor was created to describe.
In the second case, the buffer descriptor was simply created to describe a
a system-dependent "user buffer" (or buffer chain, maybe) that the portable
code will never actually touch... it will just be an entry in the buffer
chain that is eventually passed down to the "depend()" routines for
transmission. "outBoardSize" will always reflect the actual (total) length
of this opaque entity.
The flag "opaqueData" is used to distinguish which of the two cases apply
to each BufferDescriptor in a chain; if the flag is True, we have the
second case; if the flag is False, we have the first case.
If we need to build a BufferDescriptor for less than all of an incoming
"opaque data descriptor" we will call a system dependent routine build
one of these "opaque data descriptors" for the size that we need. In this
case, this newly created "opaque data descriptor" might need to be freed
when the transmit completes; to signify this we use the
"freeOpaqueDataDescriptor" flag.
A note on the out-board data buffer (the first case, above):
"outBoardAllocatedSize" always is the actual allocated size of the data
buffer; "outBoardSize" is the "in use" size of the data buffer;
"outBoardBuffer" always points to the start of the buffer; "outBoardData"
points to the start of the "in use" data. In the second case (above;
opaque data) "outBoardAllcoatedSize" and "outBoardSize" will always be
the same, and "outBoardBuffer" and "outBoardData" will always be the
same (the start of the opaque thing or its system dependent descriptor).
This same set of rules basically holds for the on-board data except that
the "allocated" size is fixed (at MaxOnBoardBytes); "outBoardSize" is the
actual "in use" size of the on-board data buffer; the "onBoardData"
pointer fills the role of "outBoardData," pointing at the "in use" portion
of the on-board data buffer: "onBoardBuffer."
*/
typedef struct buffDesc { struct buffDesc far *next;
/* Next chunk in list. */
int outBoardDataValid : 1,
/* Does this chunk contain
valid out-board data? */
onBoardDataValid : 1,
/* Does this chunk contain
valid on-board data? */
opaqueData : 1, /* If outBoardDataValid,
is the data "opaque" or
is it a real "char *"
buffer? See the above
comments. */
freeData : 1, /* When this chunk is freed,
should the non-opaque out-
data buffer also be freed?
Valid only if outBoardData-
Valid and Not opaqueData. */
prependInPlace : 1,
/* See above comments. Valid
only if outBoardDataValid
and Not opaqueData. */
freeOpaqueDataDescriptor : 1,
/* See above comments, valid
only if outBoardDataValid
and opaqueData is True. */
dummmyLastFlag : 1;
long outBoardSize; /* Size, in bytes, of the
out-board data in this
chunk. Valid only if
outBoardDataValid is
True. */
long outBoardAllocatedSize;
/* The size, in bytes, of the
space actually allocated for
for the out-board buffer;
will be great than or equal
to outBoardSize. */
long onBoardSize; /* Size, in bytes, of the
on-board data in this
chunk. Valid only if
onBoardDataValid is
True. */
char far *data; /* The actual "write position"
within this chunk; where
the newest alloacted header
should be filled in. This
should be set to either
outBoardData or onBoardData
depending on where the most
"recent" header was
allocated. Note that we
will never directly write
into opaque data. */
char far *outBoardBuffer;
/* Data for this chunk: a
real "char *" buffer if
opaqueData is False;
an "opaque thing" if
opaqueData is True;
This pointer SHOULD NOT be
modified. Only valid if
"outBoardDataValid" is
True.*/
char far *outBoardData;
/* The start of "in use"
portion of the out-board
data, generally it will be
the same as "outBoard-
Buffer," but if only a
subsequent portion is
used, it will point to the
start location. This will
always be the same as
"outBoardBuffer" if
"opaqueData" is True.
Only valid if
"outBoardDataValid" is
True. */
char far *onBoardData; /* The start of the "in use"
part of "onBoardBuffer;"
only valid if
"onBoardDataValid" is
True. */
char onBoardBuffer[MaxOnBoardBytes];
/* On board data for smallish
chunks. */
TransmitCompleteHandler *transmitCompleteHandler;
/* If the higher levels want
transmit complete
notification, we fill in
the routine here. */
long unsigned userData;
/* User data for the above
call. */
AppleTalkErrorCode errorCode;
/* The transmit's completion
code, set to ATnoError
by default. */
OpenSocket openSocket; /* The socket on whos behalf
we're doing a transmit,
so we can keep a Link to
the socket during the
operation. */
} far *BufferDescriptor;
/* To futher reduce memory thrashing we keep a list of free buffer descriptors.
These may, or may not, have a valid (non-on-board) data buffer along with
them. The maximum non-on-board data buffer that we will keep around is
as follows. It's large enough to hold the largest header that will need
to be prepended to a Ddp datagram.
If this size is smaller than MaxOnBoardBytes, this functionality will
efectively be disabled. */
#if defined(Xyplex)
#define MaxKeptBufferBytes 0 /* See comments at header. */
#else
#define MaxKeptBufferBytes (MaximumHeaderLength + LongDdpHeaderLength)
#endif
/* The list of free buffer descriptrs is anchored here. Note that if we free
a buffer descriptor and the data is free-able and larger than
MaxKeptBufferBytes, we will free the data and set the out-board size to
zero. The buffer descriptor itself could then be reused. We will also
do this when we free a buffer descriptor that describes memory that is
not ours (i.e. a buffer descriptor for user suppiled buffering; the
freeData bit was reset when the free was requested). */
#ifndef InitializeData
extern
#endif
BufferDescriptor freeBufferDescriptorList;
#ifndef InitializeData
extern
#endif
int freeBufferDescriptorCount;
/* We will keep maximum of the following number of buffer descriptors on the
above list. */
#define MaxFreeBufferDescriptors 30
/* Allocate and attach a new header to an existing buffer chain. The data
will be marked as free-able. */
extern BufferDescriptor far AllocateHeader(BufferDescriptor chain,
long size);
/* Attach an existing chunk of data to an exisitng buffer chain. The data
will be marked as non-free-able. */
extern BufferDescriptor far AttachHeader(BufferDescriptor chain,
long size,
char far *data,
Boolean opaqueData);
/* Free a buffer chain and its assocciated free-able data. */
extern void far FreeBufferChain(BufferDescriptor chain);
/* Compute the actual, in use, size of a buffer chain. */
extern long far SizeOfBufferChain(BufferDescriptor chain);
/* Compute the Ddp checksum of a buffer chain. */
extern short unsigned far DdpChecksumBufferChain(BufferDescriptor chain,
long actualLength,
long leadingBytesToSkip);
/* Given a buffer descriptor, adjust the most recent header to reflect new
"in use" pointers and sizes. A negative adjustment cause less data to
be considered "in use," a positive adjustment causes more data to be
considered "in use." */
extern void far AdjustBufferDescriptor(BufferDescriptor descriptor,
long adjustment);
/* Given a multi-chunk buffer chain, coalesce it into a single chunk
chain and free the orignal. */
extern BufferDescriptor far CoalesceBufferChain(BufferDescriptor chain);
/* Create a copy of a buffer descriptor (basically the same as
CoalesceBufferChain, but don't free the orignal). */
extern BufferDescriptor far CopyBufferChain(BufferDescriptor chain);
/* Given a buffer descriptor chain, create a new one describing a subset of
the original. This routine generally does not copy any data, so the
original buffer descriptor may not be freed before the subset descriptor
is freed. */
extern BufferDescriptor far SubsetBufferDescriptor(BufferDescriptor chain,
long offset, long size);
/* Move a specified amount of data from "out-board data" to a "char *"
buffer. This routine handles both "char *" and "opaque" out-board
data. */
extern void far MoveOutBoardData(char far *target, BufferDescriptor chunk,
long offset, long size);
/* Move opaque data to a "char *" buffer. */
extern void far MoveFromOpaque(char far *target, void far *opaque,
long offset, long size);
/* Move a "char *" buffer to opaque data. */
extern void far MoveToOpaque(void far *opaque, long offset,
char far *buffer, long size);
/* Move an opaque buffer to an opaque buffer. Overlapping areas should
work "correctly" this routine is used to "synch-up" Atp responses. */
extern void far MoveOpaqueToOpaque(void far *targetOpaque, long targetOffset,
void far *sourceOpaque, long sourceOffset,
long size);
/* The "strlen()" function for opaque data. */
extern size_t far StrlenOpaque(void far *opaque, long offset);
/* Make an opaque data descriptor for a specified "char *" buffer. The
last argument is returned as True if the returned descriptor is a "real
thing" that must be freed when we're done with it (this refers to the
descriptor, not the described data). */
extern void far *MakeOpaqueDataDescriptor(char far *buffer, long size,
Boolean far
*freeOpaqueDataDescriptor);
/* Given an opaque data descriptor, create a new opaque data descriptor that
describes a subset of the original -- leave the original unmodified. The
last argument is returned as True if the returned descriptor is a "real
thing" that must be freed when we're done with it (this refers to the
descriptor, not the described data). */
extern void far * far SubsetOpaqueDataDescriptor(void far *master,
long offset,
long size,
Boolean far
*freeOpaqueDataDescriptor);
/* Free and opaque data descriptor; this frees the descriptor NOT the data.
This routine will be used to free descriptors that were created by the
stack when "subsetting" passed opaque data descriptors. */
extern void far FreeOpaqueDataDescriptor(void far *descriptor);
/* Allocate a new buffer chunk. The data will be marked as free-able. */
#define NewBufferDescriptor(size) AllocateHeader(Empty, size)
/* Create a buffer chunk for an existing chunk of data. The data will be
marked as non-free-able. */
#define DescribeBuffer(size, data, opaque) AttachHeader(Empty, size, \
data, opaque)