Please wait until the page is fully downloaded and then press the "Expand" button or the blue line numbers.

0002001 /*
0002002 This file contains routines for buffer management.
0002003 
0002004 Copyright 1995 Philip Homburg
0002005 */
acc_freelist / buf512_freelist / accessors[] , buffers512[]

While being processed by the network service, packets and configuration data are temporarily stored in buffers associated with struct's named "accessors". These accessors are chained together to form linked lists and can be manipulated by a number of functions. There are two linked lists of signifigance in buf.c: acc_freelist and buf512_freelist. After initialization, these linked lists are as follows:



where the elements of buffers512[] are of type buf512_t:

typedef struct buf512 

{
buf_t buf_header;
char buf_data[512]; /* the user data is found here */
} buf512_t

typedef struct buf
{
int buf_linkC;
buffree_t buf_free;
size_t buf_size;
char *buf_data_p;
} buf_t;
and the elements of accessors[] are of type acc_t:

typedef struct acc

{
int acc_linkC;
int acc_offset, acc_length;
buf_t *acc_buffer;
struct acc *acc_next, *acc_ext_link;
} acc_t;
The fields of these struct's are described in the context of the functions that access them.

buf512_freelist is the linked list of accessors that have associated buffers and acc_freelist is the linked list of accessors that do not have associated buffers. When a buffer is needed, an accessor from buf512_freelist is taken (see bf_memreq() below). When a single accessor or a segment of the linked list is duplicated, the duplicate accessor is taken from acc_freelist (see bf_dupacc() and bf_cut() below).

If an accessor is at the beginning of a linked list or if only a single accessor is referencing it, acc_linkC will be one. If more than one accessor references another accessor, however, acc_linkC for the referenced accessor will be greater than one. Similarly, if only a single accessor references a buffer, buf_linkC will be one. If more than one accessor references a buffer, the buffer's buf_linkC will be greater than one. For two good examples of functions that affect acc_linkC/buf_linkC, see bf_dupacc() and bf_cut() below.

As with other queues within the network service, the memory for the acc_freelist queue and the buf512_freelist queue (and its associated buffers) come from arrays with a limited number of elements. This must be done because memory within Minix is scarce (for one reason, Minix does not have virtual memory).

When buffer space for data is needed (for example, for an incoming ethernet packet), bf_memreq() is called to acquire the space. For example, if ETH_MAX_PACK_SIZE (#define'd as 1514) bytes of buffer space are required, bf_memreq() will remove 3 accessors from buf512_freelist and will return a pointer to the first accessor:



If an accessor needs to be duplicated, bf_dupacc() is called. For example, if acc (see figure below) is needed to be duplicated, bf_dupacc(acc) will return new_acc:



Note that the buf_linkC of buffers512[127] and the acc_linkC of accessors[65] are incremented to 2. Also note that the accessor returned by bf_dupacc() (in this case, new_acc) is taken from acc_freelist and not from buf512_freelist.

After a chain of accessors is no longer needed, the chain can be freed by calling bf_free(). However, if either acc_linkC or buf_linkC of one of the accessors or their associated buffers in the linked list is not equal to one, then the entire chain will not be freed. For example, if buf_afree(acc1) is called for the following chain:



Then the resulting chain will be:



bf_afree() returns acc1 (accessors[63]) to acc_freelist (recall that acc_freelist is the linked list of acc_t's without an associated buffer). However, buffers512[127] cannot be freed because acc2 (accessors[64]) still references it.

bf_afree() is called after an accessor's associated data is no longer needed (for example, after a packet has been sent off by the ethernet driver).

If a section of a linked list needs to be duplicated (as opposed to a single accessor - see bf_dupacc() above), bf_cut() is called. For example, if a section of length 50 starting at an offset of 75 of the linked list below needs to be duplicated, bf_cut(data, 75, 50) is called:



bf_cut() is used in a number of scenarios, including cutting a received ethernet packet to size. bf_afree() is generally called after bf_cut() to free up the original accessor linked list.

If only the beginning of a linked list can be freed, bf_delhead() is called. If acc_linkC and buf_linkC are one for all of the relevant accessors and their associated buffers in the linked list, the operation is straight-forward:



bf_delhead() is often called to remove the header (e.g., ip header) from a packet. Note that the buffers of the accessors returned to the buf512_freelist have their buf_linkC field set to zero (0).

bf_append() appends one accessor linked list to another accessor linked list. For example, if the payload of an ethernet packet (1500 bytes) is appended to an ethernet header (14 bytes):



the resulting linked list is as follows:



If data is not already packed and aligned, bf_align(acc, size, alignment) packs SIZE bytes from ACC, a linked list of accessors, by calling bf_pack(). This packing is necessary to ensure that all of the fields from a header are easily accessed. For example, the ip code aligns a packet's header contained in the accessors before accessing the various ip header fields.


0002006 
0002007 #define BUF_IMPLEMENTATION       1       /* Avoid some macros */
0002008 
0002009 #include "inet.h"
0002010 
0002011 #include <stdlib.h>
0002012 #include <string.h>
0002013 
0002014 #include "generic/assert.h"
0002015 #include "generic/buf.h"
0002016 #include "generic/type.h"
0002017 
0002018 THIS_FILE
0002019 
0002020 #ifndef BUF_USEMALLOC
0002021 #define BUF_USEMALLOC       0
0002022 #endif
0002023 
0002024 #ifndef BUF512_NR
0002025 #if CRAMPED
CRAMPED

CRAMPED is #define'd in inet.h as 0 for an 80836 processor or better and 1 for anything less (e.g., 8086). In the figures and discussions in this documentation, it is assumed that the system is an 80836 or better.

If the system is not even an 80386, it is a fair assumption that there is not much memory to work with (i.e., the memory is "cramped").


0002026 #define BUF512_NR       32
0002027 #else
0002028 #define BUF512_NR       128
On line 2071, an array of BUF512_NR (128) buffer elements (of type buf512_t - see line 2059) elements is created. These buffers are used to build outgoing packets and store incoming packets. These buffers are associated with accessors in the manner described at the top of this file.


0002029 #endif
0002030 #endif
0002031 #ifndef BUF2K_NR
0002032 #define BUF2K_NR       0
0002033 #endif
0002034 #ifndef BUF32K_NR
0002035 #define BUF32K_NR       0
0002036 #endif
0002037 
0002038 #define ACC_NR              ((BUF512_NR+BUF2K_NR+BUF32K_NR)*3/2)
Assuming that BUF2K_NR and BUF32K_NR are 0 (which is the default), ACC_NR will be 192.

ACC_NR = (128 + 0 + 0) * 3/2 = 192


0002039 #define CLIENT_NR       6
The six "clients" are ethernet (0), psip (1), ip (2), icmp (3), tcp (4), and udp (5). For more details, see bf_logon() on line 2199.


0002040 
0002041 #define DECLARE_TYPE(Tag, Type, Size)                                   \
0002042          typedef struct Tag                                          \
0002043          {                                                        \
0002044                   buf_t buf_header;                                   \
0002045                   char buf_data[Size];                                   \
0002046          } Type
0002047 

/* The following is not used for the default configuration.





0002048 #if BUF_USEMALLOC
0002049 #define DECLARE_STORAGE(Type, Ident, Nitems)                            \
0002050          PRIVATE Type *Ident
0002051 
0002052 #define ALLOC_STORAGE(Ident, Nitems, Label)                            \
0002053          do                                                        \
0002054          {                                                        \
0002055                   printf("buf.c: malloc %d %s\n", Nitems, Label);              \
0002056                   Ident= malloc(sizeof(*Ident) * Nitems);                     \
0002057                   if (!Ident)                                          \
0002058                            ip_panic(( "unable to alloc %s", Label ));       \
0002059          } while(0)
do while(0)

Note that the do loop in the macro ends with "while(0)". Therefore, this loop will execute only once.

Here is an explanation of this construct (from Steve Summit - scs@eskimo.com):

10.4:	What's the best way to write a multi-statement macro?


A: The usual goal is to write a macro that can be invoked as if it
were a statement consisting of a single function call. This
means that the "caller" will be supplying the final semicolon,
so the macro body should not. The macro body cannot therefore
be a simple brace-enclosed compound statement, because syntax
errors would result if it were invoked (apparently as a single
statement, but with a resultant extra semicolon) as the if
branch of an if/else statement with an explicit else clause.

The traditional solution, therefore, is to use

#define MACRO(arg1, arg2) do { \
/* declarations */ \
stmt1; \
stmt2; \
/* ... */ \
} while(0) /* (no trailing ; ) */

When the caller appends a semicolon, this expansion becomes a
single statement regardless of context. (An optimizing compiler
will remove any "dead" tests or branches on the constant
condition 0, although lint may complain.)



0002060 #else

*/



0002061 #define DECLARE_STORAGE(Type, Ident, Nitems)                            \
0002062          PRIVATE Type Ident[Nitems]
0002063 
0002064 #define ALLOC_STORAGE(Ident, Nitems, Label)                            \
0002065          (void)0
In other words, do nothing if malloc() is not used to allocate space for the buffers. By default, malloc() is not used. Instead, the global variable buffers512[] is used for the buffer space.


0002066 #endif
0002067 
0002068 #if BUF512_NR
0002069 DECLARE_TYPE(buf512, buf512_t, 512);
The macro DECLARE_TYPE() is #define'd on line 2041. DECLARE_TYPE(buf512, buf512_t, 512) produces the following code:

typedef struct buf512

{
buf_t buf_header;
char buf_data[512];
} buf512_t

typedef struct buf
{
int buf_linkC;
buffree_t buf_free;
size_t buf_size;
char *buf_data_p;
} buf_t;
Click here for a description of the preceding struct's.


0002070 PRIVATE acc_t *buf512_freelist;
0002071 DECLARE_STORAGE(buf512_t, buffers512, BUF512_NR);
The macro DECLARE_STORAGE() is #define'd on lines 2061-2062. DECLARE_STORAGE(buf512_5, buffers512, BUF512_NR) produces the following code:

PRIVATE buf512_5 buffers512[BUF512_NR]

where BUF512_NR is #define'd above as 128.

So there will be will be 128 buffers with a storage of 512 bytes (.5 KB) each for a total of 64KB. This value is equal to the maximum size of an IPv4 datagram. However, data link protocols typically do not produce datagrams of this size.

Click here for a description of the preceding array.



0002072 FORWARD void bf_512free ARGS(( acc_t *acc ));
0002073 #endif
0002074 #if BUF2K_NR
0002075 DECLARE_TYPE(buf2K, buf2K_t, (2*1024));
0002076 PRIVATE acc_t *buf2K_freelist;
0002077 DECLARE_STORAGE(buf2K_t, buffers2K, BUF2K_NR);
0002078 FORWARD void bf_2Kfree ARGS(( acc_t *acc ));
0002079 #endif
0002080 #if BUF32K_NR
0002081 DECLARE_TYPE(buf32K, buf32K_t, (32*1024));
0002082 PRIVATE acc_t *buf32K_freelist;
0002083 DECLARE_STORAGE(buf32K_t, buffers32K, BUF32K_NR);
0002084 FORWARD void bf_32Kfree ARGS(( acc_t *acc ));
0002085 #endif
0002086 
0002087 PRIVATE acc_t *acc_freelist;
0002088 DECLARE_STORAGE(acc_t, accessors, ACC_NR);
The macro DECLARE_STORAGE() is #define'd on lines 2061-2062. DECLARE_STORAGE(acc_t, accessors, ACC_NR) produces the following code:

PRIVATE acc_t accessors[ACC_NR]

where ACC_NR is #define's above as 192.

Click here for a description of this array.


0002089 
0002090 PRIVATE bf_freereq_t freereq[CLIENT_NR];
freereq[] is an array of pointers to functions that consists of 6 elements. CLIENT_NR is #define'd as 6 and is the number of clients in the network service (eth, psip, ip, icmp, tcp, and udp; see bf_logon() on line 2199). These functions free buffers used by their respective client. For example, the element in freereq[] corresponding to the ethernet client is eth_buffree().

bf_freereq_t is declared as a type in buf.h:

typedef void (*bf_freereq_t) ARGS(( int priority ));

In other words, a variable of type bf_freereq_t is a pointer to a function that returns a void and takes an int as a parameter.



0002091 PRIVATE size_t bf_buf_gran;
0002092 
0002093 PUBLIC size_t bf_free_bufsize;
bf_free_bufsize is the size of all the buffers that are associated with acc's on the buf512_freelist.


0002094 PUBLIC acc_t *bf_temporary_acc;
0002095 

/* The following is not used for the default configuration.





0002096 #ifdef BUF_CONSISTENCY_CHECK
0002097 int inet_buf_debug;
0002098 unsigned buf_generation;
0002099 PRIVATE bf_checkreq_t checkreq[CLIENT_NR];
0002100 #endif

*/



0002101 
0002102 #ifndef BUF_TRACK_ALLOC_FREE
0002103 FORWARD acc_t *bf_small_memreq ARGS(( size_t size ));
0002104 #else
0002105 FORWARD acc_t *_bf_small_memreq ARGS(( char *clnt_file, int clnt_line,
0002106                                                         size_t size ));
0002107 #define bf_small_memreq(a) _bf_small_memreq(clnt_file, clnt_line, a)
0002108 #endif
0002109 FORWARD void free_accs ARGS(( void ));
0002110 #ifdef BUF_CONSISTENCY_CHECK
0002111 FORWARD void count_free_bufs ARGS(( acc_t *list ));
0002112 FORWARD int report_buffer ARGS(( buf_t *buf, char *label, int i ));
0002113 #endif
0002114 
0002115 PUBLIC void bf_init()
bf_init()

bf_init() is called by nw_init(). bf_init() allocates space for buffers512[] and accessors[] and initializes buf512_freelist and acc_freelist.


0002116 {
0002117          int i;
0002118          size_t size;
0002119          size_t buf_s;
0002120          acc_t *acc;
0002121 
0002122          bf_buf_gran= BUF_S;
BUF_S is #define'd in inet/const.h:

#define BUF_S 512


0002123          buf_s= 0;
0002124 
0002125          for (i=0;i<CLIENT_NR;i++)
CLIENT_NR is #define'd as 6 and corresponds to the 6 "clients": eth (0), psip (1), ip (2), icmp (3), tcp (4), and udp (5). freereq[] is an array of pointers to functions that free buffers used by their respective clients (by calling bf_afree()). The loop here simply sets each element to null. bf_logon(), on the other hand, sets these elements to meaningful values. For example, the ethernet code calls bf_logon() to set the ethernet element to eth_buffree().


0002126                   freereq[i]=0;

/* The following is not used for the default configuration.





0002127 #ifdef BUF_CONSISTENCY_CHECK
0002128          for (i=0;i<CLIENT_NR;i++)
0002129                   checkreq[i]=0;
0002130 #endif
*/



0002131 
0002132 #if BUF512_NR
BUF512_NR is #define'd above as 128 if it's not CRAMPED (i.e., not in real mode). BUF2K_NR and BUF32K_NR are both #define'd as 0.


0002133          ALLOC_STORAGE(buffers512, BUF512_NR, "512B-buffers");
The macro ALLOC_STORAGE is #define'd on line 2064. For the current configuration (BUF_USEMALLOC is not defined), ALLOC_STORAGE does nothing.


0002134 #endif

/* The following is not used for the default configuration.





0002135 #if BUF2K_NR
0002136          ALLOC_STORAGE(buffers2K, BUF2K_NR, "2K-buffers");
0002137 #endif
0002138 #if BUF32K_NR
0002139          ALLOC_STORAGE(buffers32K, BUF32K_NR, "32K-buffers");
0002140 #endif
0002141          ALLOC_STORAGE(accessors, ACC_NR, "accs");
*/



0002142 
0002143          acc_freelist= NULL;
0002144          for (i=0;i<ACC_NR;i++)
This for loop zeroes out all of the accessors and initializes the acc_freelist linked list. Note, however, that these accessors are altered immediately after the loop by INIT_BUFFERS (see below).



0002145          {
0002146                   memset(&accessors[i], '\0', sizeof(accessors[i]));
0002147 
0002148                   accessors[i].acc_linkC= 0;
0002149                   accessors[i].acc_next= acc_freelist;
0002150                   acc_freelist= &accessors[i];
0002151          }
0002152 
INIT_BUFFERS is #define'd below and then called immediately after the #define (see line 2185).

INIT_BUFFERS initializes several fields of the accessors and their associated buffers.



0002153 #define INIT_BUFFERS(Ident, Nitems, Freelist, Freefunc)                     \
0002154          do                                                        \
0002155          {                                                        \
0002156                   Freelist= NULL;                                          \
0002157                   for (i=0;i<Nitems;i++)                                   \
0002158                   {                                                 \
0002159                            acc= acc_freelist;                            \
0002160                            if (!acc)                                   \
0002161                                     ip_panic(( "fewer accessors than buffers")); \
0002162                            acc_freelist= acc->acc_next;                     \
0002163                            acc->acc_linkC= 0;                            \
0002164                                                                      \
0002165                            memset(&Ident[i], '\0', sizeof(Ident[i]));       \
0002166                            Ident[i].buf_header.buf_linkC= 0;              \
0002167                            Ident[i].buf_header.buf_free= Freefunc;              \
When called from line 2184, Freefunc is bf_512free() (see line 2840). bf_512free() simply sticks the acc_t back on buf512_freelist, making the buffer available for future buffer requests.


0002168                            Ident[i].buf_header.buf_size=                     \
0002169                                     sizeof(Ident[i].buf_data);              \
0002170                            Ident[i].buf_header.buf_data_p=                     \
buf_data_p is a pointer to the actual data.


0002171                                     Ident[i].buf_data;                     \
0002172                                                                        \
0002173                            acc->acc_buffer= &Ident[i].buf_header;              \
0002174                            acc->acc_next= Freelist;                     \
0002175                            Freelist= acc;                                   \
0002176                   }                                                 \
0002177                   if (sizeof(Ident[0].buf_data) < bf_buf_gran)              \
0002178                            bf_buf_gran= sizeof(Ident[0].buf_data);              \
0002179                   if (sizeof(Ident[0].buf_data) > buf_s)                     \
0002180                            buf_s= sizeof(Ident[0].buf_data);              \
0002181          } while(0)
do while(0)

Note that the do loop in the macro ends with "while(0)". Therefore, this loop will execute only once.

Here is an explanation of this construct (from Steve Summit - scs@eskimo.com):

10.4:	What's the best way to write a multi-statement macro?


A: The usual goal is to write a macro that can be invoked as if it
were a statement consisting of a single function call. This
means that the "caller" will be supplying the final semicolon,
so the macro body should not. The macro body cannot therefore
be a simple brace-enclosed compound statement, because syntax
errors would result if it were invoked (apparently as a single
statement, but with a resultant extra semicolon) as the if
branch of an if/else statement with an explicit else clause.

The traditional solution, therefore, is to use

#define MACRO(arg1, arg2) do { \
/* declarations */ \
stmt1; \
stmt2; \
/* ... */ \
} while(0) /* (no trailing ; ) */

When the caller appends a semicolon, this expansion becomes a
single statement regardless of context. (An optimizing compiler
will remove any "dead" tests or branches on the constant
condition 0, although lint may complain.)



0002182 
0002183 #if BUF512_NR
0002184          INIT_BUFFERS(buffers512, BUF512_NR, buf512_freelist, bf_512free);
0002185 #endif
After this macro is executed, accessors[] is as follows:



There are two items of interest in this figure. First, note that only accessors in the buf512_freelist have buffers associated with them. Also, note that all the linkC's (acc_linkC and buf_linkC) are initialized to zero.

bf_512free() (see line 2840) is the function that frees the accessor by simply putting the accessor back on the buf512_freelist. These accessors can then be used for future requests for buffer space.


/* The following is not used in the default configuration.




0002186 #if BUF2K_NR
0002187          INIT_BUFFERS(buffers2K, BUF2K_NR, buf2K_freelist, bf_2Kfree);
0002188 #endif
0002189 #if BUF32K_NR
0002190          INIT_BUFFERS(buffers32K, BUF32K_NR, buf32K_freelist, bf_32Kfree);
0002191 #endif
*/



0002192 
0002193 #undef INIT_BUFFERS
0002194 
0002195          assert (buf_s == BUF_S);
0002196 }
0002197 
0002198 #ifndef BUF_CONSISTENCY_CHECK
0002199 PUBLIC void bf_logon(func)
0002200 bf_freereq_t func;
bf_logon()

bf_logon() is used by eth_init(), psip_init(), ip_init(), icmp_init(), tcp_init(), and udp_init() to register their functions for freeing buffers. For example, eth_init() calls bf_logon() with an argument of eth_buffree().

After bf_logon() is finished, freereq[] is configured as follows:

freereq[0]=eth_buffree
freereq[1]=psip_buffree
freereq[2]=ip_buffree
freereq[3]=icmp_buffree
freereq[4]=tcp_buffree
freereq[5]=udp_buffree



0002201 #else
0002202 PUBLIC void bf_logon(func, checkfunc)
0002203 bf_freereq_t func;
0002204 bf_checkreq_t checkfunc;
0002205 #endif
0002206 {
0002207          int i;
0002208 
0002209          for (i=0;i<CLIENT_NR;i++)
0002210                   if (!freereq[i])
The first time that bf_logon() is called, freereq[0] is set and bf_logon() returns; the second time bf_logon() is called, freereq[1] is set and bf_logon()() returns and so on.

The first "client" to call bf_logon() is the ethernet code followed by the psip code, the ip code, the icmp code, the tcp code, and then finally the udp code.


0002211                   {
0002212                            freereq[i]=func;
0002213 #ifdef BUF_CONSISTENCY_CHECK
0002214                            checkreq[i]= checkfunc;
0002215 #endif
0002216                            return;
0002217                   }
0002218 
0002219          ip_panic(( "buf.c: to many clients" ));
0002220 }
0002221 
0002222 /*
0002223 bf_memreq
0002224 */
0002225 
0002226 #ifndef BUF_TRACK_ALLOC_FREE
0002227 PUBLIC acc_t *bf_memreq(size)
bf_memreq()

After the buffers have been initialized, accessors[] looks like the following:



bf_memreq() allocates accessors to the caller. For example, if 1514 bytes of buffer space are requested immediately after the network process starts and each buffer is 512 bytes (the default), then accessors[] will look like the following:



Note that three elements of accessors[] have been removed from buf512_freelist and that the head of the chain of the 3 accessors is returned by bf_memreq(). Also note that the acc_linkC and buf_linkC fields have been set to one and acc_length and acc_offset have been set to their appropriate values.

So what happens if there are not enough buffers on the buf512_freelist to satisfy a request? On lines 2280-2290 of buf.c, functions that free buffers for the specific clients (e.g., eth_buffree()) are called until there are enough buffers on buf512_freelist.

For a complete description of the network service's buffer management, click here.


0002228 #else
0002229 PUBLIC acc_t *_bf_memreq(clnt_file, clnt_line, size)
0002230 char *clnt_file;
0002231 int clnt_line;
0002232 #endif
0002233 size_t size;
size_t is declared in include\sys\types.h:

typedef unsigned int size_t;

Variables of type size_t hold the results of the sizeof operator.



0002234 {
0002235          acc_t *head, *tail, *new_acc;
0002236          buf_t *buf;
0002237          int i,j;
0002238          size_t count;
0002239 
0002240          assert (size>0);
0002241 
0002242          head= NULL;
0002243          while (size)
0002244          {
0002245                   new_acc= NULL;
0002246 
0002247                   /* Note the tricky dangling else... */
The author is referring to the "else" on line 2260. This "else" is implemented with the macro that follows.


0002248 #define ALLOC_BUF(Freelist, Bufsize)                                   \
0002249          if (Freelist && (Bufsize == BUF_S || size <= Bufsize))              \
BUF_S is #define'd in const.h as 512. If this conditional holds true, buffer space is still needed and exists in Freelist (for our configuration, buf512_freelist) and is ready to be allocated. This macro removes one of the accessors off the Freelist (buf512_freelist).


0002250          {                                                        \
0002251                   new_acc= Freelist;                                   \
0002252                   Freelist= new_acc->acc_next;                            \
0002253                                                                    \
0002254                   assert(new_acc->acc_linkC == 0);                     \
0002255                   new_acc->acc_linkC= 1;                                   \
acc_linkC is nonzero if the accessor is no longer on the acc_freelist or the buf512_freelist. acc_linkC is greater than one if more than one accessors reference the accessor (see comments for line 2001).


0002256                   buf= new_acc->acc_buffer;                            \
0002257                   assert(buf->buf_linkC == 0);                            \
0002258                   buf->buf_linkC= 1;                                   \
0002259          }                                                        \
0002260          else
0002261 
0002262                   /* Sort attempts by buffer size */
The macro above is substituted at line 2264.


0002263 #if BUF512_NR
0002264                   ALLOC_BUF(buf512_freelist, 512)
0002265 #endif

/* The following is not used for the default configuration.




0002266 #if BUF2K_NR
0002267                   ALLOC_BUF(buf2K_freelist, 2*1024)
0002268 #endif
0002269 #if BUF32K_NR
0002270                   ALLOC_BUF(buf32K_freelist, 32*1024)
0002271 #endif
*/



0002272 #undef ALLOC_BUF
When using macros, a good practice is to undefine (#undef) the macro immediately after using it. This helps eliminate name space pollution.

We continue from here on with the "dangling else" (referred to on line 2247). This block helps free up accessors so that they can return to the buf512_freelist. They can then be acquired by this call to bf_memreq().


0002273                   {
0002274                            DBLOCK(1, printf("freeing buffers\n"));
0002275 
0002276                            bf_free_bufsize= 0;
0002277                            for (i=0; bf_free_bufsize<size && i<MAX_BUFREQ_PRI;
This loop first frees up buffers of priority 1 by calling the client (eth, psip, ip, icmp, udp, and tcp) specific functions for freeing buffers with a parameter of 1 (e.g., eth_buffree(1) and then calling the same functions with a parameter of 2 and so on until 10.

MAX_BUFREQ_PRI is #define'd in inet/generic/buf.h:

#define MAX_BUFREQ_PRI 10

Each client is responsible for determining the priority level of an accessor that they have acquired.


0002278                                     i++)
0002279                            {
0002280                                     for (j=0; j<CLIENT_NR; j++)
0002281                                     {
0002282                                              if (freereq[j])
0002283                                                     (*freereq[j])(i);
Call the client specific function for freeing buffers (e.g., eth_buffree()). These functions all call bf_afree() (see line 2347).



0002284                                     }

/* The following is not used for the default configuration.




0002285 #if DEBUG
0002286  { acc_t *acc;
0002287  j= 0; for(acc= buf512_freelist; acc; acc= acc->acc_next) j++;
0002288  printf("# of free 512-bytes buffer is now %d\n", j); }
0002289 #endif
0002290                            }
0002291 #if DEBUG
0002292  { printf("last level was level %d\n", i-1); }
0002293 #endif
*/



0002294                            if (bf_free_bufsize<size)
0002295                                     ip_panic(( "not enough buffers freed" ));
If the attempt to free up buffers is not successful, we've got problems.


0002296 
0002297                            continue;
0002298                   }
The end of the "dangling else".



0002299 

/* The followng is not used for the default configuration.




0002300 #ifdef BUF_TRACK_ALLOC_FREE
0002301                   new_acc->acc_alloc_file= clnt_file;
0002302                   new_acc->acc_alloc_line= clnt_line;
0002303                   buf->buf_alloc_file= clnt_file;
0002304                   buf->buf_alloc_line= clnt_line;
0002305 #endif
*/



0002306 
Place the first accessor at the head of the linked list and all subsequent accessors at the tail.


0002307                   if (!head)
0002308                            head= new_acc;
0002309                   else
0002310                            tail->acc_next= new_acc;
0002311                   tail= new_acc;
0002312 
0002313                   count= tail->acc_buffer->buf_size;
0002314                   if (count > size)
If the size requested is not a multiple of 512, the last accessor will have an acc_length of less than 512.


0002315                            count= size;
0002316 
0002317                   tail->acc_offset= 0;
0002318                   tail->acc_length= count;
0002319                   size -= count;
0002320          }
The end of the "while" loop that started at line 2243.


0002321          tail->acc_next= 0;
0002322 
0002323 #if DEBUG
0002324          bf_chkbuf(head);
0002325 #endif
0002326 
0002327          return head;
0002328 }
0002329 
0002330 /*
0002331 bf_small_memreq
0002332 */
0002333 
0002334 #ifndef BUF_TRACK_ALLOC_FREE
0002335 PRIVATE acc_t *bf_small_memreq(size)
This function is simply a wrapper for bf_memreq() and is called in only one location by bf_append().


0002336 #else
0002337 PRIVATE acc_t *_bf_small_memreq(clnt_file, clnt_line, size)
0002338 char *clnt_file;
0002339 int clnt_line;
0002340 #endif
0002341 size_t size;
0002342 {
0002343          return bf_memreq(size);
0002344 }
0002345 
0002346 #ifndef BUF_TRACK_ALLOC_FREE
0002347 PUBLIC void bf_afree(acc)

/* The following is not used in the default configuration.




0002348 #else
0002349 PUBLIC void _bf_afree(clnt_file, clnt_line, acc)
0002350 char *clnt_file;
0002351 int clnt_line;
0002352 #endif
0002353 acc_t *acc;
bf_afree()

After a chain of accessors is no longer needed, the chain (and not simply the single accessor passed as the parameter) can be freed by calling bf_free(). However, if either acc_linkC or buf_linkC of one of the accessors in the linked list is not equal to one (1), the entire chain will not be freed. For example, if buf_afree(acc1) is called for the following chain:



Then the resulting chain will be:



bf_afree() returns acc1 (accessors[63]) to acc_freelist (recall that acc_freelist is the linked list of acc_t's without an associated buffer). However, buffers512[127] cannot be freed because acc2 (accessors[64]) still references it.

bf_afree() is called after an accessor's associated data is no longer needed (for example, after a packet has been sent off by the ethernet driver).


0002354 {
0002355          acc_t *next_acc;
0002356          buf_t *buf;
0002357 
bf_afree() is a big while loop. Each time around the while loop, either an accessor in the linked list is freed or the loop ends. The loop ends if the accessor is the last element in the linked list or its acc_linkC is greater than one. If the accessor has an acc_linkC greater than one, more than one accessor linked list contains this accessor. For this reason, this accessor cannot be returned to either buf512_freelist or acc_freelist.

An accessor that is freed is returned to either buf512_freelist or acc_freelist. If the accessor's associated buffer has a buf_linkC equal to one, the freed accessor is the only element that is referencing the buffer and so the accessor is returned to buf512_freelist (remember that buf512_freelist contains accessors and their associated buffers). If the associated buffer has a buf_linkC greater than one, the accessor is not the only accessor that is referencing the buffer and so the buffer cannot be freed. For this reason, the freed accessor is returned to acc_freelist and not buf512_freelist (remember that acc_list contains only accessors with no associated buffers).

In the figure below, bf_afree(acc1) is called. This figure shows the state of the linked list at each iteration around the loop.



During the next iteration of the loop, the acc_linkC field of accessors[65] is decremented (line 2366) but the code breaks out of the loop and the function returns.




0002358          while (acc)
0002359          {

/* The following is not used in the default configuration.




0002360 #if defined(bf_afree)
0002361                   DIFBLOCK(1, (acc->acc_linkC <= 0),
0002362                            printf("clnt_file= %s, clnt_line= %d\n",
0002363                            clnt_file, clnt_line));
0002364 #endif
*/



0002365                   assert (acc->acc_linkC>0);
0002366                   if (--acc->acc_linkC > 0)
0002367                            break;
If this accessor is referenced by more than one accessor, do not free this accessor nor any additional accessors (note that bf_afree() immediately returns after this loop is exited).

How does an accessor have a acc_linkC greater than one? See bf_dupacc() on line 2414.



0002368 

/* The following is not used in the default configuration.




0002369 #ifdef BUF_TRACK_ALLOC_FREE
0002370                   acc->acc_free_file= clnt_file;
0002371                   acc->acc_free_line= clnt_line;
0002372 #endif
*/



0002373                   buf= acc->acc_buffer;
0002374                   assert (buf);
0002375 

/* The following is not used in the default configuration.




0002376 #if defined(bf_afree)
0002377                   DIFBLOCK(1, (buf->buf_linkC == 0),
0002378                            printf("clnt_file= %s, clnt_line= %d\n",
0002379                            clnt_file, clnt_line));
0002380 #endif
*/



0002381                   assert (buf->buf_linkC>0);
0002382                   if (--buf->buf_linkC > 0)
buf_linkC for a buffer can be greater than one if more than one accessor references it. For example, for the figure below, the buffer associated with acc2 (buffers512[127]) is referenced by two accessors, acc1 and acc2.



If more than one accessors references an accessor's associated buffer, the accessor will be freed without its associated buffer (i.e., the accessor will be returned to acc_freelist).


0002383                   {
0002384                            acc->acc_buffer= NULL;
0002385                            next_acc= acc->acc_next;
0002386                            acc->acc_next= acc_freelist;
0002387                            acc_freelist= acc;

/* The following is not used in the default configuration.




0002388 #ifdef BUF_CONSISTENCY_CHECK
0002389                            if (inet_buf_debug)
0002390                            {
0002391                                     acc->acc_offset= 0xdeadbeaf;
0002392                                     acc->acc_length= 0xdeadbeaf;
0002393                                     acc->acc_buffer= (buf_t *)0xdeadbeaf;
0002394                                     acc->acc_ext_link= (acc_t *)0xdeadbeaf;
0002395                            }
0002396 #endif
*/



0002397                            acc= next_acc;
0002398                            continue;
0002399                   }
0002400 
0002401                   bf_free_bufsize += buf->buf_size;
bf_free_bufsize is the size of the buffers in buf512_freelist. Increase bf_free_bufsize by the size of the buffer just released.


/* The following is not used in the default configuration.




0002402 #ifdef BUF_TRACK_ALLOC_FREE
0002403                   buf->buf_free_file= clnt_file;
0002404                   buf->buf_free_line= clnt_line;
0002405 #endif
*/



0002406                   next_acc= acc->acc_next;
0002407                   buf->buf_free(acc);
For the current configuration, buf_free is the function bf_512free().

bf_512free() simply puts the acc back on the buf512_freelist linked list. Remember that buf512_freelist is the linked list of all the free accessors that have associated buffers and that acc_freelist is the linked list of all the free accessors that do not have associated buffers.


0002408                   acc= next_acc;
0002409                   continue;
0002410          }
0002411 }
0002412 
0002413 #ifndef BUF_TRACK_ALLOC_FREE
0002414 PUBLIC acc_t *bf_dupacc(acc_ptr)

/* The following is not used in the default configuration.




0002415 #else
0002416 PUBLIC acc_t *_bf_dupacc(clnt_file, clnt_line, acc_ptr)
0002417 char *clnt_file;
0002418 int clnt_line;
0002419 #endif
*/



0002420 register acc_t *acc_ptr;
bf_dupacc()

bf_dupacc(acc_ptr) creates a new accessor that is a duplicate of acc_ptr, bf_dupacc()'s only parameter.

More specifically, bf_dupacc() removes an accessor from acc_freelist and copies the accessor referred to by acc_ptr and sets acc_linkC of the new accessor to one. If acc_next is non-null, bf_dupacc() also increments acc_linkC of acc_next (the next accessor in the linked list). And if acc_buffer is non-null, bf_dupacc() also increments buf_linkC of the buffer.

This process is best described by a diagram:



Note that the link counts (acc_linkC and buf_linkC) for accessors[65] and buffers512[127] are incremented.

Remember that free accessors associated with buffers reside on buf512_freelist and free accessors not associated with buffers reside on acc_freelist. In addition, acc_linkC is one or greater if the accessor is no longer on either of the freelists and is greater than one if more than one accessor refers to it (through acc_next). buf_linkC is one or greater if its associated accessor (or accessors) are not on buf512_freelist and is greater than one if more than one accessor refers to it (through acc_buffer).



0002421 {
0002422          register acc_t *new_acc;
0002423          int i, j;
0002424 
0002425          if (!acc_freelist)
0002426          {
0002427                   free_accs();
free_accs()

If there are no accessors on acc_freelist (the linked list of unused accessors without buffers), bf_dupacc() calls free_accs() to free up accessors. free_accs() goes through all the different priority levels for the 6 different clients (eth, psip, ip, icmp, tcp, and udp), calling the client-specific buffer-freeing functions (e.g., eth_buffree()).


0002428                   if (!acc_freelist)
0002429                            ip_panic(( "buf.c: out of accessors" ));
0002430          }
Recall that acc_freelist contains free accessors that do not have associated buffers. buf512_freelist contains free accessors that have associated buffers. The duplicate accessor comes from acc_freelist.


0002431          new_acc= acc_freelist;
0002432          acc_freelist= new_acc->acc_next;
0002433 
0002434          *new_acc= *acc_ptr;
The new accessor becomes a copy of the accessor passed in (acc_ptr).


0002435          if (acc_ptr->acc_next)
0002436                   acc_ptr->acc_next->acc_linkC++;
0002437          if (acc_ptr->acc_buffer)
0002438                   acc_ptr->acc_buffer->buf_linkC++;
As described in the comments on line 2414, acc_linkC of the next accessor in the linked list is incremented and buf_linkC of the associated buffer is incremented.


0002439          new_acc->acc_linkC= 1;
Indicate that the accessor is in use.


/* The following is not used in the default configuration.




0002440 #ifdef BUF_TRACK_ALLOC_FREE
0002441          new_acc->acc_alloc_file= clnt_file;
0002442          new_acc->acc_alloc_line= clnt_line;
0002443 #endif
*/



0002444          return new_acc;
0002445 }
0002446 
0002447 PUBLIC size_t bf_bufsize(acc_ptr)
bf_bufsize()

bf_bufsize() returns the total buffer size of a linked list of accessors (i.e., the sum of acc_length for the accessors in a linked list).

For a detailed description of the network service's buffer management, click here.


0002448 register acc_t *acc_ptr;
0002449 {
0002450          register size_t size;
0002451 
0002452 assert(acc_ptr);
0002453 
0002454          size=0;
0002455 
0002456          while (acc_ptr)
Go until the end of the accessor linked list.


0002457          {
0002458 assert(acc_ptr >= accessors && acc_ptr <= &accessors[ACC_NR-1]);
0002459                   size += acc_ptr->acc_length;
Note that acc_length of an accessor may be less than buf_size. For example, if an ethernet packet is dumped into the buffers of a linked list of accessors by the ethernet driver and the size of the packet is less than a multiple of buf_size, the acc_length field of the last accessor in the linked list will be less than than buf_size.


0002460                   acc_ptr= acc_ptr->acc_next;
0002461          }
0002462          return size;
0002463 }
0002464 
0002465 #ifndef BUF_TRACK_ALLOC_FREE
0002466 PUBLIC acc_t *bf_packIffLess(pack, min_len)

/* The following is not used in the default configuration.




0002467 #else
0002468 PUBLIC acc_t *_bf_packIffLess(clnt_file, clnt_line, pack, min_len)
0002469 char *clnt_file;
0002470 int clnt_line;
0002471 #endif
*/



0002472 acc_t *pack;
0002473 int min_len;
bf_packIffLess()

If the data in a linked list of accessors is less than min_len (the second parameter), bf_packIffLess(pack, min_len) packs the data by calling bf_pack().

bf_packIffLess() is often called to ensure that a packet's header is in a single contiguous buffer so that the individual fields of the header can be easily accessed.

For a detailed description of the network service's buffer management, click here.


0002474 {
0002475          if (!pack || pack->acc_length >= min_len)
0002476                   return pack;
0002477 

/* The following is not used in the default configuration.




0002478 #if DEBUG
0002479 #ifdef bf_packIffLess
0002480  { where(); printf("calling bf_pack because of %s %d: %d\n", bf_pack_file,
0002481          bf_pack_line, min_len); }
0002482 #endif
0002483 #endif
*/



0002484          return bf_pack(pack);
0002485 }
0002486 
0002487 #ifndef BUF_TRACK_ALLOC_FREE
0002488 PUBLIC acc_t *bf_pack(old_acc)

/* The following is not used in the default configuration.




0002489 #else
0002490 PUBLIC acc_t *_bf_pack(clnt_file, clnt_line, old_acc)
0002491 char *clnt_file;
0002492 int clnt_line;
0002493 #endif
*/



0002494 acc_t *old_acc;
bf_pack()

bf_pack(old_acc) creates a new linked list of accessors of old_acc's equivalent length and copies the data from old_acc to it. In this way, the data is compressed (or packed).

For example, bf_pack(old_acc) will return new_acc:



(Note that 300+200+300=800=512+288.)


0002495 {
0002496          acc_t *new_acc, *acc_ptr_old, *acc_ptr_new;
0002497          size_t size, offset_old, offset_new, block_size, block_size_old;
0002498 
0002499          /* Check if old acc is good enough. */
If old_acc is null (in other words, there is no linked list of accessors), there's nothing to pack. If old_acc is only a single accessor in the linked list (i.e., old_acc->acc_next is null) and the accessor or its buffer is not a part of another accessor linked list (i.e., acc_linkC and buf_linkC are one), the buffer is already as "packed" as it ever will be.

If the accessor or buffer is shared by another linked list of accessors (i.e., acc_linkC or buf_linkC is greater than one), a new accessor is acquired by bf_memreq() and the buffer from the old accessor is copied to this buffer and the acc_linkC of the accessor and buf_linkC of its associated buffer are decremented. In this way, the buffer from the new accessor is no longer associated with another accessor linked list.


0002500          if (!old_acc || !old_acc->acc_next && old_acc->acc_linkC == 1 &&
0002501                   old_acc->acc_buffer->buf_linkC == 1)
0002502          {
0002503                   return old_acc;
0002504          }
0002505 
0002506          size= bf_bufsize(old_acc);
bf_bufsize()

bf_bufsize() returns the total buffer size of a linked list of accessors (i.e., the sum of acc_length for the accessors in a linked list).

For a detailed description of the network service's buffer management, click here.


0002507          assert(size > 0);
0002508          new_acc= bf_memreq(size);
The existing linked list of accessors will not be modified. A new linked list of accessors is instead created with bf_memreq().


bf_memreq()


After the buffers have been initialized, accessors[] looks like the following:



bf_memreq() allocates accessors to the caller. For example, if 1514 bytes of buffer space are requested immediately after the network process starts and each buffer is 512 bytes (the default), then accessors[] will look like the following:



Note that three elements of accessors[] have been removed from buf512_freelist and that the head of the chain of the 3 accessors is returned by bf_memreq(). Also note that the acc_linkC and buf_linkC fields have been set to one and acc_length and acc_offset have been set to their appropriate values.

So what happens if there are not enough buffers on the buf512_freelist to satisfy a request? On lines 2280-2290 of buf.c, functions that free buffers for the specific clients (e.g., eth_buffree()) are called until there are enough buffers on buf512_freelist.

For a complete description of the network service's buffer management, click here.


0002509          acc_ptr_old= old_acc;
0002510          acc_ptr_new= new_acc;
0002511          offset_old= 0;
0002512          offset_new= 0;
0002513          while (size)
The code within the while loop consists of bookkeeping and copying.

For example, in the scenario described in the comments on line 2488, the 300 bytes from old_acc's first buffer are copied to new_acc's first buffer. Next, the 200 bytes from old_acc's second buffer are copied to new_acc's first buffer. Next, 12 bytes from old_acc's third buffer are copied to new_acc's first buffer and then the remaining 288 bytes are copied to new_acc's second buffer.


0002514          {
0002515                   assert (acc_ptr_old);
0002516                   if (offset_old == acc_ptr_old->acc_length)
If true, all of the data from the current old buffer has already been copied to the current new buffer. Move on to the next old buffer.


0002517                   {
0002518                            offset_old= 0;
0002519                            acc_ptr_old= acc_ptr_old->acc_next;
0002520                            continue;
0002521                   }
0002522                   assert (offset_old < acc_ptr_old->acc_length);
0002523                   block_size_old= acc_ptr_old->acc_length - offset_old;
All of the data from the current old buffer may not be able to be copied into the current new buffer. The rest of the data will be copied into the next new buffer (on the next iteration).


0002524                   assert (acc_ptr_new);
0002525                   if (offset_new == acc_ptr_new->acc_length)
0002526                   {
0002527                            offset_new= 0;
0002528                            acc_ptr_new= acc_ptr_new->acc_next;
0002529                            continue;
0002530                   }
0002531                   assert (offset_new < acc_ptr_new->acc_length);
0002532                   block_size= acc_ptr_new->acc_length - offset_new;
0002533                   if (block_size > block_size_old)
0002534                            block_size= block_size_old;
0002535                   memcpy(ptr2acc_data(acc_ptr_new)+offset_new,
0002536                            ptr2acc_data(acc_ptr_old)+offset_old, block_size);
bf_temporary_acc is a pointer to acc_t, defined in line 2094 as:



memcpy()


memcpy is declared in include/string.h:

void *memcpy(void *s1, const void *s2, size_t n)

memcpy() copies n bytes from location s1 to location s2.


ptr2acc_data()


The macro ptr2acc_data is #define'd in inet/generic/buf.h as:

#define ptr2acc_data(/* acc_t * */ a) (bf_temporary_acc=(a), \
(&bf_temporary_acc->acc_buffer->buf_data_p[bf_temporary_acc-> \
acc_offset]))

ptr2acc_data() simply returns a pointer to the actual data within an accessor.

ptr2acc_data() is usually called so that the fields of a header (e.g., ip header) can be analyzed.


0002537                   offset_new += block_size;
0002538                   offset_old += block_size;
0002539                   size -= block_size;
0002540          }
0002541          bf_afree(old_acc);
bf_afree()

After a chain of accessors is no longer needed, the chain (and not simply the single accessor passed as the parameter) can be freed by calling bf_free(). However, if either acc_linkC or buf_linkC of one of the accessors in the linked list is not equal to one (1), the entire chain will not be freed. For example, if buf_afree(acc1) is called for the following chain:



Then the resulting chain will be:



bf_afree() returns acc1 (accessors[63]) to acc_freelist (recall that acc_freelist is the linked list of acc_t's without an associated buffer). However, buffers512[127] cannot be freed because acc2 (accessors[64]) still references it.

bf_afree() is called after an accessor's associated data is no longer needed (for example, after a packet has been sent off by the ethernet driver).


0002542          return new_acc;
0002543 }
0002544 
0002545 #ifndef BUF_TRACK_ALLOC_FREE
0002546 PUBLIC acc_t *bf_cut (data, offset, length)

/* The following is not used in the default configuration.


0002547 #else
0002548 PUBLIC acc_t *_bf_cut (clnt_file, clnt_line, data, offset, length)
0002549 char *clnt_file;
0002550 int clnt_line;
0002551 #endif
*/



0002552 register acc_t *data;
0002553 register unsigned offset;
0002554 register unsigned length;
bf_cut()

If a section of a linked list needs to be duplicated, bf_cut(data, offset, length) is called. For example, if a section of length 50 starting at an offset of 75 of the linked list below needs to be duplicated, bf_cut(data, 75, 50) is called:



Note that the original linked list remains unchanged and that acc_linkC for all the accessors in the new linked list is one.

If length (the second parameter) is zero, simply duplicate the first accessor in the linked list but set acc_length=0 and acc_next=null. In other words, create a linked list of length one accessor whose acc_length is 0.

bf_cut() is used in a number of scenarios, including cutting a received ethernet packet to size.

For a full description of the network service's buffer management, click here.



0002555 {
0002556          register acc_t *head, *tail;
0002557 
0002558          if (!data && !offset && !length)
0002559                   return 0;

/* The following is not used in the default configuration.




0002560 #ifdef BUF_TRACK_ALLOC_FREE
0002561          assert(data ||
0002562                   (printf("from %s, %d: %u, %u\n",
0002563                   clnt_file, clnt_line, offset, length), 0));
0002564 #else
*/



0002565          assert(data);
0002566 #endif
0002567 
0002568          assert(data);
0002569 #if DEBUG
0002570          bf_chkbuf(data);
0002571 #endif
0002572 
0002573          if (!length)
If length (the second parameter) is zero, simply duplicate the first accessor in the linked list but set acc_length=0 and acc_next=null. In other words, create an accessor linked list of length one and the acc_length of this one accessor will be 0.


0002574          {
0002575                   head= bf_dupacc(data);
bf_dupacc()

bf_dupacc(acc_ptr) creates a new accessor that is a duplicate of acc_ptr, bf_dupacc()'s only parameter.

More specifically, bf_dupacc() removes an accessor from acc_freelist and copies the accessor referred to by acc_ptr and sets acc_linkC of the new accessor to one. If acc_next is non-null, bf_dupacc() also increments acc_linkC of acc_next (the next accessor in the linked list). And if acc_buffer is non-null, bf_dupacc() also increments buf_linkC of the buffer.

This process is best described by a diagram:



Note that the link counts (acc_linkC and buf_linkC) for accessors[65] and buffers512[127] are incremented.

Remember that free accessors associated with buffers reside on buf512_freelist and free accessors not associated with buffers reside on acc_freelist. In addition, acc_linkC is one or greater if the accessor is no longer on either of the freelists and is greater than one if more than one accessor refers to it (through acc_next). buf_linkC is one or greater if its associated accessor (or accessors) are not on buf512_freelist and is greater than one if more than one accessor refers to it (through acc_buffer).



0002576                   bf_afree(head->acc_next);
One of the things that bf_dupacc() does is to increment acc_linkC of acc_next by one. Since acc_next is set to null on the next line, acc_linkC is decremented by one.

Remember that acc_linkC for all accessors not on the freelists (buf512_freelist or acc_freelist) have values greater than or equal to one. If an accessor is referenced by acc_next by more than one other accessor, its acc_linkC will be greater than one.


bf_afree()


After a chain of accessors is no longer needed, the chain (and not simply the single accessor passed as the parameter) can be freed by calling bf_free(). However, if either acc_linkC or buf_linkC of one of the accessors in the linked list is not equal to one (1), the entire chain will not be freed. For example, if buf_afree(acc1) is called for the following chain:



Then the resulting chain will be:



bf_afree() returns acc1 (accessors[63]) to acc_freelist (recall that acc_freelist is the linked list of acc_t's without an associated buffer). However, buffers512[127] cannot be freed because acc2 (accessors[64]) still references it.

bf_afree() is called after an accessor's associated data is no longer needed (for example, after a packet has been sent off by the ethernet driver).


0002577                   head->acc_next= 0;
0002578                   head->acc_length= 0;

/* The following is not used in the default configuration.




0002579 #if DEBUG
0002580                   bf_chkbuf(data);
0002581 #endif
*/



0002582                   return head;
0002583          }
If length (the second parameter) is not zero (the usual case), a section of the original linked list is duplicated:



Note that the new accessors come from acc_freelist. Recall that acc_freelist is made up of accessors without associated buffers. buf512_freelist is made up of accessors with associated buffers.


0002584          while (data && offset>=data->acc_length)
Determine which accessor's buffer to begin duplicating.


0002585          {
0002586                   offset -= data->acc_length;
0002587                   data= data->acc_next;
0002588          }
0002589 
0002590          assert (data);
0002591 
Create the head of the new linked list.


0002592          head= bf_dupacc(data);
bf_dupacc()

bf_dupacc(acc_ptr) creates a new accessor that is a duplicate of acc_ptr, bf_dupacc()'s only parameter.

More specifically, bf_dupacc() removes an accessor from acc_freelist and copies the accessor referred to by acc_ptr and sets acc_linkC of the new accessor to one. If acc_next is non-null, bf_dupacc() also increments acc_linkC of acc_next (the next accessor in the linked list). And if acc_buffer is non-null, bf_dupacc() also increments buf_linkC of the buffer.

This process is best described by a diagram:



Note that the link counts (acc_linkC and buf_linkC) for accessors[65] and buffers512[127] are incremented.

Remember that free accessors associated with buffers reside on buf512_freelist and free accessors not associated with buffers reside on acc_freelist. In addition, acc_linkC is one or greater if the accessor is no longer on either of the freelists and is greater than one if more than one accessor refers to it (through acc_next). buf_linkC is one or greater if its associated accessor (or accessors) are not on buf512_freelist and is greater than one if more than one accessor refers to it (through acc_buffer).



0002593          bf_afree(head->acc_next);
One of the things that bf_dupacc() does is to increment acc_linkC of acc_next by one. Since acc_next is set to null on the next line, acc_linkC is decremented by one.

Remember that acc_linkC for all accessors not on the freelists (buf512_freelist or acc_freelist) have values greater than or equal to one. If an accessor is referenced by acc_next by more than one other accessor, its acc_linkC will be greater than one.

Note that this is the rationale for the bf_afree() on lines 2610 and 2626.


bf_afree()


After a chain of accessors is no longer needed, the chain (and not simply the single accessor passed as the parameter) can be freed by calling bf_free(). However, if either acc_linkC or buf_linkC of one of the accessors in the linked list is not equal to one (1), the entire chain will not be freed. For example, if buf_afree(acc1) is called for the following chain:



Then the resulting chain will be:



bf_afree() returns acc1 (accessors[63]) to acc_freelist (recall that acc_freelist is the linked list of acc_t's without an associated buffer). However, buffers512[127] cannot be freed because acc2 (accessors[64]) still references it.

bf_afree() is called after an accessor's associated data is no longer needed (for example, after a packet has been sent off by the ethernet driver).


0002594          head->acc_next= 0;
0002595          head->acc_offset += offset;
0002596          head->acc_length -= offset;
0002597          if (length >= head->acc_length)
0002598                   length -= head->acc_length;
0002599          else
0002600          {
0002601                   head->acc_length= length;
0002602                   length= 0;
0002603          }
0002604          tail= head;
0002605          data= data->acc_next;
0002606          while (data && length && length>=data->acc_length)
Create the midsection of the linked list.


0002607          {
0002608                   tail->acc_next= bf_dupacc(data);
0002609                   tail= tail->acc_next;
0002610                   bf_afree(tail->acc_next);
0002611                   tail->acc_next= 0;
0002612                   data= data->acc_next;
0002613                   length -= tail->acc_length;
0002614          }
0002615          if (length)
Create the tail of the linked list.


0002616          {

/* The following is not used in the default configuration.




0002617 #ifdef bf_cut
0002618                   assert (data ||
0002619                            (printf("bf_cut called from %s:%d\n",
0002620                            clnt_file, clnt_line), 0));
0002621 #else
*/



0002622                   assert (data);
0002623 #endif
0002624                   tail->acc_next= bf_dupacc(data);
0002625                   tail= tail->acc_next;
0002626                   bf_afree(tail->acc_next);
0002627                   tail->acc_next= 0;
0002628                   tail->acc_length= length;
0002629          }
0002630 #if DEBUG
0002631          bf_chkbuf(data);
0002632 #endif
0002633          return head;
0002634 }
0002635 
0002636 #ifndef BUF_TRACK_ALLOC_FREE
0002637 PUBLIC acc_t *bf_delhead (data, offset)

/* The following is not used in the default configuration.




0002638 #else
0002639 PUBLIC acc_t *_bf_delhead (clnt_file, clnt_line, data, offset)
0002640 char *clnt_file;
0002641 int clnt_line;
0002642 #endif
*/


'register' is a declaration modifier that requests that the compiler use a cpu register instead of ram (which is slower) for the variable. It is common to declare loop counter variables as register variables.


0002643 register acc_t *data;
0002644 register unsigned offset;
bf_delhead()

If only the beginning of a linked list can be freed, bf_delhead() is called. If acc_linkC and buf_linkC are one for all of the relevant accessors and their associated buffers in the linked list, the operation is straight-forward:



bf_delhead() is often called to remove the header (e.g., ip header) from a packet.

For a detailed description of the network service's buffer management, click here.


0002645 {
0002646          acc_t *new_acc;
0002647 
0002648          assert(data);
0002649 
0002650          /* Find the acc we need to modify. */
The following example shows an ethernet header being removed. Initially, data points to an ethernet packet with its ethernet header.






0002651          new_acc= data;
0002652          while(offset >= new_acc->acc_length)
Advance new_acc past the accessors that contain buffers that will be removed. For our example, since only 14 bytes will be removed and since 14 bytes falls within the first accessor's buffer, new_acc does not advance beyond the first accessor.


0002653          {
0002654                   offset -= new_acc->acc_length;
0002655                   new_acc= new_acc->acc_next;

/* The following is not used in the default configuration.




0002656 #ifdef BUF_TRACK_ALLOC_FREE
0002657                   assert(new_acc || (printf("called from %s, %d\n",
0002658                            clnt_file, clnt_line),0));
0002659 #else
*/



0002660                   assert(new_acc);
0002661 #endif
0002662          }
Since new_acc did not advance beyond data, the linked list appears as follows:






0002663 
0002664          /* Discard the old acc(s) */
For our example, since new_acc does not advance, no accessors will be freed by bf_afree() and the linked list does not change.


0002665          if (new_acc != data)
0002666          {
0002667                   new_acc->acc_linkC++;
The acc_linkC field of new_acc is incremented to prevent bf_afree() from freeing new_acc.


0002668                   bf_afree(data);
bf_afree()

After a chain of accessors is no longer needed, the chain (and not simply the single accessor passed as the parameter) can be freed by calling bf_free(). However, if either acc_linkC or buf_linkC of one of the accessors in the linked list is not equal to one (1), the entire chain will not be freed. For example, if buf_afree(acc1) is called for the following chain:



Then the resulting chain will be:



bf_afree() returns acc1 (accessors[63]) to acc_freelist (recall that acc_freelist is the linked list of acc_t's without an associated buffer). However, buffers512[127] cannot be freed because acc2 (accessors[64]) still references it.

bf_afree() is called after an accessor's associated data is no longer needed (for example, after a packet has been sent off by the ethernet driver).


0002669                   data= new_acc;
0002670          }
0002671 
0002672          /* Make sure that acc_linkC == 1 */
0002673          if (data->acc_linkC != 1)
If acc_linkC is greater than one, the accessor that data and new_acc reference is also a link in another accessor linked list. Since this function modifies the acc_length and acc_offset fields of the accessor, call bf_dupacc() to duplicate the accessor referenced by data so that the other link list(s) are not affected.


0002674          {
0002675                   new_acc= bf_dupacc(data);
bf_dupacc()

bf_dupacc(acc_ptr) creates a new accessor that is a duplicate of acc_ptr, bf_dupacc()'s only parameter.

More specifically, bf_dupacc() removes an accessor from acc_freelist and copies the accessor referred to by acc_ptr and sets acc_linkC of the new accessor to one. If acc_next is non-null, bf_dupacc() also increments acc_linkC of acc_next (the next accessor in the linked list). And if acc_buffer is non-null, bf_dupacc() also increments buf_linkC of the buffer.

This process is best described by a diagram:



Note that the link counts (acc_linkC and buf_linkC) for accessors[65] and buffers512[127] are incremented.

Remember that free accessors associated with buffers reside on buf512_freelist and free accessors not associated with buffers reside on acc_freelist. In addition, acc_linkC is one or greater if the accessor is no longer on either of the freelists and is greater than one if more than one accessor refers to it (through acc_next). buf_linkC is one or greater if its associated accessor (or accessors) are not on buf512_freelist and is greater than one if more than one accessor refers to it (through acc_buffer).



0002676                   bf_afree(data);
bf_afree()

After a chain of accessors is no longer needed, the chain (and not simply the single accessor passed as the parameter) can be freed by calling bf_free(). However, if either acc_linkC or buf_linkC of one of the accessors in the linked list is not equal to one (1), the entire chain will not be freed. For example, if buf_afree(acc1) is called for the following chain:



Then the resulting chain will be:



bf_afree() returns acc1 (accessors[63]) to acc_freelist (recall that acc_freelist is the linked list of acc_t's without an associated buffer). However, buffers512[127] cannot be freed because acc2 (accessors[64]) still references it.

bf_afree() is called after an accessor's associated data is no longer needed (for example, after a packet has been sent off by the ethernet driver).


0002677                   data= new_acc;
0002678          }
For our example, since no other accessor linked list also contains the accessor referenced by data, the linked list remains as before.


0002679 
0002680          /* Delete the last bit by modifying acc_offset and acc_length */
0002681          data->acc_offset += offset;
0002682          data->acc_length -= offset;




0002683          return data;
0002684 }
0002685 
0002686 /*
0002687 bf_append
0002688 */
0002689 
0002690 #ifndef BUF_TRACK_ALLOC_FREE
0002691 PUBLIC acc_t *bf_append(data_first, data_second)

/* The following is not used in the default configuration.




0002692 #else
0002693 PUBLIC acc_t *_bf_append(clnt_file, clnt_line, data_first, data_second)
0002694 char *clnt_file;
0002695 int clnt_line;
0002696 #endif
*/



0002697 acc_t *data_first;
0002698 acc_t *data_second;
bf_append()

bf_append() appends one accessor linked list to another accessor linked list. For example, if the payload of an ethernet packet (1500 bytes) is appended to an ethernet header (14 bytes):



the resulting linked list is as follows:






0002699 {
The two linked lists of accessors, data_first and data_second, in the figure below are used as an example in the comments below.






0002700          acc_t *head, *tail, *new_acc, *acc_ptr_new, tmp_acc, *curr;
0002701          char *src_ptr, *dst_ptr;
0002702          size_t size, offset_old, offset_new, block_size_old, block_size;
0002703 
Verify that there are indeed two linked lists to join together and not just one.


0002704          if (!data_first)
0002705                   return data_second;
0002706          if (!data_second)
0002707                   return data_first;
0002708 
0002709          head= 0;
0002710          while (data_first)
0002711          {
0002712                   if (data_first->acc_linkC == 1)
0002713                            curr= data_first;
0002714                   else
0002715                   {
If acc_linkC is nonzero for any of the accessors, not only is the first accessor duplicated but all accessors that follow are duplicated. This is done to prevent changes on the linked lists that share accessors with the linked list that begins with data_first.


0002716                            curr= bf_dupacc(data_first);
bf_dupacc()

bf_dupacc(acc_ptr) creates a new accessor that is a duplicate of acc_ptr, bf_dupacc()'s only parameter.

More specifically, bf_dupacc() removes an accessor from acc_freelist and copies the accessor referred to by acc_ptr and sets acc_linkC of the new accessor to one. If acc_next is non-null, bf_dupacc() also increments acc_linkC of acc_next (the next accessor in the linked list). And if acc_buffer is non-null, bf_dupacc() also increments buf_linkC of the buffer.

This process is best described by a diagram:



Note that the link counts (acc_linkC and buf_linkC) for accessors[65] and buffers512[127] are incremented.

Remember that free accessors associated with buffers reside on buf512_freelist and free accessors not associated with buffers reside on acc_freelist. In addition, acc_linkC is one or greater if the accessor is no longer on either of the freelists and is greater than one if more than one accessor refers to it (through acc_next). buf_linkC is one or greater if its associated accessor (or accessors) are not on buf512_freelist and is greater than one if more than one accessor refers to it (through acc_buffer).



0002717                            assert (curr->acc_linkC == 1);
0002718                            bf_afree(data_first);
bf_afree()

After a chain of accessors is no longer needed, the chain (and not simply the single accessor passed as the parameter) can be freed by calling bf_free(). However, if either acc_linkC or buf_linkC of one of the accessors in the linked list is not equal to one (1), the entire chain will not be freed. For example, if buf_afree(acc1) is called for the following chain:



Then the resulting chain will be:



bf_afree() returns acc1 (accessors[63]) to acc_freelist (recall that acc_freelist is the linked list of acc_t's without an associated buffer). However, buffers512[127] cannot be freed because acc2 (accessors[64]) still references it.

bf_afree() is called after an accessor's associated data is no longer needed (for example, after a packet has been sent off by the ethernet driver).


0002719                   }
0002720                   data_first= curr->acc_next;
0002721                   if (!curr->acc_length)
Get rid of any accessors in the first linked list that have no data.


0002722                   {
0002723                            curr->acc_next= 0;
0002724                            bf_afree(curr);
bf_afree()

After a chain of accessors is no longer needed, the chain (and not simply the single accessor passed as the parameter) can be freed by calling bf_free(). However, if either acc_linkC or buf_linkC of one of the accessors in the linked list is not equal to one (1), the entire chain will not be freed. For example, if buf_afree(acc1) is called for the following chain:



Then the resulting chain will be:



bf_afree() returns acc1 (accessors[63]) to acc_freelist (recall that acc_freelist is the linked list of acc_t's without an associated buffer). However, buffers512[127] cannot be freed because acc2 (accessors[64]) still references it.

bf_afree() is called after an accessor's associated data is no longer needed (for example, after a packet has been sent off by the ethernet driver).


0002725                            continue;
0002726                   }
0002727                   if (!head)
0002728                            head= curr;
0002729                   else
0002730                            tail->acc_next= curr;
0002731                   tail= curr;
0002732          }
At this point, the two linked lists appear as follows:






0002733          if (!head)
0002734                   return data_second;
0002735          tail->acc_next= 0;
At this point, acc_next should point to null anyway (the last link in a linked list always points to null).


0002736 
0002737          while (data_second && !data_second->acc_length)
Remove the empty acc_t's at the beginning of the linked list.


0002738          {
0002739                   curr= data_second;
0002740                   data_second= data_second->acc_next;
0002741                   if (data_second)
0002742                            data_second->acc_linkC++;
0002743                   bf_afree(curr);
0002744          }
0002745          if (!data_second)
There is no data in the second linked list.


0002746                   return head;
0002747 
0002748          if (tail->acc_length + data_second->acc_length >
0002749                   tail->acc_buffer->buf_size)
In this case, there's no possibility to merge the tail of the first linked list with the head of the second linked list so just stick them together and return the head of the first linked list.





0002750          {
0002751                   tail->acc_next= data_second;
0002752                   return head;
0002753          }
0002754 
The rest of the code involves merging the last buffer of the first linked list with the first buffer of the second linked list.


0002755          if (tail->acc_buffer->buf_size == bf_buf_gran &&
0002756                   tail->acc_buffer->buf_linkC == 1)
If more than one accessor references the buffer (i.e., buf_linkC > 1), do not alter the buffer.

bf_buf_gran is the same size as buf_size (512). It is unclear under what circumstances bf_buf_gran would differ from buf_size.


0002757          {
0002758                   if (tail->acc_offset)
0002759                   {
0002760                            memmove(tail->acc_buffer->buf_data_p,
0002761                                     ptr2acc_data(tail), tail->acc_length);
0002762                            tail->acc_offset= 0;
0002763                   }
0002764                   dst_ptr= ptr2acc_data(tail) + tail->acc_length;
0002765                   src_ptr= ptr2acc_data(data_second);
0002766                   memcpy(dst_ptr, src_ptr, data_second->acc_length);
Copy the data from the first buffer in the second linked list to the last buffer in the first linked list.


0002767                   tail->acc_length += data_second->acc_length;
0002768                   tail->acc_next= data_second->acc_next;
0002769                   if (data_second->acc_next)
0002770                            data_second->acc_next->acc_linkC++;
Make sure that the second accessor in the second linked list isn't freed by the call to bf_afree().


0002771                   bf_afree(data_second);
bf_afree()

After a chain of accessors is no longer needed, the chain (and not simply the single accessor passed as the parameter) can be freed by calling bf_free(). However, if either acc_linkC or buf_linkC of one of the accessors in the linked list is not equal to one (1), the entire chain will not be freed. For example, if buf_afree(acc1) is called for the following chain:



Then the resulting chain will be:



bf_afree() returns acc1 (accessors[63]) to acc_freelist (recall that acc_freelist is the linked list of acc_t's without an associated buffer). However, buffers512[127] cannot be freed because acc2 (accessors[64]) still references it.

bf_afree() is called after an accessor's associated data is no longer needed (for example, after a packet has been sent off by the ethernet driver).


0002772                   return head;
0002773          }
0002774 
If more than one accessor references the last buffer of the first linked list, a new accessor and its associated buffer must be acquired through bf_small_memreq(). After the new accessor is acquired, the data in the last buffer of the first linked list and the first buffer of the last linked list must be copied to the new accessor.


0002775          new_acc= bf_small_memreq(tail->acc_length+data_second->acc_length);
bf_small_memreq() is a wrapper for bf_memreq().


bf_memreq()


After the buffers have been initialized, accessors[] looks like the following:



bf_memreq() allocates accessors to the caller. For example, if 1514 bytes of buffer space are requested immediately after the network process starts and each buffer is 512 bytes (the default), then accessors[] will look like the following:



Note that three elements of accessors[] have been removed from buf512_freelist and that the head of the chain of the 3 accessors is returned by bf_memreq(). Also note that the acc_linkC and buf_linkC fields have been set to one and acc_length and acc_offset have been set to their appropriate values.

So what happens if there are not enough buffers on the buf512_freelist to satisfy a request? On lines 2280-2290 of buf.c, functions that free buffers for the specific clients (e.g., eth_buffree()) are called until there are enough buffers on buf512_freelist.

For a complete description of the network service's buffer management, click here.


0002776          acc_ptr_new= new_acc;
0002777          offset_old= 0;
0002778          offset_new= 0;
0002779          size= tail->acc_length;
0002780          while (size)
Copy the data of the last buffer of the first linked list to the new buffer.


0002781          {
0002782 assert (acc_ptr_new);
0002783                   if (offset_new == acc_ptr_new->acc_length)
0002784                   {
0002785                            offset_new= 0;
0002786                            acc_ptr_new= acc_ptr_new->acc_next;
0002787                            continue;
0002788                   }
0002789 assert (offset_new < acc_ptr_new->acc_length);
0002790 assert (offset_old < tail->acc_length);
0002791                   block_size_old= tail->acc_length - offset_old;
0002792                   block_size= acc_ptr_new->acc_length - offset_new;
0002793                   if (block_size > block_size_old)
0002794                            block_size= block_size_old;
0002795                   memcpy(ptr2acc_data(acc_ptr_new)+offset_new,
0002796                            ptr2acc_data(tail)+offset_old, block_size);
ptr2acc_data()

The macro ptr2acc_data is #define'd in inet/generic/buf.h as:

#define ptr2acc_data(/* acc_t * */ a) (bf_temporary_acc=(a), \
(&bf_temporary_acc->acc_buffer->buf_data_p[bf_temporary_acc-> \
acc_offset]))

ptr2acc_data() simply returns a pointer to the actual data within an accessor.

ptr2acc_data() is usually called so that the fields of a header (e.g., ip header) can be analyzed.


0002797                   offset_new += block_size;
0002798                   offset_old += block_size;
0002799                   size -= block_size;
0002800          }
0002801          offset_old= 0;
0002802          size= data_second->acc_length;
0002803          while (size)
Copy the data of the first buffer of the second accessor linked list to the buffer of the accessor just acquired.


0002804          {
0002805 assert (acc_ptr_new);
0002806                   if (offset_new == acc_ptr_new->acc_length)
0002807                   {
0002808                            offset_new= 0;
0002809                            acc_ptr_new= acc_ptr_new->acc_next;
0002810                            continue;
0002811                   }
0002812 assert (offset_new < acc_ptr_new->acc_length);
0002813 assert (offset_old < data_second->acc_length);
0002814                   block_size_old= data_second->acc_length - offset_old;
0002815                   block_size= acc_ptr_new->acc_length - offset_new;
0002816                   if (block_size > block_size_old)
0002817                            block_size= block_size_old;
0002818                   memcpy(ptr2acc_data(acc_ptr_new)+offset_new,
0002819                            ptr2acc_data(data_second)+offset_old, block_size);
ptr2acc_data()

The macro ptr2acc_data is #define'd in inet/generic/buf.h as:

#define ptr2acc_data(/* acc_t * */ a) (bf_temporary_acc=(a), \
(&bf_temporary_acc->acc_buffer->buf_data_p[bf_temporary_acc-> \
acc_offset]))

ptr2acc_data() simply returns a pointer to the actual data within an accessor.

ptr2acc_data() is usually called so that the fields of a header (e.g., ip header) can be analyzed.


0002820                   offset_new += block_size;
0002821                   offset_old += block_size;
0002822                   size -= block_size;
0002823          }
The new accessor that was acquired by bf_small_memreq() must have the same values as the accessor it replaced.


0002824          tmp_acc= *tail;
0002825          *tail= *new_acc;
0002826          *new_acc= tmp_acc;
0002827 
0002828          bf_afree(new_acc);
bf_afree()

After a chain of accessors is no longer needed, the chain (and not simply the single accessor passed as the parameter) can be freed by calling bf_free(). However, if either acc_linkC or buf_linkC of one of the accessors in the linked list is not equal to one (1), the entire chain will not be freed. For example, if buf_afree(acc1) is called for the following chain:



Then the resulting chain will be:



bf_afree() returns acc1 (accessors[63]) to acc_freelist (recall that acc_freelist is the linked list of acc_t's without an associated buffer). However, buffers512[127] cannot be freed because acc2 (accessors[64]) still references it.

bf_afree() is called after an accessor's associated data is no longer needed (for example, after a packet has been sent off by the ethernet driver).


0002829          while (tail->acc_next)
I don't believe that this will ever be true.

CHRISTOS, IS THIS TRUE?


0002830                   tail= tail->acc_next;
0002831 
0002832          tail->acc_next= data_second->acc_next;
Join the two linked lists together.


0002833          if (data_second->acc_next)
0002834                   data_second->acc_next->acc_linkC++;
0002835          bf_afree(data_second);
bf_afree()

After a chain of accessors is no longer needed, the chain (and not simply the single accessor passed as the parameter) can be freed by calling bf_free(). However, if either acc_linkC or buf_linkC of one of the accessors in the linked list is not equal to one (1), the entire chain will not be freed. For example, if buf_afree(acc1) is called for the following chain:



Then the resulting chain will be:



bf_afree() returns acc1 (accessors[63]) to acc_freelist (recall that acc_freelist is the linked list of acc_t's without an associated buffer). However, buffers512[127] cannot be freed because acc2 (accessors[64]) still references it.

bf_afree() is called after an accessor's associated data is no longer needed (for example, after a packet has been sent off by the ethernet driver).


0002836          return head;
0002837 }
0002838 
0002839 #if BUF512_NR
0002840 PRIVATE void bf_512free(acc)
0002841 acc_t *acc;
0002842 {

/* The following is not used in the default configuration.




0002843 #ifdef BUF_CONSISTENCY_CHECK
0002844          if (inet_buf_debug)
0002845                   memset(acc->acc_buffer->buf_data_p, 0xa5, 512);
0002846 #endif
*/



0002847          acc->acc_next= buf512_freelist;
0002848          buf512_freelist= acc;
0002849 }
0002850 #endif

/* The following is not used in the default configuration.




0002851 #if BUF2K_NR
0002852 PRIVATE void bf_2Kfree(acc)
0002853 acc_t *acc;
0002854 {
0002855 #ifdef BUF_CONSISTENCY_CHECK
0002856          if (inet_buf_debug)
0002857                   memset(acc->acc_buffer->buf_data_p, 0xa5, 2*1024);
0002858 #endif
0002859          acc->acc_next= buf2K_freelist;
0002860          buf2K_freelist= acc;
0002861 }
0002862 #endif
0002863 #if BUF32K_NR
0002864 PRIVATE void bf_32Kfree(acc)
0002865 acc_t *acc;
0002866 {
0002867 #ifdef BUF_CONSISTENCY_CHECK
0002868          if (inet_buf_debug)
0002869                   memset(acc->acc_buffer->buf_data_p, 0xa5, 32*1024);
0002870 #endif
0002871          acc->acc_next= buf32K_freelist;
0002872          buf32K_freelist= acc;
0002873 }
0002874 #endif
0002875 
0002876 #ifdef BUF_CONSISTENCY_CHECK
0002877 PUBLIC int bf_consistency_check()
0002878 {
0002879          acc_t *acc;
0002880          buf_t *buf;
0002881          int silent;
0002882          int error;
0002883          int i;
0002884 
0002885          buf_generation++;
0002886 
0002887          for (i=0; i<CLIENT_NR; i++)
0002888          {
0002889                   if (checkreq[i])
0002890                            (*checkreq[i])();
0002891          }
0002892 
0002893          /* Add information about free accessors */
0002894          for(acc= acc_freelist; acc; acc= acc->acc_next)
0002895          {
0002896                   if (acc->acc_generation == buf_generation-1)
0002897                   {
0002898                            acc->acc_generation= buf_generation;
0002899                            acc->acc_check_linkC= 0;
0002900                   }
0002901                   else
0002902                   {
0002903                            assert(acc->acc_generation == buf_generation &&
0002904                                     acc->acc_check_linkC > 0);
0002905                            acc->acc_check_linkC= -acc->acc_check_linkC;
0002906                   }
0002907          }
0002908 
0002909 #if BUF512_NR
0002910          count_free_bufs(buf512_freelist);
0002911 #endif
0002912 #if BUF2K_NR
0002913          count_free_bufs(buf2K_freelist);
0002914 #endif
0002915 #if BUF32K_NR
0002916          count_free_bufs(buf32K_freelist);
0002917 #endif
0002918 
0002919          error= 0;
0002920 
0002921          /* Report about accessors */
0002922          silent= 0;
0002923          for (i=0, acc= accessors; i<ACC_NR; i++, acc++)
0002924          {
0002925                   if (acc->acc_generation != buf_generation)
0002926                   {
0002927                            error++;
0002928                            assert(acc->acc_generation == buf_generation-1);
0002929                            acc->acc_generation= buf_generation;
0002930                            if (!silent)
0002931                            {
0002932                                     printf(
0002933 "acc[%d] (0x%x) has been lost with count %d, last allocated at %s, %d\n",
0002934          i, acc, acc->acc_linkC, acc->acc_alloc_file, acc->acc_alloc_line);
0002935 #if 0
0002936                                     silent= 1;
0002937 #endif
0002938                            }
0002939                            continue;
0002940                   }
0002941                   if (acc->acc_check_linkC == acc->acc_linkC)
0002942                            continue;
0002943                   error++;
0002944                   if (acc->acc_check_linkC < 0)
0002945                   {
0002946                            if (!silent)
0002947                            {
0002948                                     printf(
0002949 "acc[%d] is freed but still in use, allocated at %s, %d, freed at %s, %d\n",
0002950                                     i, acc->acc_alloc_file, acc->acc_alloc_line,
0002951                                     acc->acc_free_file, acc->acc_free_line);
0002952                            }
0002953                            acc->acc_check_linkC= -acc->acc_check_linkC;
0002954                            if (acc->acc_check_linkC == acc->acc_linkC)
0002955                            {
0002956                                     silent= 1;
0002957                                     continue;
0002958                            }
0002959                   }
0002960                   if (!silent)
0002961                   {
0002962                            printf(
0002963 "# of tracked links (%d) for acc[%d] don't match with stored link count %d\n",
0002964                                     acc->acc_check_linkC, i, acc->acc_linkC);
0002965                            printf("acc[%d] was allocated at %s, %d\n",
0002966                                     i, acc->acc_alloc_file, acc->acc_alloc_line);
0002967                            silent=1;
0002968                   }
0002969          }
0002970 
0002971          /* Report about buffers */
0002972 #if BUF512_NR
0002973          {
0002974                   for (i= 0; i<BUF512_NR; i++)
0002975                   {
0002976                            error |= report_buffer(&buffers512[i].buf_header,
0002977                                     "512-buffer", i);
0002978                   }
0002979          }
0002980 #endif
0002981 #if BUF2K_NR
0002982          {
0002983                   for (i= 0; i<BUF2K_NR; i++)
0002984                   {
0002985                            error |= report_buffer(&buffers2K[i].buf_header,
0002986                                     "2K-buffer", i);
0002987                   }
0002988          }
0002989 #endif
0002990 #if BUF32K_NR
0002991          {
0002992                   for (i= 0; i<BUF32K_NR; i++)
0002993                   {
0002994                            error |= report_buffer(&buffers32K[i].buf_header,
0002995                                     "32K-buffer", i);
0002996                   }
0002997          }
0002998 #endif
0002999 
0003000          return !error;
0003001 }
0003002 
0003003 PRIVATE void count_free_bufs(list)
0003004 acc_t *list;
0003005 {
0003006          acc_t *acc;
0003007          buf_t *buf;
0003008 
0003009          for(acc= list; acc; acc= acc->acc_next)
0003010          {
0003011                   if (acc->acc_generation != buf_generation-1)
0003012                   {
0003013                            assert(acc->acc_generation == buf_generation &&
0003014                                     acc->acc_check_linkC > 0);
0003015                            acc->acc_check_linkC= -acc->acc_check_linkC;
0003016                            continue;
0003017                   }
0003018                   acc->acc_generation= buf_generation;
0003019                   acc->acc_check_linkC= 0;
0003020 
0003021                   buf= acc->acc_buffer;
0003022                   if (buf->buf_generation == buf_generation-1)
0003023                   {
0003024                            buf->buf_generation= buf_generation;
0003025                            buf->buf_check_linkC= 0;
0003026                            continue;
0003027                   }
0003028                   assert(buf->buf_generation == buf_generation &&
0003029                            buf->buf_check_linkC > 0);
0003030                   buf->buf_check_linkC= -buf->buf_check_linkC;
0003031          }
0003032 }
0003033 
0003034 PRIVATE int report_buffer(buf, label, i)
0003035 buf_t *buf;
0003036 char *label;
0003037 int i;
0003038 {
0003039          if (buf->buf_generation != buf_generation)
0003040          {
0003041                   assert(buf->buf_generation == buf_generation-1);
0003042                   buf->buf_generation= buf_generation;
0003043                   printf(
0003044 "%s[%d] (0x%x) has been lost with count %d, last allocated at %s, %d\n",
0003045                            label, i, buf,
0003046                            buf->buf_linkC, buf->buf_alloc_file,
0003047                            buf->buf_alloc_line);
0003048                   return 1;
0003049          }
0003050          if (buf->buf_check_linkC == buf->buf_linkC)
0003051                   return 0;
0003052          if (buf->buf_check_linkC < 0)
0003053          {
0003054                   printf(
0003055 "%s[%d] is freed but still in use, allocated at %s, %d, freed at %s, %d\n",
0003056                            label, i, buf->buf_alloc_file, buf->buf_alloc_line,
0003057                            buf->buf_free_file, buf->buf_free_line);
0003058                   buf->buf_check_linkC= -buf->buf_check_linkC;
0003059                   if (buf->buf_check_linkC == buf->buf_linkC)
0003060                            return 1;
0003061          }
0003062          printf(
0003063 "# of tracked links (%d) for %s[%d] don't match with stored link count %d\n",
0003064                            buf->buf_check_linkC, label, i, buf->buf_linkC);
0003065          printf("%s[%d] was allocated at %s, %d\n",
0003066                   label, i, buf->buf_alloc_file, buf->buf_alloc_line);
0003067          return 1;
0003068 }
0003069 
0003070 PUBLIC void bf_check_acc(acc)
0003071 acc_t *acc;
0003072 {
0003073          buf_t *buf;
0003074 
0003075          while(acc != NULL)
0003076          {
0003077                   if (acc->acc_generation == buf_generation)
0003078                   {
0003079                            assert(acc->acc_check_linkC > 0);
0003080                            acc->acc_check_linkC++;
0003081                            return;
0003082                   }
0003083                   assert(acc->acc_generation == buf_generation-1);
0003084                   acc->acc_generation= buf_generation;
0003085                   acc->acc_check_linkC= 1;
0003086 
0003087                   buf= acc->acc_buffer;
0003088                   if (buf->buf_generation == buf_generation)
0003089                   {
0003090                            assert(buf->buf_check_linkC > 0);
0003091                            buf->buf_check_linkC++;
0003092                   }
0003093                   else
0003094                   {
0003095                            assert(buf->buf_generation == buf_generation-1);
0003096                            buf->buf_generation= buf_generation;
0003097                            buf->buf_check_linkC= 1;
0003098                   }
0003099 
0003100                   acc= acc->acc_next;
0003101          }
0003102 }
0003103 
0003104 PUBLIC void _bf_mark_acc(clnt_file, clnt_line, acc)
0003105 char *clnt_file;
0003106 int clnt_line;
0003107 acc_t *acc;
0003108 {
0003109          buf_t *buf;
0003110 
0003111          for (; acc; acc= acc->acc_next)
0003112          {
0003113                   acc->acc_alloc_file= clnt_file;
0003114                   acc->acc_alloc_line= clnt_line;
0003115                   buf= acc->acc_buffer;
0003116                   buf->buf_alloc_file= clnt_file;
0003117                   buf->buf_alloc_line= clnt_line;
0003118          }
0003119 }
0003120 #endif
*/



0003121 
0003122 PRIVATE void free_accs()
free_accs()

If there are no accessors on acc_freelist (the linked list of unused accessors without buffers), bf_dupacc() calls free_accs() to free up accessors. free_accs() goes through all the different priority levels for the 6 different clients (eth, psip, ip, icmp, tcp, and udp), calling the client-specific buffer-freeing functions (e.g., eth_buffree()).


0003123 {
0003124          int i, j;
0003125 
0003126          DBLOCK(1, printf("free_accs\n"));
0003127 
0003128          for (i=0; !acc_freelist && i<MAX_BUFREQ_PRI; i++)
MAX_BUFREQ_PRI is #define'd in inet/generic/buf.h:

#define MAX_BUFREQ_PRI 10

Each client is responsible for determining the priority level of an accessor that they have acquired.


0003129          {
0003130                   for (j=0; j<CLIENT_NR; j++)
0003131                   {
0003132                            bf_free_bufsize= 0;
0003133                            if (freereq[j])
0003134                            {
0003135                                     (*freereq[j])(i);
Call the client-specific buffer-freeing function (e.g., eth_buffree()) for a given priority.


0003136                            }
0003137                   }
0003138          }
0003139 #if DEBUG
0003140          printf("last level was level %d\n", i-1);
0003141 #endif
0003142 }
0003143 
0003144 #ifndef BUF_TRACK_ALLOC_FREE
0003145 PUBLIC acc_t *bf_align(acc, size, alignment)
bf_align()

If data is not already packed and aligned, bf_align(acc, size, alignment) packs size (bf_align's second parameter) bytes from acc, bf_align()'s first parameter and a linked list of accessors (i.e., a packet), by calling bf_pack(). This packing is necessary to ensure that all of the fields from a header are easily accessed. For example, the ip code aligns a packet's header contained in the accessors before accessing the various ip header fields.

For a detailed description of the network service's buffer management, click here.


0003146 #else
0003147 PUBLIC acc_t *_bf_align(clnt_file, clnt_line, acc, size, alignment)
0003148 char *clnt_file;
0003149 int clnt_line;
0003150 #endif
0003151 acc_t *acc;
0003152 size_t size;
0003153 size_t alignment;
0003154 {
0003155          char *ptr;
0003156          size_t buf_size;
0003157          acc_t *head, *tail;
0003158 
0003159          /* Fast check if the buffer is aligned already. */
0003160          if (acc->acc_length >= size)
0003161          {
0003162                   ptr= ptr2acc_data(acc);
0003163                   if (((unsigned)ptr & (alignment-1)) == 0)
0003164                            return acc;
If the data is already packed and aligned, do nothing.

Note that both bf_pack() (line 3176) and bf_cut() (lines 3179-3180) return accessors with buffers that are aligned.


0003165          }
0003166          buf_size= bf_bufsize(acc);
0003167 #ifdef bf_align
0003168          assert(size != 0 && buf_size != 0 ||
0003169                   (printf("bf_align(..., %d, %d) from %s, %d\n",
0003170                            size, alignment, clnt_file, clnt_line),0));
0003171 #else
0003172          assert(size != 0 && buf_size != 0);
0003173 #endif
0003174          if (buf_size <= size)
0003175          {
0003176                   acc= bf_pack(acc);
Note that one of the side effects of bf_pack() is that data is aligned. For example, even if the first accessor in the linked list has an acc_offset greater than zero, the first accessor in the new, packed linked list will have an acc_offset of zero. This effectively aligns the data.


bf_pack()


bf_pack(old_acc) creates a new linked list of accessors of old_acc's equivalent length and copies the data from old_acc to it. In this way, the data is compressed (or packed).

For example, bf_pack(old_acc) will return new_acc:



(Note that 300+200+300=800=512+288.)


0003177                   return acc;
0003178          }
The first size (bf_align()'s second parameter) bytes are placed in the first accessor (created by the first call to bf_cut()) and then packed. The remaining bytes are placed in the buffers of the accessor linked list created by the second call to bf_cut().


0003179          head= bf_cut(acc, 0, size);
bf_cut()

If a section of a linked list needs to be duplicated, bf_cut(data, offset, length) is called. For example, if a section of length 50 starting at an offset of 75 of the linked list below needs to be duplicated, bf_cut(data, 75, 50) is called:



Note that the original linked list remains unchanged and that acc_linkC for all the accessors in the new linked list is one.

If length (the second parameter) is zero, simply duplicate the first accessor in the linked list but set acc_length=0 and acc_next=null. In other words, create a linked list of length one accessor whose acc_length is 0.

bf_cut() is used in a number of scenarios, including cutting a received ethernet packet to size.

For a full description of the network service's buffer management, click here.



0003180          tail= bf_cut(acc, size, buf_size-size);
bf_cut()

If a section of a linked list needs to be duplicated, bf_cut(data, offset, length) is called. For example, if a section of length 50 starting at an offset of 75 of the linked list below needs to be duplicated, bf_cut(data, 75, 50) is called:



Note that the original linked list remains unchanged and that acc_linkC for all the accessors in the new linked list is one.

If length (the second parameter) is zero, simply duplicate the first accessor in the linked list but set acc_length=0 and acc_next=null. In other words, create a linked list of length one accessor whose acc_length is 0.

bf_cut() is used in a number of scenarios, including cutting a received ethernet packet to size.

For a full description of the network service's buffer management, click here.



0003181          bf_afree(acc);
bf_afree()

After a chain of accessors is no longer needed, the chain (and not simply the single accessor passed as the parameter) can be freed by calling bf_free(). However, if either acc_linkC or buf_linkC of one of the accessors in the linked list is not equal to one (1), the entire chain will not be freed. For example, if buf_afree(acc1) is called for the following chain:



Then the resulting chain will be:



bf_afree() returns acc1 (accessors[63]) to acc_freelist (recall that acc_freelist is the linked list of acc_t's without an associated buffer). However, buffers512[127] cannot be freed because acc2 (accessors[64]) still references it.

bf_afree() is called after an accessor's associated data is no longer needed (for example, after a packet has been sent off by the ethernet driver).


0003182          head= bf_pack(head);
bf_pack()

bf_pack(old_acc) creates a new linked list of accessors of old_acc's equivalent length and copies the data from old_acc to it. In this way, the data is compressed (or packed).

For example, bf_pack(old_acc) will return new_acc:



(Note that 300+200+300=800=512+288.)


0003183          assert(head->acc_next == NULL);
0003184          head->acc_next= tail;
0003185          return head;
0003186 }
0003187 
0003188 #if 0

/* The following is not used in the default configuration.




0003189 int chk_acc(acc)
0003190 acc_t *acc;
0003191 {
0003192          int acc_nr;
0003193 
0003194          if (!acc)
0003195                   return 1;
0003196          if (acc < accessors || acc >= &accessors[ACC_NR])
0003197                   return 0;
0003198          acc_nr= acc-accessors;
0003199          return acc == &accessors[acc_nr];
0003200 }
0003201 #endif
0003202 
*/



0003203 /*
0003204  * $PchId: buf.c,v 1.10 1995/11/23 11:25:25 philip Exp $
0003205  */