Exemplo n.º 1
0
int
main(int argc, char **argv)
{
	thread thread_obj;

	/* Allocate the room */
	req = (REQ *) MALLOC(sizeof (REQ));

	/* Command line parser */
	if (!parse_cmdline(argc, argv, req)) {
		FREE(req);
		exit(0);
	}

	/* Check minimum configuration need */
	if (!req->addr_ip && !req->addr_port && !req->url) {
		FREE(req);
		exit(0);
	}

	/* Init the reference timer */
	req->ref_time = timer_tol(timer_now());
	DBG("Reference timer = %lu\n", req->ref_time);

	/* Init SSL context */
	init_ssl();

	/* Signal handling initialization  */
	signal_init();

	/* Create the master thread */
	master = thread_make_master();

	/* Register the GET request */
	init_sock();

	/*
	 * Processing the master thread queues,
	 * return and execute one ready thread.
	 * Run until error, used for debuging only.
	 * Note that not calling launch_scheduler() does
	 * not activate SIGCHLD handling, however, this
	 * is no issue here.
	 */
	while (thread_fetch(master, &thread_obj))
		thread_call(&thread_obj);

	/* Finalize output informations */
	if (req->verbose)
		printf("Global response time for [%s] =%lu\n",
		       req->url, req->response_time - req->ref_time);

	/* exit cleanly */
	SSL_CTX_free(req->ctx);
	free_sock(sock);
	FREE(req);
	exit(0);
}
Exemplo n.º 2
0
void on_T303(void *user) /* CONNECTING */
{
    SOCKET *sock = user;

    diag(COMPONENT,DIAG_DEBUG,"T303 on %s",kptr_print(&sock->id));
    if (sock->state != ss_connecting) complain(sock,"T303");
    SEND_ERROR(sock->id,-ETIMEDOUT);
    sock->conn_timer = NULL;
    free_sock(sock);
}
Exemplo n.º 3
0
void on_T308_2(void *user) /* WAIT_REL or REL_REQ */
{
    SOCKET *sock = user;

    diag(COMPONENT,DIAG_WARN,"Trouble: T308_2 has expired");
    if (sock->state != ss_wait_rel && sock->state != ss_rel_req)
        complain(sock,"T308_2");
    sock->conn_timer = NULL;
    if (sock->state == ss_rel_req) send_close(sock);
    free_sock(sock);
}
Exemplo n.º 4
0
/** 
 *  on_read - event read
 */ 
void on_read(int sock, short event, void* arg)
{
    struct sock_ev* ev = (struct sock_ev*)arg;
    ev->buffer = (char*)malloc(MEM_SIZE);
    memset(ev->buffer, 0, sizeof(char));
    if (recv(sock, ev->buffer, MEM_SIZE, 0) <= 0) {
        free_sock(ev);
        close(sock);
        return;
    }
	char *cmd = joinstr("%s", ev->buffer);
    event_set(ev->write_ev, sock, EV_WRITE, on_write, exec_cmd(cmd));
    event_add(ev->write_ev, NULL);
}
Exemplo n.º 5
0
static void setup_call(SIG_ENTITY *sig,unsigned long call_ref)
{
    SOCKET *sock,*this,**walk;
    struct sockaddr_atmsvc in_addr;
    struct atm_sap in_sap;
    struct atm_qos in_qos;
    unsigned int problem;
    int i;

    problem = sap_decode(&in_dsc,&in_addr,&in_sap,&in_qos,sig->uni);
    if (problem) {
	send_release_complete(sig,call_ref,IE_PB_CAUSE(problem),
	  IE_PB_IE(problem));
	return;
    }
    if (!atmsvc_addr_in_use(in_addr)) {
	send_release_complete(sig,call_ref,ATM_CV_UNALLOC);
	return;
    }
    if (!allow(&in_addr,ACL_IN)) {
	send_release_complete(sig,call_ref,ATM_CV_REJ_CLIR);
	return;
    }
    this = new_sock(kptr_null);
    this->sig = sig;
    sock = lookup_sap(&in_addr,&in_sap,&in_qos,&this->local,&this->sap,
      &this->qos,0);
    if (!sock) {
	free_sock(this);
	send_release_complete(sig,call_ref,ATM_CV_INCOMP_DEST);
	return;
    }
    this->state = sig->mode == sm_net ? ss_proceeding : ss_indicated;
    this->call_state = cs_in_proc;
    this->call_ref = call_ref;
    if (q_present(&in_dsc,QF_ep_ref))
	this->ep_ref = cvt_ep_ref(sig,q_fetch(&in_dsc,QF_ep_ref));
#ifdef CISCO
    else
#endif
    if (sig->mode == sm_net) {
	int error;

	error = send_call_proceeding(this);
	if (error) {
	    free_sock(this);
	    send_release_complete(sig,call_ref,ATM_CV_NO_CI);
	    return;
	}
    }
    /* if (sock->local) *this->local->sas_addr = sock->local->sas_addr; ??? */
    diag(COMPONENT,DIAG_DEBUG,"AAL type %ld",q_fetch(&in_dsc,QF_aal_type));
    if (sig->mode == sm_user) { /* already set by send_call_proceeding */
	int vpci;

	vpci = q_fetch(&in_dsc,QF_vpi);
	this->pvc.sap_family = AF_ATMPVC;
	this->pvc.sap_addr.itf = get_itf(sig,&vpci);
	this->pvc.sap_addr.vpi = vpci;
	this->pvc.sap_addr.vci = q_fetch(&in_dsc,QF_vci);
    }
    diag(COMPONENT,DIAG_DEBUG,"ITF.VPI.VCI: %d.%d.%d",this->pvc.sap_addr.itf,
      this->pvc.sap_addr.vpi,this->pvc.sap_addr.vci);
    if (q_present(&in_dsc,QF_cgpn)) { /* should handle E.164 too */
	char buffer[MAX_ATM_ADDR_LEN+1];
	int plan;

	plan = q_fetch(&in_dsc,QF_cgpn_plan);
	switch (plan) {
	    case ATM_NP_AEA:
		i = q_read(&in_dsc,QF_cgpn,(void *) this->remote.sas_addr.prv,
		  ATM_ESA_LEN);
		break;
	    case ATM_NP_E164:
		i = q_read(&in_dsc,QF_cgpn,(void *) this->remote.sas_addr.pub,
		  ATM_E164_LEN);
		break;
	    default:
		diag(COMPONENT,DIAG_WARN,"Ignoring cgpn with unrecognized "
		  "numbering plan 0x%x\n",plan);
		i = 0;
	}
	if (i) {
	    this->remote.sas_family = AF_ATMSVC;
	    if (atm2text(buffer,MAX_ATM_ADDR_LEN+1,
	      (struct sockaddr *) &this->remote,pretty) < 0)
		strcpy(buffer,"<invalid address>");
	    diag(COMPONENT,DIAG_DEBUG,"Incoming call from %s",buffer);
	}
    }
    send_kernel(kptr_null,sock->id,as_indicate,0,&this->pvc,&this->remote,
      &in_addr,&this->sap,&this->qos);
    for (walk = &sock->listen; *walk; walk = &(*walk)->listen);
    *walk = this;
    diag(COMPONENT,DIAG_DEBUG,"SE vpi.vci=%d.%d",this->pvc.sap_addr.vpi,
      this->pvc.sap_addr.vci);
}
Exemplo n.º 6
0
static void uni_call(SOCKET *sock,unsigned char mid)
{
    char buffer[MAX_ATM_ADDR_LEN+1];
    int error;

    switch (mid) {
	case ATM_MSG_STATUS: /* 5.5.6.12 */
	    {
		CALL_STATE state;

		/*
		 * NOTE: T322 isn't implemented yet, but when it is, make sure
		 *	 to only stop it on STATUS iff the cause is
		 *	 ATM_CV_RESP_STAT_ENQ. Supplementary services break if
		 *	 you stop on any STATUS.
		 */
		state = q_fetch(&in_dsc,QF_call_state);
		if (state == cs_null) break; /* clear call */
		if (sock->call_state == cs_rel_req || sock->call_state ==
		  cs_rel_ind) return;
		if (state != sock->call_state)
		    diag(COMPONENT,DIAG_WARN,"STATUS %s received in state %s",
		      cs_name[state],cs_name[sock->call_state]);
	    }
	    return;
	default:
	    ;
    }
    switch (mid) {
	case ATM_MSG_CALL_PROC: /* CONNECTING, WAIT_REL, REL_REQ */
	    if (sock->state == ss_wait_rel || sock->state == ss_rel_req) {
		send_status(sock->sig,sock,0,ATM_CV_INCOMP_MSG,
		  ATM_MSG_CALL_PROC);
		return;
	    }
	    if (sock->state != ss_connecting) break;
	    /* check for 2nd CALL_PROC @@@ */
	    STOP_TIMER(sock);
	    if (q_present(&in_dsc,QG_conn_id)) {
		int vpci;

		vpci = q_fetch(&in_dsc,QF_vpi);
		sock->pvc.sap_family = AF_ATMPVC;
		sock->pvc.sap_addr.itf = get_itf(sock->sig,&vpci);
		sock->pvc.sap_addr.vpi = vpci;
		sock->pvc.sap_addr.vci = q_fetch(&in_dsc,QF_vci);
		diag(COMPONENT,DIAG_DEBUG,"ITF.VPI.VCI: %d.%d.%d",
		  sock->pvc.sap_addr.itf,sock->pvc.sap_addr.vpi,
		  sock->pvc.sap_addr.vci);
	    }
	    START_TIMER(sock,T310);
	    sock->call_state = cs_out_proc;
	    return;
	case ATM_MSG_CONNECT: /* CONNECTING, REL_REQ */
	    if (sock->state == ss_rel_req) {
		send_status(sock->sig,sock,0,ATM_CV_INCOMP_MSG,ATM_MSG_CONNECT);
		return;
	    }
	    if (sock->state != ss_connecting) break;
	    STOP_TIMER(sock);
	    if (q_present(&in_dsc,QG_conn_id)) {
		int vpci;

		vpci = q_fetch(&in_dsc,QF_vpi);
		sock->pvc.sap_family = AF_ATMPVC;
		sock->pvc.sap_addr.itf = get_itf(sock->sig,&vpci);
		sock->pvc.sap_addr.vpi = vpci;
		sock->pvc.sap_addr.vci = q_fetch(&in_dsc,QF_vci);
		diag(COMPONENT,DIAG_DEBUG,"ITF.VPI.VCI: %d/%d.%d",
		  sock->pvc.sap_addr.itf,sock->pvc.sap_addr.vpi,
		  sock->pvc.sap_addr.vci);
	    }
	    error = 0;
	    if (!sock->pvc.sap_addr.vpi && !sock->pvc.sap_addr.vci)
		error = -EPROTO;
	    /* more problems */
	    if (error) {
		set_error(sock,error);
		send_release(sock,0); /* @@@ cause follows reason ??? */
		START_TIMER(sock,T308_1);
		new_state(sock,ss_rel_req);
		return;
	    }
	    send_connect_ack(sock);
	    /* @@@ fill in sock->remote */
	    /* @@@ fill in traffic parameters */
	    send_kernel(sock->id,kptr_null,as_okay,0,&sock->pvc,NULL,
	      &sock->local,&sock->sap,&sock->qos);
	    new_state(sock,ss_connected);
#if defined(Q2963_1) || defined(DYNAMIC_UNI)
	    sock->owner = 1;
#endif
	    if (atm2text(buffer,MAX_ATM_ADDR_LEN+1,(struct sockaddr *)
	      &sock->remote,0) < 0) strcpy(buffer,"<invalid>");
	    diag(COMPONENT,DIAG_INFO,"Active open succeeded (CR 0x%06X, "
	      "ID %s, to %s)",sock->call_ref,kptr_print(&sock->id),buffer);
	    return;
	case ATM_MSG_CONN_ACK: /* ACCEPTING, WAIT_REL, REL_REQ */
	    diag(COMPONENT,DIAG_DEBUG,"CA vpi.vci=%d.%d",
	      sock->pvc.sap_addr.vpi,sock->pvc.sap_addr.vci);
	    if (sock->state == ss_wait_rel || sock->state == ss_rel_req) {
		send_status(sock->sig,sock,0,ATM_CV_INCOMP_MSG,
		  ATM_MSG_CONN_ACK);
		return;
	    }
	    if (sock->state != ss_accepting) break;
	    STOP_TIMER(sock);
	    send_kernel(sock->id,kptr_null,as_okay,0,NULL,NULL,&sock->local,
	      &sock->sap,NULL);
	    new_state(sock,ss_connected);
#if defined(Q2963_1) || defined(DYNAMIC_UNI)
	    sock->owner = 0;
#endif
	    if (atm2text(buffer,MAX_ATM_ADDR_LEN+1, (struct sockaddr *)
	      &sock->remote,0) < 0) strcpy(buffer,"<invalid>");
	    diag(COMPONENT,DIAG_INFO,"Passive open succeeded (CR 0x%06X, "
	      "ID %s, from %s)",sock->call_ref,kptr_print(&sock->id),buffer);
	    return;
	case ATM_MSG_RELEASE: /* all states */
	    {
		unsigned char cause;

		cause = q_fetch(&in_dsc,QF_cause);
		diag(COMPONENT,DIAG_DEBUG,"Cause %d (%s)",cause,cause > 127 ?
		  "invalid cause" : cause_text[cause]);
	    }
	    switch (sock->state) {
		case ss_connecting:
		    set_error(sock,-ECONNREFUSED);
		    /* fall through */
		case ss_accepting:
		    set_error(sock,-ECONNRESET); /* ERESTARTSYS ? */
		    send_release_complete(sock->sig,sock->call_ref,0);
		    SEND_ERROR(sock->id,sock->error);
		    STOP_TIMER(sock);
		    free_sock(sock);
		    return;
		case ss_rel_req:
		    send_close(sock);
		    /* fall through */
		case ss_wait_rel:
		    STOP_TIMER(sock);
		    free_sock(sock);
		    return;
#if defined(Q2963_1) || defined(DYNAMIC_UNI)
		case ss_mod_req:
#endif
		    STOP_TIMER(sock);
		    /* fall through */
#if defined(Q2963_1) || defined(DYNAMIC_UNI)
		case ss_mod_lcl:
		case ss_mod_rcv:
		case ss_mod_fin_ok:
		case ss_mod_fin_fail:
		case ss_mod_fin_ack:
#endif
		case ss_connected:
		    diag(COMPONENT,DIAG_INFO,"Passive close (CR 0x%06X)",
		      sock->call_ref);
#if defined(Q2963_1) || defined(DYNAMIC_UNI)
		    if (timer_handler(sock->conn_timer) == on_T361)
			STOP_TIMER(sock);
#endif
		    send_close(sock);
		    new_state(sock,ss_rel_ind);
		    return;
		case ss_indicated:
		    /* fall through */
		case ss_proceeding:
		    send_release_complete(sock->sig,sock->call_ref,0);
		    new_state(sock,ss_zombie);
		    /* fall through */
		case ss_rel_ind:
		    return;
		default:
		    send_release_complete(sock->sig,sock->call_ref,0);
			/* @@@ should be ATM_CV_INCOMP_MSG */
		    break;
	    }
	    break;
	case ATM_MSG_RESTART:
		set_error(sock,-ENETRESET);
		/* fall through */
	case ATM_MSG_STATUS: /* fall through when clearing */
	case ATM_MSG_REL_COMP: /* basically any state (except LISTENING and
				  ZOMBIE) */
	    {
		unsigned char cause;

		if (mid != ATM_MSG_REL_COMP || !q_present(&in_dsc,QF_cause))
		    cause = 0;
		else {
		    cause = q_fetch(&in_dsc,QF_cause);
		    diag(COMPONENT,DIAG_DEBUG,"Cause %d (%s)",cause,
		      cause > 127 ? "invalid cause" : cause_text[cause]);
		}
		switch (sock->state) {
		    case ss_connecting:
			set_error(sock,cause == ATM_CV_UNALLOC ?
			  -EADDRNOTAVAIL : cause == ATM_CV_RES_UNAVAIL ||
#if defined(UNI31) || defined(UNI40) || defined(DYNAMIC_UNI)
			  cause == ATM_CV_UCR_UNAVAIL_NEW ||
#endif
			  cause == ATM_CV_NO_ROUTE_DEST ? -EHOSTUNREACH :
			  cause == ATM_CV_NUM_CHANGED ? -EREMCHG :
			  cause == ATM_CV_DEST_OOO ? -EHOSTDOWN :
			  -ECONNREFUSED);
			/* fall through */
		    case ss_accepting:
			set_error(sock,-ECONNRESET); /* ERESTARTSYS ? */
			SEND_ERROR(sock->id,sock->error);
			STOP_TIMER(sock);
			free_sock(sock);
			return;
		    case ss_rel_req:
			send_close(sock);
			/* fall through */
		    case ss_wait_rel:
			STOP_TIMER(sock);
			free_sock(sock);
			return;
#if defined(Q2963_1) || defined(DYNAMIC_UNI)
		    case ss_mod_req:
#endif
			STOP_TIMER(sock);
			/* fall through */
#if defined(Q2963_1) || defined(DYNAMIC_UNI)
		    case ss_mod_lcl:
		    case ss_mod_rcv:
		    case ss_mod_fin_ok:
		    case ss_mod_fin_fail:
		    case ss_mod_fin_ack:
#endif
		    case ss_connected:
			diag(COMPONENT,DIAG_INFO,"Passive close (CR 0x%06X)",
			  sock->call_ref);
#if defined(Q2963_1) || defined(DYNAMIC_UNI)
			if (timer_handler(sock->conn_timer) == on_T361)
			    STOP_TIMER(sock);
#endif
			send_close(sock);
			/* fall through */
		    case ss_rel_ind:
			new_state(sock,ss_wait_close);
			return;
		    case ss_indicated:
			/* fall through */
		    case ss_proceeding:
			new_state(sock,ss_zombie);
			return;
		    default:
			break;
		}
		break; /* fail */
	    }
	case ATM_MSG_ALERTING:
	    /*
	     * We basically ignore this junk message, except for the connection
	     * identifier it may carry.
	     */
	    if (q_present(&in_dsc,QG_conn_id)) {
		int vpci;

		vpci = q_fetch(&in_dsc,QF_vpi);
		sock->pvc.sap_family = AF_ATMPVC;
		sock->pvc.sap_addr.itf = get_itf(sock->sig,&vpci);
		sock->pvc.sap_addr.vpi = vpci;
		sock->pvc.sap_addr.vci = q_fetch(&in_dsc,QF_vci);
		diag(COMPONENT,DIAG_DEBUG,"ITF.VPI.VCI: %d.%d.%d",
		  sock->pvc.sap_addr.itf,sock->pvc.sap_addr.vpi,
		  sock->pvc.sap_addr.vci);
	    }
	    return;
	case ATM_MSG_NOTIFY:
		/* silently ignore this junk */
	    return;
#if defined(Q2963_1) || defined(DYNAMIC_UNI)
/*
 * Buglet ahead: should actually test "call_state"
 */
	case ATM_MSG_MODIFY_REQ:
	    if (!(sock->sig->uni & S_Q2963_1)) goto _default;
	    if (sock->state != ss_connected || sock->owner) break;
	    sock->new_qos = sock->qos;
	    if (q_present(&in_dsc,QF_fw_pcr_01))
		sock->new_qos.rxtp.max_pcr = q_fetch(&in_dsc,QF_fw_pcr_01);
	    if (q_present(&in_dsc,QF_bw_pcr_01))
		sock->new_qos.txtp.max_pcr = q_fetch(&in_dsc,QF_bw_pcr_01);
	    send_kernel(sock->id,kptr_null,as_modify,
	      ATM_MF_INC_RSV | ATM_MF_DEC_RSV | ATM_MF_DEC_SHP,
	      NULL,NULL,NULL,NULL,&sock->new_qos);
	    new_state(sock,ss_mod_rcv);
	    return;
	case ATM_MSG_MODIFY_ACK:
	    if (!(sock->sig->uni & S_Q2963_1)) goto _default;
	    if (sock->state != ss_mod_req) break;
	    STOP_TIMER(sock);
	    sock->qos = sock->new_qos;
	    if (q_present(&in_dsc,QG_bbrt)) send_conn_avail(sock);
	    send_kernel(sock->id,kptr_null,as_modify,ATM_MF_SET,NULL,NULL,NULL,
	      NULL,&sock->qos);
	    new_state(sock,ss_mod_fin_ok);
	    return;
	case ATM_MSG_MODIFY_REJ:
	    if (!(sock->sig->uni & S_Q2963_1)) goto _default;
	    if (sock->state != ss_mod_req) break;
	    STOP_TIMER(sock);
	    sock->error = -EAGAIN;
	    send_kernel(sock->id,kptr_null,as_modify,ATM_MF_SET,NULL,NULL,NULL,
	      NULL,&sock->qos);
	    new_state(sock,ss_mod_fin_fail);
	    return;
	case ATM_MSG_CONN_AVAIL:
	    if (!(sock->sig->uni & S_Q2963_1)) goto _default;
	    if (sock->state != ss_connected || sock->owner) break;
	    STOP_TIMER(sock);
	    send_kernel(sock->id,kptr_null,as_modify,ATM_MF_SET,NULL,NULL,NULL,
	      NULL,&sock->qos);
	    new_state(sock,ss_mod_fin_ack);
	    return;
	_default: /* jump here if we don't want to understand a message */
#endif
	default:
	    diag(COMPONENT,DIAG_WARN,"Bad signaling message %d",mid);
	    send_status(sock->sig,sock,0,ATM_CV_UNKNOWN_MSG_TYPE,mid);
	    return;
    }
    diag(COMPONENT,DIAG_WARN,
      "Signaling message %s is incompatible with state %s/%s (%d?%d)",
      mid2name(mid),state_name[sock->state],cs_name[sock->call_state],
      (int) sock->state,(int) sock->call_state);
    send_status(sock->sig,sock,0,ATM_CV_INCOMP_MSG,mid);
}
Exemplo n.º 7
0
/* Tcp state process method is implemented via RFC 793 #SEGMENT ARRIVE */
void tcp_process(struct pkbuf *pkb, struct tcp_segment *seg, struct sock *sk)
{
	struct tcp_sock *tsk = tcpsk(sk);
	struct tcp *tcphdr = seg->tcphdr;
	tcp_dbg_state(tsk);
	if (!tsk || tsk->state == TCP_CLOSED)
		return tcp_closed(tsk, pkb, seg);
	if (tsk->state == TCP_LISTEN)
		return tcp_listen(pkb, seg, tsk);
	if (tsk->state == TCP_SYN_SENT)
		return tcp_synsent(pkb, seg, tsk);
	if (tsk->state >= TCP_MAX_STATE)
		goto drop;
	/* first check sequence number */
	tcpsdbg("1. check seq");
	if (seq_check(seg, tsk) < 0) {
		/* incoming segment is not acceptable */
		if (!tcphdr->rst)
			tsk->flags |= TCP_F_ACKNOW; /*reply ACK seq=snd.nxt, ack=rcv.nxt*/
		goto drop;
	}
	/* second check the RST bit */
	tcpsdbg("2. check rst");
	if (tcphdr->rst) {
		/* abort a connection */
		switch (tsk->state) {
		case TCP_SYN_RECV:
			if (tsk->parent) {	/* passive open */
				tcp_unhash(&tsk->sk);
			} else {
				/*
				 * signal user "connection refused"
				 * when both users open simultaneously.
				 * XXX: test
				 */
				if (tsk->wait_connect)
					wake_up(tsk->wait_connect);
			}
			break;
		case TCP_ESTABLISHED:
		case TCP_FIN_WAIT1:
		case TCP_FIN_WAIT2:
		case TCP_CLOSE_WAIT:
			/* RECEIVE and SEND receive reset response */
			/* flush all segments queue */
			/* signal user "connection reset" */
			break;
		case TCP_CLOSING:
		case TCP_LAST_ACK:
		case TCP_TIME_WAIT:
			break;
		}
		tcp_set_state(tsk, TCP_CLOSED);
		tcp_unhash(&tsk->sk);
		tcp_unbhash(tsk);
		goto drop;
	}
	/* third check security and precedence (ignored) */
	tcpsdbg("3. NO check security and precedence");
	/* fourth check the SYN bit */
	tcpsdbg("4. check syn");
	if (tcphdr->syn) {
		/* only LISTEN and SYN-SENT can receive SYN */
		tcp_send_reset(tsk, seg);
		/* RECEIVE and SEND receive reset response */
		/* flush all segments queue */
		/* signal user "connection reset" */
		/*
		 * RFC 1122: error corrections of RFC 793:
		 * In SYN-RECEIVED state and if the connection was initiated
		 * with a passive OPEN, then return this connection to the
		 * LISTEN state and return.
		 * - We delete child tsk directly,
		 *   and its parent has been in LISTEN state.
		 */
		if (tsk->state == TCP_SYN_RECV && tsk->parent)
			tcp_unhash(&tsk->sk);
		tcp_set_state(tsk, TCP_CLOSED);
		free_sock(&tsk->sk);
	}
	/* fifth check the ACK field */
	tcpsdbg("5. check ack");
	/*
	 * RFC 793 say:
	 * 1. we should drop the segment and return
	 *    if the ACK bit is off.
	 * 2. Once in the ESTABLISHED state all segments must
	 *    carry current acknowledgment information.
	 * Should we do it ?
	 * -No for xinu
	 * -No for linux
	 */
	if (!tcphdr->ack)
		goto drop;
	switch (tsk->state) {
	case TCP_SYN_RECV:
		/*
		 * previous state LISTEN :
		 *  snd_nxt = iss + 1
		 *  snd_una = iss
		 * previous state SYN-SENT:
		 *  snd_nxt = iss+1
		 *  snd_una = iss
		 * Should we update snd_una to seg->ack here?
		 *  -Unknown for RFC 793
		 *  -Yes for xinu
		 *  -Yes for Linux
		 *  +Yes for tapip
		 * Are 'snd.una == seg.ack' right?
		 *  -Yes for RFC 793
		 *  -Yes for 4.4BSD-Lite
		 *  -Yes for xinu, although duplicate ACK
		 *  -Yes for Linux,
		 *  +Yes for tapip
		 */
		if (tsk->snd_una <= seg->ack && seg->ack <= tsk->snd_nxt) {
			if (tcp_synrecv_ack(tsk) < 0) {
				tcpsdbg("drop");
				goto drop;		/* Should we drop it? */
			}
			tsk->snd_una = seg->ack;
			/* RFC 1122: error corrections of RFC 793(SND.W**) */
			__tcp_update_window(tsk, seg);
			tcp_set_state(tsk, TCP_ESTABLISHED);
		} else {
			tcp_send_reset(tsk, seg);
			goto drop;
		}
		break;
	case TCP_ESTABLISHED:
	case TCP_CLOSE_WAIT:
	case TCP_LAST_ACK:
	case TCP_FIN_WAIT1:
	case TCP_CLOSING:
		tcpsdbg("SND.UNA %u < SEG.ACK %u <= SND.NXT %u",
				tsk->snd_una, seg->ack, tsk->snd_nxt);
		if (tsk->snd_una < seg->ack && seg->ack <= tsk->snd_nxt) {
			tsk->snd_una = seg->ack;
			/*
			 * remove any segments on the restransmission
			 * queue which are thereby entirely acknowledged
			 */
			if (tsk->state == TCP_FIN_WAIT1) {
				tcp_set_state(tsk, TCP_FIN_WAIT2);
			} else if (tsk->state == TCP_CLOSING) {
				tcp_set_timewait_timer(tsk);
				goto drop;
			} else if (tsk->state == TCP_LAST_ACK) {
				tcp_set_state(tsk, TCP_CLOSED);
				tcp_unhash(&tsk->sk);
				/* for tcp active open */
				tcp_unbhash(tsk);
				goto drop;
			}
		} else if (seg->ack > tsk->snd_nxt) {	/* something not yet sent */
			/* reply ACK ack = ? */
			goto drop;
		} else if (seg->ack <= tsk->snd_una) {	/* duplicate ACK */
			/*
			 * RFC 793 say we can ignore duplicate ACK.
			 * What does `ignore` mean?
			 * Should we conitnue and not drop segment ?
			 * -Yes for xinu
			 * -Yes for linux
			 * -Yes for 4.4BSD-Lite
			 * +Yes for tapip
			 *
			 * After three-way handshake connection is established,
			 * then SND.UNA == SND.NXT, which means next remote
			 * packet ACK is always duplicate. Although this
			 * happens frequently, we should not view it as an
			 * error.
			 *
			 * Close simultaneously in FIN_WAIT1 also causes this.
			 *
			 * Also window update packet will cause this situation.
			 */
		}
		tcp_update_window(tsk, seg);
		break;
	case TCP_FIN_WAIT2:
	/*
          In addition to the processing for the ESTABLISHED state, if
          the retransmission queue is empty, the user's CLOSE can be
          acknowledged ("ok") but do not delete the TCB. (wait FIN)
	 */
		break;
	case TCP_TIME_WAIT:
	/*
          The only thing that can arrive in this state is a
          retransmission of the remote FIN.  Acknowledge it, and restart
          the 2 MSL timeout.
	 */
		break;
	}

	/* sixth check the URG bit */
	tcpsdbg("6. check urg");
	if (tcphdr->urg) {
		switch (tsk->state) {
		case TCP_ESTABLISHED:
		case TCP_FIN_WAIT1:
		case TCP_FIN_WAIT2:
	/*
        If the URG bit is set, RCV.UP <- max(RCV.UP,SEG.UP), and signal
        the user that the remote side has urgent data if the urgent
        pointer (RCV.UP) is in advance of the data consumed.  If the
        user has already been signaled (or is still in the "urgent
        mode") for this continuous sequence of urgent data, do not
        signal the user again.
	 */
			break;
		case TCP_CLOSE_WAIT:
		case TCP_CLOSING:
		case TCP_LAST_ACK:
		case TCP_TIME_WAIT:
			/* ignore */
			/* Should we conitnue or drop? */
			break;
		case TCP_SYN_RECV:
			/* ?? */
			break;
		}
	}
	/* seventh process the segment text */
	tcpsdbg("7. segment text");
	switch (tsk->state) {
	case TCP_ESTABLISHED:
	case TCP_FIN_WAIT1:
	case TCP_FIN_WAIT2:
		if (tcphdr->psh || seg->dlen > 0)
			tcp_recv_text(tsk, seg, pkb);
		break;
	/*
	 * CLOSE-WAIT|CLOSING|LAST-ACK|TIME-WAIT:
	 *  FIN has been received, so we ignore the segment text.
	 *
	 * OTHER STATES: segment is ignored!
	 */
	}
	/* eighth check the FIN bit */
	tcpsdbg("8. check fin");
	if (tcphdr->fin) {
		switch (tsk->state) {
		case TCP_SYN_RECV:
			/*
			 * SYN-RECV means remote->local connection is established
			 * see TCP/IP Illustrated Vol.2, tcp_input() L1127-1134
			 */
		case TCP_ESTABLISHED:
			/* waiting user to close */
			tcp_set_state(tsk, TCP_CLOSE_WAIT);
			tsk->flags |= TCP_F_PUSH;
			tsk->sk.ops->recv_notify(&tsk->sk);
			break;
		case TCP_FIN_WAIT1:
			/* both users close simultaneously */
			tcp_set_state(tsk, TCP_CLOSING);
			break;
		case TCP_CLOSE_WAIT:	/* Remain in the CLOSE-WAIT state */
		case TCP_CLOSING:	/* Remain in the CLOSING state */
		case TCP_LAST_ACK:	/* Remain in the LAST-ACK state */
			/* dont handle it, must be duplicate FIN */
			break;
		case TCP_TIME_WAIT:	/* Remain in the TIME-WAIT state */
			/* restart the 2 MSL time-wait timeout */
			tsk->timewait.timeout = TCP_TIMEWAIT_TIMEOUT;
			break;
		case TCP_FIN_WAIT2:
			/* FIXME: turn off the other timers. */
			tcp_set_timewait_timer(tsk);
			break;
		}
		/* singal the user "connection closing" */
		/* return any pending RECEIVEs with same message */
		/* advance rcv.nxt over fin */
		tsk->rcv_nxt = seg->seq + 1;
		/* send ACK for FIN */
		tsk->flags |= TCP_F_ACKNOW;
		/*
		 * FIN implies PUSH for any segment text not yet delivered
		 * to the user.
		 */
	}
drop:
	/* TODO: use ack delay timer instead of sending ack now */
	if (tsk->flags & (TCP_F_ACKNOW|TCP_F_ACKDELAY))
		tcp_send_ack(tsk, seg);
	free_pkb(pkb);
}