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()
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;
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);
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;
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);
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;
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);
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);
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));
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;
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);
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;
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;
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);
0050656 result= NW_OK;
0050657 break;
0050658 }
0050659 result= tcp_setconf(tcp_fd);
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);
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);
0050701 result= NW_OK;
0050702 break;
0050703 }
0050704 result= tcp_connect(tcp_fd);
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);
0050711 result= NW_OK;
0050712 break;
0050713 }
0050714 result= tcp_listen(tcp_fd);
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);
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);
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;
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);
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);
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);
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);
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);
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);
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);
0050936 return NW_OK;
0050937 }
0050938
0050939
0050940 /*
0050941 tcp_setopt
0050942 */
0050943
0050944 PRIVATE int tcp_setopt(tcp_fd)
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);
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);
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);
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))
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))
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;
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;
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;
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()
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);
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;
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);
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;
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;
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))
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;
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;
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);
0051486 }
0051487
0051488 PUBLIC void tcp_reply_write(tcp_fd, reply)
0051489 tcp_fd_t *tcp_fd;
0051490 size_t reply;
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);
0051496 }
0051497
0051498 PUBLIC void tcp_reply_read(tcp_fd, reply)
0051499 tcp_fd_t *tcp_fd;
0051500 size_t reply;
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);
0051506 }
0051507
0051508 PUBLIC int tcp_write(fd, count)
0051509 int fd;
0051510 size_t count;
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);
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);
0051528 return NW_OK;
0051529 }
0051530 if (tcp_conn->tc_flags & TCF_FIN_SENT)
0051531 {
0051532 reply_thr_get (tcp_fd, ESHUTDOWN, FALSE);
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);
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);
0051552 tcp_conn->tc_busy--;
0051553 tcp_conn_write(tcp_conn, 0);
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;
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;
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);
0051631 }
0051632
0051633 /*
0051634 tcp_close
0051635 */
0051636
0051637 PUBLIC void tcp_close(fd)
0051638 int fd;
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);
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);
0051671 }
0051672
0051673 PUBLIC int tcp_cancel(fd, which_operation)
0051674 int fd;
0051675 int which_operation;
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);
0051695 else
0051696 reply_thr_get (tcp_fd, EINTR, FALSE);
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);
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);
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);
0051726 reply_thr_get (tcp_fd, EINTR, TRUE);
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);
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;
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);
0051756 return NW_OK;
0051757 }
0051758 if (tcp_fd->tf_flags & TFF_CONNECT)
0051759 {
0051760 tcp_reply_ioctl(tcp_fd, EISCONN);
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);
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);
0051775 if (tcp_conn)
0051776 {
0051777 if (tcp_conn->tc_fd)
0051778 {
0051779 tcp_reply_ioctl(tcp_fd, EADDRINUSE);
0051780 return NW_OK;
0051781 }
0051782 }
0051783 else
0051784 {
0051785 tcp_conn= find_empty_conn();
0051786 if (!tcp_conn)
0051787 {
0051788 tcp_reply_ioctl(tcp_fd, EAGAIN);
0051789 return NW_OK;
0051790 }
0051791 }
0051792 tcp_fd->tf_conn= tcp_conn;
0051793
0051794 return tcp_su4connect(tcp_fd);
0051795 }
0051796
0051797 /*
0051798 tcp_su4connect
0051799 */
0051800
0051801 PRIVATE int tcp_su4connect(tcp_fd)
0051802 tcp_fd_t *tcp_fd;
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);
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);
0051828
0051829 tcp_conn_write(tcp_conn, 0);
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;
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;
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);
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);
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);
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);
0051901 return NW_OK;
0051902 }
0051903 tcp_fd->tf_conn= tcp_conn;
0051904 return tcp_su4listen(tcp_fd);
0051905 }
0051906 }
0051907 tcp_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);
0051912 return NW_OK;
0051913 }
0051914 tcp_fd->tf_conn= tcp_conn;
0051915 return tcp_su4listen(tcp_fd);
0051916 }
0051917
0051918 PRIVATE void tcp_buffree (priority)
0051919 int priority;
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);
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);
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;
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);
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);
0052055 }
0052056
0052057 /*
0052058 tcp_setup_conn
0052059 */
0052060
0052061 PRIVATE void tcp_setup_conn(tcp_conn)
0052062 tcp_conn_t *tcp_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 */