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

0050001 /*
0050002 tcp.c
0050003 
0050004 Copyright 1995 Philip Homburg
0050005 */
0050006 
0050007 #include "inet.h"
0050008 #include "buf.h"
0050009 #include "clock.h"
0050010 #include "event.h"
0050011 #include "type.h"
0050012 
0050013 #if !CRAMPED
0050014 #include "io.h"
0050015 #include "ip.h"
0050016 #endif
0050017 #include "sr.h"
0050018 #include "assert.h"
0050019 #include "tcp.h"
0050020 #include "tcp_int.h"
0050021 
0050022 THIS_FILE
0050023 
0050024 PUBLIC tcp_port_t *tcp_port_table;
0050025 PUBLIC tcp_fd_t tcp_fd_table[TCP_FD_NR];
0050026 PUBLIC tcp_conn_t tcp_conn_table[TCP_CONN_NR];
0050027 
0050028 FORWARD void tcp_main ARGS(( tcp_port_t *port ));
0050029 FORWARD acc_t *tcp_get_data ARGS(( int fd, size_t offset,
0050030          size_t count, int for_ioctl ));
0050031 FORWARD int tcp_put_data ARGS(( int fd, size_t offset,
0050032          acc_t *data, int for_ioctl ));
0050033 FORWARD void tcp_put_pkt ARGS(( int fd, acc_t *data, size_t datalen ));
0050034 FORWARD void read_ip_packets ARGS(( tcp_port_t *port ));
0050035 FORWARD int tcp_setconf ARGS(( tcp_fd_t *tcp_fd ));
0050036 FORWARD int tcp_setopt ARGS(( tcp_fd_t *tcp_fd ));
0050037 FORWARD int tcp_connect ARGS(( tcp_fd_t *tcp_fd ));
0050038 FORWARD int tcp_listen ARGS(( tcp_fd_t *tcp_fd ));
0050039 FORWARD tcpport_t find_unused_port ARGS(( int fd ));
0050040 FORWARD int is_unused_port ARGS(( Tcpport_t port ));
0050041 FORWARD int reply_thr_put ARGS(( tcp_fd_t *tcp_fd, int reply,
0050042          int for_ioctl ));
0050043 FORWARD void reply_thr_get ARGS(( tcp_fd_t *tcp_fd, int reply,
0050044          int for_ioctl ));
0050045 FORWARD tcp_conn_t *find_conn_entry ARGS(( Tcpport_t locport,
0050046          ipaddr_t locaddr, Tcpport_t remport, ipaddr_t readaddr ));
0050047 FORWARD tcp_conn_t *find_empty_conn ARGS(( void ));
0050048 FORWARD tcp_conn_t *find_best_conn ARGS(( ip_hdr_t *ip_hdr,
0050049          tcp_hdr_t *tcp_hdr ));
0050050 FORWARD int maybe_listen ARGS(( ipaddr_t locaddr, Tcpport_t locport,
0050051                                     ipaddr_t remaddr, Tcpport_t remport ));
0050052 FORWARD int conn_right4fd ARGS(( tcp_conn_t *tcp_conn, tcp_fd_t *tcp_fd ));
0050053 FORWARD int tcp_su4connect ARGS(( tcp_fd_t *tcp_fd ));
0050054 FORWARD void tcp_buffree ARGS(( int priority ));
0050055 #ifdef BUF_CONSISTENCY_CHECK
0050056 FORWARD void tcp_bufcheck ARGS(( void ));
0050057 #endif
0050058 FORWARD void tcp_setup_conn ARGS(( tcp_conn_t *tcp_conn ));
0050059 
0050060 PUBLIC void tcp_prep()
tcp_prep()




0050061 {
0050062          tcp_port_table= alloc(ip_conf_nr * sizeof(tcp_port_table[0]));
0050063 }
0050064 
0050065 PUBLIC void tcp_init()
tcp_init()




0050066 {
0050067          int i, j, k;
0050068          tcp_fd_t *tcp_fd;
0050069          tcp_port_t *tcp_port;
0050070          tcp_conn_t *tcp_conn;
0050071 
0050072          assert (BUF_S >= sizeof(struct nwio_ipopt));
0050073          assert (BUF_S >= sizeof(struct nwio_ipconf));
0050074          assert (BUF_S >= sizeof(struct nwio_tcpconf));
0050075          assert (BUF_S >= IP_MAX_HDR_SIZE + TCP_MAX_HDR_SIZE);
0050076 
0050077 #if ZERO
0050078          for (i=0, tcp_fd= tcp_fd_table; i<TCP_FD_NR; i++, tcp_fd++)
0050079          {
0050080                   tcp_fd->tf_flags= TFF_EMPTY;
0050081          }
0050082 
0050083          for (i=0, tcp_conn= tcp_conn_table; i<TCP_CONN_NR; i++,
0050084                   tcp_fd++)
0050085          {
0050086                   tcp_conn->tc_flags= TCF_EMPTY;
0050087                   tcp_conn->tc_busy= 0;
0050088          }
0050089 #endif
0050090 
0050091 #ifndef BUF_CONSISTENCY_CHECK
0050092          bf_logon(tcp_buffree);
0050093 #else
0050094          bf_logon(tcp_buffree, tcp_bufcheck);
0050095 #endif
0050096 
0050097          for (i=0, tcp_port= tcp_port_table; i<ip_conf_nr; i++, tcp_port++)
0050098          {
0050099                   tcp_port->tp_ipdev= i;
0050100 
0050101 #if ZERO
0050102                   tcp_port->tp_flags= TPF_EMPTY;
0050103                   tcp_port->tp_state= TPS_EMPTY;
0050104                   tcp_port->tp_snd_head= NULL;
0050105                   tcp_port->tp_snd_tail= NULL;
0050106                   ev_init(&tcp_port->tp_snd_event);
0050107 #endif
0050108                   for (j= 0; j<TCP_CONN_HASH_NR; j++)
0050109                   {
0050110                            for (k= 0; k<4; k++)
0050111                            {
0050112                                     tcp_port->tp_conn_hash[j][k]=
0050113                                              &tcp_conn_table[0];
0050114                            }
0050115                   }
0050116 
0050117                   sr_add_minor(if2minor(ip_conf[i].ic_ifno, TCP_DEV_OFF),
0050118                            i, tcp_open, tcp_close, tcp_read,
0050119                            tcp_write, tcp_ioctl, tcp_cancel);
sr_fd / sr_fd_table[] / sr_add_minor()

One of the most important data arrays in the network service is sr_fd_table[], an array of 64 struct sr_fd's. Each sr_fd element in sr_fd_table[] corresponds to either a device or an opened file descriptor to a device (i.e., a "channel"):

typedef struct sr_fd

{
int srf_flags;
int srf_fd;
int srf_port;
sr_open_t srf_open;
sr_close_t srf_close;
sr_write_t srf_write;
sr_read_t srf_read;
sr_ioctl_t srf_ioctl;
sr_cancel_t srf_cancel;
mq_t *srf_ioctl_q, *srf_ioctl_q_tail;
mq_t *srf_read_q, *srf_read_q_tail;
mq_t *srf_write_q, *srf_write_q_tail;
} sr_fd_t;
For each device (e.g., /dev/udp0), an element in sr_fd_table[] is configured by sr_add_minor(). For example, for the following inet.conf file:

eth0 DP8390 0 { default; };
psip1;

an element (i.e., a struct sr_fd) is configured for each of the following devices:

/dev/eth0 sr_fd_table[1]
/dev/ip0 sr_fd_table[2]
/dev/tcp0 sr_fd_table[3]
/dev/udp0 sr_fd_table[4]

/dev/psip1 sr_fd_table[17]
/dev/ip1 sr_fd_table[18]
/dev/tcp1 sr_fd_table[19]
/dev/udp1 sr_fd_table[20]




sr_add_minor() is called in the initialization routines for the various protocols: mnx_eth.c (osdep_eth_init()), psip.c (psip_enable()), ip.c (ip_init()), tcp.c (tcp_init()), and udp.c (udp_init()).



When a device file (e.g., /dev/udp0) is opened by a process, the element that corresponds to the device is copied to an element that is currently unoccupied (see sr_open()). In this way, a "channel" is opened. Using this technique, a channel can be opened, closed, and manipulated without affecting the elements of the descriptors initially set by sr_add_minor().


int srf_flags:

srf_flags is a combination of the following:

#define SFF_FREE 0x00
#define SFF_MINOR 0x01
#define SFF_INUSE 0x02
#define SFF_BUSY 0x3C
#define SFF_IOCTL_IP 0x04
#define SFF_READ_IP 0x08
#define SFF_WRITE_IP 0x10
#define SFF_PENDING_REQ 0x30
#define SFF_SUSPENDED 0x1C0
#define SFF_IOCTL_SUSP 0x40
#define SFF_READ_SUSP 0x80
#define SFF_WRITE_SUSP

srf_flags is initialized to SFF_FREE for each element in sr_fd_table[]. If the channel corresponds to a device file, srf_flags is set to SFF_INUSE | SFF_MINOR. If the channel does not correspond to a device file, srf_flags is set simply to SFF_INUSE.

When a request comes in for a read, write, or ioctl operation and the network service is not already processing another request for the same operation, srf_flags is set to SFF_READ_IP, SFF_WRITE_IP, or SFF_IOCTL_IP. However, if an operation is attempted but the underlying protocol is still processing a previous request of the same nature (e.g., udp_write()), the appropriate flag (SFF_IOCTL_SUSP, SFF_READ_SUSP, or SFF_WRITE_SUSP) in srf_flags is set.


int srf_fd, srf_port:

srf_fd and srf_port are both set by sr_add_minor(). For the channels in srf_fd_table[] that correspond to the device files (e.g., /dev/udp0), srf_fd is set to the minor device number of the device. For example, if /dev/udp0 is added to sr_fd_table[] and the interface number of the device file is 0 (see comments for ip_conf[]), then the minor device number is:

if2minor(ifno, dev) = ((0)*16 + UDP_DEV = 0 + 4 = 4

For the channels in srf_fd_table[] that do not correspond to a device file, srf_fd is the file descriptor for the appropriate protocol. For example, if the file system requests that a udp channel be opened, srf_open is dereferenced and udp_open() is called. udp_open() opens a udp file descriptor and returns the index of the corresponding element in udp_fd_table[]. srf_fd is set to the index of this element.

Later, when the file system requests a read or a write on the open channel, srf_fd is passed into the protocol-specific read or write function (e.g., udp_read()), allowing the protocol-specific function to locate the appropriate file descriptor (e.g., udp file descriptor).

srf_port is more straight-forward. srf_port is the index in the protocol's port table. For example, if a system has two udp device files (/dev/udp0 and /dev/udp1), udp_port_table[] will have two entries, 0 and 1. Therefore, srf_port for the entry in sr_fd_table[] that corresponds to /dev/udp0 will be 0 and srf_port for the entry that corresponds to /dev/udp1 will be 1.


sr_open_t srf_open:
sr_close_t srf_close:
sr_write_t srf_write:
sr_read_t srf_read:
sr_ioctl_t srf_ioctl:
sr_cancel_t srf_cancel:


The fields above are all protocol-specific functions and and are all set by sr_add_minor(). For example, when sr_add_minor() is called by udp_init(), srf_open, srf_close, srf_write, srf_read, srf_ioctl, and srf_cancel are set to the pointers of the functions udp_open(), udp_close(), udp_write(), udp_read(), udp_ioctl(), and udp_cancel(). Later, when the file system makes a request to the network service, these functions will be called. For example, if the file system requests that data is written to a channel, srf_write is dereferenced and, if the channel is a udp channel, udp_write() is called.

mq_t *srf_ioctl_q, *srf_ioctl_q_tail:
mq_t *srf_read_q, *srf_read_q_tail:
mq_t *srf_write_q, *srf_write_q_tail:


The fields above are linked lists of ioctl, read, and write messages waiting to be processed. When a message requesting an ioctl, read, or write operation is received, the message is placed at the end of the linked list (unless there are no previous messages of this type that have not already been processed).


After the initialization of the network service, sr_rec() is called upon receipt of messages from the file system in the endless loop within main(). sr_rec() then calls a function to handle the specific request. For open requests, sr_rec() calls sr_open(); for read, write, and io requests, sr_rec() calls sr_rwio(); for close requests, sr_rec() calls sr_close(); for cancel requests, sr_rec() calls sr_cancel().


0050120 
0050121                   tcp_main(tcp_port);
0050122          }
0050123 }
0050124 
0050125 PRIVATE void tcp_main(tcp_port)
0050126 tcp_port_t *tcp_port;
tcp_main()




0050127 {
0050128          int result, i;
0050129          tcp_conn_t *tcp_conn;
0050130          tcp_fd_t *tcp_fd;
0050131 
0050132          switch (tcp_port->tp_state)
0050133          {
0050134          case TPS_EMPTY:
0050135                   tcp_port->tp_state= TPS_SETPROTO;
0050136                   tcp_port->tp_ipfd= ip_open(tcp_port->tp_ipdev,
0050137                            tcp_port->tp_ipdev, tcp_get_data,
0050138                            tcp_put_data, tcp_put_pkt);
ip_open()

ip_open() finds an available ip file descriptor in ip_fd_table[], sets a few of the ip file descriptor's fields, and then returns the index of the ip file descriptor within ip_fd_table[]. ip_open() is called by higher-level code (e.g., udp_main()) and the returned ip file descriptor is then associated with a higher-level port (e.g., udp port).



Note that there will only be a few ip file descriptors open at any given time. There will be an ip file descriptor opened for each interface for each client (udp, tcp, and icmp) and there will be one ip file descriptor opened each time the /dev/ip file is opened directly (as opposed to when, for example, the /dev/udp file is opened).


0050139                   if (tcp_port->tp_ipfd < 0)
0050140                   {
0050141                            tcp_port->tp_state= TPS_ERROR;
0050142                            DBLOCK(1, printf("%s, %d: unable to open ip port\n",
0050143                                     __FILE__, __LINE__));
0050144                            return;
0050145                   }
0050146 
0050147                   result= ip_ioctl(tcp_port->tp_ipfd, NWIOSIPOPT);
ip_ioctl()

ip_ioctl(fd, req) performs one of several tasks on the ip file descriptor whose index within ip_fd_table[] is fd, the first parameter. The task performed depends on req, the second parameter.

NWIOSIPOPT: Set the options (the if_ipopt field of the ip file descriptor) on the ip file descriptor. For example, during the initialization of a physical udp port, ip_ioctl() is called with req equal to NWIOSIPOPT.

An example of an ip iption (i.e., ip flag) is the NWIO_EN_BROAD flag. This flag is set if the ip file descriptor accepts broadcast packets. The options desired are obtained from the user process. For example, if a udp port opened up the ip file descriptor, udp_get_data() is (indirectly) called to obtain the configuration data.

NWIOGIPOPT: Send the ip file descriptor's options to the user process requesting the information. The information is sent in a struct of type nwio_ipopt_t.

NWIOSIPCONF: Configure the ip port (for example, the ip address can be configured) that corresponds to the ip file descriptor fd. The fields are obtained from the user process. For a detailed description of the different settings, click here.

NWIOGIPCONF: Send the ip address/subnet information (i.e., send a nwio_ipconf_t struct) to the next higher layer. For example, if the next higher layer is udp, ip_ioctl() calls (indirectly) udp_put_data(), which sets the ip address for the udp port (i.e., sets the up_ipaddr field of the corresponding element in udp_port_table[]).

NWIOGIPIROUTE, NWIOSIPIROUTE, NWIOGIPOROUTE, NWIODIPIROUTE, NWIOSIPOROUTE: It is possible to influence the route taken by a packet. These ioctl requests alter the input and output routing tables.


0050148                   if (result == NW_SUSPEND)
0050149                            tcp_port->tp_flags |= TPF_SUSPEND;
0050150                   if (result < 0)
0050151                   {
0050152                            return;
0050153                   }
0050154                   if (tcp_port->tp_state != TPS_GETCONF)
0050155                            return;
0050156                   /* drops through */
0050157          case TPS_GETCONF:
0050158                   tcp_port->tp_flags &= ~TPF_SUSPEND;
0050159 
0050160                   result= ip_ioctl(tcp_port->tp_ipfd, NWIOGIPCONF);
0050161                   if (result == NW_SUSPEND)
0050162                            tcp_port->tp_flags |= TPF_SUSPEND;
0050163                   if (result < 0)
0050164                   {
0050165                            return;
0050166                   }
0050167                   if (tcp_port->tp_state != TPS_MAIN)
0050168                            return;
0050169                   /* drops through */
0050170          case TPS_MAIN:
0050171                   tcp_port->tp_flags &= ~TPF_SUSPEND;
0050172                   tcp_port->tp_pack= 0;
0050173 
0050174                   tcp_conn= &tcp_conn_table[tcp_port->tp_ipdev];
0050175                   tcp_conn->tc_flags= TCF_INUSE;
0050176                   assert(!tcp_conn->tc_busy);
0050177                   tcp_conn->tc_locport= 0;
0050178                   tcp_conn->tc_locaddr= tcp_port->tp_ipaddr;
0050179                   tcp_conn->tc_remport= 0;
0050180                   tcp_conn->tc_remaddr= 0;
0050181                   tcp_conn->tc_state= TCS_CLOSED;
0050182                   tcp_conn->tc_fd= 0;
0050183                   tcp_conn->tc_connInprogress= 0;
0050184                   tcp_conn->tc_orglisten= FALSE;
0050185                   tcp_conn->tc_senddis= 0;
0050186                   tcp_conn->tc_ISS= 0;
0050187                   tcp_conn->tc_SND_UNA= tcp_conn->tc_ISS;
0050188                   tcp_conn->tc_SND_TRM= tcp_conn->tc_ISS;
0050189                   tcp_conn->tc_SND_NXT= tcp_conn->tc_ISS;
0050190                   tcp_conn->tc_SND_UP= tcp_conn->tc_ISS;
0050191                   tcp_conn->tc_IRS= 0;
0050192                   tcp_conn->tc_RCV_LO= tcp_conn->tc_IRS;
0050193                   tcp_conn->tc_RCV_NXT= tcp_conn->tc_IRS;
0050194                   tcp_conn->tc_RCV_HI= tcp_conn->tc_IRS;
0050195                   tcp_conn->tc_RCV_UP= tcp_conn->tc_IRS;
0050196                   tcp_conn->tc_port= tcp_port;
0050197                   tcp_conn->tc_rcvd_data= NULL;
0050198                   tcp_conn->tc_adv_data= NULL;
0050199                   tcp_conn->tc_send_data= 0;
0050200                   tcp_conn->tc_remipopt= NULL;
0050201                   tcp_conn->tc_tcpopt= NULL;
0050202                   tcp_conn->tc_frag2send= 0;
0050203                   tcp_conn->tc_tos= TCP_DEF_TOS;
0050204                   tcp_conn->tc_ttl= IP_MAX_TTL;
0050205                   tcp_conn->tc_rcv_wnd= TCP_MAX_RCV_WND_SIZE;
0050206                   tcp_conn->tc_rt_dead= TCP_DEF_RT_DEAD;
0050207                   tcp_conn->tc_stt= 0;
0050208                   tcp_conn->tc_0wnd_to= 0;
0050209                   tcp_conn->tc_rtt= TCP_DEF_RTT;
0050210                   tcp_conn->tc_mss= TCP_DEF_MSS;
0050211                   tcp_conn->tc_error= NW_OK;
0050212                   tcp_conn->tc_snd_wnd= TCP_MAX_SND_WND_SIZE;
0050213                   tcp_conn->tc_snd_cinc=
0050214                            (long)TCP_DEF_MSS*TCP_DEF_MSS/TCP_MAX_SND_WND_SIZE+1;
0050215 
0050216                   tcp_conn->tc_rt_time= 0;
0050217                   tcp_conn->tc_rt_seq= 0;
0050218                   tcp_conn->tc_rt_threshold= tcp_conn->tc_ISS;
0050219 
0050220                   for (i=0, tcp_fd= tcp_fd_table; i<TCP_FD_NR; i++,
0050221                            tcp_fd++)
0050222                   {
0050223                            if (!(tcp_fd->tf_flags & TFF_INUSE))
0050224                                     continue;
0050225                            if (tcp_fd->tf_port != tcp_port)
0050226                                     continue;
0050227                            if (tcp_fd->tf_flags & TFF_IOC_INIT_SP)
0050228                            {
0050229                                     tcp_fd->tf_flags &= ~TFF_IOC_INIT_SP;
0050230                                     tcp_ioctl(i, tcp_fd->tf_ioreq);
0050231                            }
0050232                   }
0050233                   read_ip_packets(tcp_port);
read_ip_packets() / tcp




0050234                   return;
0050235 
0050236 #if !CRAMPED
0050237          default:
0050238                   ip_panic(( "unknown state" ));
0050239 #endif
0050240          }
0050241 }
0050242 
0050243 PRIVATE acc_t *tcp_get_data (port, offset, count, for_ioctl)
0050244 int port;
0050245 size_t offset;
0050246 size_t count;
0050247 int for_ioctl;
tcp_get_data()




0050248 {
0050249          tcp_port_t *tcp_port;
0050250          int result;
0050251 
0050252          tcp_port= &tcp_port_table[port];
0050253 
0050254          switch (tcp_port->tp_state)
0050255          {
0050256          case TPS_SETPROTO:
0050257                   if (!count)
0050258                   {
0050259                            result= (int)offset;
0050260                            if (result<0)
0050261                            {
0050262                                     tcp_port->tp_state= TPS_ERROR;
0050263                                     break;
0050264                            }
0050265                            tcp_port->tp_state= TPS_GETCONF;
0050266                            if (tcp_port->tp_flags & TPF_SUSPEND)
0050267                                     tcp_main(tcp_port);
tcp_main()




0050268                            return NW_OK;
0050269                   }
0050270 assert (!offset);
0050271 assert (count == sizeof(struct nwio_ipopt));
0050272                   {
0050273                            struct nwio_ipopt *ipopt;
0050274                            acc_t *acc;
0050275 
0050276                            acc= bf_memreq(sizeof(*ipopt));
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.


0050277                            ipopt= (struct nwio_ipopt *)ptr2acc_data(acc);
nwio_ipopt

The nwio_ipopt struct is used to pass ip option values from a higher-layer level (e.g., icmp, udp) to the ip layer during the configuration of an ip file descriptor. Note that an ip file descriptor cannot be used until it is configured.

typedef struct nwio_ipopt

{
u32_t nwio_flags;
ipaddr_t nwio_rem;
ip_hdropt_t nwio_hdropt;
u8_t nwio_tos;
u8_t nwio_ttl;
u8_t nwio_df;
ipproto_t nwio_proto;
} nwio_ipopt_t;
u32_t nwio_flags:

nwio_flags will be a combination of the flags below. Most of the flags within a set are exclusionary. For example, both NWIO_REMSPEC and NWIO_REMANY can't both be set.

Note that "EN" stands for "ENable" and "DI" stands for "DIsable".

#define NWIO_EXCL 0x00000001l
#define NWIO_SHARED 0x00000002l
#define NWIO_COPY 0x00000003l

From ip(4):

"The options covered by NWIO_ACC_MASK control the number of channels that can use one IP protocol. If NWIO_EXCL is specified then only that channel can use a certain IP protocol. If NWIO_SHARED then multiple channels that all have to specify NWIO_SHARED can use the same IP protocol, but incoming packets will be delivered to a most one channel. NWIO_COPY does not impose any restrictions. Every channel gets a copy of an incoming packet."

Note that, for whatever reason, NWIO_EXCL behaves exactly as NWIO_COPY. Every channel receives a copy of an incoming packet.

The access flags are important during the read of an ip file descriptor.

#define NWIO_EN_LOC 0x00000010l
#define NWIO_DI_LOC 0x00100000l
#define NWIO_EN_BROAD 0x00000020l
#define NWIO_DI_BROAD 0x00200000l

NWIO_EN_LOC specifies that this file descriptor can receive packets destined for this machine and NWIO_EN_BROAD specifies that this file descriptor can receive broadcast packets.

#define NWIO_REMSPEC 0x00000100l
#define NWIO_REMANY 0x01000000l

If the NWIO_REMANY flag is set, this file descriptor can send packets to any destination. If, on the other hand, the NWIO_REMSPEC flag is set, this file descriptor can only communicate with a single host. This host is specified by nwio_rem (see below).

#define NWIO_PROTOSPEC 0x00000200l
#define NWIO_PROTOANY 0x02000000l

If NWIO_PROTOANY is set, the ip file descriptor will accept packets of any protocol type. However, if NWIO_PROTOSPEC is set, only packets with a protocol type of nwio_proto (see below) are accepted.

#define NWIO_HDR_O_SPEC 0x00000400l
#define NWIO_HDR_O_ANY 0x04000000l

If the NWIO_HDR_O_SPEC flag in nwio_flags is set, nwio_hdropt (see below) must be set. If this is the case, the extra header information for all outgoing packets will be taken from nwio_hdropt, nwio_tos, nwio_ttl, and nwio_df (see below).

#define NWIO_RWDATONLY 0x00001000l
#define NWIO_RWDATALL 0x10000000l

NWIO_RWDATALL is a little tricky. If the NWIO_RWDATALL flag is set, the header was omitted when passing the packet down to ip code and the NWIO_EN_LOC, NWIO_DI_BROAD, NWIO_REMSPEC, NWIO_PROTOSPEC and NWIO_HDR_O_SPEC flags must all be set (and NWIO_REMANY and NWIO_PROTOANY cannot be set). In other words, this file descriptor can only send the data to one destination using one protocol.

During the configuration of an ip file descriptor being opened by the udp code, ip_ioctl() calls udp_get_data() (indirectly) to get configuration information. udp_get_data() returns the following configuration information:

NWIO_COPY | NWIO_EN_LOC | NWIO_EN_BROAD | NWIO_REMANY | NWIO_PROTOSPEC | NWIO_HDR_O_ANY | NWIO_RWDATALL

ipaddr_t nwio_rem:

If the NWIO_REMSPEC flag in nwio_flags is set (see above), nwio_rem is the ip address of the destination host.


ip_hdropt_t nwio_hdropt:

The ip header length is flexible to allow for extra options. For example, in addition to the normal fields (e.g., destination ip address), an ip header may specify the route it wishes to take or request that the route be recorded.

that it wishes to record a route or to ip_chk_hdropt().


u8_t nwio_tos:

"tos" stands for "Type Of Service". nwio_tos is initialized to 0 but can be changed by ip_ioctl().


u8_t nwio_ttl:

"ttl" stands for "Time To Live", which is the number of hops that a packet can take before being dropped by a router. nwio_ttl is initialized to 255 but can be changed by ip_ioctl().


u8_t nwio_df:

nwio_df specifies whether fragmentation is allowed or not. nwio_df is initialized to FALSE but, again, can be changed by ip_ioctl().


ipproto_t nwio_proto:

nwio_proto can take one of the values below. Obviously, if the udp code opens up an ip file descriptor, nwio_proto will be IPPROTO_UDP. The same is true for icmp and tcp.

#define IPPROTO_ICMP 1
#define IPPROTO_TCP 6
#define IPPROTO_UDP 17

This field is used in conjunction with the NWIO_PROTOSPEC flag in nwio_flags. If this flag is set, nwio_proto must be set.






0050278                            ipopt->nwio_flags= NWIO_COPY |
0050279                                     NWIO_EN_LOC | NWIO_DI_BROAD |
0050280                                     NWIO_REMANY | NWIO_PROTOSPEC |
0050281                                     NWIO_HDR_O_ANY | NWIO_RWDATALL;
0050282                            ipopt->nwio_proto= IPPROTO_TCP;
0050283                            return acc;
0050284                   }
0050285          case TPS_MAIN:
0050286                   assert(tcp_port->tp_flags & TPF_WRITE_IP);
0050287                   if (!count)
0050288                   {
0050289                            result= (int)offset;
0050290                            if (result<0)
0050291                            {
0050292                                     if (result == EDSTNOTRCH)
0050293                                     {
0050294                                              if (tcp_port->tp_snd_head)
0050295                                              {
0050296                                                     tcp_notreach(tcp_port->
0050297                                                            tp_snd_head);
0050298                                              }
0050299                                     }
0050300                                     else
0050301                                     {
0050302                                              ip_warning((
0050303                                              "ip_write failed with error: %d\n",
0050304                                                                   result ));
0050305                                     }
0050306                            }
0050307                            assert (tcp_port->tp_pack);
0050308                            bf_afree (tcp_port->tp_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).


0050309                            tcp_port->tp_pack= 0;
0050310 
0050311                            if (tcp_port->tp_flags & TPF_WRITE_SP)
0050312                            {
0050313                                     tcp_port->tp_flags &= ~(TPF_WRITE_SP|
0050314                                              TPF_WRITE_IP);
0050315                                     if (tcp_port->tp_snd_head)
0050316                                              tcp_port_write(tcp_port);
0050317                            }
0050318                            else
0050319                                     tcp_port->tp_flags &= ~TPF_WRITE_IP;
0050320                   }
0050321                   else
0050322                   {
0050323                            return bf_cut (tcp_port->tp_pack, offset,
0050324                                     count);
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.



0050325                   }
0050326                   break;
0050327          default:
0050328 #if !CRAMPED
0050329                   printf("tcp_get_data(%d, 0x%x, 0x%x) called but tp_state= 0x%x\n",
0050330                            port, offset, count, tcp_port->tp_state);
0050331 #endif
0050332                   break;
0050333          }
0050334          return NW_OK;
0050335 }
0050336 
0050337 PRIVATE int tcp_put_data (fd, offset, data, for_ioctl)
0050338 int fd;
0050339 size_t offset;
0050340 acc_t *data;
0050341 int for_ioctl;
tcp_put_data()




0050342 {
0050343          tcp_port_t *tcp_port;
0050344          int result;
0050345 
0050346          tcp_port= &tcp_port_table[fd];
0050347 
0050348          switch (tcp_port->tp_state)
0050349          {
0050350          case TPS_GETCONF:
0050351                   if (!data)
0050352                   {
0050353                            result= (int)offset;
0050354                            if (result<0)
0050355                            {
0050356                                     tcp_port->tp_state= TPS_ERROR;
0050357                                     return NW_OK;
0050358                            }
0050359                            tcp_port->tp_state= TPS_MAIN;
0050360                            if (tcp_port->tp_flags & TPF_SUSPEND)
0050361                                     tcp_main(tcp_port);
tcp_main()




0050362                   }
0050363                   else
0050364                   {
0050365                            struct nwio_ipconf *ipconf;
nwio_ipconf_t

Type nwio_ipconf_t contains the ip address information of an ip port (i.e., an element in ip_port_table[]:

typedef struct nwio_ipconf

{
u32_t nwic_flags;
ipaddr_t nwic_ipaddr;
ipaddr_t nwic_netmask;
} nwio_ipconf_t;
nwic_flags: reflects whether the ip address and the subnet mask have been set. The different flags are as follows:

#define NWIC_NOFLAGS 0x0
#define NWIC_FLAGS 0x3
#define NWIC_IPADDR_SET 0x1
#define NWIC_NETMASK_SET 0x2

nwic_ipaddr: the ip address (e.g., 192.168.5.5)

nwic_netmask: the subnet mask (e.g., 255.255.255.0)


0050366 
0050367                            data= bf_packIffLess(data, sizeof(*ipconf));
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.


0050368                            ipconf= (struct nwio_ipconf *)ptr2acc_data(data);
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.


0050369 assert (ipconf->nwic_flags & NWIC_IPADDR_SET);
0050370                            tcp_port->tp_ipaddr= ipconf->nwic_ipaddr;
0050371                            bf_afree(data);
0050372                   }
0050373                   break;
0050374          case TPS_MAIN:
0050375                   assert(tcp_port->tp_flags & TPF_READ_IP);
0050376                   if (!data)
0050377                   {
0050378                            result= (int)offset;
0050379                            if (result<0)
0050380                                     ip_panic(( "ip_read() failed" ));
0050381 
0050382                            if (tcp_port->tp_flags & TPF_READ_SP)
0050383                            {
0050384                                     tcp_port->tp_flags &= ~(TPF_READ_SP|
0050385                                              TPF_READ_IP);
0050386                                     read_ip_packets(tcp_port);
read_ip_packets() / tcp




0050387                            }
0050388                            else
0050389                                     tcp_port->tp_flags &= ~TPF_READ_IP;
0050390                   }
0050391                   else
0050392                   {
0050393                            assert(!offset);       
0050394                            /* this is an invalid assertion but ip sends
0050395                             * only whole datagrams up */
0050396                            tcp_put_pkt(fd, data, bf_bufsize(data));
tcp_put_pkt()




0050397                   }
0050398                   break;
0050399          default:
0050400 #if !CRAMPED
0050401                   printf("tcp_put_data(%d, 0x%x, 0x%x) called but tp_state= 0x%x\n",
0050402          fd, offset, data, tcp_port->tp_state);
0050403 #endif
0050404                   break;
0050405          }
0050406          return NW_OK;
0050407 }
0050408 
0050409 /*
0050410 tcp_put_pkt
0050411 */
0050412 
0050413 PRIVATE void tcp_put_pkt(fd, data, datalen)
0050414 int fd;
0050415 acc_t *data;
0050416 size_t datalen;
tcp_put_pkt()




0050417 {
0050418          tcp_port_t *tcp_port;
0050419          tcp_conn_t *tcp_conn, **conn_p;
0050420          ip_hdr_t *ip_hdr;
0050421          tcp_hdr_t *tcp_hdr;
0050422          acc_t *ip_pack, *tcp_pack;
0050423          size_t ip_datalen, tcp_datalen, ip_hdr_len, tcp_hdr_len;
0050424          u16_t sum;
0050425          u32_t bits;
0050426          int hash;
0050427          ipaddr_t srcaddr, dstaddr;
0050428          tcpport_t srcport, dstport;
0050429 
0050430          tcp_port= &tcp_port_table[fd];
0050431 
0050432          /* Extract the IP header. */
0050433          ip_hdr= (ip_hdr_t *)ptr2acc_data(data);
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.


0050434          ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2;
0050435          ip_datalen= datalen - ip_hdr_len;
0050436          if (ip_datalen == 0)
0050437          {
0050438                   DBLOCK(1, printf("tcp_put_pkt: no TCP header\n"));
0050439                   bf_afree(data);
0050440                   return;
0050441          }
0050442          data->acc_linkC++;
0050443          ip_pack= data;
0050444          ip_pack= bf_align(ip_pack, ip_hdr_len, 4);
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.


0050445          ip_hdr= (ip_hdr_t *)ptr2acc_data(ip_pack);
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.


0050446          data= bf_delhead(data, 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.


0050447 
0050448          /* Compute the checksum */
0050449          sum= tcp_pack_oneCsum(ip_hdr, data);
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.


0050450 
0050451          /* Extract the TCP header */
0050452          if (ip_datalen < TCP_MIN_HDR_SIZE)
0050453          {
0050454                   DBLOCK(1, printf("truncated TCP header\n"));
0050455                   bf_afree(ip_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).


0050456                   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).


0050457                   return;
0050458          }
0050459          data= bf_packIffLess(data, TCP_MIN_HDR_SIZE);
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.


0050460          tcp_hdr= (tcp_hdr_t *)ptr2acc_data(data);
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.


0050461          tcp_hdr_len= (tcp_hdr->th_data_off & TH_DO_MASK) >> 2;
0050462                   /* actualy (>> 4) << 2 */
0050463          if (ip_datalen < tcp_hdr_len || tcp_hdr_len < TCP_MIN_HDR_SIZE)
0050464          {
0050465                   if (tcp_hdr_len < TCP_MIN_HDR_SIZE)
0050466                   {
0050467                            DBLOCK(1, printf("strange tcp header length %d\n",
0050468                                     tcp_hdr_len));
0050469                   }
0050470                   else
0050471                   {
0050472                            DBLOCK(1, printf("truncated TCP header\n"));
0050473                   }
0050474                   bf_afree(ip_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).


0050475                   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).


0050476                   return;
0050477          }
0050478          data->acc_linkC++;
0050479          tcp_pack= data;
0050480          tcp_pack= bf_align(tcp_pack, tcp_hdr_len, 4);
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.


0050481          tcp_hdr= (tcp_hdr_t *)ptr2acc_data(tcp_pack);
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.


0050482          if (ip_datalen == tcp_hdr_len)
0050483          {
0050484                   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).


0050485                   data= NULL;
0050486          }
0050487          else
0050488                   data= bf_delhead(data, tcp_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.


0050489          tcp_datalen= ip_datalen-tcp_hdr_len;
0050490 
0050491          if ((u16_t)~sum)
0050492          {
0050493                   DBLOCK(1, printf("checksum error in tcp packet\n");
0050494                            printf("tcp_pack_oneCsum(...)= 0x%x length= %d\n",
0050495                            (u16_t)~sum, tcp_datalen);
0050496                            printf("src ip_addr= "); writeIpAddr(ip_hdr->ih_src);
0050497                            printf("\n"));
0050498                   bf_afree(ip_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).


0050499                   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).


0050500                   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).


0050501                   return;
0050502          }
0050503 
0050504          srcaddr= ip_hdr->ih_src;
0050505          dstaddr= ip_hdr->ih_dst;
0050506          srcport= tcp_hdr->th_srcport;
0050507          dstport= tcp_hdr->th_dstport;
0050508          bits= srcaddr ^ dstaddr ^ srcport ^ dstport;
0050509          bits= (bits >> 16) ^ bits;
0050510          bits= (bits >> 8) ^ bits;
0050511          hash= ((bits >> TCP_CONN_HASH_SHIFT) ^ bits) & (TCP_CONN_HASH_NR-1);
0050512          conn_p= tcp_port->tp_conn_hash[hash];
0050513          if (conn_p[0]->tc_locport == dstport &&
0050514                   conn_p[0]->tc_remport == srcport &&
0050515                   conn_p[0]->tc_remaddr == srcaddr &&
0050516                   conn_p[0]->tc_locaddr == dstaddr)
0050517          {
0050518                   tcp_conn= conn_p[0];
0050519          }
0050520          else if (conn_p[1]->tc_locport == dstport &&
0050521                   conn_p[1]->tc_remport == srcport &&
0050522                   conn_p[1]->tc_remaddr == srcaddr &&
0050523                   conn_p[1]->tc_locaddr == dstaddr)
0050524          {
0050525                   tcp_conn= conn_p[1];
0050526                   conn_p[1]= conn_p[0];
0050527                   conn_p[0]= tcp_conn;
0050528          }
0050529          else if (conn_p[2]->tc_locport == dstport &&
0050530                   conn_p[2]->tc_remport == srcport &&
0050531                   conn_p[2]->tc_remaddr == srcaddr &&
0050532                   conn_p[2]->tc_locaddr == dstaddr)
0050533          {
0050534                   tcp_conn= conn_p[2];
0050535                   conn_p[2]= conn_p[1];
0050536                   conn_p[1]= conn_p[0];
0050537                   conn_p[0]= tcp_conn;
0050538          }
0050539          else if (conn_p[3]->tc_locport == dstport &&
0050540                   conn_p[3]->tc_remport == srcport &&
0050541                   conn_p[3]->tc_remaddr == srcaddr &&
0050542                   conn_p[3]->tc_locaddr == dstaddr)
0050543          {
0050544                   tcp_conn= conn_p[3];
0050545                   conn_p[3]= conn_p[2];
0050546                   conn_p[2]= conn_p[1];
0050547                   conn_p[1]= conn_p[0];
0050548                   conn_p[0]= tcp_conn;
0050549          }
0050550          else
0050551                   tcp_conn= NULL;
0050552          if (tcp_conn != NULL && tcp_conn->tc_state == TCS_CLOSED ||
0050553                   (tcp_hdr->th_flags & THF_SYN))
0050554          {
0050555                   tcp_conn= NULL;
0050556          }
0050557 
0050558          if (tcp_conn == NULL)
0050559          {
0050560                   tcp_conn= find_best_conn(ip_hdr, tcp_hdr);
0050561                   if (!tcp_conn)
0050562                   {
0050563                            /* listen backlog hack */
0050564                            bf_afree(ip_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).


0050565                            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).


0050566                            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).


0050567                            return;
0050568                   }
0050569                   if (tcp_conn->tc_state != TCS_CLOSED)
0050570                   {
0050571                            conn_p[3]= conn_p[2];
0050572                            conn_p[2]= conn_p[1];
0050573                            conn_p[1]= conn_p[0];
0050574                            conn_p[0]= tcp_conn;
0050575                   }
0050576          }
0050577          assert(tcp_conn->tc_busy == 0);
0050578          tcp_conn->tc_busy++;
0050579          tcp_frag2conn(tcp_conn, ip_hdr, tcp_hdr, data, tcp_datalen);
tcp_frag2conn()




0050580          tcp_conn->tc_busy--;
0050581          bf_afree(ip_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).


0050582          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).


0050583 }
0050584 
0050585 
0050586 PUBLIC int tcp_open (port, srfd, get_userdata, put_userdata, put_pkt)
0050587 int port;
0050588 int srfd;
0050589 get_userdata_t get_userdata;
0050590 put_userdata_t put_userdata;
0050591 put_pkt_t put_pkt;
tcp_open()




0050592 {
0050593          int i;
0050594          tcp_fd_t *tcp_fd;
0050595 
0050596          for (i=0; i<TCP_FD_NR && (tcp_fd_table[i].tf_flags & TFF_INUSE);
0050597                   i++);
0050598          if (i>=TCP_FD_NR)
0050599          {
0050600                   return EAGAIN;
0050601          }
0050602 
0050603          tcp_fd= &tcp_fd_table[i];
0050604 
0050605          tcp_fd->tf_flags= TFF_INUSE;
0050606          tcp_fd->tf_flags |= TFF_PUSH_DATA;       /* XXX */
0050607 
0050608          tcp_fd->tf_port= &tcp_port_table[port];
0050609          tcp_fd->tf_srfd= srfd;
0050610          tcp_fd->tf_tcpconf.nwtc_flags= TCP_DEF_CONF;
0050611          tcp_fd->tf_tcpconf.nwtc_remaddr= 0;
0050612          tcp_fd->tf_tcpconf.nwtc_remport= 0;
0050613          tcp_fd->tf_tcpopt.nwto_flags= TCP_DEF_OPT;
0050614          tcp_fd->tf_get_userdata= get_userdata;
0050615          tcp_fd->tf_put_userdata= put_userdata;
0050616          tcp_fd->tf_conn= 0;
0050617          return i;
0050618 }
0050619 
0050620 /*
0050621 tcp_ioctl
0050622 */
0050623 PUBLIC int tcp_ioctl (fd, req)
0050624 int fd;
0050625 ioreq_t req;
tcp_ioctl()




0050626 {
0050627          tcp_fd_t *tcp_fd;
0050628          tcp_port_t *tcp_port;
0050629          tcp_conn_t *tcp_conn;
0050630          nwio_tcpconf_t *tcp_conf;
0050631          nwio_tcpopt_t *tcp_opt;
0050632          acc_t *conf_acc, *opt_acc;
0050633          int result;
0050634 
0050635          tcp_fd= &tcp_fd_table[fd];
0050636 
0050637 assert (tcp_fd->tf_flags & TFF_INUSE);
0050638 
0050639          tcp_port= tcp_fd->tf_port;
0050640          tcp_fd->tf_flags |= TFF_IOCTL_IP;
0050641          tcp_fd->tf_ioreq= req;
0050642 
0050643          if (tcp_port->tp_state != TPS_MAIN)
0050644          {
0050645                   tcp_fd->tf_flags |= TFF_IOC_INIT_SP;
0050646                   return NW_SUSPEND;
0050647          }
0050648 
0050649          switch (req)
0050650          {
0050651          case NWIOSTCPCONF:
0050652                   if (tcp_fd->tf_flags & TFF_CONNECTED)
0050653                   {
0050654                            tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
0050655                            reply_thr_get (tcp_fd, EISCONN, TRUE);
reply_thr_get() / reply_thr_put() / tcp




0050656                            result= NW_OK;
0050657                            break;
0050658                   }
0050659                   result= tcp_setconf(tcp_fd);
tcp_setconf()




0050660                   break;
0050661          case NWIOGTCPCONF:
0050662                   conf_acc= bf_memreq(sizeof(*tcp_conf));
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.


0050663 assert (conf_acc->acc_length == sizeof(*tcp_conf));
0050664                   tcp_conf= (nwio_tcpconf_t *)ptr2acc_data(conf_acc);
0050665 
0050666                   *tcp_conf= tcp_fd->tf_tcpconf;
0050667                   if (tcp_fd->tf_flags & TFF_CONNECTED)
0050668                   {
0050669                            tcp_conn= tcp_fd->tf_conn;
0050670                            tcp_conf->nwtc_locport= tcp_conn->tc_locport;
0050671                            tcp_conf->nwtc_remaddr= tcp_conn->tc_remaddr;
0050672                            tcp_conf->nwtc_remport= tcp_conn->tc_remport;
0050673                   }
0050674                   tcp_conf->nwtc_locaddr= tcp_fd->tf_port->tp_ipaddr;
0050675                   result= (*tcp_fd->tf_put_userdata)(tcp_fd->tf_srfd,
0050676                            0, conf_acc, TRUE);
0050677                   tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
0050678                   reply_thr_put(tcp_fd, result, TRUE);
reply_thr_get() / reply_thr_put() / tcp




0050679                   result= NW_OK;
0050680                   break;
0050681          case NWIOSTCPOPT:
0050682                   result= tcp_setopt(tcp_fd);
0050683                   break;
0050684          case NWIOGTCPOPT:
0050685                   opt_acc= bf_memreq(sizeof(*tcp_opt));
0050686                   assert (opt_acc->acc_length == sizeof(*tcp_opt));
0050687                   tcp_opt= (nwio_tcpopt_t *)ptr2acc_data(opt_acc);
0050688 
0050689                   *tcp_opt= tcp_fd->tf_tcpopt;
0050690                   result= (*tcp_fd->tf_put_userdata)(tcp_fd->tf_srfd,
0050691                            0, opt_acc, TRUE);
0050692                   tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
0050693                   reply_thr_put(tcp_fd, result, TRUE);
0050694                   result= NW_OK;
0050695                   break;
0050696          case NWIOTCPCONN:
0050697                   if (tcp_fd->tf_flags & TFF_CONNECTED)
0050698                   {
0050699                            tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
0050700                            reply_thr_get (tcp_fd, EISCONN, TRUE);
reply_thr_get() / reply_thr_put() / tcp




0050701                            result= NW_OK;
0050702                            break;
0050703                   }
0050704                   result= tcp_connect(tcp_fd);
tcp_connect()




0050705                   break;
0050706          case NWIOTCPLISTEN:
0050707                   if (tcp_fd->tf_flags & TFF_CONNECTED)
0050708                   {
0050709                            tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
0050710                            reply_thr_get (tcp_fd, EISCONN, TRUE);
reply_thr_get() / reply_thr_put() / tcp




0050711                            result= NW_OK;
0050712                            break;
0050713                   }
0050714                   result= tcp_listen(tcp_fd);
tcp_listen()




0050715                   break;
0050716          case NWIOTCPSHUTDOWN:
0050717                   if (!(tcp_fd->tf_flags & TFF_CONNECTED))
0050718                   {
0050719                            tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
0050720                            reply_thr_get (tcp_fd, ENOTCONN, TRUE);
reply_thr_get() / reply_thr_put() / tcp




0050721                            result= NW_OK;
0050722                            break;
0050723                   }
0050724                   tcp_fd->tf_flags |= TFF_IOCTL_IP;
0050725                   tcp_fd->tf_ioreq= req;
0050726                   tcp_conn= tcp_fd->tf_conn;
0050727 
0050728                   tcp_conn->tc_busy++;
0050729                   tcp_fd_write(tcp_conn);
0050730                   tcp_conn->tc_busy--;
0050731                   tcp_conn_write(tcp_conn, 0);
0050732                   if (!(tcp_fd->tf_flags & TFF_IOCTL_IP))
0050733                            return NW_OK;
0050734                   else
0050735                            return NW_SUSPEND;
0050736                   break;
0050737          default:
0050738                   tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
0050739                   reply_thr_get(tcp_fd, EBADIOCTL, TRUE);
reply_thr_get() / reply_thr_put() / tcp




0050740                   result= NW_OK;
0050741                   break;
0050742          }
0050743          return result;
0050744 }
0050745 
0050746 
0050747 /*
0050748 tcp_setconf
0050749 */
0050750 
0050751 PRIVATE int tcp_setconf(tcp_fd)
0050752 tcp_fd_t *tcp_fd;
tcp_setconf()




0050753 {
0050754          nwio_tcpconf_t *tcpconf;
0050755          nwio_tcpconf_t oldconf, newconf;
0050756          acc_t *data;
0050757          int result;
0050758          tcpport_t port;
0050759          tcp_fd_t *fd_ptr;
0050760          unsigned int new_en_flags, new_di_flags,
0050761                   old_en_flags, old_di_flags, all_flags, flags;
0050762          int i;
0050763 
0050764          data= (*tcp_fd->tf_get_userdata)
0050765                   (tcp_fd->tf_srfd, 0,
0050766                   sizeof(nwio_tcpconf_t), TRUE);
0050767 
0050768          if (!data)
0050769                   return EFAULT;
0050770 
0050771          data= bf_packIffLess(data, sizeof(nwio_tcpconf_t));
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.


0050772 assert (data->acc_length == sizeof(nwio_tcpconf_t));
0050773 
0050774          tcpconf= (nwio_tcpconf_t *)ptr2acc_data(data);
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.


0050775          oldconf= tcp_fd->tf_tcpconf;
0050776          newconf= *tcpconf;
0050777 
0050778          old_en_flags= oldconf.nwtc_flags & 0xffff;
0050779          old_di_flags= (oldconf.nwtc_flags >> 16) &
0050780                   0xffff;
0050781          new_en_flags= newconf.nwtc_flags & 0xffff;
0050782          new_di_flags= (newconf.nwtc_flags >> 16) &
0050783                   0xffff;
0050784          if (new_en_flags & new_di_flags)
0050785          {
0050786                   tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
0050787                   reply_thr_get(tcp_fd, EBADMODE, TRUE);
reply_thr_get() / reply_thr_put() / tcp




0050788                   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).


0050789                   return NW_OK;
0050790          }
0050791 
0050792          /* NWTC_ACC_MASK */
0050793          if (new_di_flags & NWTC_ACC_MASK)
0050794          {
0050795                   tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
0050796                   reply_thr_get(tcp_fd, EBADMODE, TRUE);
reply_thr_get() / reply_thr_put() / tcp




0050797                   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).


0050798                   return NW_OK;
0050799                   /* access modes can't be disabled */
0050800          }
0050801 
0050802          if (!(new_en_flags & NWTC_ACC_MASK))
0050803                   new_en_flags |= (old_en_flags & NWTC_ACC_MASK);
0050804          
0050805          /* NWTC_LOCPORT_MASK */
0050806          if (new_di_flags & NWTC_LOCPORT_MASK)
0050807          {
0050808                   tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
0050809                   reply_thr_get(tcp_fd, EBADMODE, TRUE);
reply_thr_get() / reply_thr_put() / tcp




0050810                   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).


0050811                   return NW_OK;
0050812                   /* the loc ports can't be disabled */
0050813          }
0050814          if (!(new_en_flags & NWTC_LOCPORT_MASK))
0050815          {
0050816                   new_en_flags |= (old_en_flags &
0050817                            NWTC_LOCPORT_MASK);
0050818                   newconf.nwtc_locport= oldconf.nwtc_locport;
0050819          }
0050820          else if ((new_en_flags & NWTC_LOCPORT_MASK) == NWTC_LP_SEL)
0050821          {
0050822                   newconf.nwtc_locport= find_unused_port(tcp_fd-
0050823                            tcp_fd_table);
find_unused_port()

find_unused_port() attempts to claim an unused port number. The first port number that is requested is equal to the index number of the udp file descriptor plus 0xC000 (49152). If this port is not available, the port number is incremented until an unclaimed port number is found. So for the sixth udp file descriptor (i.e., udp_fd_table[5]), find_unused_port() first tries port 49157 (49152 + 5), then tries 49158, and so on until an available port if found.

find_unused_port() is called only a single time: while setting a udp file descriptor's options with udp_setopt() (more specifically, if a user process attempts to set the NWUO_LP_SEL (Local Port SELect) flag).


0050824          }
0050825          else if ((new_en_flags & NWTC_LOCPORT_MASK) == NWTC_LP_SET)
0050826          {
0050827                   if (!newconf.nwtc_locport)
0050828                   {
0050829                            tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
0050830                            reply_thr_get(tcp_fd, EBADMODE, TRUE);
reply_thr_get() / reply_thr_put() / tcp




0050831                            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).


0050832                            return NW_OK;
0050833                   }
0050834          }
0050835          
0050836          /* NWTC_REMADDR_MASK */
0050837          if (!((new_en_flags | new_di_flags) &
0050838                   NWTC_REMADDR_MASK))
0050839          {
0050840                   new_en_flags |= (old_en_flags &
0050841                            NWTC_REMADDR_MASK);
0050842                   new_di_flags |= (old_di_flags &
0050843                            NWTC_REMADDR_MASK);
0050844                   newconf.nwtc_remaddr= oldconf.nwtc_remaddr;
0050845          }
0050846          else if (new_en_flags & NWTC_SET_RA)
0050847          {
0050848                   if (!newconf.nwtc_remaddr)
0050849                   {
0050850                            tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
0050851                            reply_thr_get(tcp_fd, EBADMODE, TRUE);
reply_thr_get() / reply_thr_put() / tcp




0050852                            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).


0050853                            return NW_OK;
0050854                   }
0050855          }
0050856          else
0050857          {
0050858 assert (new_di_flags & NWTC_REMADDR_MASK);
0050859                   newconf.nwtc_remaddr= 0;
0050860          }
0050861 
0050862          /* NWTC_REMPORT_MASK */
0050863          if (!((new_en_flags | new_di_flags) & NWTC_REMPORT_MASK))
0050864          {
0050865                   new_en_flags |= (old_en_flags &
0050866                            NWTC_REMPORT_MASK);
0050867                   new_di_flags |= (old_di_flags &
0050868                            NWTC_REMPORT_MASK);
0050869                   newconf.nwtc_remport=
0050870                            oldconf.nwtc_remport;
0050871          }
0050872          else if (new_en_flags & NWTC_SET_RP)
0050873          {
0050874                   if (!newconf.nwtc_remport)
0050875                   {
0050876                            tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
0050877                            reply_thr_get(tcp_fd, EBADMODE, TRUE);
reply_thr_get() / reply_thr_put() / tcp




0050878                            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).


0050879                            return NW_OK;
0050880                   }
0050881          }
0050882          else
0050883          {
0050884 assert (new_di_flags & NWTC_REMPORT_MASK);
0050885                   newconf.nwtc_remport= 0;
0050886          }
0050887 
0050888          newconf.nwtc_flags= ((unsigned long)new_di_flags
0050889                   << 16) | new_en_flags;
0050890          all_flags= new_en_flags | new_di_flags;
0050891 
0050892          /* check the access modes */
0050893          if ((all_flags & NWTC_LOCPORT_MASK) != NWTC_LP_UNSET)
0050894          {
0050895                   for (i=0, fd_ptr= tcp_fd_table; i<TCP_FD_NR; i++, fd_ptr++)
0050896                   {
0050897                            if (fd_ptr == tcp_fd)
0050898                                     continue;
0050899                            if (!(fd_ptr->tf_flags & TFF_INUSE))
0050900                                     continue;
0050901                            if (fd_ptr->tf_port != tcp_fd->tf_port)
0050902                                     continue;
0050903                            flags= fd_ptr->tf_tcpconf.nwtc_flags;
0050904                            if ((flags & NWTC_LOCPORT_MASK) == NWTC_LP_UNSET)
0050905                                     continue;
0050906                            if (fd_ptr->tf_tcpconf.nwtc_locport !=
0050907                                     newconf.nwtc_locport)
0050908                                     continue;
0050909                            if ((flags & NWTC_ACC_MASK) != (all_flags &
0050910                                     NWTC_ACC_MASK) ||
0050911                                     (all_flags & NWTC_ACC_MASK) == NWTC_EXCL)
0050912                            {
0050913                                     tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
0050914                                     reply_thr_get(tcp_fd, EADDRINUSE, TRUE);
0050915                                     bf_afree(data);
0050916                                     return NW_OK;
0050917                            }
0050918                   }
0050919          }
0050920                                     
0050921          tcp_fd->tf_tcpconf= newconf;
0050922 
0050923          if ((all_flags & NWTC_ACC_MASK) &&
0050924                   ((all_flags & NWTC_LOCPORT_MASK) == NWTC_LP_SET ||
0050925                   (all_flags & NWTC_LOCPORT_MASK) == NWTC_LP_SEL) &&
0050926                   (all_flags & NWTC_REMADDR_MASK) &&
0050927                   (all_flags & NWTC_REMPORT_MASK))
0050928                   tcp_fd->tf_flags |= TFF_CONF_SET;
0050929          else
0050930          {
0050931                   tcp_fd->tf_flags &= ~TFF_CONF_SET;
0050932          }
0050933          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).


0050934          tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
0050935          reply_thr_get(tcp_fd, NW_OK, TRUE);
reply_thr_get() / reply_thr_put() / tcp




0050936          return NW_OK;
0050937 }
0050938 
0050939 
0050940 /*
0050941 tcp_setopt
0050942 */
0050943 
0050944 PRIVATE int tcp_setopt(tcp_fd)
tcp_setopt()




0050945 tcp_fd_t *tcp_fd;
0050946 {
0050947          nwio_tcpopt_t *tcpopt;
0050948          nwio_tcpopt_t oldopt, newopt;
0050949          acc_t *data;
0050950          int result;
0050951          tcpport_t port;
0050952          tcp_fd_t *fd_ptr;
0050953          unsigned int new_en_flags, new_di_flags,
0050954                   old_en_flags, old_di_flags, all_flags, flags;
0050955          int i;
0050956 
0050957          data= (*tcp_fd->tf_get_userdata) (tcp_fd->tf_srfd, 0,
0050958                   sizeof(nwio_tcpopt_t), TRUE);
0050959 
0050960          if (!data)
0050961                   return EFAULT;
0050962 
0050963          data= bf_packIffLess(data, sizeof(nwio_tcpopt_t));
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.


0050964 assert (data->acc_length == sizeof(nwio_tcpopt_t));
0050965 
0050966          tcpopt= (nwio_tcpopt_t *)ptr2acc_data(data);
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.


0050967          oldopt= tcp_fd->tf_tcpopt;
0050968          newopt= *tcpopt;
0050969 
0050970          old_en_flags= oldopt.nwto_flags & 0xffff;
0050971          old_di_flags= (oldopt.nwto_flags >> 16) &
0050972                   0xffff;
0050973          new_en_flags= newopt.nwto_flags & 0xffff;
0050974          new_di_flags= (newopt.nwto_flags >> 16) &
0050975                   0xffff;
0050976          if (new_en_flags & new_di_flags)
0050977          {
0050978                   tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
0050979                   reply_thr_get(tcp_fd, EBADMODE, TRUE);
reply_thr_get() / reply_thr_put() / tcp




0050980                   return NW_OK;
0050981          }
0050982 
0050983          /* NWTO_SND_URG_MASK */
0050984          if (!((new_en_flags | new_di_flags) &
0050985                   NWTO_SND_URG_MASK))
0050986          {
0050987                   new_en_flags |= (old_en_flags &
0050988                            NWTO_SND_URG_MASK);
0050989                   new_di_flags |= (old_di_flags &
0050990                            NWTO_SND_URG_MASK);
0050991          }
0050992 
0050993          /* NWTO_RCV_URG_MASK */
0050994          if (!((new_en_flags | new_di_flags) &
0050995                   NWTO_RCV_URG_MASK))
0050996          {
0050997                   new_en_flags |= (old_en_flags &
0050998                            NWTO_RCV_URG_MASK);
0050999                   new_di_flags |= (old_di_flags &
0051000                            NWTO_RCV_URG_MASK);
0051001          }
0051002 
0051003          /* NWTO_BSD_URG_MASK */
0051004          if (!((new_en_flags | new_di_flags) &
0051005                   NWTO_BSD_URG_MASK))
0051006          {
0051007                   new_en_flags |= (old_en_flags &
0051008                            NWTO_BSD_URG_MASK);
0051009                   new_di_flags |= (old_di_flags &
0051010                            NWTO_BSD_URG_MASK);
0051011          }
0051012          else
0051013          {
0051014                   if (tcp_fd->tf_conn == NULL)
0051015                   {
0051016                            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).


0051017                            tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
0051018                            reply_thr_get(tcp_fd, EINVAL, TRUE);
reply_thr_get() / reply_thr_put() / tcp




0051019                            return NW_OK;
0051020                   }
0051021          }
0051022 
0051023          /* NWTO_DEL_RST_MASK */
0051024          if (!((new_en_flags | new_di_flags) &
0051025                   NWTO_DEL_RST_MASK))
0051026          {
0051027                   new_en_flags |= (old_en_flags &
0051028                            NWTO_DEL_RST_MASK);
0051029                   new_di_flags |= (old_di_flags &
0051030                            NWTO_DEL_RST_MASK);
0051031          }
0051032 
0051033          newopt.nwto_flags= ((unsigned long)new_di_flags
0051034                   << 16) | new_en_flags;
0051035          tcp_fd->tf_tcpopt= newopt;
0051036          if (newopt.nwto_flags & NWTO_SND_URG)
0051037                   tcp_fd->tf_flags |= TFF_WR_URG;
0051038          else
0051039                   tcp_fd->tf_flags &= ~TFF_WR_URG;
0051040 
0051041          if (newopt.nwto_flags & NWTO_RCV_URG)
0051042                   tcp_fd->tf_flags |= TFF_RECV_URG;
0051043          else
0051044                   tcp_fd->tf_flags &= ~TFF_RECV_URG;
0051045 
0051046          if (tcp_fd->tf_conn)
0051047          {
0051048                   if (newopt.nwto_flags & NWTO_BSD_URG)
0051049                   {
0051050                            tcp_fd->tf_conn->tc_flags |= TCF_BSD_URG;
0051051                   }
0051052                   else
0051053                   {
0051054                            tcp_fd->tf_conn->tc_flags &= ~TCF_BSD_URG;
0051055                   }
0051056          }
0051057 
0051058          if (newopt.nwto_flags & NWTO_DEL_RST)
0051059                   tcp_fd->tf_flags |= TFF_DEL_RST;
0051060          else
0051061                   tcp_fd->tf_flags &= ~TFF_DEL_RST;
0051062 
0051063          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).


0051064          tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
0051065          reply_thr_get(tcp_fd, NW_OK, TRUE);
reply_thr_get() / reply_thr_put() / tcp




0051066          return NW_OK;
0051067 }
0051068 
0051069 
0051070 PRIVATE tcpport_t find_unused_port(fd)
0051071 int fd;
find_unused_port()

find_unused_port() attempts to claim an unused port number. The first port number that is requested is equal to the index number of the udp file descriptor plus 0xC000 (49152). If this port is not available, the port number is incremented until an unclaimed port number is found. So for the sixth udp file descriptor (i.e., udp_fd_table[5]), find_unused_port() first tries port 49157 (49152 + 5), then tries 49158, and so on until an available port if found.

find_unused_port() is called only a single time: while setting a udp file descriptor's options with udp_setopt() (more specifically, if a user process attempts to set the NWUO_LP_SEL (Local Port SELect) flag).


0051072 {
0051073          tcpport_t port, nw_port;
0051074 
0051075          nw_port= htons(0xC000+fd);
0051076          if (is_unused_port(nw_port))
is_unused_port() / tcp




0051077                   return nw_port;
0051078 
0051079          for (port= 0xC000+TCP_FD_NR; port < 0xFFFF; port++)
0051080          {
0051081                   nw_port= htons(port);
0051082                   if (is_unused_port(nw_port))
is_unused_port() / tcp




0051083                            return nw_port;
0051084          }
0051085 #if !CRAMPED
0051086          ip_panic(( "unable to find unused port (shouldn't occur)" ));
0051087          return 0;
0051088 #endif
0051089 }
0051090 
0051091 PRIVATE int is_unused_port(port)
0051092 tcpport_t port;
is_unused_port() / tcp




0051093 {
0051094          int i;
0051095          tcp_fd_t *tcp_fd;
0051096          tcp_conn_t *tcp_conn;
0051097 
0051098          for (i= 0, tcp_fd= tcp_fd_table; i<TCP_FD_NR; i++,
0051099                   tcp_fd++)
0051100          {
0051101                   if (!(tcp_fd->tf_flags & TFF_CONF_SET))
0051102                            continue;
0051103                   if (tcp_fd->tf_tcpconf.nwtc_locport == port)
0051104                            return FALSE;
0051105          }
0051106          for (i= ip_conf_nr, tcp_conn= tcp_conn_table+i;
0051107                   i<TCP_CONN_NR; i++, tcp_conn++)
0051108                   /* the first ip_conf_nr ports are special */
0051109          {
0051110                   if (!(tcp_conn->tc_flags & TCF_INUSE))
0051111                            continue;
0051112                   if (tcp_conn->tc_locport == port)
0051113                            return FALSE;
0051114          }
0051115          return TRUE;
0051116 }
0051117 
0051118 PRIVATE int reply_thr_put(tcp_fd, reply, for_ioctl)
0051119 tcp_fd_t *tcp_fd;
0051120 int reply;
0051121 int for_ioctl;
0051122 {
0051123          assert (tcp_fd);
0051124 
0051125          return (*tcp_fd->tf_put_userdata)(tcp_fd->tf_srfd, reply,
0051126                   (acc_t *)0, for_ioctl);
0051127 }
0051128 
0051129 PRIVATE void reply_thr_get(tcp_fd, reply, for_ioctl)
0051130 tcp_fd_t *tcp_fd;
0051131 int reply;
0051132 int for_ioctl;
reply_thr_get() / reply_thr_put() / tcp




0051133 {
0051134          acc_t *result;
0051135          result= (*tcp_fd->tf_get_userdata)(tcp_fd->tf_srfd, reply,
0051136                   (size_t)0, for_ioctl);
0051137          assert (!result);
0051138 }
0051139 
0051140 PUBLIC int tcp_su4listen(tcp_fd)
0051141 tcp_fd_t *tcp_fd;
tcp_su4listen()




0051142 {
0051143          tcp_conn_t *tcp_conn;
0051144          acc_t *tmp_acc;
0051145 
0051146          tcp_conn= tcp_fd->tf_conn;
0051147 
0051148          tcp_conn->tc_locport= tcp_fd->tf_tcpconf.nwtc_locport;
0051149          tcp_conn->tc_locaddr= tcp_fd->tf_port->tp_ipaddr;
0051150          if (tcp_fd->tf_tcpconf.nwtc_flags & NWTC_SET_RP)
0051151                   tcp_conn->tc_remport= tcp_fd->tf_tcpconf.nwtc_remport;
0051152          else
0051153                   tcp_conn->tc_remport= 0;
0051154          if (tcp_fd->tf_tcpconf.nwtc_flags & NWTC_SET_RA)
0051155                   tcp_conn->tc_remaddr= tcp_fd->tf_tcpconf.nwtc_remaddr;
0051156          else
0051157                   tcp_conn->tc_remaddr= 0;
0051158 
0051159          tcp_setup_conn(tcp_conn);
0051160          tcp_conn->tc_port= tcp_fd->tf_port;
0051161          tcp_conn->tc_fd= tcp_fd;
0051162          tcp_conn->tc_connInprogress= 1;
0051163          tcp_conn->tc_orglisten= TRUE;
0051164          tcp_conn->tc_state= TCS_LISTEN;
0051165          tcp_conn->tc_rt_dead= TCP_DEF_RT_MAX_LISTEN;
0051166          return NW_SUSPEND;
0051167 }
0051168 
0051169 /*
0051170 find_empty_conn
0051171 
0051172 This function returns a connection that is not inuse.
0051173 This includes connections that are never used, and connections without a
0051174 user that are not used for a while.
0051175 */
0051176 
0051177 PRIVATE tcp_conn_t *find_empty_conn()
find_empty_conn()




0051178 {
0051179          int i;
0051180          tcp_conn_t *tcp_conn;
0051181          int state;
0051182 
0051183          for (i=ip_conf_nr, tcp_conn= tcp_conn_table+i;
0051184                   i<TCP_CONN_NR; i++, tcp_conn++)
0051185                   /* the first ip_conf_nr connections are reserved for
0051186                    * RSTs
0051187                    */
0051188          {
0051189                   if (tcp_conn->tc_flags == TCF_EMPTY)
0051190                   {
0051191                            tcp_conn->tc_connInprogress= 0;
0051192                            tcp_conn->tc_fd= NULL;
0051193                            return tcp_conn;
0051194                   }
0051195                   if (tcp_conn->tc_fd)
0051196                            continue;
0051197                   if (tcp_conn->tc_senddis > get_time())
0051198                            continue;
0051199                   if (tcp_conn->tc_state != TCS_CLOSED)
0051200                   {
0051201                             tcp_close_connection (tcp_conn, ENOCONN);
tcp_close_connection()




0051202                   }
0051203                   tcp_conn->tc_flags= 0;
0051204                   return tcp_conn;
0051205          }
0051206          return NULL;
0051207 }
0051208 
0051209 
0051210 /*
0051211 find_conn_entry
0051212 
0051213 This function return a connection matching locport, locaddr, remport, remaddr.
0051214 If no such connection exists NULL is returned.
0051215 If a connection exists without mainuser it is closed.
0051216 */
0051217 
0051218 PRIVATE tcp_conn_t *find_conn_entry(locport, locaddr, remport, remaddr)
0051219 tcpport_t locport;
0051220 ipaddr_t locaddr;
0051221 tcpport_t remport;
0051222 ipaddr_t remaddr;
find_conn_entry()




0051223 {
0051224          tcp_conn_t *tcp_conn;
0051225          int i, state;
0051226 
0051227          assert(remport);
0051228          assert(remaddr);
0051229          for (i=ip_conf_nr, tcp_conn= tcp_conn_table+i; i<TCP_CONN_NR;
0051230                   i++, tcp_conn++)
0051231                   /* the first ip_conf_nr connections are reserved for
0051232                            RSTs */
0051233          {
0051234                   if (tcp_conn->tc_flags == TCF_EMPTY)
0051235                            continue;
0051236                   if (tcp_conn->tc_locport != locport ||
0051237                            tcp_conn->tc_locaddr != locaddr ||
0051238                            tcp_conn->tc_remport != remport ||
0051239                            tcp_conn->tc_remaddr != remaddr)
0051240                            continue;
0051241                   if (tcp_conn->tc_fd)
0051242                            return tcp_conn;
0051243                   state= tcp_conn->tc_state;
0051244                   if (state != TCS_CLOSED)
0051245                   {
0051246                            tcp_close_connection(tcp_conn, ENOCONN);
tcp_close_connection()




0051247                   }
0051248                   return tcp_conn;
0051249          }
0051250          return NULL;
0051251 }
0051252 
0051253 PRIVATE void read_ip_packets(tcp_port)
0051254 tcp_port_t *tcp_port;
read_ip_packets() / tcp




0051255 {
0051256          int result;
0051257 
0051258          do
0051259          {
0051260                   tcp_port->tp_flags |= TPF_READ_IP;
0051261                   result= ip_read(tcp_port->tp_ipfd, TCP_MAX_DATAGRAM);
ip_read()

If there are unexpired packets in the ip file descriptor fd's read queue, ip_read(fd, count) passes count (ip_read()'s second parameter) bytes off to the next-higher layer by calling packet2user(). If the packets in the file descriptor's read queue have expired, ip_read() discards the packets.

ip_read() is (indirectly) called by sr_rwio() when a process reads an ip device file (e.g., /dev/ip).

In the udp code, ip_read() is called by read_ip_packets() during the initialization of the udp code. Normally, ip_read() is not called by the udp code after the initialization.


0051262                   if (result == NW_SUSPEND)
0051263                   {
0051264                            tcp_port->tp_flags |= TPF_READ_SP;
0051265                            return;
0051266                   }
0051267                   assert(result == NW_OK);
0051268                   tcp_port->tp_flags &= ~TPF_READ_IP;
0051269          } while(!(tcp_port->tp_flags & TPF_READ_IP));
0051270 }
0051271 
0051272 /*
0051273 find_best_conn
0051274 */
0051275 
0051276 PRIVATE tcp_conn_t *find_best_conn(ip_hdr, tcp_hdr)
0051277 ip_hdr_t *ip_hdr;
0051278 tcp_hdr_t *tcp_hdr;
find_best_conn()




0051279 {
0051280          
0051281          int best_level, new_level;
0051282          tcp_conn_t *best_conn, *listen_conn, *tcp_conn;
0051283          tcp_fd_t *tcp_fd;
0051284          int i;
0051285          ipaddr_t locaddr;
0051286          ipaddr_t remaddr;
0051287          tcpport_t locport;
0051288          tcpport_t remport;
0051289 
0051290          locaddr= ip_hdr->ih_dst;
0051291          remaddr= ip_hdr->ih_src;
0051292          locport= tcp_hdr->th_dstport;
0051293          remport= tcp_hdr->th_srcport;
0051294          if (!remport)       /* This can interfere with a listen, so we reject it
0051295                             * by clearing the requested port
0051296                             */
0051297                   locport= 0;
0051298                   
0051299          best_level= 0;
0051300          best_conn= NULL;
0051301          listen_conn= NULL;
0051302          for (i= ip_conf_nr, tcp_conn= tcp_conn_table+i;
0051303                   i<TCP_CONN_NR; i++, tcp_conn++)
0051304                   /* the first ip_conf_nr connections are reserved for
0051305                            RSTs */
0051306          {
0051307                   if (!(tcp_conn->tc_flags & TCF_INUSE))
0051308                            continue;
0051309                   /* First fast check for open connections. */
0051310                   if (tcp_conn->tc_locaddr == locaddr &&
0051311                            tcp_conn->tc_locport == locport &&
0051312                            tcp_conn->tc_remport == remport &&
0051313                            tcp_conn->tc_remaddr == remaddr &&
0051314                            tcp_conn->tc_fd)
0051315                   {
0051316                            return tcp_conn;
0051317                   }
0051318 
0051319                   /* Now check for listens and abandoned connections. */
0051320                   if (tcp_conn->tc_locaddr != locaddr)
0051321                   {
0051322                            continue;
0051323                   }
0051324                   new_level= 0;
0051325                   if (tcp_conn->tc_locport)
0051326                   {
0051327                            if (tcp_conn->tc_locport != locport)
0051328                            {
0051329                                     continue;
0051330                            }
0051331                            new_level += 4;
0051332                   }
0051333                   if (tcp_conn->tc_remport)
0051334                   {
0051335                            if (tcp_conn->tc_remport != remport)
0051336                            {
0051337                                     continue;
0051338                            }
0051339                            new_level += 1;
0051340                   }
0051341                   if (tcp_conn->tc_remaddr)
0051342                   {
0051343                            if (tcp_conn->tc_remaddr != remaddr)
0051344                            {
0051345                                     continue;
0051346                            }
0051347                            new_level += 2;
0051348                   }
0051349                   if (new_level<best_level)
0051350                            continue;
0051351                   if (new_level != 7 && tcp_conn->tc_state != TCS_LISTEN)
0051352                            continue;
0051353                   if (new_level == 7 && !tcp_conn->tc_fd)
0051354                            /* We found an abandoned connection */
0051355                   {
0051356                            if (best_conn && tcp_Lmod4G(tcp_conn->tc_ISS,
0051357                                     best_conn->tc_ISS))
0051358                            {
0051359                                     continue;
0051360                            }
0051361                            best_conn= tcp_conn;
0051362                            continue;
0051363                   }
0051364                   if (!(tcp_hdr->th_flags & THF_SYN))
0051365                            continue;
0051366                   best_level= new_level;
0051367                   listen_conn= tcp_conn;
0051368          }
0051369          if (!best_conn && !listen_conn)
0051370          {
0051371                   if ((tcp_hdr->th_flags & THF_SYN) &&
0051372                            maybe_listen(locaddr, locport, remaddr, remport))
maybe_listen()




0051373                   {
0051374                            /* Quick hack to implement listen back logs:
0051375                             * if a SYN arrives and there is no listen waiting
0051376                             * for that packet, then no reply is sent.
0051377                             */
0051378                            return NULL;
0051379                   }
0051380 
0051381                   for (i=0, tcp_conn= tcp_conn_table; i<ip_conf_nr;
0051382                            i++, tcp_conn++)
0051383                   {
0051384                            /* find valid port to send RST */
0051385                            if ((tcp_conn->tc_flags & TCF_INUSE) &&
0051386                                     tcp_conn->tc_locaddr==locaddr)
0051387                            {
0051388                                     break;
0051389                            }
0051390                   }
0051391                   assert (tcp_conn);
0051392                   assert (tcp_conn->tc_state == TCS_CLOSED);
0051393 
0051394                   tcp_conn->tc_locport= locport;
0051395                   tcp_conn->tc_locaddr= locaddr;
0051396                   tcp_conn->tc_remport= remport;
0051397                   tcp_conn->tc_remaddr= remaddr;
0051398                   assert (!tcp_conn->tc_fd);
0051399                   return tcp_conn;
0051400          }
0051401 
0051402          if (best_conn)
0051403          {
0051404                   assert(!best_conn->tc_fd);
0051405                   if (!listen_conn)
0051406                            return best_conn;
0051407 
0051408                   tcp_fd= listen_conn->tc_fd;
0051409                   assert(tcp_fd && listen_conn->tc_connInprogress &&
0051410                            tcp_fd->tf_conn == listen_conn);
0051411 
0051412                   if (best_conn->tc_state != TCS_CLOSED)
0051413                            tcp_close_connection(best_conn, ENOCONN);
0051414 
0051415                   listen_conn->tc_ISS= best_conn->tc_ISS;
0051416                   if (best_conn->tc_senddis > listen_conn->tc_senddis)
0051417                            listen_conn->tc_senddis= best_conn->tc_senddis;
0051418                   return listen_conn;
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.


0051419          }
0051420          assert (listen_conn);
0051421          return listen_conn;
0051422 }
0051423 
0051424 /*
0051425 maybe_listen
0051426 */
0051427 PRIVATE int maybe_listen(locaddr, locport, remaddr, remport)
0051428 ipaddr_t locaddr;
0051429 tcpport_t locport;
0051430 ipaddr_t remaddr;
0051431 tcpport_t remport;
maybe_listen()




0051432 {
0051433          int i;
0051434          tcp_conn_t *tcp_conn;
0051435          tcp_fd_t *fd;
0051436 
0051437          for (i= ip_conf_nr, tcp_conn= tcp_conn_table+i;
0051438                   i<TCP_CONN_NR; i++, tcp_conn++)
0051439          {
0051440                   if (!(tcp_conn->tc_flags & TCF_INUSE))
0051441                            continue;
0051442 
0051443                   if (tcp_conn->tc_locaddr != locaddr)
0051444                   {
0051445                            continue;
0051446                   }
0051447                   if (tcp_conn->tc_locport != locport )
0051448                   {
0051449                            continue;
0051450                   }
0051451                   if (!tcp_conn->tc_orglisten)
0051452                            continue;
0051453                   fd= tcp_conn->tc_fd;
0051454                   if (!fd)
0051455                            continue;
0051456                   if ((fd->tf_tcpconf.nwtc_flags & NWTC_SET_RP) &&
0051457                            tcp_conn->tc_remport != remport)
0051458                   {
0051459                            continue;
0051460                   }
0051461                   if ((fd->tf_tcpconf.nwtc_flags & NWTC_SET_RA) &&
0051462                            tcp_conn->tc_remaddr != remaddr)
0051463                   {
0051464                            continue;
0051465                   }
0051466                   if (!(fd->tf_flags & TFF_DEL_RST))
0051467                            continue;
0051468                   return 1;
0051469 
0051470          }
0051471          return 0;
0051472 }
0051473 
0051474 
0051475 PUBLIC void tcp_reply_ioctl(tcp_fd, reply)
0051476 tcp_fd_t *tcp_fd;
0051477 int reply;
tcp_reply_ioctl()




0051478 {
0051479          assert (tcp_fd->tf_flags & TFF_IOCTL_IP);
0051480          assert (tcp_fd->tf_ioreq == NWIOTCPSHUTDOWN ||
0051481                   tcp_fd->tf_ioreq == NWIOTCPLISTEN ||
0051482                   tcp_fd->tf_ioreq == NWIOTCPCONN);
0051483          
0051484          tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
0051485          reply_thr_get (tcp_fd, reply, TRUE);
reply_thr_get() / reply_thr_put() / tcp




0051486 }
0051487 
0051488 PUBLIC void tcp_reply_write(tcp_fd, reply)
0051489 tcp_fd_t *tcp_fd;
0051490 size_t reply;
tcp_reply_write()




0051491 {
0051492          assert (tcp_fd->tf_flags & TFF_WRITE_IP);
0051493 
0051494          tcp_fd->tf_flags &= ~TFF_WRITE_IP;
0051495          reply_thr_get (tcp_fd, reply, FALSE);
reply_thr_get() / reply_thr_put() / tcp




0051496 }
0051497 
0051498 PUBLIC void tcp_reply_read(tcp_fd, reply)
0051499 tcp_fd_t *tcp_fd;
0051500 size_t reply;
tcp_reply_read()




0051501 {
0051502          assert (tcp_fd->tf_flags & TFF_READ_IP);
0051503 
0051504          tcp_fd->tf_flags &= ~TFF_READ_IP;
0051505          reply_thr_put (tcp_fd, reply, FALSE);
reply_thr_get() / reply_thr_put() / tcp




0051506 }
0051507 
0051508 PUBLIC int tcp_write(fd, count)
0051509 int fd;
0051510 size_t count;
tcp_write()




0051511 {
0051512          tcp_fd_t *tcp_fd;
0051513          tcp_conn_t *tcp_conn;
0051514 
0051515          tcp_fd= &tcp_fd_table[fd];
0051516 
0051517          assert (tcp_fd->tf_flags & TFF_INUSE);
0051518 
0051519          if (!(tcp_fd->tf_flags & TFF_CONNECTED))
0051520          {
0051521                   reply_thr_get (tcp_fd, ENOTCONN, FALSE);
reply_thr_get() / reply_thr_put() / tcp




0051522                   return NW_OK;
0051523          }
0051524          tcp_conn= tcp_fd->tf_conn;
0051525          if (tcp_conn->tc_state == TCS_CLOSED)
0051526          {
0051527                   reply_thr_get(tcp_fd, tcp_conn->tc_error, FALSE);
reply_thr_get() / reply_thr_put() / tcp




0051528                   return NW_OK;
0051529          }
0051530          if (tcp_conn->tc_flags & TCF_FIN_SENT)
0051531          {
0051532                   reply_thr_get (tcp_fd, ESHUTDOWN, FALSE);
reply_thr_get() / reply_thr_put() / tcp




0051533                   return NW_OK;
0051534          }
0051535 
0051536          tcp_fd->tf_flags |= TFF_WRITE_IP;
0051537          tcp_fd->tf_write_offset= 0;
0051538          tcp_fd->tf_write_count= count;
0051539 
0051540          /* Start the timer (if necessary) */
0051541          if (tcp_conn->tc_SND_UNA == tcp_conn->tc_SND_NXT &&
0051542                   tcp_conn->tc_transmit_seq == tcp_conn->tc_SND_UNA)
0051543          {
0051544                   tcp_set_send_timer(tcp_conn);
tcp_set_send_timer()




0051545          }
0051546          assert(tcp_conn->tc_transmit_timer.tim_active ||
0051547                   (tcp_print_conn(tcp_conn), printf("\n"), 0));
0051548 
0051549          assert(tcp_conn->tc_busy == 0);
0051550          tcp_conn->tc_busy++;
0051551          tcp_fd_write(tcp_conn);
tcp_fd_write()




0051552          tcp_conn->tc_busy--;
0051553          tcp_conn_write(tcp_conn, 0);
tcp_conn_write()




0051554 
0051555          if (!(tcp_fd->tf_flags & TFF_WRITE_IP))
0051556                   return NW_OK;
0051557          else
0051558                   return NW_SUSPEND;
0051559 }
0051560 
0051561 PUBLIC int
0051562 tcp_read(fd, count)
0051563 int fd;
0051564 size_t count;
tcp_read()




0051565 {
0051566          tcp_fd_t *tcp_fd;
0051567          tcp_conn_t *tcp_conn;
0051568 
0051569          tcp_fd= &tcp_fd_table[fd];
0051570 
0051571          assert (tcp_fd->tf_flags & TFF_INUSE);
0051572 
0051573          if (!(tcp_fd->tf_flags & TFF_CONNECTED))
0051574          {
0051575                   reply_thr_put (tcp_fd, ENOTCONN, FALSE);
0051576                   return NW_OK;
0051577          }
0051578          tcp_conn= tcp_fd->tf_conn;
0051579 
0051580          tcp_fd->tf_flags |= TFF_READ_IP;
0051581          tcp_fd->tf_read_offset= 0;
0051582          tcp_fd->tf_read_count= count;
0051583 
0051584          assert(tcp_conn->tc_busy == 0);
0051585          tcp_conn->tc_busy++;
0051586          tcp_fd_read(tcp_conn, 0);
0051587          tcp_conn->tc_busy--;
0051588          if (!(tcp_fd->tf_flags & TFF_READ_IP))
0051589                   return NW_OK;
0051590          else
0051591                   return NW_SUSPEND;
0051592 }
0051593 
0051594 /*
0051595 tcp_restart_connect
0051596 
0051597 reply the success or failure of a connect to the user.
0051598 */
0051599 
0051600 
0051601 PUBLIC void tcp_restart_connect(tcp_fd)
0051602 tcp_fd_t *tcp_fd;
tcp_restart_connect()




0051603 {
0051604          tcp_conn_t *tcp_conn;
0051605          int reply;
0051606 
0051607          assert(tcp_fd);
0051608          assert(tcp_fd->tf_flags & TFF_IOCTL_IP);
0051609          assert(tcp_fd->tf_ioreq == NWIOTCPLISTEN ||
0051610                   tcp_fd->tf_ioreq == NWIOTCPCONN);
0051611 
0051612          tcp_conn= tcp_fd->tf_conn;
0051613 
0051614          assert(tcp_conn);
0051615          assert(tcp_conn->tc_connInprogress);
0051616 
0051617          if (tcp_conn->tc_state == TCS_CLOSED)
0051618          {
0051619                   reply= tcp_conn->tc_error;
0051620                   assert(tcp_conn->tc_fd == tcp_fd);
0051621                   tcp_fd->tf_conn= NULL;
0051622                   tcp_conn->tc_fd= NULL;
0051623          }
0051624          else
0051625          {
0051626                   tcp_fd->tf_flags |= TFF_CONNECTED;
0051627                   reply= NW_OK;
0051628          }
0051629          tcp_conn->tc_connInprogress= 0;
0051630          tcp_reply_ioctl (tcp_fd, reply);
tcp_reply_ioctl()




0051631 }
0051632 
0051633 /*
0051634 tcp_close
0051635 */
0051636 
0051637 PUBLIC void tcp_close(fd)
0051638 int fd;
tcp_close()




0051639 {
0051640          tcp_fd_t *tcp_fd;
0051641          tcp_conn_t *tcp_conn;
0051642 
0051643          tcp_fd= &tcp_fd_table[fd];
0051644 
0051645          assert (tcp_fd->tf_flags & TFF_INUSE);
0051646          assert (!(tcp_fd->tf_flags &
0051647                   (TFF_IOCTL_IP|TFF_READ_IP|TFF_WRITE_IP)));
0051648 
0051649          tcp_fd->tf_flags &= ~TFF_INUSE;
0051650          if (!tcp_fd->tf_conn)
0051651                   return;
0051652 
0051653          tcp_conn= tcp_fd->tf_conn;
0051654          assert(tcp_conn->tc_fd == tcp_fd);
0051655          tcp_conn->tc_fd= 0;
0051656 
0051657          assert (!tcp_conn->tc_connInprogress);
0051658 
0051659          tcp_shutdown (tcp_conn);
tcp_shutdown()




0051660          if (tcp_conn->tc_state == TCS_ESTABLISHED)
0051661          {
0051662                   tcp_conn->tc_state= TCS_CLOSING;
0051663          }
0051664 
0051665          /* Set the retransmission timeout a bit smaller. */
0051666          tcp_conn->tc_rt_dead= TCP_DEF_RT_MAX_CLOSING;
0051667 
0051668          /* If all data has been acknowledged, close the connection. */
0051669          if (tcp_conn->tc_SND_UNA == tcp_conn->tc_SND_NXT)
0051670                   tcp_close_connection(tcp_conn, ENOTCONN);
tcp_close_connection()




0051671 }
0051672 
0051673 PUBLIC int tcp_cancel(fd, which_operation)
0051674 int fd;
0051675 int which_operation;
tcp_cancel()




0051676 {
0051677          tcp_fd_t *tcp_fd;
0051678          tcp_conn_t *tcp_conn;
0051679          int i;
0051680 
0051681          tcp_fd= &tcp_fd_table[fd];
0051682 
0051683          assert (tcp_fd->tf_flags & TFF_INUSE);
0051684 
0051685          tcp_conn= tcp_fd->tf_conn;
0051686 
0051687          switch (which_operation)
0051688          {
0051689          case SR_CANCEL_WRITE:
0051690                   assert (tcp_fd->tf_flags & TFF_WRITE_IP);
0051691                   tcp_fd->tf_flags &= ~TFF_WRITE_IP;
0051692 
0051693                   if (tcp_fd->tf_write_offset)
0051694                            reply_thr_get (tcp_fd, tcp_fd->tf_write_offset, FALSE);
reply_thr_get() / reply_thr_put() / tcp




0051695                   else
0051696                            reply_thr_get (tcp_fd, EINTR, FALSE);
reply_thr_get() / reply_thr_put() / tcp




0051697                   break;
0051698          case SR_CANCEL_READ:
0051699                   assert (tcp_fd->tf_flags & TFF_READ_IP);
0051700                   tcp_fd->tf_flags &= ~TFF_READ_IP;
0051701                   if (tcp_fd->tf_read_offset)
0051702                            reply_thr_put (tcp_fd, tcp_fd->tf_read_offset, FALSE);
reply_thr_get() / reply_thr_put() / tcp




0051703                   else
0051704                            reply_thr_put (tcp_fd, EINTR, FALSE);
0051705                   break;
0051706          case SR_CANCEL_IOCTL:
0051707 assert (tcp_fd->tf_flags & TFF_IOCTL_IP);
0051708                   tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
0051709 
0051710                   switch (tcp_fd->tf_ioreq)
0051711                   {
0051712                   case NWIOGTCPCONF:
0051713                            reply_thr_put (tcp_fd, EINTR, TRUE);
reply_thr_get() / reply_thr_put() / tcp




0051714                            break;
0051715                   case NWIOSTCPCONF:
0051716                   case NWIOTCPSHUTDOWN:
0051717                            reply_thr_get (tcp_fd, EINTR, TRUE);
0051718                            break;
0051719                   case NWIOTCPCONN:
0051720                   case NWIOTCPLISTEN:
0051721                            assert (tcp_conn->tc_connInprogress);
0051722                            tcp_conn->tc_connInprogress= 0;
0051723                            tcp_conn->tc_fd= 0;
0051724                            tcp_fd->tf_conn= 0;
0051725                            tcp_close_connection(tcp_conn, ENOCONN);
tcp_close_connection()




0051726                            reply_thr_get (tcp_fd, EINTR, TRUE);
reply_thr_get() / reply_thr_put() / tcp




0051727                            break;
0051728                   default:
0051729                            ip_warning(( "unknown ioctl inprogress: 0x%x",
0051730                                     tcp_fd->tf_ioreq ));
0051731                            reply_thr_get (tcp_fd, EINTR, TRUE);
reply_thr_get() / reply_thr_put() / tcp




0051732                            break;
0051733                   }
0051734                   break;
0051735 #if !CRAMPED
0051736          default:
0051737                   ip_panic(( "unknown cancel request" ));
0051738 #endif
0051739          }
0051740          return NW_OK;
0051741 }
0051742 
0051743 /*
0051744 tcp_connect
0051745 */
0051746 
0051747 PRIVATE int tcp_connect(tcp_fd)
0051748 tcp_fd_t *tcp_fd;
tcp_connect()




0051749 {
0051750          tcp_conn_t *tcp_conn;
0051751          int state;
0051752 
0051753          if (!(tcp_fd->tf_flags & TFF_CONF_SET))
0051754          {
0051755                   tcp_reply_ioctl(tcp_fd, EBADMODE);
tcp_reply_ioctl()




0051756                   return NW_OK;
0051757          }
0051758          if (tcp_fd->tf_flags & TFF_CONNECT)
0051759          {
0051760                   tcp_reply_ioctl(tcp_fd, EISCONN);
tcp_reply_ioctl()




0051761                   return NW_OK;
0051762          }
0051763          if ((tcp_fd->tf_tcpconf.nwtc_flags & (NWTC_SET_RA|NWTC_SET_RP))
0051764                   != (NWTC_SET_RA|NWTC_SET_RP))
0051765          {
0051766                   tcp_reply_ioctl(tcp_fd, EBADMODE);
tcp_reply_ioctl()




0051767                   return NW_OK;
0051768          }
0051769 
0051770          assert(!tcp_fd->tf_conn);
0051771          tcp_conn= find_conn_entry(tcp_fd->tf_tcpconf.nwtc_locport,
0051772                   tcp_fd->tf_port->tp_ipaddr,
0051773                   tcp_fd->tf_tcpconf.nwtc_remport,
0051774                   tcp_fd->tf_tcpconf.nwtc_remaddr);
find_conn_entry()




0051775          if (tcp_conn)
0051776          {
0051777                   if (tcp_conn->tc_fd)
0051778                   {
0051779                            tcp_reply_ioctl(tcp_fd, EADDRINUSE);
tcp_reply_ioctl()




0051780                            return NW_OK;
0051781                   }
0051782          }
0051783          else
0051784          {
0051785                   tcp_conn= find_empty_conn();
find_empty_conn()




0051786                   if (!tcp_conn)
0051787                   {
0051788                            tcp_reply_ioctl(tcp_fd, EAGAIN);
tcp_reply_ioctl()




0051789                            return NW_OK;
0051790                   }
0051791          }
0051792          tcp_fd->tf_conn= tcp_conn;
0051793 
0051794          return tcp_su4connect(tcp_fd);
tcp_su4connect()




0051795 }
0051796 
0051797 /*
0051798 tcp_su4connect
0051799 */
0051800 
0051801 PRIVATE int tcp_su4connect(tcp_fd)
0051802 tcp_fd_t *tcp_fd;
tcp_su4connect()




0051803 {
0051804          tcp_conn_t *tcp_conn;
0051805          acc_t *tmp_acc;
0051806 
0051807          tcp_conn= tcp_fd->tf_conn;
0051808 
0051809          tcp_conn->tc_locport= tcp_fd->tf_tcpconf.nwtc_locport;
0051810          tcp_conn->tc_locaddr= tcp_fd->tf_port->tp_ipaddr;
0051811 
0051812          assert (tcp_fd->tf_tcpconf.nwtc_flags & NWTC_SET_RP);
0051813          assert (tcp_fd->tf_tcpconf.nwtc_flags & NWTC_SET_RA);
0051814          tcp_conn->tc_remport= tcp_fd->tf_tcpconf.nwtc_remport;
0051815          tcp_conn->tc_remaddr= tcp_fd->tf_tcpconf.nwtc_remaddr;
0051816 
0051817          tcp_setup_conn(tcp_conn);
tcp_setup_conn()




0051818 
0051819          tcp_conn->tc_fd= tcp_fd;
0051820          tcp_conn->tc_port= tcp_fd->tf_port;
0051821          tcp_conn->tc_connInprogress= 1;
0051822          tcp_conn->tc_orglisten= FALSE;
0051823          tcp_conn->tc_state= TCS_SYN_SENT;
0051824          tcp_conn->tc_rt_dead= TCP_DEF_RT_MAX_CONNECT;
0051825 
0051826          /* Start the timer (if necessary) */
0051827          tcp_set_send_timer(tcp_conn);
tcp_set_send_timer()




0051828 
0051829          tcp_conn_write(tcp_conn, 0);
tcp_conn_write()




0051830 
0051831          if (tcp_conn->tc_connInprogress)
0051832                   return NW_SUSPEND;
0051833          else
0051834                   return NW_OK;
0051835 }
0051836 
0051837 PRIVATE int conn_right4fd(tcp_conn, tcp_fd)
0051838 tcp_fd_t *tcp_fd;
0051839 tcp_conn_t *tcp_conn;
conn_right4fd()




0051840 {
0051841          unsigned long flags;
0051842 
0051843          flags= tcp_fd->tf_tcpconf.nwtc_flags;
0051844 
0051845          if (tcp_fd->tf_tcpconf.nwtc_locport != tcp_conn->tc_locport)
0051846                   return FALSE;
0051847 
0051848          if ((flags & NWTC_SET_RA) && tcp_fd->tf_tcpconf.nwtc_remaddr !=
0051849                   tcp_conn->tc_remaddr)
0051850                   return FALSE;
0051851 
0051852          if ((flags & NWTC_SET_RP) && tcp_fd->tf_tcpconf.nwtc_remport !=
0051853                   tcp_conn->tc_remport)
0051854                   return FALSE;
0051855 
0051856          if (tcp_fd->tf_port != tcp_conn->tc_port)
0051857                   return FALSE;
0051858 
0051859          return TRUE;
0051860 }
0051861 
0051862 /*
0051863 tcp_listen
0051864 */
0051865 
0051866 PRIVATE int tcp_listen(tcp_fd)
0051867 tcp_fd_t *tcp_fd;
tcp_listen()




0051868 {
0051869          tcp_conn_t *tcp_conn;
0051870          int state;
0051871 
0051872          if (!(tcp_fd->tf_flags & TFF_CONF_SET))
0051873          {
0051874                   tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
0051875                   reply_thr_get(tcp_fd, EBADMODE, TRUE);
reply_thr_get() / reply_thr_put() / tcp




0051876                   return NW_OK;
0051877          }
0051878          if (tcp_fd->tf_flags & TFF_CONNECT)
0051879          {
0051880                   tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
0051881                   reply_thr_get(tcp_fd, EISCONN, TRUE);
reply_thr_get() / reply_thr_put() / tcp




0051882                   return NW_OK;
0051883          }
0051884          tcp_conn= tcp_fd->tf_conn;
0051885          assert(!tcp_conn);
0051886 
0051887          if ((tcp_fd->tf_tcpconf.nwtc_flags & (NWTC_SET_RA|NWTC_SET_RP))
0051888                   == (NWTC_SET_RA|NWTC_SET_RP))
0051889          {
0051890                   tcp_conn= find_conn_entry(
0051891                            tcp_fd->tf_tcpconf.nwtc_locport,
0051892                            tcp_fd->tf_port->tp_ipaddr,
0051893                            tcp_fd->tf_tcpconf.nwtc_remport,
0051894                            tcp_fd->tf_tcpconf.nwtc_remaddr);
find_conn_entry()




0051895                   if (tcp_conn)
0051896                   {
0051897                            if (tcp_conn->tc_fd)
0051898                            {
0051899                                     tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
0051900                                     reply_thr_get (tcp_fd, EADDRINUSE, TRUE);
reply_thr_get() / reply_thr_put() / tcp




0051901                                     return NW_OK;
0051902                            }
0051903                            tcp_fd->tf_conn= tcp_conn;
0051904                            return tcp_su4listen(tcp_fd);
tcp_su4connect()




0051905                   }
0051906          }
0051907          tcp_conn= find_empty_conn();
find_empty_conn()




0051908          if (!tcp_conn)
0051909          {
0051910                   tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
0051911                   reply_thr_get (tcp_fd, EAGAIN, TRUE);
reply_thr_get() / reply_thr_put() / tcp




0051912                   return NW_OK;
0051913          }
0051914          tcp_fd->tf_conn= tcp_conn;
0051915          return tcp_su4listen(tcp_fd);
tcp_su4connect()




0051916 }
0051917 
0051918 PRIVATE void tcp_buffree (priority)
0051919 int priority;
tcp_buffree()




0051920 {
0051921          int i;
0051922          tcp_conn_t *tcp_conn;
0051923 
0051924          if (priority == TCP_PRI_FRAG2SEND)
0051925          {
0051926                   for (i=0, tcp_conn= tcp_conn_table; i<TCP_CONN_NR; i++,
0051927                            tcp_conn++)
0051928                   {
0051929                            if (!(tcp_conn->tc_flags & TCF_INUSE))
0051930                                     continue;
0051931                            if (!tcp_conn->tc_frag2send)
0051932                                     continue;
0051933                            if (tcp_conn->tc_busy)
0051934                                     continue;
0051935                            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).


0051936                            tcp_conn->tc_frag2send= 0;
0051937                   }
0051938          }
0051939 
0051940          if (priority == TCP_PRI_CONN_EXTRA)
0051941          {
0051942                   for (i=0, tcp_conn= tcp_conn_table; i<TCP_CONN_NR; i++,
0051943                            tcp_conn++)
0051944                   {
0051945                            if (!(tcp_conn->tc_flags & TCF_INUSE))
0051946                                     continue;
0051947                            if (tcp_conn->tc_busy)
0051948                                     continue;
0051949                            if (tcp_conn->tc_adv_data)
0051950                            {
0051951                                     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).


0051952                                     tcp_conn->tc_adv_data= NULL;
0051953                            }
0051954                   }
0051955          }
0051956 
0051957          if (priority == TCP_PRI_CONNwoUSER)
0051958          {
0051959                   for (i=0, tcp_conn= tcp_conn_table; i<TCP_CONN_NR; i++,
0051960                            tcp_conn++)
0051961                   {
0051962                            if (!(tcp_conn->tc_flags & TCF_INUSE))
0051963                                     continue;
0051964                            if (tcp_conn->tc_busy)
0051965                                     continue;
0051966                            if (tcp_conn->tc_fd)
0051967                                     continue;
0051968                            if (tcp_conn->tc_state == TCS_CLOSED)
0051969                                     continue;
0051970                            if (tcp_conn->tc_rcvd_data == NULL &&
0051971                                     tcp_conn->tc_send_data == NULL)
0051972                            {
0051973                                     continue;
0051974                            }
0051975                            tcp_close_connection (tcp_conn, EOUTOFBUFS);
tcp_close_connection()




0051976                   }
0051977          }
0051978 
0051979          if (priority == TCP_PRI_CONN_INUSE)
0051980          {
0051981                   for (i=0, tcp_conn= tcp_conn_table; i<TCP_CONN_NR; i++,
0051982                            tcp_conn++)
0051983                   {
0051984                            if (!(tcp_conn->tc_flags & TCF_INUSE))
0051985                                     continue;
0051986                            if (tcp_conn->tc_busy)
0051987                                     continue;
0051988                            if (tcp_conn->tc_state == TCS_CLOSED)
0051989                                     continue;
0051990                            if (tcp_conn->tc_rcvd_data == NULL &&
0051991                                     tcp_conn->tc_send_data == NULL)
0051992                            {
0051993                                     continue;
0051994                            }
0051995                            tcp_close_connection (tcp_conn, EOUTOFBUFS);
tcp_close_connection()




0051996                   }
0051997          }
0051998 }
0051999 
0052000 #ifdef BUF_CONSISTENCY_CHECK
0052001 PRIVATE void tcp_bufcheck()
0052002 {
0052003          int i;
0052004          tcp_conn_t *tcp_conn;
0052005          tcp_port_t *tcp_port;
0052006 
0052007          for (i= 0, tcp_port= tcp_port_table; i<ip_conf_nr; i++, tcp_port++)
0052008          {
0052009                   if (tcp_port->tp_pack)
0052010                            bf_check_acc(tcp_port->tp_pack);
0052011          }
0052012          for (i= 0, tcp_conn= tcp_conn_table; i<TCP_CONN_NR; i++, tcp_conn++)
0052013          {
0052014                   assert(!tcp_conn->tc_busy);
0052015                   if (tcp_conn->tc_rcvd_data)
0052016                            bf_check_acc(tcp_conn->tc_rcvd_data);
0052017                   if (tcp_conn->tc_adv_data)
0052018                            bf_check_acc(tcp_conn->tc_adv_data);
0052019                   if (tcp_conn->tc_send_data)
0052020                            bf_check_acc(tcp_conn->tc_send_data);
0052021                   if (tcp_conn->tc_remipopt)
0052022                            bf_check_acc(tcp_conn->tc_remipopt);
0052023                   if (tcp_conn->tc_tcpopt)
0052024                            bf_check_acc(tcp_conn->tc_tcpopt);
0052025                   if (tcp_conn->tc_frag2send)
0052026                            bf_check_acc(tcp_conn->tc_frag2send);
0052027          }
0052028 }
0052029 #endif
0052030 
0052031 PUBLIC void tcp_notreach(tcp_conn)
0052032 tcp_conn_t *tcp_conn;
tcp_notreach()




0052033 {
0052034          int new_ttl;
0052035 
0052036          new_ttl= tcp_conn->tc_ttl;
0052037          if (new_ttl == IP_MAX_TTL)
0052038          {
0052039                   if (tcp_conn->tc_state == TCS_SYN_SENT)
0052040                            tcp_close_connection(tcp_conn, EDSTNOTRCH);
tcp_close_connection()




0052041                   return;
0052042          }
0052043          else if (new_ttl == TCP_DEF_TTL)
0052044                   new_ttl= TCP_DEF_TTL_NEXT;
0052045          else
0052046          {
0052047                   new_ttl *= 2;
0052048                   if (new_ttl> IP_MAX_TTL)
0052049                            new_ttl= IP_MAX_TTL;
0052050          }
0052051          tcp_conn->tc_ttl= new_ttl;
0052052          tcp_conn->tc_stt= 0;
0052053          tcp_conn->tc_SND_TRM= tcp_conn->tc_SND_UNA;
0052054          tcp_conn_write(tcp_conn, 1);
tcp_conn_write()




0052055 }
0052056 
0052057 /*
0052058 tcp_setup_conn
0052059 */
0052060 
0052061 PRIVATE void tcp_setup_conn(tcp_conn)
0052062 tcp_conn_t *tcp_conn;
tcp_setup_conn()




0052063 {
0052064          assert(!tcp_conn->tc_connInprogress);
0052065          if (tcp_conn->tc_flags & TCF_INUSE)
0052066          {
0052067                   assert (tcp_conn->tc_state == TCS_CLOSED);
0052068                   assert (!tcp_conn->tc_send_data);
0052069                   if (tcp_conn->tc_senddis < get_time())
0052070                            tcp_conn->tc_ISS= 0;
0052071          }
0052072          else
0052073          {
0052074                   assert(!tcp_conn->tc_busy);
0052075                   tcp_conn->tc_senddis= 0;
0052076                   tcp_conn->tc_ISS= 0;
0052077                   tcp_conn->tc_tos= TCP_DEF_TOS;
0052078                   tcp_conn->tc_ttl= TCP_DEF_TTL;
0052079                   tcp_conn->tc_rcv_wnd= TCP_MAX_RCV_WND_SIZE;
0052080                   tcp_conn->tc_fd= NULL;
0052081          }
0052082          if (!tcp_conn->tc_ISS)
0052083          {
0052084                   tcp_conn->tc_ISS= (get_time()/HZ)*ISS_INC_FREQ;
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.


0052085          }
0052086          tcp_conn->tc_SND_UNA= tcp_conn->tc_ISS;
0052087          tcp_conn->tc_SND_TRM= tcp_conn->tc_ISS;
0052088          tcp_conn->tc_SND_NXT= tcp_conn->tc_ISS+1;
0052089          tcp_conn->tc_SND_UP= tcp_conn->tc_ISS;
0052090          tcp_conn->tc_SND_PSH= tcp_conn->tc_ISS;
0052091          tcp_conn->tc_IRS= 0;
0052092          tcp_conn->tc_RCV_LO= tcp_conn->tc_IRS;
0052093          tcp_conn->tc_RCV_NXT= tcp_conn->tc_IRS;
0052094          tcp_conn->tc_RCV_HI= tcp_conn->tc_IRS;
0052095          tcp_conn->tc_RCV_UP= tcp_conn->tc_IRS;
0052096 
0052097          assert(tcp_conn->tc_rcvd_data == NULL);
0052098          assert(tcp_conn->tc_adv_data == NULL);
0052099          assert(tcp_conn->tc_send_data == NULL);
0052100          tcp_conn->tc_remipopt= NULL;
0052101          tcp_conn->tc_tcpopt= NULL;
0052102 
0052103          assert(tcp_conn->tc_frag2send == NULL);
0052104 
0052105          tcp_conn->tc_stt= 0;
0052106          tcp_conn->tc_rt_dead= TCP_DEF_RT_DEAD;
0052107          tcp_conn->tc_0wnd_to= 0;
0052108          tcp_conn->tc_rtt= TCP_DEF_RTT;
0052109          tcp_conn->tc_mss= TCP_DEF_MSS;
0052110          tcp_conn->tc_error= NW_OK;
0052111          tcp_conn->tc_snd_cwnd= tcp_conn->tc_SND_UNA + 2*tcp_conn->tc_mss;
0052112          tcp_conn->tc_snd_cthresh= TCP_MAX_SND_WND_SIZE;
0052113          tcp_conn->tc_snd_cinc=
0052114                   (long)TCP_DEF_MSS*TCP_DEF_MSS/TCP_MAX_SND_WND_SIZE+1;
0052115          tcp_conn->tc_snd_wnd= TCP_MAX_SND_WND_SIZE;
0052116          tcp_conn->tc_rt_time= 0;
0052117          tcp_conn->tc_rt_seq= 0;
0052118          tcp_conn->tc_rt_threshold= tcp_conn->tc_ISS;
0052119          tcp_conn->tc_flags= TCF_INUSE;
0052120 
0052121          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.


0052122          tcp_conn->tc_transmit_seq= 0;
0052123 }
0052124 
0052125 /*
0052126  * $PchId: tcp.c,v 1.14.2.2 1999/11/17 22:05:27 philip Exp $
0052127  */