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

0058001 /*
0058002 tcp_send.c
0058003 
0058004 Copyright 1995 Philip Homburg
0058005 */
0058006 
0058007 #include "inet.h"
0058008 #include "buf.h"
0058009 #include "clock.h"
0058010 #include "event.h"
0058011 #include "type.h"
0058012 
0058013 #include "assert.h"
0058014 #include "io.h"
0058015 #include "ip.h"
0058016 #include "tcp.h"
0058017 #include "tcp_int.h"
0058018 
0058019 THIS_FILE
0058020 
0058021 FORWARD acc_t *make_pack ARGS(( tcp_conn_t *tcp_conn ));
0058022 FORWARD void tcp_send_timeout ARGS(( int conn, struct timer *timer ));
0058023 FORWARD void do_snd_event ARGS(( event_t *ev, ev_arg_t arg ));
0058024 
0058025 PUBLIC void tcp_conn_write (tcp_conn, enq)
0058026 tcp_conn_t *tcp_conn;
0058027 int enq;                            /* Writes need to be enqueued. */
tcp_conn_write()




0058028 {
0058029          tcp_port_t *tcp_port;
0058030          ev_arg_t snd_arg;
0058031 
0058032          assert (tcp_conn->tc_flags & TCF_INUSE);
0058033 
0058034          tcp_port= tcp_conn->tc_port;
0058035          if (tcp_conn->tc_flags & TCF_MORE2WRITE)
0058036                   return;
0058037 
0058038          /* XXX - do we really have something to send here? */
0058039 
0058040          tcp_conn->tc_flags |= TCF_MORE2WRITE;
0058041          tcp_conn->tc_send_link= NULL;
0058042          if (!tcp_port->tp_snd_head)
0058043          {
0058044                   tcp_port->tp_snd_head= tcp_conn;
0058045                   tcp_port->tp_snd_tail= tcp_conn;
0058046                   if (enq)
0058047                   {
0058048                            snd_arg.ev_ptr= tcp_port;
0058049                            if (!ev_in_queue(&tcp_port->tp_snd_event))
event_t / ev_enqueue() / ev_process() / ev_init() / ev_in_queue()

The event_t typedef is declared in inet/generic/event.h:

typedef struct event

{
ev_func_t ev_func;
ev_arg_t ev_arg;
struct event *ev_next;
} event_t;
If an event needs to be scheduled, ev_enqueue() is called to place the event in the system-wide event queue whose head is ev_head. ev_process() is eventually called from the main loop in inet.c to process the events. ev_in_queue(ev) simply returns TRUE if the event ev, ev_in_queue()'s only parameter, has a non-null value for func (see below) and FALSE if func is null. In this way, ev_in_queue() determines whether the event has been configured.

ev_init(ev) simply zeroes out the ev_func and ev_next fields of the event ev, ev_init()'s only parameter.

ev_func: A function (e.g., ip_process_loopb()) that performs some task.

ev_arg:

typedef union ev_arg

{
int ev_int;
void *ev_ptr;
} ev_arg_t;
ev_arg is ev_func's argument. In the case of a packet destined for the loopback address (127.0.0.1), the argument will be the ip port associated with the ip file descriptor that is sending out the packet. In the case of a message from the ethernet task that caused a deadlock, ev_arg is a pointer to the message's destination ethernet port.

ev_next: The next event in the system-wide event queue.


0058050                            {
0058051                                     ev_enqueue(&tcp_port->tp_snd_event,
0058052                                              do_snd_event, snd_arg);
event_t / ev_enqueue() / ev_process() / ev_init() / ev_in_queue()

The event_t typedef is declared in inet/generic/event.h:

typedef struct event

{
ev_func_t ev_func;
ev_arg_t ev_arg;
struct event *ev_next;
} event_t;
If an event needs to be scheduled, ev_enqueue() is called to place the event in the system-wide event queue whose head is ev_head. ev_process() is eventually called from the main loop in inet.c to process the events. ev_in_queue(ev) simply returns TRUE if the event ev, ev_in_queue()'s only parameter, has a non-null value for func (see below) and FALSE if func is null. In this way, ev_in_queue() determines whether the event has been configured.

ev_init(ev) simply zeroes out the ev_func and ev_next fields of the event ev, ev_init()'s only parameter.

ev_func: A function (e.g., ip_process_loopb()) that performs some task.

ev_arg:

typedef union ev_arg

{
int ev_int;
void *ev_ptr;
} ev_arg_t;
ev_arg is ev_func's argument. In the case of a packet destined for the loopback address (127.0.0.1), the argument will be the ip port associated with the ip file descriptor that is sending out the packet. In the case of a message from the ethernet task that caused a deadlock, ev_arg is a pointer to the message's destination ethernet port.

ev_next: The next event in the system-wide event queue.do_snd_event() / tcp




0058053                            }
0058054                   }
0058055                   else
0058056                            tcp_port_write(tcp_port);
tcp_port_write()




0058057          }
0058058          else
0058059          {
0058060                   tcp_port->tp_snd_tail->tc_send_link= tcp_conn;
0058061                   tcp_port->tp_snd_tail= tcp_conn;
0058062          }
0058063 }
0058064 
0058065 PRIVATE void do_snd_event(ev, arg)
0058066 event_t *ev;
0058067 ev_arg_t arg;
do_snd_event() / tcp




0058068 {
0058069          tcp_port_t *tcp_port;
0058070 
0058071          tcp_port= arg.ev_ptr;
0058072 
0058073          assert(ev == &tcp_port->tp_snd_event);
0058074          tcp_port_write(tcp_port);
tcp_port_write()




0058075 }
0058076 
0058077 PUBLIC void tcp_port_write(tcp_port)
0058078 tcp_port_t *tcp_port;
tcp_port_write()




0058079 {
0058080          tcp_conn_t *tcp_conn;
0058081          acc_t *pack2write;
0058082          int r;
0058083 
0058084          assert (!(tcp_port->tp_flags & TPF_WRITE_IP));
0058085 
0058086          while(tcp_port->tp_snd_head)
0058087          {
0058088                   tcp_conn= tcp_port->tp_snd_head;
0058089                   assert(tcp_conn->tc_flags & TCF_MORE2WRITE);
0058090 
0058091                   for(;;)
0058092                   {
0058093                            if (tcp_conn->tc_frag2send)
0058094                            {
0058095                                     pack2write= tcp_conn->tc_frag2send;
0058096                                     tcp_conn->tc_frag2send= 0;
0058097                            }
0058098                            else
0058099                            {
0058100                                     tcp_conn->tc_busy++;
0058101                                     pack2write= make_pack(tcp_conn);
make_pack() / tcp




0058102                                     tcp_conn->tc_busy--;
0058103                                     if (!pack2write)
0058104                                              break;
0058105                            }
0058106                            r= ip_send(tcp_port->tp_ipfd, pack2write,
0058107                                     bf_bufsize(pack2write));
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.


0058108                            if (r != NW_OK)
0058109                            {
0058110                                     if (r == NW_WOULDBLOCK)
0058111                                              break;
0058112                                     if (r == EDSTNOTRCH)
0058113                                     {
0058114                                              tcp_notreach(tcp_conn);
tcp_notreach()




0058115                                              continue;
0058116                                     }
0058117                                     else if (r == EBADDEST)
0058118                                              continue;
0058119                            }
0058120                            assert(r == NW_OK ||
0058121                                     (printf("ip_send failed, error %d\n", r),0));
0058122                   }
0058123 
0058124                   if (pack2write)
0058125                   {
0058126                            tcp_port->tp_flags |= TPF_WRITE_IP;
0058127                            tcp_port->tp_pack= pack2write;
0058128 
0058129                            r= ip_write (tcp_port->tp_ipfd,
0058130                                     bf_bufsize(pack2write));
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.


0058131                            if (r == NW_SUSPEND)
0058132                            {
0058133                                     tcp_port->tp_flags |= TPF_WRITE_SP;
0058134                                     return;
0058135                            }
0058136                            assert(r == NW_OK);
0058137                            tcp_port->tp_flags &= ~TPF_WRITE_IP;
0058138                            assert(!(tcp_port->tp_flags &
0058139                                     (TPF_WRITE_IP|TPF_WRITE_SP)));
0058140                            continue;
0058141                   }
0058142                   tcp_conn->tc_flags &= ~TCF_MORE2WRITE;
0058143                   tcp_port->tp_snd_head= tcp_conn->tc_send_link;
0058144 
0058145          }
0058146 }
0058147 
0058148 PRIVATE acc_t *make_pack(tcp_conn)
0058149 tcp_conn_t *tcp_conn;
make_pack() / tcp




0058150 {
0058151          acc_t *pack2write, *tmp_pack, *tcp_pack;
0058152          tcp_hdr_t *tcp_hdr;
0058153          ip_hdr_t *ip_hdr;
0058154          int tot_hdr_size, ip_hdr_len;
0058155          u32_t seg_seq, seg_lo_data, queue_lo_data, seg_hi, seg_hi_data;
0058156          u16_t seg_up;
0058157          u8_t seg_flags;
0058158          time_t new_dis;
0058159          size_t pack_size;
0058160          time_t curr_time;
0058161          u8_t *optptr;
0058162 
0058163          assert(tcp_conn->tc_busy);
0058164          curr_time= get_time();
get_time()

get_time() returns the number of clock ticks since reboot.

Several of the clients (eth, arp, ip, tcp, and udp) use get_time() to determine an appropriate timeout value for a given operation. For example, the arp code calls get_time() to determine an appropriate amount of time to wait for a response from an arp request before giving up.


0058165          switch (tcp_conn->tc_state)
0058166          {
0058167          case TCS_CLOSED:
0058168                   return 0;
0058169          case TCS_SYN_RECEIVED:
0058170          case TCS_SYN_SENT:
0058171 
0058172                   if (tcp_conn->tc_SND_TRM == tcp_conn->tc_SND_NXT &&
0058173                            !(tcp_conn->tc_flags & TCF_SEND_ACK))
0058174                   {
0058175                            return 0;
0058176                   }
0058177 
0058178                   tcp_conn->tc_flags &= ~TCF_SEND_ACK;
0058179 
0058180                   /* Include a max segment size option. */
0058181                   assert(tcp_conn->tc_tcpopt == NULL);
0058182                   tcp_conn->tc_tcpopt= bf_memreq(4);
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.


0058183                   optptr= (u8_t *)ptr2acc_data(tcp_conn->tc_tcpopt);
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.


0058184                   optptr[0]= TCP_OPT_MSS;
0058185                   optptr[1]= 4;
0058186                   optptr[2]= tcp_conn->tc_mss >> 8;
0058187                   optptr[3]= tcp_conn->tc_mss & 0xFF;
0058188 
0058189                   pack2write= tcp_make_header(tcp_conn, &ip_hdr, &tcp_hdr,
0058190                            (acc_t *)0);
tcp_make_header()




0058191 
0058192                   bf_afree(tcp_conn->tc_tcpopt);
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).


0058193                   tcp_conn->tc_tcpopt= NULL;
0058194 
0058195                   if (!pack2write)
0058196                   {
0058197                            DBLOCK(1, printf("connection closed while inuse\n"));
0058198                            return 0;
0058199                   }
0058200                   tot_hdr_size= bf_bufsize(pack2write);
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.


0058201                   seg_seq= tcp_conn->tc_SND_TRM;
0058202                   if (tcp_conn->tc_state == TCS_SYN_SENT)
0058203                            seg_flags= 0;
0058204                   else
0058205                            seg_flags= THF_ACK;       /* except for TCS_SYN_SENT
0058206                                                  * ack is always present */
0058207 
0058208                   if (seg_seq == tcp_conn->tc_ISS)
0058209                   {
0058210                            assert(tcp_conn->tc_transmit_timer.tim_active ||
0058211                                     (tcp_print_conn(tcp_conn), printf("\n"), 0));
0058212                            seg_flags |= THF_SYN;
0058213                            tcp_conn->tc_SND_TRM++;
0058214                   }
0058215 
0058216                   tcp_hdr->th_seq_nr= htonl(seg_seq);
htons() / ntohs() / htonl() / ntohl()

From htons(3):

"htons() converts a 16-bit quantity from host byte order to network byte order."

Different CPU architectures group multiple bytes differently. For example, on a "little-endian" machine (an example of which is the Intel CPU), the value 0x1234 is stored in memory as 0x3412. However, on a "big-endian" machine, the value 0x1234 is stored in memory as 0x1234.

It is important that values in a header are sent across a network in a consistent manner independent of the architecture of the sending or receiving system. For this reason, a standard was chosen. The standard chosen was big-endian although it could have just as well been little-endian.

htons() is defined in /include/net/hton.h, as:
#define htons(x) (_tmp=(x), ((_tmp>>8) & 0xff) | ((_tmp<<8) & 0xff00))

ntohs() converts a 16-bit quantity from network byte order to host byte order, the reverse of htons().

htonl() and ntohl() are identical to htons() and ntohs() except that they convert 32-bit quantities instead of 16-bit quantities.

Processes generally supply header information when sending packets. The data in these fields is converted to the network format (i.e., big-endian) by the process before the process copies the data to the network service.


0058217                   tcp_hdr->th_ack_nr= htonl(tcp_conn->tc_RCV_NXT);
htons() / ntohs() / htonl() / ntohl()

From htons(3):

"htons() converts a 16-bit quantity from host byte order to network byte order."

Different CPU architectures group multiple bytes differently. For example, on a "little-endian" machine (an example of which is the Intel CPU), the value 0x1234 is stored in memory as 0x3412. However, on a "big-endian" machine, the value 0x1234 is stored in memory as 0x1234.

It is important that values in a header are sent across a network in a consistent manner independent of the architecture of the sending or receiving system. For this reason, a standard was chosen. The standard chosen was big-endian although it could have just as well been little-endian.

htons() is defined in /include/net/hton.h, as:
#define htons(x) (_tmp=(x), ((_tmp>>8) & 0xff) | ((_tmp<<8) & 0xff00))

ntohs() converts a 16-bit quantity from network byte order to host byte order, the reverse of htons().

htonl() and ntohl() are identical to htons() and ntohs() except that they convert 32-bit quantities instead of 16-bit quantities.

Processes generally supply header information when sending packets. The data in these fields is converted to the network format (i.e., big-endian) by the process before the process copies the data to the network service.


0058218                   tcp_hdr->th_flags= seg_flags;
0058219                   tcp_hdr->th_window= htons(tcp_conn->tc_mss);
htons() / ntohs() / htonl() / ntohl()

From htons(3):

"htons() converts a 16-bit quantity from host byte order to network byte order."

Different CPU architectures group multiple bytes differently. For example, on a "little-endian" machine (an example of which is the Intel CPU), the value 0x1234 is stored in memory as 0x3412. However, on a "big-endian" machine, the value 0x1234 is stored in memory as 0x1234.

It is important that values in a header are sent across a network in a consistent manner independent of the architecture of the sending or receiving system. For this reason, a standard was chosen. The standard chosen was big-endian although it could have just as well been little-endian.

htons() is defined in /include/net/hton.h, as:
#define htons(x) (_tmp=(x), ((_tmp>>8) & 0xff) | ((_tmp<<8) & 0xff00))

ntohs() converts a 16-bit quantity from network byte order to host byte order, the reverse of htons().

htonl() and ntohl() are identical to htons() and ntohs() except that they convert 32-bit quantities instead of 16-bit quantities.

Processes generally supply header information when sending packets. The data in these fields is converted to the network format (i.e., big-endian) by the process before the process copies the data to the network service.


0058220                            /* Initially we allow one segment */
0058221 
0058222                   ip_hdr->ih_length= htons(tot_hdr_size);
0058223 
0058224                   pack2write->acc_linkC++;
0058225                   ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2;
0058226                   tcp_pack= bf_delhead(pack2write, ip_hdr_len);
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.


0058227                   tcp_hdr->th_chksum= ~tcp_pack_oneCsum(ip_hdr, tcp_pack);
tcp_pack_oneCsum()

tcp_pack_oneCsum() computes the checksum of a tcp packet (including several fields of its ip header). It accomplishes this by computing the checksum (by calling oneC_sum()) of each of the tcp packet's buffers.

Note that a checksum is used to determine if errors occurred during the transmission of data.


0058228                   bf_afree(tcp_pack);
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).


0058229 
0058230                   new_dis= curr_time + 2*HZ*tcp_conn->tc_ttl;
0058231                   if (new_dis > tcp_conn->tc_senddis)
0058232                            tcp_conn->tc_senddis= new_dis;
0058233                   return pack2write;
0058234 
0058235          case TCS_ESTABLISHED:
0058236          case TCS_CLOSING:
0058237                   seg_seq= tcp_conn->tc_SND_TRM;
0058238 
0058239                   seg_flags= 0;
0058240                   pack2write= 0;
0058241                   seg_up= 0;
0058242                   if (tcp_conn->tc_flags & TCF_SEND_ACK)
0058243                   {
0058244                            seg_flags= THF_ACK;
0058245                            tcp_conn->tc_flags &= ~TCF_SEND_ACK;
0058246 
0058247                            pack2write= tcp_make_header (tcp_conn, &ip_hdr,
0058248                                     &tcp_hdr, (acc_t *)0);
tcp_make_header()




0058249                            if (!pack2write)
0058250                            {
0058251                                     return NULL;
0058252                            }
0058253                   }
0058254 
0058255                   if (tcp_conn->tc_SND_UNA != tcp_conn->tc_SND_NXT)
0058256                   {
0058257                            assert(tcp_LEmod4G(seg_seq, tcp_conn->tc_SND_NXT));
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0058258 
0058259                            if (seg_seq == tcp_conn->tc_snd_cwnd)
0058260                            {
0058261                                     DBLOCK(2,
0058262                                              printf("no data: window is closed\n"));
0058263                                     goto after_data;
0058264                            }
0058265 
0058266                            /* Assert that our SYN has been ACKed. */
0058267                            assert(tcp_conn->tc_SND_UNA != tcp_conn->tc_ISS);
0058268 
0058269                            seg_lo_data= seg_seq;
0058270                            queue_lo_data= tcp_conn->tc_SND_UNA;
0058271 
0058272                            seg_hi= tcp_conn->tc_SND_NXT;
0058273                            seg_hi_data= seg_hi;
0058274                            if (tcp_conn->tc_flags & TCF_FIN_SENT)
0058275                            {
0058276                                     if (seg_seq != seg_hi)
0058277                                              seg_flags |= THF_FIN;
0058278                                     if (queue_lo_data == seg_hi_data)
0058279                                              queue_lo_data--;
0058280                                     if (seg_lo_data == seg_hi_data)
0058281                                              seg_lo_data--;
0058282                                     seg_hi_data--;
0058283                            }
0058284 
0058285                            if (!pack2write)
0058286                            {
0058287                                     pack2write= tcp_make_header (tcp_conn,
0058288                                              &ip_hdr, &tcp_hdr, (acc_t *)0);
tcp_make_header()




0058289                                     if (!pack2write)
0058290                                     {
0058291                                              return NULL;
0058292                                     }
0058293                            }
0058294 
0058295                            tot_hdr_size= bf_bufsize(pack2write);
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.


0058296                            if (seg_hi_data - seg_lo_data > tcp_conn->tc_mss -
0058297                                     tot_hdr_size)
0058298                            {
0058299                                     seg_hi_data= seg_lo_data + tcp_conn->tc_mss -
0058300                                              tot_hdr_size;
0058301                                     seg_hi= seg_hi_data;
0058302                                     seg_flags &= ~THF_FIN;
0058303                            }
0058304 
0058305                            if (tcp_Gmod4G(seg_hi, tcp_conn->tc_snd_cwnd))
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0058306                            {
0058307                                     seg_hi_data= tcp_conn->tc_snd_cwnd;
0058308                                     seg_hi= seg_hi_data;
0058309                                     seg_flags &= ~THF_FIN;
0058310                            }
0058311 
0058312                            if (seg_hi-seg_seq == 0)
0058313                            {
0058314                                     DBLOCK(0x20,
0058315                                     printf("no data: no data available\n"));
0058316                                     goto after_data;
0058317                            }
0058318 
0058319                            if (seg_seq != tcp_conn->tc_SND_UNA &&
0058320                                     seg_hi_data-seg_lo_data+tot_hdr_size <
0058321                                     tcp_conn->tc_mss)
0058322                            {
0058323                                     DBLOCK(0x20,
0058324                                              printf("no data: partial packet\n"));
0058325                                     seg_flags &= ~THF_FIN;
0058326                                     goto after_data;
0058327                            }
0058328 
0058329                            if (tcp_GEmod4G(tcp_conn->tc_SND_UP, seg_lo_data))
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0058330                            {
0058331                                     if (tcp_GEmod4G(tcp_conn->tc_SND_UP,
0058332                                              seg_hi_data))
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0058333                                     {
0058334                                              seg_up= seg_hi_data-seg_seq;
0058335                                     }
0058336                                     else
0058337                                     {
0058338                                              seg_up= tcp_conn->tc_SND_UP-seg_seq;
0058339                                     }
0058340                                     seg_flags |= THF_URG;
0058341                                     if ((tcp_conn->tc_flags & TCF_BSD_URG) &&
0058342                                              seg_up == 0)
0058343                                     {
0058344                                              /* A zero urgent pointer doesn't mean
0058345                                               * anything when BSD semantics are
0058346                                               * used (urgent pointer points to the
0058347                                               * first no urgent byte). The use of
0058348                                               * a zero urgent pointer also crashes
0058349                                               * a Solaris 2.3 kernel. If urgent
0058350                                               * pointer doesn't have BSD semantics
0058351                                               * then an urgent pointer of zero
0058352                                               * simply indicates that there is one
0058353                                               * urgent byte.
0058354                                               */
0058355                                              seg_flags &= ~THF_URG;
0058356                                     }
0058357                            }
0058358                            else
0058359                                     seg_up= 0;
0058360 
0058361                            if (tcp_Gmod4G(tcp_conn->tc_SND_PSH, seg_lo_data) &&
0058362                                     tcp_LEmod4G(tcp_conn->tc_SND_PSH, seg_hi_data))
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0058363                            {
0058364                                     seg_flags |= THF_PSH;
0058365                            }
0058366 
0058367                            tcp_conn->tc_SND_TRM= seg_hi;
0058368 
0058369                            assert(tcp_conn->tc_transmit_timer.tim_active ||
0058370                                     (tcp_print_conn(tcp_conn), printf("\n"), 0));
tcp_print_conn()




0058371                            if (tcp_conn->tc_rt_seq == 0 &&
0058372                                     tcp_Gmod4G(seg_seq, tcp_conn->tc_rt_threshold))
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0058373                            {
0058374                                     tcp_conn->tc_rt_time= curr_time;
0058375                                     tcp_conn->tc_rt_seq=
0058376                                              tcp_conn->tc_rt_threshold= seg_seq;
0058377                            }
0058378 
0058379                            if (seg_hi_data-seg_lo_data)
0058380                            {
0058381 #if DEBUG & 0
0058382                                     assert(tcp_check_conn(tcp_conn));
0058383                                     assert((seg_hi_data-queue_lo_data <=
0058384                                              bf_bufsize(tcp_conn->tc_send_data) &&
0058385                                              seg_lo_data-queue_lo_data <=
0058386                                              bf_bufsize(tcp_conn->tc_send_data) &&
0058387                                              seg_hi_data>seg_lo_data)||
0058388                                              (tcp_print_conn(tcp_conn),
0058389                                              printf(
0058390                   " seg_hi_data= 0x%x, seg_lo_data= 0x%x, queue_lo_data= 0x%x\n",
0058391                                              seg_hi_data, seg_lo_data,
0058392                                              queue_lo_data), 0));
0058393 #endif
0058394 
0058395                                     tmp_pack= pack2write;
0058396                                     while (tmp_pack->acc_next)
0058397                                              tmp_pack= tmp_pack->acc_next;
0058398                                     tmp_pack->acc_next=
0058399                                              bf_cut(tcp_conn->tc_send_data,
0058400                                              (unsigned)(seg_lo_data-queue_lo_data),
0058401                                              (unsigned) (seg_hi_data-seg_lo_data));
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.



0058402                            }
0058403                            seg_flags |= THF_ACK;
0058404                   }
0058405 
0058406 after_data:
0058407                   if (!(seg_flags & THF_ACK))
0058408                   {
0058409                            if (pack2write)
0058410                                     bf_afree(pack2write);
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).


0058411                            return NULL;
0058412                   }
0058413 
0058414                   tcp_hdr->th_seq_nr= htonl(seg_seq);
htons() / ntohs() / htonl() / ntohl()

From htons(3):

"htons() converts a 16-bit quantity from host byte order to network byte order."

Different CPU architectures group multiple bytes differently. For example, on a "little-endian" machine (an example of which is the Intel CPU), the value 0x1234 is stored in memory as 0x3412. However, on a "big-endian" machine, the value 0x1234 is stored in memory as 0x1234.

It is important that values in a header are sent across a network in a consistent manner independent of the architecture of the sending or receiving system. For this reason, a standard was chosen. The standard chosen was big-endian although it could have just as well been little-endian.

htons() is defined in /include/net/hton.h, as:
#define htons(x) (_tmp=(x), ((_tmp>>8) & 0xff) | ((_tmp<<8) & 0xff00))

ntohs() converts a 16-bit quantity from network byte order to host byte order, the reverse of htons().

htonl() and ntohl() are identical to htons() and ntohs() except that they convert 32-bit quantities instead of 16-bit quantities.

Processes generally supply header information when sending packets. The data in these fields is converted to the network format (i.e., big-endian) by the process before the process copies the data to the network service.


0058415                   tcp_hdr->th_ack_nr= htonl(tcp_conn->tc_RCV_NXT);
htons() / ntohs() / htonl() / ntohl()

From htons(3):

"htons() converts a 16-bit quantity from host byte order to network byte order."

Different CPU architectures group multiple bytes differently. For example, on a "little-endian" machine (an example of which is the Intel CPU), the value 0x1234 is stored in memory as 0x3412. However, on a "big-endian" machine, the value 0x1234 is stored in memory as 0x1234.

It is important that values in a header are sent across a network in a consistent manner independent of the architecture of the sending or receiving system. For this reason, a standard was chosen. The standard chosen was big-endian although it could have just as well been little-endian.

htons() is defined in /include/net/hton.h, as:
#define htons(x) (_tmp=(x), ((_tmp>>8) & 0xff) | ((_tmp<<8) & 0xff00))

ntohs() converts a 16-bit quantity from network byte order to host byte order, the reverse of htons().

htonl() and ntohl() are identical to htons() and ntohs() except that they convert 32-bit quantities instead of 16-bit quantities.

Processes generally supply header information when sending packets. The data in these fields is converted to the network format (i.e., big-endian) by the process before the process copies the data to the network service.


0058416                   tcp_hdr->th_flags= seg_flags;
0058417                   tcp_hdr->th_window= htons(tcp_conn->tc_RCV_HI -
0058418                            tcp_conn->tc_RCV_NXT);
0058419                   tcp_hdr->th_urgptr= htons(seg_up);
htons() / ntohs() / htonl() / ntohl()

From htons(3):

"htons() converts a 16-bit quantity from host byte order to network byte order."

Different CPU architectures group multiple bytes differently. For example, on a "little-endian" machine (an example of which is the Intel CPU), the value 0x1234 is stored in memory as 0x3412. However, on a "big-endian" machine, the value 0x1234 is stored in memory as 0x1234.

It is important that values in a header are sent across a network in a consistent manner independent of the architecture of the sending or receiving system. For this reason, a standard was chosen. The standard chosen was big-endian although it could have just as well been little-endian.

htons() is defined in /include/net/hton.h, as:
#define htons(x) (_tmp=(x), ((_tmp>>8) & 0xff) | ((_tmp<<8) & 0xff00))

ntohs() converts a 16-bit quantity from network byte order to host byte order, the reverse of htons().

htonl() and ntohl() are identical to htons() and ntohs() except that they convert 32-bit quantities instead of 16-bit quantities.

Processes generally supply header information when sending packets. The data in these fields is converted to the network format (i.e., big-endian) by the process before the process copies the data to the network service.


0058420 
0058421                   pack_size= bf_bufsize(pack2write);
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.


0058422                   ip_hdr->ih_length= htons(pack_size);
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.


0058423 
0058424                   pack2write->acc_linkC++;
0058425                   ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2;
0058426                   tcp_pack= bf_delhead(pack2write, ip_hdr_len);
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.


0058427                   tcp_hdr->th_chksum= ~tcp_pack_oneCsum(ip_hdr, tcp_pack);
tcp_pack_oneCsum()

tcp_pack_oneCsum() computes the checksum of a tcp packet (including several fields of its ip header). It accomplishes this by computing the checksum (by calling oneC_sum()) of each of the tcp packet's buffers.

Note that a checksum is used to determine if errors occurred during the transmission of data.


0058428                   bf_afree(tcp_pack);
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).


0058429 
0058430                   new_dis= curr_time + 2*HZ*tcp_conn->tc_ttl;
0058431                   if (new_dis > tcp_conn->tc_senddis)
0058432                            tcp_conn->tc_senddis= new_dis;
0058433 
0058434                   return pack2write;
0058435 #if !CRAMPED
0058436          default:
0058437                   DBLOCK(1, tcp_print_conn(tcp_conn); printf("\n"));
0058438                   ip_panic(( "Illegal state" ));
0058439 #endif
0058440          }
0058441          assert(0);
0058442          return NULL;
0058443 }
0058444 
0058445 /*
0058446 tcp_release_retrans
0058447 */
0058448 
0058449 PUBLIC void tcp_release_retrans(tcp_conn, seg_ack, new_win)
0058450 tcp_conn_t *tcp_conn;
0058451 u32_t seg_ack;
0058452 u16_t new_win;
tcp_release_retrans()




0058453 {
0058454          size_t size, offset;
0058455          acc_t *pack;
0058456          time_t retrans_time, curr_time, rtt;
0058457          u32_t queue_lo, queue_hi;
0058458          u16_t mss, cthresh;
0058459          unsigned window;
0058460 
0058461          assert(tcp_conn->tc_busy);
0058462          assert (tcp_GEmod4G(seg_ack, tcp_conn->tc_SND_UNA));
0058463          assert (tcp_LEmod4G(seg_ack, tcp_conn->tc_SND_NXT));
0058464 
0058465          curr_time= get_time();
get_time()

get_time() returns the number of clock ticks since reboot.

Several of the clients (eth, arp, ip, tcp, and udp) use get_time() to determine an appropriate timeout value for a given operation. For example, the arp code calls get_time() to determine an appropriate amount of time to wait for a response from an arp request before giving up.


0058466          if (tcp_conn->tc_rt_seq != 0 &&
0058467                   tcp_Gmod4G(seg_ack, tcp_conn->tc_rt_seq))
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0058468          {
0058469                   assert(curr_time >= tcp_conn->tc_rt_time);
0058470                   retrans_time= curr_time-tcp_conn->tc_rt_time;
0058471                   rtt= tcp_conn->tc_rtt;
0058472 
0058473                   DBLOCK(0x20, printf(
0058474                   "tcp_release_retrans, conn[%d]: retrans_time= %ld ms\n",
0058475                            tcp_conn-tcp_conn_table, retrans_time*1000/HZ));
0058476 
0058477 
0058478                   tcp_conn->tc_rt_seq= 0;
0058479 
0058480                   if (rtt == TCP_RTT_GRAN*CLOCK_GRAN &&
0058481                            retrans_time <= TCP_RTT_GRAN*CLOCK_GRAN)
0058482                   {
0058483                            /* Common in fast networks. Nothing to do. */
0058484                   }
0058485                   else if (rtt >= retrans_time && rtt <= 2*retrans_time)
0058486                   {
0058487                            /* Nothing to do. We assume that a factor 2 for
0058488                             * variance is enough.
0058489                             */
0058490                   }
0058491                   else if (retrans_time > rtt)
0058492                   {
0058493                            /* Retrans time is really too small. */
0058494 
0058495                            tcp_conn->tc_rtt= rtt*2;
0058496                            if (tcp_conn->tc_rtt > TCP_RTT_MAX)
0058497                            {
0058498 #if DEBUG
0058499                                     static int warned /* = 0 */;
0058500 
0058501                                     if (!warned)
0058502                                     {
0058503                                              printf(
0058504 "tcp_release_retrans: warning retransmission time is limited to %d ms\n",
0058505                                           TCP_RTT_MAX*1000/HZ);
0058506                                              warned= 1;
0058507                                     }
0058508 #endif
0058509                                     tcp_conn->tc_rtt= TCP_RTT_MAX;
0058510                            }
0058511                            assert (tcp_conn->tc_rtt);
0058512 
0058513                            DBLOCK(0x10, printf(
0058514 "tcp_release_retrans, conn[%d]: (was too small) retrans_time= %ld ms, rtt= %ld ms\n",
0058515                                     tcp_conn-tcp_conn_table, retrans_time*1000/HZ,
0058516                                     tcp_conn->tc_rtt*1000/HZ));
0058517 
0058518 
0058519                   }
0058520                   else if (seg_ack - tcp_conn->tc_rt_seq == tcp_conn->tc_mss)
0058521                   {
0058522                            /* Retrans time is really too big. */
0058523                            rtt= (rtt*3)>>2;
0058524                            if (rtt < TCP_RTT_GRAN*CLOCK_GRAN)
0058525                                     rtt= TCP_RTT_GRAN*CLOCK_GRAN;
0058526                            tcp_conn->tc_rtt= rtt;
0058527                            assert (tcp_conn->tc_rtt);
0058528 
0058529                            DBLOCK(0x10, printf(
0058530 "tcp_release_retrans, conn[%d]: (was too big) retrans_time= %ld ms, rtt= %ld ms\n",
0058531                                     tcp_conn-tcp_conn_table, retrans_time*1000/HZ,
0058532                                     tcp_conn->tc_rtt*1000/HZ));
0058533                   }
0058534                   else
0058535                   {
0058536                            /* Retrans time might be too big. Try a bit smaller. */
0058537                            rtt= (rtt*31)>>5;
0058538                            if (rtt < TCP_RTT_GRAN*CLOCK_GRAN)
0058539                                     rtt= TCP_RTT_GRAN*CLOCK_GRAN;
0058540                            tcp_conn->tc_rtt= rtt;
0058541                            assert (tcp_conn->tc_rtt);
0058542 
0058543                            DBLOCK(0x20, printf(
0058544 "tcp_release_retrans, conn[%d]: (maybe too big) retrans_time= %ld ms, rtt= %ld ms\n",
0058545                                     tcp_conn-tcp_conn_table, retrans_time*1000/HZ,
0058546                                     tcp_conn->tc_rtt*1000/HZ));
0058547                   }
0058548          }
0058549 
0058550          /* Update the current window. */
0058551          window= tcp_conn->tc_snd_cwnd-tcp_conn->tc_SND_UNA;
0058552          mss= tcp_conn->tc_mss;
0058553          assert(seg_ack != tcp_conn->tc_SND_UNA);
0058554 
0058555          /* For every real ACK we try to increase the current window
0058556           * with 1 mss.
0058557           */
0058558          window += mss;
0058559 
0058560          /* If the window becomes larger than the current threshold,
0058561           * increment the threshold by a small amount and set the
0058562           * window to the threshold.
0058563           */
0058564          cthresh= tcp_conn->tc_snd_cthresh;
0058565          if (window > cthresh)
0058566          {
0058567                   cthresh += tcp_conn->tc_snd_cinc;
0058568                   tcp_conn->tc_snd_cthresh= cthresh;
0058569                   window= cthresh;
0058570          }
0058571 
0058572          /* If the window is larger than the window advertised by the
0058573           * receiver, set the window size to the advertisement.
0058574           */
0058575          if (window > new_win)
0058576                   window= new_win;
0058577 
0058578          tcp_conn->tc_snd_cwnd= seg_ack+window;
0058579 
0058580          /* Release data queued for retransmissions. */
0058581          queue_lo= tcp_conn->tc_SND_UNA;
0058582          queue_hi= tcp_conn->tc_SND_NXT;
0058583 
0058584          tcp_conn->tc_SND_UNA= seg_ack;
0058585          if (tcp_Lmod4G(tcp_conn->tc_SND_TRM, seg_ack))
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0058586          {
0058587                   tcp_conn->tc_SND_TRM= seg_ack;
0058588          }
0058589          assert(tcp_GEmod4G(tcp_conn->tc_snd_cwnd, seg_ack));
0058590 
0058591          if (queue_lo == tcp_conn->tc_ISS)
0058592                   queue_lo++;
0058593 
0058594          if (tcp_conn->tc_flags & TCF_FIN_SENT)
0058595          {
0058596                   if (seg_ack == queue_hi)
0058597                            seg_ack--;
0058598                   if (queue_lo == queue_hi)
0058599                            queue_lo--;
0058600                   queue_hi--;
0058601          }
0058602 
0058603          offset= seg_ack - queue_lo;
0058604          size= queue_hi - seg_ack;
0058605          pack= tcp_conn->tc_send_data;
0058606          tcp_conn->tc_send_data= 0;
0058607 
0058608          if (!size)
0058609          {
0058610                   bf_afree(pack);
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).


0058611 
0058612                   /* Reset window if a write is completed */
0058613                   tcp_conn->tc_snd_cwnd= tcp_conn->tc_SND_UNA +
0058614                            2*tcp_conn->tc_mss;
0058615          }
0058616          else
0058617          {
0058618                   pack= bf_delhead(pack, 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.


0058619                   tcp_conn->tc_send_data= pack;
0058620          }
0058621 
0058622          if (tcp_Gmod4G(tcp_conn->tc_SND_TRM, tcp_conn->tc_snd_cwnd))
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0058623                   tcp_conn->tc_SND_TRM= tcp_conn->tc_snd_cwnd;
0058624 
0058625          /* Copy in new data if a write request is pending and
0058626           * SND_NXT-SND_TRM is less than 1 mss.
0058627           */
0058628          if (tcp_conn->tc_fd)
0058629          {
0058630                   if ((tcp_conn->tc_fd->tf_flags &
0058631                            (TFF_WRITE_IP|TFF_IOCTL_IP)) &&
0058632                            tcp_conn->tc_SND_NXT-tcp_conn->tc_SND_TRM <
0058633                            tcp_conn->tc_mss)
0058634                   {
0058635                            tcp_fd_write(tcp_conn);
tcp_fd_write()




0058636                   }
0058637          }
0058638          else
0058639          {
0058640                   if (tcp_conn->tc_SND_UNA == tcp_conn->tc_SND_NXT)
0058641                   {
0058642                            assert(tcp_conn->tc_state == TCS_CLOSING);
0058643                            DBLOCK(0x10,
0058644                            printf("all data sent in abondoned connection\n"));
0058645                            tcp_close_connection(tcp_conn, ENOTCONN);
tcp_close_connection()




0058646                            return;
0058647                   }
0058648          }
0058649 
0058650          DIFBLOCK(2, (tcp_conn->tc_snd_cwnd == tcp_conn->tc_SND_TRM),
0058651                   printf("not sending: zero window\n"));
0058652 
0058653          if (tcp_conn->tc_snd_cwnd != tcp_conn->tc_SND_TRM &&
0058654                   tcp_conn->tc_SND_NXT != tcp_conn->tc_SND_TRM)
0058655          {
0058656                   tcp_conn_write(tcp_conn, 1);
tcp_conn_write()




0058657          }
0058658 
0058659 }
0058660 
0058661 /*
0058662 tcp_send_timeout
0058663 */
0058664 
0058665 PRIVATE void tcp_send_timeout(conn, timer)
0058666 int conn;
0058667 struct timer *timer;
tcp_send_timeout()




0058668 {
0058669          tcp_conn_t *tcp_conn;
0058670          u16_t mss, mss2;
0058671          time_t curr_time, stt, timeout;
0058672 
0058673          curr_time= get_time();
get_time()

get_time() returns the number of clock ticks since reboot.

Several of the clients (eth, arp, ip, tcp, and udp) use get_time() to determine an appropriate timeout value for a given operation. For example, the arp code calls get_time() to determine an appropriate amount of time to wait for a response from an arp request before giving up.


0058674 
0058675          tcp_conn= &tcp_conn_table[conn];
0058676          assert(tcp_conn->tc_flags & TCF_INUSE);
0058677          assert(tcp_conn->tc_state != TCS_CLOSED);
0058678          assert(tcp_conn->tc_state != TCS_LISTEN);
0058679 
0058680          if (tcp_conn->tc_SND_NXT == tcp_conn->tc_SND_UNA)
0058681          {
0058682                   /* Nothing to do */
0058683                   assert(tcp_conn->tc_SND_TRM == tcp_conn->tc_SND_UNA);
0058684 
0058685                   /* A new write sets the timer if tc_transmit_seq == SND_UNA */
0058686                   tcp_conn->tc_transmit_seq= tcp_conn->tc_SND_UNA;
0058687                   tcp_conn->tc_stt= 0;
0058688                   tcp_conn->tc_0wnd_to= 0;
0058689                   assert(!tcp_conn->tc_fd ||
0058690                            !(tcp_conn->tc_fd->tf_flags & TFF_WRITE_IP));
0058691                   return;
0058692          }
0058693 
0058694          if (tcp_conn->tc_transmit_seq != tcp_conn->tc_SND_UNA)
0058695          {
0058696                   /* Some data has been acknowledged since the last time the
0058697                    * timer was set, set the timer again. */
0058698                   tcp_conn->tc_transmit_seq= tcp_conn->tc_SND_UNA;
0058699                   tcp_conn->tc_stt= 0;
0058700                   tcp_conn->tc_0wnd_to= 0;
0058701 
0058702                   DBLOCK(0x20, printf(
0058703          "tcp_send_timeout: conn[%d] setting timer to %ld ms (+%ld ms)\n",
0058704                            tcp_conn-tcp_conn_table,
0058705                            (curr_time+tcp_conn->tc_rtt)*1000/HZ,
0058706                            tcp_conn->tc_rtt*1000/HZ));
0058707 
0058708                   clck_timer(&tcp_conn->tc_transmit_timer,
0058709                            curr_time+tcp_conn->tc_rtt,
0058710                            tcp_send_timeout, tcp_conn-tcp_conn_table);
clck_timer()

clck_timer(timer, timeout, func, fd) configures timer, clck_timer()'s first parameter, based on timeout, func, and fd (clck_timer()'s second, third, and fourth parameters) and places the timer in its appropriate position in timer_chain. In other words, if the new timer is scheduled to expire before any other timer, it is inserted at the head of the linked list and if the new timer is scheduled to expire after all the other timers, it is inserted at the tail of the linked list. If the new timer is scheduled to expire before any other timers, clck_timer() calls set_timer(), which sends a message to the clock task with a revised expiration time for the synchronous alarm.

An example of a client calling clck_timer() to insert a timer in timer_chain is the arp client.


0058711                   return;
0058712          }
0058713 
0058714          if (tcp_conn->tc_stt == 0)
0058715          {
0058716                   /* Some packet arrived but did not acknowledge any data.
0058717                    * Apparently, the other side is still alive and has a
0058718                    * reason to transmit. We can asume a zero window.
0058719                    */
0058720 
0058721                   DBLOCK(0x10, printf("conn[%d] setting zero window timer\n",
0058722                            tcp_conn-tcp_conn_table));
0058723 
0058724                   if (tcp_conn->tc_0wnd_to < TCP_0WND_MIN)
0058725                            tcp_conn->tc_0wnd_to= TCP_0WND_MIN;
0058726                   else if (tcp_conn->tc_0wnd_to < tcp_conn->tc_rtt)
0058727                            tcp_conn->tc_0wnd_to= tcp_conn->tc_rtt;
0058728                   else
0058729                   {
0058730                            tcp_conn->tc_0wnd_to *= 2;
0058731                            if (tcp_conn->tc_0wnd_to > TCP_0WND_MAX)
0058732                                     tcp_conn->tc_0wnd_to= TCP_0WND_MAX;
0058733                   }
0058734                   tcp_conn->tc_stt= curr_time;
0058735                   
0058736                   tcp_conn->tc_rt_seq= 0;
0058737 
0058738                   DBLOCK(0x20, printf(
0058739          "tcp_send_timeout: conn[%d] setting timer to %ld ms (+%ld ms)\n",
0058740                            tcp_conn-tcp_conn_table,
0058741                            (curr_time+tcp_conn->tc_0wnd_to)*1000/HZ,
0058742                            tcp_conn->tc_0wnd_to*1000/HZ));
0058743 
0058744                   clck_timer(&tcp_conn->tc_transmit_timer,
0058745                            curr_time+tcp_conn->tc_0wnd_to,
0058746                            tcp_send_timeout, tcp_conn-tcp_conn_table);
clck_timer()

clck_timer(timer, timeout, func, fd) configures timer, clck_timer()'s first parameter, based on timeout, func, and fd (clck_timer()'s second, third, and fourth parameters) and places the timer in its appropriate position in timer_chain. In other words, if the new timer is scheduled to expire before any other timer, it is inserted at the head of the linked list and if the new timer is scheduled to expire after all the other timers, it is inserted at the tail of the linked list. If the new timer is scheduled to expire before any other timers, clck_timer() calls set_timer(), which sends a message to the clock task with a revised expiration time for the synchronous alarm.

An example of a client calling clck_timer() to insert a timer in timer_chain is the arp client.


0058747                   return;
0058748          }
0058749 
0058750          DIFBLOCK(0x10, (tcp_conn->tc_fd == 0),
0058751                   printf("conn[%d] timeout in abondoned connection\n",
0058752                   tcp_conn-tcp_conn_table));
0058753 
0058754          /* At this point, we have do a retransmission, or send a zero window
0058755           * probe, which is almost the same.
0058756           */
0058757 
0058758          DBLOCK(0x20, printf("tcp_send_timeout: conn[%d] una= %u, rtt= %dms\n",
0058759                   tcp_conn-tcp_conn_table,
0058760                   tcp_conn->tc_SND_UNA, tcp_conn->tc_rtt*1000/HZ));
0058761 
0058762          /* Update threshold sequence number for retransmission calculation. */
0058763          if (tcp_Gmod4G(tcp_conn->tc_SND_TRM, tcp_conn->tc_rt_threshold))
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0058764                   tcp_conn->tc_rt_threshold= tcp_conn->tc_SND_TRM;
0058765 
0058766          tcp_conn->tc_SND_TRM= tcp_conn->tc_SND_UNA;
0058767 
0058768          mss= tcp_conn->tc_mss;
0058769          mss2= 2*mss;
0058770 
0058771          if (tcp_conn->tc_snd_cwnd == tcp_conn->tc_SND_UNA)
0058772                   tcp_conn->tc_snd_cwnd++;
0058773          if (tcp_Gmod4G(tcp_conn->tc_snd_cwnd, tcp_conn->tc_SND_UNA + mss2))
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0058774          {
0058775                   tcp_conn->tc_snd_cwnd= tcp_conn->tc_SND_UNA + mss2;
0058776                   if (tcp_Gmod4G(tcp_conn->tc_SND_TRM, tcp_conn->tc_snd_cwnd))
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0058777                            tcp_conn->tc_SND_TRM= tcp_conn->tc_snd_cwnd;
0058778 
0058779                   tcp_conn->tc_snd_cthresh /= 2;
0058780                   if (tcp_conn->tc_snd_cthresh < mss2)
0058781                            tcp_conn->tc_snd_cthresh= mss2;
0058782          }
0058783 
0058784          stt= tcp_conn->tc_stt;
0058785          assert(stt <= curr_time);
0058786          if (curr_time-stt > tcp_conn->tc_rt_dead)
0058787          {
0058788                   tcp_close_connection(tcp_conn, ETIMEDOUT);
tcp_close_connection()




0058789                   return;
0058790          }
0058791 
0058792          timeout= (curr_time-stt) >> 3;
0058793          if (timeout < tcp_conn->tc_rtt)
0058794                   timeout= tcp_conn->tc_rtt;
0058795          timeout += curr_time;
0058796 
0058797          DBLOCK(0x20, printf(
0058798          "tcp_send_timeout: conn[%d] setting timer to %ld ms (+%ld ms)\n",
0058799                   tcp_conn-tcp_conn_table, timeout*1000/HZ,
0058800                   (timeout-curr_time)*1000/HZ));
0058801 
0058802          clck_timer(&tcp_conn->tc_transmit_timer, timeout,
0058803                   tcp_send_timeout, tcp_conn-tcp_conn_table);
clck_timer()

clck_timer(timer, timeout, func, fd) configures timer, clck_timer()'s first parameter, based on timeout, func, and fd (clck_timer()'s second, third, and fourth parameters) and places the timer in its appropriate position in timer_chain. In other words, if the new timer is scheduled to expire before any other timer, it is inserted at the head of the linked list and if the new timer is scheduled to expire after all the other timers, it is inserted at the tail of the linked list. If the new timer is scheduled to expire before any other timers, clck_timer() calls set_timer(), which sends a message to the clock task with a revised expiration time for the synchronous alarm.

An example of a client calling clck_timer() to insert a timer in timer_chain is the arp client.


0058804 
0058805          if (tcp_conn->tc_rt_seq == 0)
0058806          {
0058807                   tcp_conn->tc_rt_time= curr_time-tcp_conn->tc_rtt;
0058808                   tcp_conn->tc_rt_seq= tcp_conn->tc_SND_UNA;
0058809          }
0058810 
0058811          tcp_conn_write(tcp_conn, 0);
tcp_conn_write()




0058812 }
0058813 
0058814 
0058815 PUBLIC void tcp_fd_write(tcp_conn)
0058816 tcp_conn_t *tcp_conn;
tcp_fd_write()




0058817 {
0058818          tcp_fd_t *tcp_fd;
0058819          int urg, nourg, push;
0058820          u32_t max_seq;
0058821          size_t max_count, max_trans, write_count, send_count;
0058822          acc_t *data, *tmp_acc, *send_data;
0058823 
0058824          assert(tcp_conn->tc_busy);
0058825          tcp_fd= tcp_conn->tc_fd;
0058826 
0058827          if ((tcp_fd->tf_flags & TFF_IOCTL_IP) &&
0058828                   !(tcp_fd->tf_flags & TFF_WRITE_IP))
0058829          {
0058830                   if (tcp_fd->tf_ioreq != NWIOTCPSHUTDOWN)
0058831                            return;
0058832                   DBLOCK(0x10, printf("NWIOTCPSHUTDOWN\n"));
0058833                   if (tcp_conn->tc_state == TCS_CLOSED)
0058834                   {
0058835                            tcp_reply_ioctl (tcp_fd, tcp_conn->tc_error);
tcp_reply_ioctl()




0058836                            return;
0058837                   }
0058838                   if (!(tcp_conn->tc_flags & TCF_FIN_SENT))
0058839                   {
0058840                            DBLOCK(0x10, printf("calling tcp_shutdown\n"));
0058841                            tcp_shutdown (tcp_conn);
tcp_shutdown()




0058842                   }
0058843                   else
0058844                   {
0058845                            if (tcp_conn->tc_SND_UNA == tcp_conn->tc_SND_NXT)
0058846                            {
0058847                                     tcp_reply_ioctl (tcp_fd, NW_OK);
tcp_reply_ioctl()




0058848                                     DBLOCK(0x10, printf("shutdown completed\n"));
0058849                            }
0058850                            else
0058851                            {
0058852                                     DBLOCK(0x10,
0058853                                              printf("shutdown still inprogress\n"));
0058854                            }
0058855                   }
0058856                   return;
0058857          }
0058858 
0058859          assert (tcp_fd->tf_flags & TFF_WRITE_IP);
0058860          if (tcp_conn->tc_state == TCS_CLOSED)
0058861          {
0058862                   if (tcp_fd->tf_write_offset)
0058863                   {
0058864                            tcp_reply_write(tcp_fd,
0058865                                     tcp_fd->tf_write_offset);
tcp_reply_write()




0058866                   }
0058867                   else
0058868                            tcp_reply_write(tcp_fd, tcp_conn->tc_error);
tcp_reply_write()




0058869                   return;
0058870          }
0058871 
0058872          urg= (tcp_fd->tf_flags & TFF_WR_URG);
0058873          push= (tcp_fd->tf_flags & TFF_PUSH_DATA);
0058874 
0058875          max_seq= tcp_conn->tc_SND_UNA + tcp_conn->tc_snd_wnd;
0058876          if (urg)
0058877                   max_seq++;
0058878          max_count= max_seq - tcp_conn->tc_SND_UNA;
0058879          max_trans= max_seq - tcp_conn->tc_SND_NXT;
0058880          if (tcp_fd->tf_write_count <= max_trans)
0058881                   write_count= tcp_fd->tf_write_count;
0058882          else
0058883                   write_count= max_trans;
0058884          if (write_count)
0058885          {
0058886                   if (tcp_conn->tc_flags & TCF_BSD_URG)
0058887                   {
0058888                            if (tcp_Gmod4G(tcp_conn->tc_SND_NXT,
0058889                                     tcp_conn->tc_SND_UNA))
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0058890                            {
0058891                                     nourg= tcp_LEmod4G(tcp_conn->tc_SND_UP,
0058892                                              tcp_conn->tc_SND_UNA);
tcp_LEmod4G() / tcp_GEmod4G() / tcp_Lmod4G() / tcp_Gmod4G()




0058893                                     if ((urg && nourg) || (!urg && !nourg))
0058894                                     {
0058895                                              DBLOCK(0x20,
0058896                                                     printf("not sending\n"));
0058897                                              return;
0058898                                     }
0058899                            }
0058900                   }
0058901                   data= (*tcp_fd->tf_get_userdata)
0058902                            (tcp_fd->tf_srfd, tcp_fd->tf_write_offset,
0058903                            write_count, FALSE);
0058904 
0058905                   if (!data)
0058906                   {
0058907                            if (tcp_fd->tf_write_offset)
0058908                            {
0058909                                     tcp_reply_write(tcp_fd,
0058910                                              tcp_fd->tf_write_offset);
tcp_reply_write()




0058911                            }
0058912                            else
0058913                                     tcp_reply_write(tcp_fd, EFAULT);
tcp_reply_write()




0058914                            return;
0058915                   }
0058916                   tcp_fd->tf_write_offset += write_count;
0058917                   tcp_fd->tf_write_count -= write_count;
0058918 
0058919                   send_data= tcp_conn->tc_send_data;
0058920                   tcp_conn->tc_send_data= 0;
0058921                   send_data= bf_append(send_data, data);
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:






0058922                   tcp_conn->tc_send_data= send_data;
0058923                   tcp_conn->tc_SND_NXT += write_count;
0058924                   if (urg)
0058925                   {
0058926                            if (tcp_conn->tc_flags & TCF_BSD_URG)
0058927                                     tcp_conn->tc_SND_UP= tcp_conn->tc_SND_NXT;
0058928                            else
0058929                                     tcp_conn->tc_SND_UP= tcp_conn->tc_SND_NXT-1;
0058930                   }
0058931                   if (push && !tcp_fd->tf_write_count)
0058932                            tcp_conn->tc_SND_PSH= tcp_conn->tc_SND_NXT;
0058933          }
0058934          if (!tcp_fd->tf_write_count)
0058935          {
0058936                   tcp_reply_write(tcp_fd, tcp_fd->tf_write_offset);
tcp_reply_write()




0058937          }
0058938 }
0058939 
0058940 /*
0058941 tcp_shutdown
0058942 */
0058943 
0058944 PUBLIC void tcp_shutdown(tcp_conn)
0058945 tcp_conn_t *tcp_conn;
tcp_shutdown()




0058946 {
0058947          switch (tcp_conn->tc_state)
0058948          {
0058949          case TCS_CLOSED:
0058950          case TCS_LISTEN:
0058951          case TCS_SYN_SENT:
0058952          case TCS_SYN_RECEIVED:
0058953                   tcp_close_connection(tcp_conn, ENOTCONN);
0058954                   return;
0058955          }
0058956 
0058957          if (tcp_conn->tc_flags & TCF_FIN_SENT)
0058958                   return;
0058959          tcp_conn->tc_flags |= TCF_FIN_SENT;
0058960          tcp_conn->tc_SND_NXT++;
0058961 
0058962          assert (tcp_check_conn(tcp_conn) ||
0058963                   (tcp_print_conn(tcp_conn), printf("\n"), 0));
0058964 
0058965          tcp_conn_write(tcp_conn, 1);
tcp_conn_write()




0058966 
0058967          /* Start the timer (if necessary) */
0058968          tcp_set_send_timer(tcp_conn);
tcp_set_send_timer()




0058969 }
0058970 
0058971 PUBLIC void tcp_set_send_timer(tcp_conn)
0058972 tcp_conn_t *tcp_conn;
tcp_set_send_timer()




0058973 {
0058974          time_t curr_time;
0058975 
0058976          assert(tcp_conn->tc_state != TCS_CLOSED);
0058977          assert(tcp_conn->tc_state != TCS_LISTEN);
0058978 
0058979          curr_time= get_time();
get_time()

get_time() returns the number of clock ticks since reboot.

Several of the clients (eth, arp, ip, tcp, and udp) use get_time() to determine an appropriate timeout value for a given operation. For example, the arp code calls get_time() to determine an appropriate amount of time to wait for a response from an arp request before giving up.


0058980 
0058981          /* Start the timer */
0058982 
0058983          DBLOCK(0x20, printf(
0058984          "tcp_set_send_timer: conn[%d] setting timer to %ld ms (+%ld ms)\n",
0058985                   tcp_conn-tcp_conn_table,
0058986                   (curr_time+tcp_conn->tc_rtt)*1000/HZ,
0058987                   tcp_conn->tc_rtt*1000/HZ));
0058988 
0058989          clck_timer(&tcp_conn->tc_transmit_timer,
0058990                   curr_time+tcp_conn->tc_rtt,
0058991                   tcp_send_timeout, tcp_conn-tcp_conn_table);
0058992                   tcp_conn->tc_stt= curr_time;
clck_timer()

clck_timer(timer, timeout, func, fd) configures timer, clck_timer()'s first parameter, based on timeout, func, and fd (clck_timer()'s second, third, and fourth parameters) and places the timer in its appropriate position in timer_chain. In other words, if the new timer is scheduled to expire before any other timer, it is inserted at the head of the linked list and if the new timer is scheduled to expire after all the other timers, it is inserted at the tail of the linked list. If the new timer is scheduled to expire before any other timers, clck_timer() calls set_timer(), which sends a message to the clock task with a revised expiration time for the synchronous alarm.

An example of a client calling clck_timer() to insert a timer in timer_chain is the arp client.


0058993 
0058994          tcp_conn->tc_stt= curr_time;
0058995 }
0058996 
0058997 /*
0058998 tcp_close_connection
0058999 
0059000 */
0059001 
0059002 PUBLIC void tcp_close_connection(tcp_conn, error)
0059003 tcp_conn_t *tcp_conn;
0059004 int error;
tcp_close_connection()




0059005 {
0059006          tcp_port_t *tcp_port;
0059007          tcp_fd_t *tcp_fd;
0059008          tcp_conn_t *tc;
0059009 
0059010          assert (tcp_check_conn(tcp_conn));
0059011          assert (tcp_conn->tc_flags & TCF_INUSE);
0059012 
0059013          tcp_conn->tc_error= error;
0059014          tcp_port= tcp_conn->tc_port;
0059015          tcp_fd= tcp_conn->tc_fd;
0059016          if (tcp_conn->tc_state == TCS_CLOSED)
0059017                   return;
0059018 
0059019          tcp_conn->tc_state= TCS_CLOSED;
0059020          DBLOCK(0x10, tcp_print_state(tcp_conn); printf("\n"));
0059021 
0059022          if (tcp_fd)
0059023          {
0059024                   tcp_conn->tc_busy++;
0059025                   assert(tcp_fd->tf_conn == tcp_conn);
0059026 
0059027                   if (tcp_fd->tf_flags & TFF_READ_IP)
0059028                            tcp_fd_read (tcp_conn, 1);
0059029                   assert (!(tcp_fd->tf_flags & TFF_READ_IP));
0059030 
0059031                   if (tcp_fd->tf_flags & TFF_WRITE_IP)
0059032                   {
0059033                            tcp_fd_write(tcp_conn);
tcp_fd_write()




0059034                            tcp_conn_write(tcp_conn, 1);
tcp_conn_write()




0059035                   }
0059036                   assert (!(tcp_fd->tf_flags & TFF_WRITE_IP));
0059037                   if (tcp_fd->tf_flags & TFF_IOCTL_IP)
0059038                   {
0059039                            tcp_fd_write(tcp_conn);
0059040                            tcp_conn_write(tcp_conn, 1);
0059041                   }
0059042                   if (tcp_fd->tf_flags & TFF_IOCTL_IP)
0059043                            assert(tcp_fd->tf_ioreq != NWIOTCPSHUTDOWN);
0059044 
0059045                   if (tcp_conn->tc_connInprogress)
0059046                            tcp_restart_connect(tcp_conn->tc_fd);
tcp_restart_connect()




0059047                   assert (!tcp_conn->tc_connInprogress);
0059048                   assert (!(tcp_fd->tf_flags & TFF_IOCTL_IP) ||
0059049                            (printf("req= 0x%lx\n", tcp_fd->tf_ioreq), 0));
0059050                   tcp_conn->tc_busy--;
0059051          }
0059052 
0059053          if (tcp_conn->tc_rcvd_data)
0059054          {
0059055                   bf_afree(tcp_conn->tc_rcvd_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).


0059056                   tcp_conn->tc_rcvd_data= NULL;
0059057          }
0059058          tcp_conn->tc_flags &= ~TCF_FIN_RECV;
0059059          tcp_conn->tc_RCV_LO= tcp_conn->tc_RCV_NXT;
0059060 
0059061          if (tcp_conn->tc_adv_data)
0059062          {
0059063                   bf_afree(tcp_conn->tc_adv_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).


0059064                   tcp_conn->tc_adv_data= NULL;
0059065          }
0059066 
0059067          if (tcp_conn->tc_send_data)
0059068          {
0059069                   bf_afree(tcp_conn->tc_send_data);
0059070                   tcp_conn->tc_send_data= NULL;
0059071                   tcp_conn->tc_SND_TRM=
0059072                            tcp_conn->tc_SND_NXT= tcp_conn->tc_SND_UNA;
0059073          }
0059074          tcp_conn->tc_SND_TRM= tcp_conn->tc_SND_NXT= tcp_conn->tc_SND_UNA;
0059075 
0059076          if (tcp_conn->tc_remipopt)
0059077          {
0059078                   bf_afree(tcp_conn->tc_remipopt);
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).


0059079                   tcp_conn->tc_remipopt= NULL;
0059080          }
0059081 
0059082          if (tcp_conn->tc_tcpopt)
0059083          {
0059084                   bf_afree(tcp_conn->tc_tcpopt);
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).


0059085                   tcp_conn->tc_tcpopt= NULL;
0059086          }
0059087 
0059088          if (tcp_conn->tc_frag2send)
0059089          {
0059090                   bf_afree(tcp_conn->tc_frag2send);
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).


0059091                   tcp_conn->tc_frag2send= NULL;
0059092          }
0059093          if (tcp_conn->tc_flags & TCF_MORE2WRITE)
0059094          {
0059095                   for (tc= tcp_port->tp_snd_head; tc; tc= tc->tc_send_link)
0059096                   {
0059097                            if (tc->tc_send_link == tcp_conn)
0059098                                     break;
0059099                   }
0059100                   if (tc == NULL)
0059101                   {
0059102                            assert(tcp_port->tp_snd_head == tcp_conn);
0059103                            tcp_port->tp_snd_head= tcp_conn->tc_send_link;
0059104                   }
0059105                   else
0059106                   {
0059107                            tc->tc_send_link= tcp_conn->tc_send_link;
0059108                            if (tc->tc_send_link == NULL)
0059109                                     tcp_port->tp_snd_tail= tc;
0059110                   }
0059111                   tcp_conn->tc_flags &= ~TCF_MORE2WRITE;
0059112          }
0059113 
0059114          clck_untimer (&tcp_conn->tc_transmit_timer);
clck_untimer()

clck_untimer(timer) releases timer, clck_untimer()'s only parameter. If necessary, clck_untimer() sends a message to the clock task requesting a synchronous alarm with a revised expiration time (actually, clck_untimer() calls set_timer(), which would send the message). Remember that the synchronous alarm task is aware of only a single alarm at any given time.


0059115          tcp_conn->tc_transmit_seq= 0;
0059116 
0059117                                              /* clear all flags but TCF_INUSE */
0059118          tcp_conn->tc_flags &= TCF_INUSE;
0059119          assert (tcp_check_conn(tcp_conn));
0059120 }
0059121 
0059122 /*
0059123  * $PchId: tcp_send.c,v 1.12 1996/12/17 07:57:11 philip Exp $
0059124  */