mirror of https://github.com/lianthony/NT4.0
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
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)
|