/*
 * tcp.c
 *
 * Copyright 2004, Minoru Murashima. All rights reserved.
 * Distributed under the terms of the BSD License.
 *
 * Transmission control Protocl.
 */


#include<config.h>
#include<types.h>
#include<lib.h>
#include<errno.h>
#include<mm.h>
#include<proc.h>
#include<time.h>
#include<lock.h>
#include<interrupt.h>
#include<signal.h>
#include<fs.h>
#include<console.h>
#include<net/net.h>
#include<net/ether.h>
#include<net/ip.h>
#include<net/tcp.h>
#include<net/netlib.h>
#include<debug.h>
#include<test.h>


//#define DEBUG_TCP 1

#ifdef DEBUG_TCP
	#define STATIC
	#define INLINE
#else
	#define STATIC static
	#define INLINE	inline
#endif


/**************************************************************************
 *
 * 共通
 *
 **************************************************************************/


enum{
	/* TCP flag. */
	TCP_FLG_FIN = 1<<0,
	TCP_FLG_SYN = 1<<1,
	TCP_FLG_RST = 1<<2,
	TCP_FLG_PSH = 1<<3,
	TCP_FLG_ACK = 1<<4,
	TCP_FLG_URG = 1<<5,

	TCP_WIN_SIZE=0xffff,	/* Window size. */
};


typedef struct{
	uint8_t  kind;
	uint8_t  len;
	uint16_t mss;
}MSS;


//================================== パブリック ========================================


/*
 * PUBLIC
 * 疑似ヘッダの設定。
 * parameters : dectination IP,pseudo header address,data size
 */
STATIC INLINE void setPseudoHead(in_addr_t dstip,in_addr_t srcip,uint16_t size,PSEUDO_HEADER *pshead)
{
	pshead->dstip=dstip;
	pshead->srcip=srcip;
	pshead->tmp=0;
	pshead->prot=IPPROTO_TCP;
	pshead->len=swapWord(size);
}


/*
 * PUBLIC
 * Get sequence number.
 * return : sequence number
 */
STATIC INLINE uint32_t getSeqNumber()
{
	/* 4msで１増やす（RFC793）。 */
	return rdtsc()/clock_1m*4;
}


/*
 * PUBLIC
 * 受信TCPバイト数を返す
 */
STATIC INLINE int getTcpSize(IP_HEADER *ip)
{
	return swapWord(ip->len) - (ip->verhead & 0xf) * 4;
}


/*
 * PUBLIC
 * 受信TCPデータバイト数を返す
 */
STATIC int getTcpDataSize(IP_HEADER *ip)
{
	TCP_HEADER *tcp = (TCP_HEADER*)ip->data;


	return getTcpSize(ip) - (tcp->headlen >> 4) * 4;
}


/**************************************************************************
 *
 * ヘッダーオプション。
 *
 **************************************************************************/


enum{
	/* Header option. */
	TCP_KIND_END=  0,
	TCP_KIND_NOP=  1,
	TCP_KIND_MSS=  2,
	TCP_KIND_WSC=  3,
	TCP_KIND_TSTMP=8,

	TCP_OPT_MAXSIZE=32,		/* TCP オプションの最大サイズ。 */
};


typedef struct{
	uint32_t timeStamp;
	uint32_t timeEcho;
	uint16_t mss;
	uint8_t  winscal;
}OPTIONS;


//================================== パブリック ========================================


/*
 * Get TCP options.
 * parameters : option address
 */
STATIC void getTcpOptions(uchar *c, int size, OPTIONS *optst)
{
	uchar *last;


	last = c + size;
	while (c < last)
	{
		switch (*c)
		{
			case TCP_KIND_MSS:
				optst->mss = *(uint16_t*)(c + 2);
				c += 4;
				break;
			case TCP_KIND_WSC:
				optst->winscal = *(uint8_t*)(c + 2);
				c += 3;
				break;
			case TCP_KIND_TSTMP:
				optst->timeStamp = *(uint32_t*)(c + 2);
				optst->timeEcho = *(uint32_t*)(c + 6);
				c += 10;
				break;
			case TCP_KIND_NOP:
				c += 1;
				break;
			case TCP_KIND_END:
				break;
			default:
				c += *(c + 1);
		}
	}
}


/**************************************************************************
 *
 * 送信
 *
 **************************************************************************/


enum{
	SEND_BUF_SIZE = 0x1000,		// 送信バッファサイズ
};


//================================== パブリック ========================================


// Transmit a tcp segment.
// 《注意》オプションデータは必ずintで割り切れるサイズにすること。
STATIC void transSegment(
	SOCKET *sock,
	uint8_t flag,
	void *opt,
	int opt_size,
	void *data,
	int data_size,
	uint16_t wndsize)
{
	char head[sizeof(PSEUDO_HEADER) + sizeof(TCP_HEADER) + TCP_OPT_MAXSIZE];
	TRANS_BUF_INFO tbi;
	TCP_HEADER *send_tcp = (TCP_HEADER*)(head + sizeof(PSEUDO_HEADER));

	// 疑似ヘッダの設定
	setPseudoHead(sock->dstip, getSrcip(sock->dstip), sizeof(TCP_HEADER) + opt_size+data_size, (PSEUDO_HEADER*)head);

	// バッファテーブルの設定
	tbi.data[2] = data;
	tbi.size[2] = data_size;
	tbi.data[1] = (char*)send_tcp;
	tbi.size[1] = sizeof(TCP_HEADER) + opt_size;
	tbi.ipType = IPPROTO_TCP;

	// Make TCP header.
	send_tcp->srcport = sock->srcport;
	send_tcp->dstport = sock->dstport;
	send_tcp->seqnum =  swapInt32(sock->seqnum);
	send_tcp->acknum =  swapInt32(sock->acknum);
	send_tcp->headlen = ((sizeof(TCP_HEADER) + opt_size) / sizeof(uint32_t)) << 4;
	send_tcp->flag = flag;
	send_tcp->wndsize = swapWord(wndsize);
	send_tcp->chksum = 0;
	send_tcp->urgpoint = 0;
	memcpy(send_tcp->option, opt, opt_size);
	send_tcp->chksum = calcSumM((uint*)head, data, sizeof(PSEUDO_HEADER) + sizeof(TCP_HEADER) + opt_size, data_size);
/************************************************************************************************************************
{
	union{
		uint ui;
		uchar uc[4];
	}src_ip;

	src_ip.ui = sock->dstip;
	printk("send srcport=%x,dstport=%x,seqnum=%x,acknum=%x,flag=%x,ip=%u.%u.%u.%u\n",
		swapWord(send_tcp->srcport),swapWord(send_tcp->dstport),swapInt32(send_tcp->seqnum),swapInt32(send_tcp->acknum),
		send_tcp->flag,src_ip.uc[0],src_ip.uc[1],src_ip.uc[2],src_ip.uc[3]);
}
************************************************************************************************************************/
	// 送信
	transIp(sock, &tbi, sock->dstip, 0);
}


// Send FIN ack.
STATIC void sendFinAck(SOCKET *sock)
{
	sock->stat |= SOCK_CNCT_RECV_FIN;
	sock->acknum += 1;
	transSegment(sock, TCP_FLG_ACK, NULL, 0, NULL, 0, TCP_WIN_SIZE);
}


// リセットセグメントの送信
STATIC INLINE void transReset(SOCKET *sock, TCP_HEADER *tcp)
{
	sock->seqnum= 0;
	sock->acknum= swapInt32(tcp->seqnum) + 1;
	transSegment(sock, TCP_FLG_RST, NULL, 0, NULL, 0, TCP_WIN_SIZE);
}


// コネクションがない場合のリセットセグメントの送信。
STATIC void sendReset(IP_HEADER *ip)
{
	SOCKET sock;
	TCP_HEADER *tcp = (TCP_HEADER*)ip->data;

	sock.srcport = tcp->dstport;
	sock.dstport = tcp->srcport;
	sock.dstip = ip->srcip;
	transReset(&sock, tcp);
}


// クローズしたソケットから応答する。
STATIC void ackFromCloseSock(SOCKET *sock, IP_HEADER *ip)
{
	TCP_HEADER *tcp = (TCP_HEADER*)ip->data;

	sock->acknum += getTcpDataSize(ip);

	/* FIN送信に対する応答か？ */
	if (swapInt32(tcp->acknum) == sock->seqnum){
		sock->stat |= SOCK_CNCT_RECV_FINACK;
	}

	/* FIN受信の応答 */
	if (tcp->flag & TCP_FLG_FIN){
		if (sock->stat & SOCK_CNCT_RECV_FINACK){
			sendFinAck(sock);
		}
		else{
			if (swapInt32(tcp->acknum) == sock->seqnum){
				sock->stat |= SOCK_CNCT_RECV_FINACK;
				sendFinAck(sock);
			}
		}
	}

	sock->waitTime = sys_time();
}


// 送信データ一時保存バッファに保存されたデータを、引数のスタート位置から
// バッファの最後の位置まで、送信最大サイズごとに送信する。
// return : 送信サイズ（未送信は入れない）
STATIC int sendFromBuf(SOCKET *sock, const size_t i_sendStart, const uint8_t transFlag)
{
	size_t sendLast = getLastRingBuf(sock->ringBuf);	// ループ処理最後のデータ送信位置
	size_t sendStart = i_sendStart;						// ループ内処理ごとのデータ送信開始位置
	int sendBufLen;										// ループ内処理ごとの送信ウィンドウサイズ
	
	// 引数のスタート位置は、必ず送信データ一時保存バッファの開始位置と最後の位置の間にあること。
	ASSERT((getStartRingBuf(sock->ringBuf) <= i_sendStart) && (i_sendStart <= getLastRingBuf(sock->ringBuf)));
	
	// 引数のスタート位置が送信データ一時保存バッファのスタート位置より後なら、連続送信中とみなして
	// 送信データ一時保存バッファから送信バッファの現在位置にコピーして送信する。
	// 引数のスタート位置が送信データ一時保存バッファのスタート位置と同じなら、新たに送信し直すものとみなして
	// 送信データ一時保存バッファから送信バッファの最初にコピーして送信する。
	if (i_sendStart == getStartRingBuf(sock->ringBuf)){
		sendBufLen = SEND_BUF_SIZE;
		sock->sendBuf.curLen = 0;
		sock->seqnum = i_sendStart;
	}
	else{
		sendBufLen = SEND_BUF_SIZE - (i_sendStart - getStartRingBuf(sock->ringBuf));
	}
	while (sendStart < sendLast){
		int sendLen = (sock->mss <= (sendLast - sendStart))? sock->mss : (sendLast - sendStart);
		sendLen = (sendLen <= (sock->mss - sock->sendBuf.curLen))? sendLen : (sock->mss - sock->sendBuf.curLen);
		readRingBuf(sock->ringBuf, sendStart, sendLen, sock->sendBuf.buf + sock->sendBuf.curLen);
		sock->sendBuf.curLen += sendLen;
		if (sock->sendBuf.curLen == sock->mss){
			sendBufLen -= sock->mss;
			transSegment(sock, transFlag, NULL, 0, sock->sendBuf.buf, sock->mss, sendBufLen);
			sock->seqnum += sock->mss;
			sock->sendBuf.curLen = 0;
		}
		sendStart += sendLen;
	}
	
	return sendLast - i_sendStart - sock->sendBuf.curLen;
}


/**************************************************************************
 *
 * 受信
 *
 **************************************************************************/


/* PUBLIC */
static int waitCnctLock;	/* 受信待ちリンク用ロックゲート。 */


//================================== プライベート ========================================


static SOCKET waitCnctSc;	/* 受信待ちリンク。 */
static SOCKET waitLstnSc;	/* リッスンリンク。 */


/*
 * ＊＊＊ 割り込み処理関数 ＊＊＊
 * 待ちソケットを探す。
 * return : 0 = 通常終了する 1 = タスクを起こす -1 = エラー
 */
STATIC int searchSocket(IP_HEADER *ip)
{
	SOCKET *sock;
	IP_BUFFER *ipBuf;
	TCP_HEADER *tcp = (TCP_HEADER*)ip->data;

/****************************************************************************************
union{
	uint ui;
	uchar uc[4];
}srcIp;

if ((ip->srcip == 0x20019ac) && (swapWord(tcp->srcport) == 20)){
	srcIp.ui = ip->srcip;
	printk("searchSocket() %u.%u.%u.%u srcport=%u dstport=%u seq=%x ",
		srcIp.uc[0],srcIp.uc[1],srcIp.uc[2],srcIp.uc[3],
		swapWord(tcp->srcport),swapWord(tcp->dstport),
		swapInt32(tcp->seqnum));
}
****************************************************************************************/
	/* コネクションリンクから探す。 */
	for (sock = waitCnctSc.next; sock != &waitCnctSc; sock = sock->next){
		if ((sock->srcport == tcp->dstport) && (sock->dstport == tcp->srcport) && (sock->dstip == ip->srcip)){
			/* ソケットは既に切断されている。 */
			if (sock->stat & SOCK_DISCON_RECV){
				setIpTask(sock,ip);
				return 1;
			}

			// データをソケットに渡す
			if (allocIpBuf(ip, &ipBuf) == ERR){
				return 0;
			}
			attachRecvBufTcp(ipBuf, (IP_BUFFER**)&sock->recvBuf, &sock->lockGate);
			if (sock->waitProc != NULL){
				sys_wake(sock->waitProc);
			}
			return 1;
		}
	}

	/* リッスンリンクから探す。 */
	for (sock = waitLstnSc.next; sock != &waitLstnSc; sock = sock->next){
		if ((sock->srcport == tcp->dstport) && ((sock->srcip == INADDR_ANY) || (sock->srcip == ip->dstip))){
			if (allocIpBuf(ip,&ipBuf) == ERR){
				return 0;
			}
			attachRecvBufTcp(ipBuf, (IP_BUFFER**)&sock->recvBuf, &sock->lockGate);
			sys_wake(sock->listenThread);
			return 1;
		}
	}
	
	// 見つからず
	setIpTask(NULL, ip);
	
	return 0;
}


//================================== パブリック ========================================


/*
 * 受信データを取得する
 * return : 0 or error number
 */
STATIC int waitReceive(SOCKET *sock,uint timeout)
{
	for (;;)
	{
		IP_BUFFER *ipBuf;
		int rest;
		
		ipBuf = refIpBuf(sock->recvBuf);
		if (ipBuf == NULL){
			sock->waitProc = get_current_task();
			rest = sys_sleep(timeout);
		}
		else if (ipBuf->access == 1){
			ipBuf->access = 0;
			sock->waitProc = get_current_task();
			rest = sys_sleep(timeout);
		}
		else{
			break;
		}

		/* Time out. */
		if (rest == 0){
			if (refIpBuf(sock->recvBuf) == NULL){
				return -ETIMEDOUT;
			}
		}

		/* シグナル割り込みが起きたか？ */
		doSignalRestart();
		if (isSigint() == TRUE){
			return -EINTR;
		}
	}

	return 0;
}


/*
 * Add to connection link.
 * parameters : socket
 */
STATIC void addWaitCnctLink(SOCKET *sc)
{
	cli();
	enter_spinlock(&waitCnctLock);
	{
		sc->next = waitCnctSc.next;
		sc->prev = &waitCnctSc;
		waitCnctSc.next->prev = sc;
		waitCnctSc.next = sc;
	}
	exit_spinlock(&waitCnctLock);
	sti();
}


/*
 * Add to connection link.
 * parameters : socket
 */
STATIC void addWaitLstnLink(SOCKET *sc)
{
	cli();
	enter_spinlock(&waitCnctLock);
	{
		sc->next=waitLstnSc.next;
		sc->prev=&waitLstnSc;
		waitLstnSc.next->prev=sc;
		waitLstnSc.next=sc;
	}
	exit_spinlock(&waitCnctLock);
	sti();
}


/*
 * Delete from connection link.
 * parameters : socket
 */
STATIC void delWaitLink(SOCKET *sc)
{
	cli();
	enter_spinlock(&waitCnctLock);
	{
		sc->next->prev = sc->prev;
		sc->prev->next = sc->next;
		sc->next = sc->prev = sc;
	}
	exit_spinlock(&waitCnctLock);
	sti();
}


/*
 * リッスンソケットをポートで探す
 * parameters : source port
 * return : socket address or NULL
 */
STATIC SOCKET *searchListenSocket(in_port_t srcport)
{
	SOCKET *sc,*search_sc = NULL;
	
	
	cli();
	enter_spinlock(&waitCnctLock);
	{
		for (sc = waitLstnSc.next; sc != &waitLstnSc; sc = sc->next)
			if (sc->srcport == srcport)
			{
				search_sc = sc;
				break;
			}
	}
	exit_spinlock(&waitCnctLock);
	sti();
	
	return search_sc;
}


// 応答セグメントの確認。
// parameters : TCP HEADER, 送信済番号, 受信済番号
enum{
	ACK_EQ_SEQ_EQ = 1,	// 相手方受信済番号 = 送信済番号、相手方送信開始番号 = 受信済番号
	ACK_LW_SEQ_EQ,		// 相手方受信済番号 < 送信済番号、相手方送信開始番号 = 受信済番号
	ACK_EQ_SEQ_LW,		// 相手方受信済番号 = 送信済番号、相手方送信開始番号 < 受信済番号
	ACK_EQ_SEQ_GR,		// 相手方受信済番号 = 送信済番号、相手方送信開始番号 > 受信済番号
};
STATIC int isAck(TCP_HEADER *tcp, uint32_t sent, uint32_t received)
{
	static uchar returnValue[3][3] = {
		{ACK_EQ_SEQ_EQ,	ACK_EQ_SEQ_LW,	ACK_EQ_SEQ_GR},
		{ACK_LW_SEQ_EQ,	ERR,			ERR},
		{ERR,			ERR,			ERR},
	};
	int isAck, isSeq;
	uint32_t tcpAck = swapInt32(tcp->acknum);
	uint32_t tcpSeq = swapInt32(tcp->seqnum);


	/* フラグの比較。 */
	if ((tcp->flag & TCP_FLG_ACK) == 0)
		return ERR;

	/* ACK値とSEQ値の比較 */
	if (tcpAck == sent){
		isAck = 0;
	}
	else if (tcpAck < sent){
		isAck = 1;
	}
	else{
		isAck = 2;
	}
	if (tcpSeq == received){
		isSeq = 0;
	}
	else if (tcpSeq < received){
		isSeq = 1;
	}
	else{
		isSeq = 2;
	}

	return returnValue[isAck][isSeq];
}


/*
 * 受信データを取得する
 * レシーブバッファはリンクから切り離さない
 * parameters : socket,取得したレシーブバッファを入れるポインタ,send flag
 * return : 0 or error number
 */
STATIC int recvData(SOCKET *sock, const uint timeout)
{
	IP_BUFFER *ipBuf;
	TCP_HEADER *tcp;
	int rest;
	
	
	for (;;){
		// 受信待ち
		rest = waitReceive(sock,timeout);
		if (rest < 0){
			return rest;
		}

		ipBuf = refIpBuf(sock->recvBuf);
		tcp = (TCP_HEADER*)ipBuf->ip.data;

/****************************************************************************************************************/
//printDebug(80 * 9 + 58, "0x%x 0x%x",swapInt32(tcp->seqnum), sock->acknum);
/****************************************************************************************************************/
		// リセットフラグならコネクション切断
		if (tcp->flag & TCP_FLG_RST)
		{
			detachRecvBuf(ipBuf, (IP_BUFFER**)&sock->recvBuf, &sock->lockGate);
			freeIpBuf(ipBuf);
			return -ECONNRESET;
		}

		// 受信の確認
		switch (isAck(tcp, sock->seqnum, sock->acknum))
		{
			case ACK_EQ_SEQ_EQ:
				return 0;
			case ACK_EQ_SEQ_GR:
				// 前のセグメントが失われた可能性があるので応答を送信しておく
				ipBuf->access = 1;
				if (tcp->flag & TCP_FLG_FIN){
					sendFinAck(sock);
				}
				else{
					transSegment(sock, TCP_FLG_ACK, NULL, 0, NULL, 0, TCP_WIN_SIZE);
					
					// 空きIPバッファが無い場合はソケットの保留中のIPバッファを一つ開放する。
					if (isIpBufFree() == FALSE){
						freeRecvBuf(sock);
					}
				}
				break;
			case ACK_EQ_SEQ_LW:
				//相手側が再送信したので応答しておく。
				if (tcp->flag & TCP_FLG_FIN){
					sendFinAck(sock);
				}
				else{
					transSegment(sock, TCP_FLG_ACK, NULL, 0, NULL, 0, TCP_WIN_SIZE);
				}
				//下へ
			default:
				detachRecvBuf(ipBuf, (IP_BUFFER**)&sock->recvBuf, &sock->lockGate);
				freeIpBuf(ipBuf);
	    }
    }

	return 0;
}


/*
 * 送信後に相手方応答を確認する。
 * 応答にデータがあるときはデータを削除せずに終了。
 * parameters : ソケット,受信待ち時間（秒）,相手方応答番号（相手方受信済番号）：初期値不定
 * return : 0 or RECV_SEND_GET_DATA : 受信データがあるとき or error number
 */
enum{RECV_SEND_GET_DATA = 1,};
STATIC int recvSend(SOCKET *sock, const uint timeout, size_t *o_tcpAck)
{
	int rest;

	if (0 < timeout){
		rest = waitReceive(sock,timeout);
		if (rest < 0){
			return rest;
		}
	}

	for (;;){
		IP_BUFFER *ipBuf;
		TCP_HEADER *tcp;
		
		ipBuf = refIpBuf(sock->recvBuf);
		if (ipBuf == NULL){
			break;
		}
		tcp = (TCP_HEADER*)ipBuf->ip.data;

		if (tcp->flag & TCP_FLG_RST)
		{
			detachRecvBuf(ipBuf, (IP_BUFFER**)&sock->recvBuf, &sock->lockGate);
			freeIpBuf(ipBuf);
			return -ECONNRESET;
		}

		switch (isAck(tcp, sock->seqnum, sock->acknum))
		{
			case ACK_EQ_SEQ_EQ:
				// 下へ
			case ACK_LW_SEQ_EQ:
				*o_tcpAck = swapInt32(tcp->acknum);
				sock->window = swapWord(tcp->wndsize);
				if (0 < getTcpDataSize(&ipBuf->ip)){
					// データがある場合、レシーブ関数に渡すためパケットを残しておく。
					// ただし、前回渡したパケットが残っていたら削除する。
					if (sock->prevAck != tcp->seqnum){
						// 応答番号を記憶
						sock->prevAck = tcp->seqnum;
						return RECV_SEND_GET_DATA;
					}
				}
				if (tcp->flag & TCP_FLG_FIN){
					sendFinAck(sock);
				}
				// 下へ
			default:
				detachRecvBuf(ipBuf, (IP_BUFFER**)&sock->recvBuf, &sock->lockGate);
				freeIpBuf(ipBuf);
	    }
    }

	return 0;
}


/*
 * Init.
 */
STATIC void initReceive()
{
	waitCnctSc.next=waitCnctSc.prev=&waitCnctSc;
	waitLstnSc.next=waitLstnSc.prev=&waitLstnSc;
}


//================================== グローバル ========================================


/*
 * ＊＊＊ 割り込み処理関数 ＊＊＊
 * return : 0 or task switch=1
 */
int receiveTcp(IP_HEADER *ip)
{
	int tcpSize;
	PSEUDO_HEADER pseudoHead;


	/* チェックサムの確認。 */
	tcpSize = getTcpSize(ip);
	setPseudoHead(ip->dstip,ip->srcip,tcpSize,&pseudoHead);
	if (calcSumM((uint*)&pseudoHead,(uint*)ip->data,sizeof(PSEUDO_HEADER),tcpSize))
		return 0;
	
	/* サイズの確認 */
	if (TCP_MSS_SIZE < getTcpDataSize(ip)){
		return 0;
	}

	return searchSocket(ip);
}


/**************************************************************************
 *
 * リッスンスレッド
 *
 **************************************************************************/

enum{
	LISTEN_WAIT_MAX = 5,	/* listen待ちタイムアウト時間（秒） */
};


//================================== プライベート ========================================


/*
 * ソケットをリッスンソケットに接続する
 * 返信タイムアウトのソケットを削除する
 * parameters : リッスンソケット,ソケット
 */
STATIC void addNewSocket(SOCKET *sc, SOCKET *newsc)
{
	enum{DEL_NUM = 3};
	SOCKET **p;
	SOCKET *delSock[DEL_NUM];
	int delNum = 0;
	int i;
	uint currentTime = sys_time(NULL);
	
	// 新しいソケットを最後に接続
	newsc->waitTime = currentTime;
	newsc->newsc_next = NULL;
	cli();
	enter_spinlock(&sc->lockGate);
	{
		for (p = &sc->newsc_next;; p = &(*p)->newsc_next){
			if (*p == NULL){
				*p = newsc;
				break;
			}

			// 返信タイムアウトのソケットを抽出
			if ((LISTEN_WAIT_MAX < currentTime - (*p)->waitTime) && (refIpBuf(sc->recvBuf) != NULL)){
				if (delNum < DEL_NUM){
					delSock[delNum] = *p;
					*p = (*p)->newsc_next;
					++delNum;
					if (*p == NULL){
						*p = newsc;
						break;
					}
				}
			}
		}
	}
	exit_spinlock(&sc->lockGate);
	sti();
	
	// 返信タイムアウトソケットをコネクションリンクから削除
	for (i = 0; i < delNum; ++i){
		delWaitLink(delSock[i]);
		kfree(delSock[i]);
	}
	
}


/*
 * 新しいソケットを作成する
 * return :  0 or error number
 */
STATIC int makeNewSocket(SOCKET *sock,IP_BUFFER *ipBuf,SOCKET **o_newSock)
{
	SOCKET *newSock;
	IP_HEADER *ip;
	TCP_HEADER *tcp;
	OPTIONS optst;
	int rest;


	rest = makeSocket(sock->sockType,IPPROTO_TCP,&newSock);
	if (rest < 0)
		return rest;

	ip = &ipBuf->ip;
	tcp = (TCP_HEADER*)ip->data;

	/* オプション(MSSのみ取り込む) */
	optst.mss = TCP_MSS_SIZE;
	getTcpOptions(tcp->option,getTcpDataSize(ip),&optst);

	/*
	 * 新ソケットの設定。
	 */
	memcpy(&newSock->fs,&sock->fs,sizeof(SOCKET)-OFFSETOF(SOCKET,fs));
	newSock->dstip			= ip->srcip;
	newSock->dstport		= tcp->srcport;
	newSock->srcport		= tcp->dstport;
	newSock->sc				= newSock;
	newSock->acknum			= swapInt32(tcp->seqnum) + 1;
	newSock->seqnum			= getSeqNumber();
	newSock->prevAck		= 0;
	newSock->stat			= SOCK_LINK_ON;
	newSock->mss			= optst.mss;
	newSock->window			= swapWord(tcp->wndsize);
	newSock->sendBuf.buf	= (char*)0xa5a5a5a5;	// ガベージ値
	newSock->ringBuf		= (void*)0xa5a5a5a5;	// ガベージ値

	*o_newSock = newSock;
	
	return 0;
}


/*
 * listen待ちの接続処理
 */
STATIC void listenConnect(SOCKET *sock)
{
	IP_BUFFER *ipBuf = getRecvBuf((IP_BUFFER**)&sock->recvBuf, &sock->lockGate);
	IP_HEADER *ip = &ipBuf->ip;
	TCP_HEADER *tcp = (TCP_HEADER*)ip->data;
	MSS mss;
	SOCKET *newSock;
	

	/* 接続要求セグメントの確認。 */
	if ((tcp->flag & TCP_FLG_SYN) && (tcp->acknum == 0))
		;
	else
	{
		sendReset(&ipBuf->ip);
		freeIpBuf(ipBuf);
		return;
	}

	/* 新ソケットの作成 */
	if (makeNewSocket(sock,ipBuf,&newSock) < 0)
	{
		sendReset(&ipBuf->ip);
		freeIpBuf(ipBuf);
		return;
	}
	freeIpBuf(ipBuf);
	
	/* コネクションリンクに接続 */
	addWaitCnctLink(newSock);

	/* ヘッダーオプションの設定。 */
	mss.kind=TCP_KIND_MSS;
	mss.len= 4;
	mss.mss= swapWord(TCP_MSS_SIZE);

	/* SYN応答セグメントの送信。 */
	transSegment(newSock, TCP_FLG_SYN|TCP_FLG_ACK, &mss, sizeof(mss), NULL, 0, TCP_WIN_SIZE);

	/* リッスンソケットに接続する */
	addNewSocket(sock,newSock);
}


// スレッド終了ルーチン
STATIC void listenRoutin(SOCKET *sock)
{
	sock->listenThread = get_current_task();
	
	/* コネクション受信の開始 */
	addWaitLstnLink(sock);

	for (;;){
		if (refIpBuf(sock->recvBuf) == NULL){
			/* スリープ */
			sys_sleep(-1);

			/* リッスン状態でなければスレッド終了 */
			if ((sock->stat & SOCK_LISTEN) == 0){
				break;
			}
		}
		else{
			listenConnect(sock);
		}
	}

	/* 解放 */
	kfree(sock);
	sys_exit(0);
}


//================================== パブリック ========================================


/*
 * 接続済新ソケットを取得してソケットをリッスンソケットから削除し
 * 切断処理待ち開始時間を初期化する
 * return : 接続済新ソケット or NULL
 */
STATIC SOCKET *getFromListenSocket(SOCKET *sc)
{
	SOCKET **p,*rest = NULL;
	
	
	cli();
	enter_spinlock(&sc->lockGate);
	{
		for (p = &sc->newsc_next; *p != NULL; p = &(*p)->newsc_next){
			if (refIpBuf((*p)->recvBuf) != NULL){
				rest = *p;
				*p = rest->newsc_next;
				rest->waitTime = 0;
				break;
			}
		}
	}
	exit_spinlock(&sc->lockGate);
	sti();
	
	return rest;
}


/*
 * リッスンソケットリンクからすべてのソケットを開放する
 */
STATIC void releaseListenSocket(SOCKET *sc)
{
	SOCKET *p,*q;
	
	
	for (p = sc->newsc_next; p != NULL; p = q)
	{
		q = p->newsc_next;
		releaseIpBuf(p->recvBuf);
		kfree(p);
	}
}


/*
 * リッスンスレッドの作成
 * parameters : socket,file discripter
 * return     : 0 or error number
 */
STATIC int makeListenThread(SOCKET *sock,int fd)
{
	/* listen処理用プロセスを起動する */
	switch(forkKernelThread())
//	switch(sys_fork())
    {
		case -1:
			return -ENOBUFS;
		case 0:
			// サーバーがソケットを開放できるように
			// ファイルディスクリプタ参照カウントを減らす
			sys_close(fd);

			listenRoutin(sock);
			// Not reached.
	}
	
	/* listen処理プロセスが起動するまで待つ */
	while (sock->next == sock){
		wait_task();
	}

	return 0;
}


/*
 * リッスンスレッドの終了。
 * parameters : socket
 */
STATIC void endListenThread(SOCKET *sock)
{
	sock->stat &= ~SOCK_LISTEN;
	sys_wake(sock->listenThread);
}


/**************************************************************************
 *
 * ラップ関数
 *
 **************************************************************************/


//================================== パブリック ==========================================


// 送信バッファに残っているデータを送信する。
// return : 0 or error number
STATIC int sendRestData(SOCKET *sock, const uint8_t transFlag)
{
	enum{
		WAIT_TIME = 3,	// 応答待ち時間秒
		RESEND_MAX = 3,	// 再送信最大回数
	};
	size_t tcpAck;
	int sendBufLen;
	int c_resend;
	int endLoop;
	int rest;

	if (sock->sendBuf.curLen <= 0){
		return 0;
	}

	sendBufLen = SEND_BUF_SIZE - (getLastRingBuf(sock->ringBuf) - getStartRingBuf(sock->ringBuf));
	c_resend = 0;
	for(endLoop = 0; endLoop == 0;){
		transSegment(sock, transFlag, NULL, 0, sock->sendBuf.buf, sock->sendBuf.curLen, sendBufLen);
		sock->seqnum += sock->sendBuf.curLen + ((transFlag & TCP_FLG_FIN) == TCP_FLG_FIN);
		
		rest = recvSend(sock, WAIT_TIME, &tcpAck);
		switch (rest){
			case 0:
				// 下へ
			case RECV_SEND_GET_DATA:
				if (sock->seqnum == tcpAck){
					sock->sendBuf.curLen = 0;
					return 0;
				}
				// 下へ
			case -ETIMEDOUT:
				if (RESEND_MAX <= ++c_resend){
					endLoop = 1;
					rest = -ENOTCONN;
				}
				break;
			default:
				endLoop = 1;
		}

		sock->seqnum -= sock->sendBuf.curLen + ((transFlag & TCP_FLG_FIN) == TCP_FLG_FIN);
	}
	
	return rest;
}


/**************************************************************************
 *
 * コネクション
 *
 **************************************************************************/


enum{
	CNCT_CLOSE_WAIT_TIME = 5000,	/* 切断処理タイムアウト時間ms。 */
	REPLY_TIMEOUT = 7,				/* 返答タイムアウトミリ秒。 */
};


//================================== プライベート ========================================


static SOCKET *finSocket;		/* 切断中ソケットリンク。 */


/*
 * 切断開始ソケットをリンクに接続する。
 * parameters : socket
 */
STATIC void addCloseSocket(SOCKET *sock)
{
	sock->waitNext = finSocket;
	finSocket = sock;
	sock->waitTime = sys_time();
}


/*
 * 切断開始ソケットで、タイムアウトを探す。
 */
STATIC void delCloseTimeout()
{
	uint time;
	SOCKET *p;


	time = sys_time();
	while (finSocket != NULL)
	{
		if (CNCT_CLOSE_WAIT_TIME <= time - finSocket->waitTime)
		{
			p = finSocket->waitNext;
			delWaitLink(finSocket);
			releaseIpBuf(finSocket->recvBuf);
			kfree(finSocket);
			finSocket = p;
		}
		else
			break;
	}
}


//================================== パブリック ========================================


/*
 * コネクション切断
 * parameters :
 */
STATIC void disconnect(SOCKET *sock)
{
	/* FINセグメントの送信 */
	transSegment(sock, TCP_FLG_FIN | TCP_FLG_ACK, NULL, 0, NULL, 0, SEND_BUF_SIZE);
	sock->seqnum += 1;
	sock->stat |= SOCK_CNCT_TRANS_FIN;
	
	if (sock->stat | SOCK_DISCON_SEND){
		freeRingBuf(sock->ringBuf);
		kfree(sock->sendBuf.buf);
	}

	delCloseTimeout();		/* タイムアウトソケットを削除する。 */
	addCloseSocket(sock);	/* クローズソケットリンクに接続する。 */
}


/*
 * コネクション確立処理。
 * parameters : socket
 * return : 0 or error number
 */
STATIC int connectTo(SOCKET *sock)
{
	int rest;
	MSS mss;
	IP_BUFFER *ipBuf = NULL;
	IP_HEADER *ip;
	TCP_HEADER *tcp;
	OPTIONS optst;

	/* コネクションリンクに接続。 */
	addWaitCnctLink(sock);

	/* ヘッダーオプションの設定。 */
	mss.kind=TCP_KIND_MSS;
	mss.len= 4;
	mss.mss= swapWord(TCP_MSS_SIZE);

	/* SYNセグメントの送信。 */
	transSegment(sock, TCP_FLG_SYN, &mss, sizeof(mss), NULL, 0, TCP_WIN_SIZE);
	sock->seqnum += 1;

	/* 応答セグメントの受信。 */
	rest = waitReceive(sock,REPLY_TIMEOUT);
	if (rest < 0){
		goto ERR;
	}
	ipBuf = getRecvBuf((IP_BUFFER**)&sock->recvBuf, &sock->lockGate);
	ip = &ipBuf->ip;
	tcp = (TCP_HEADER*)ip->data;
	if (((tcp->flag & TCP_FLG_SYN) == 0) || (isAck(tcp,sock->seqnum,0) != ACK_EQ_SEQ_GR)){
		if (tcp->flag & TCP_FLG_RST){
			return -ECONNREFUSED;
		}
		transReset(sock, tcp);
		rest = -EAGAIN;
		goto ERR;
	}

	/* オプションの確認。(MSSのみ取り込む) */
	optst.mss=TCP_MSS_SIZE;
	getTcpOptions(tcp->option,getTcpDataSize(ip),&optst);
	sock->mss = optst.mss;

	/* 確認応答の送信。 */
	sock->window = swapWord(tcp->wndsize);
	sock->acknum = swapInt32(tcp->seqnum) + 1;
	sock->stat |= SOCK_CNCT_ON;
	transSegment(sock, TCP_FLG_ACK, NULL, 0, NULL, 0, TCP_WIN_SIZE);

	sock->sendBuf.buf = kmalloc(sock->mss);
	if (sock->sendBuf.buf == NULL){
		return -ENOMEM;
	}
	sock->sendBuf.curLen = 0;
	rest = allocRingBuf(SEND_BUF_SIZE, sock->seqnum, &sock->ringBuf);
	if (rest < 0){
		return rest;
	}

	freeIpBuf(ipBuf);

	return 0;
ERR:
	freeIpBuf(ipBuf);

	/* コネクションリンクから削除。 */
	delWaitLink(sock);
	releaseIpBuf(sock->recvBuf);

	return rest;
}


/**************************************************************************
 *
 * TCPサービス関数
 *
 **************************************************************************/


/*================================== グローバル ========================================*/


/*
 * IPスレッドから呼び出される
 */
void doTcpService(SOCKET *sock, IP_HEADER *ip)
{
	if (sock == NULL){
		sendReset(ip);
	}
	else{
		ackFromCloseSock(sock, ip);
	}
}


/**************************************************************************
 *
 * ソケットサービス関数
 *
 **************************************************************************/


/*
 * ソケットをコネクションから開放する。
 * parameters : socket
 * return ; 0 or 1(ソケットを開放してはいけない)
 */
int releaseSockFromConect(SOCKET *sock)
{
	if (sock->stat & SOCK_CNCT_ON){
		int isFin = 0;

		// 残っている送信データを送信する
		sendRestData(sock, TCP_FLG_PSH | TCP_FLG_ACK);

		sock->stat |= SOCK_DISCON_RECV | SOCK_DISCON_SEND;

		// 受信パケットに応答する
		while (refIpBuf(sock->recvBuf) != NULL){
			TCP_HEADER *tcp;
			IP_BUFFER *ipBuf = getRecvBuf((IP_BUFFER**)&sock->recvBuf, &sock->lockGate);

			ASSERT(ipBuf != NULL);
			sock->acknum += getTcpDataSize(&ipBuf->ip);
			tcp = (TCP_HEADER*)ipBuf->ip.data;
			isFin = tcp->flag & TCP_FLG_FIN;
			freeIpBuf(ipBuf);
		}
		if (isFin && ((sock->stat & SOCK_CNCT_RECV_FIN) == 0)){
			sendFinAck(sock);
		}
		
		if ((sock->stat & SOCK_CNCT_TRANS_FIN) == 0){
			disconnect(sock);
		}

		return 1;
	}

	if (sock->stat & SOCK_LISTEN){
		delWaitLink(sock);
		releaseIpBuf(sock->recvBuf);
		releaseListenSocket(sock);
		endListenThread(sock);

		return 1;
	}

	if (sock->stat & SOCK_LINK_ON){
		delWaitLink(sock);
		releaseIpBuf(sock->recvBuf);
	}

	return 0;
}


STATIC int send(SOCKET *sock, void *msg, const size_t i_size, int flags, struct sockaddr *to)
{
	enum{
		RESEND_MAX = 3,			// 再送信最大回数
	};
	
	// 送信ループ内で操作するデータ
	size_t unsentSize = i_size;	// ループ処理ごとの未送信サイズ
	char *sendBuf = msg;		// 送信データ
	int window = sock->window;	// ループ処理ごとの相手方ウィンドウサイズ
	int sendLen;				// ループ処理ごとの送信サイズ
	int c_resend = 0;			// 再送信回数
	int timeout = 0;			// 応答待ち時間（秒）

	// 送信バッファはコネクト時に割り当てられているはず
	ASSERT(sock->ringBuf != NULL);
	
	if ((sock->stat & SOCK_CNCT_ON) == 0){
		return -ENOTCONN;
	}
	
	for (; 0 < unsentSize; unsentSize -= sendLen){
		int rest;			// 関数戻り値
		size_t tcpAck = 0;	// 相手方受信済番号
		int sendBufLen;		// 送信一時保存バッファの空きサイズ
		size_t sendStart;	// 送信一時保存バッファの送信開始位置

		// 送信データを送信一時保存バッファに保存して送信する。
		// 送信バッファまたは相手方ウインドサイズが0になったら
		// 応答をタイムアウト秒待って、応答ない場合はバッファの最初から送信する。

		// 応答の確認
		rest = recvSend(sock, timeout, &tcpAck);
		switch (rest){
			case 0:
				if (getStartRingBuf(sock->ringBuf) < tcpAck){
					setStartRingBuf(sock->ringBuf, tcpAck);
					sendStart = getCurrentRingBuf(sock->ringBuf);
					c_resend = 0;
				}
				else if (tcpAck == getStartRingBuf(sock->ringBuf)){
					// パケットロストで相手方が再送応答をしてきたら再送信する
					window = sock->window;
					sendStart = tcpAck;
					c_resend += 1;
				}
				else{
					sendStart = getCurrentRingBuf(sock->ringBuf);
				}
				break;
			case -ETIMEDOUT:
			{
				// 送信バッファの始めから再送信する
				window = sock->window;
				sendStart = getStartRingBuf(sock->ringBuf);
				c_resend += 1;
			}
				break;
			case RECV_SEND_GET_DATA:
				return i_size - unsentSize;
			default:
				return rest;
		}

		// 一回の送信サイズは相手方ウィンドウサイズ以下、かつ送信一時保存バッファの空きサイズ以下
		sendBufLen = getAvailableSizeRingBuf(sock->ringBuf);
		sendLen = (unsentSize < window)? unsentSize : window;
		sendLen = (sendLen < sendBufLen)? sendLen : sendBufLen;
		if (0 < sendLen){
			// 送信一時保存バッファに格納
			writeRingBuf(sock->ringBuf, sendLen, sendBuf);
			sendBuf += sendLen;
			timeout = 0;
		}
		else{
			if (RESEND_MAX <= c_resend){
				return -ENOTCONN;
			}
			timeout = 1;	// 応答待ちタイムアウト秒
		}

		// 送信一時保存バッファから送信
		window -= sendFromBuf(sock, sendStart, TCP_FLG_PSH | TCP_FLG_ACK);
	}
	
	return i_size;
}


/*
 * recv()処理のディシジョンテーブル
 * 条件：FINフラグ有でデータ有か			   0 0   0 0     0 0   0 0       1 1   1 1     1 1   1 1       2 2   2 2     2 2   2 2
 * 		 ユーザーバッファがいっぱい			   0 0   0 0     1 1   1 1       0 0   0 0     1 1   1 1       0 0   0 0     1 1   1 1
 * 		 全データをユーザーに渡した			   0 0   1 1     0 0   1 1       0 0   1 1     0 0   1 1       0 0   1 1     0 0   1 1
 * 		 次のipBufを受信しているか			   0 1   0 1     0 1   0 1       0 1   0 1     0 1   0 1       0 1   0 1     0 1   0 1
 * 
 * 結果：応答する							   0     1       0     1         0     0       0     0         0     1       1     1  
 *      （再度同パケットを必要としない）
 * 		 終了								   0 0   1 0     1 1   1 1       0 0   1 1     1 1   1 1       0 0   1 1     1 1   1 1
 *      （受信終了かユーザーバッファを初期化する）
 */
static const char isSend[3][2][2]		 = {{{ 0,    1   },{ 0,    1   }},{{ 0,    0   },{ 0,     0  }},{{ 0,    1   },{ 1,    1   }}};
static const char isReturn[3][2][2][2]	 = {{{{0,0},{1,0}},{{1,1},{1,1}}},{{{0,0},{1,1}},{{1,1},{1,1}}},{{{0,0},{1,1}},{{1,1},{1,1}}}};

STATIC int recv(SOCKET *sock, struct msghdr *msg)
{
	enum{
		RECEIVE_TIMEOUT = 5,	// 受信タイムアウト秒
	};
	char *data;
	int allSize, tcpDataSize, dataSize, cpSize, iovArrey, iovOffset;
	IP_BUFFER *ipBuf;
	IP_HEADER *ip;
	int rest;

	// コネクションの確認
	if ((sock->stat & SOCK_CNCT_ON) == 0){
		return -ENOTCONN;
	}

	// すでにFINセグメントを受信しているか？
	if (sock->stat & SOCK_CNCT_RECV_FIN){
		return 0;
	}
	
	// 送信バッファの残りを送信する
	rest = sendRestData(sock, TCP_FLG_PSH | TCP_FLG_ACK);
	if (rest < 0){
		return rest;
	}

	allSize = iovArrey = iovOffset = 0;
	for (;;){
		TCP_HEADER *tcp;
		int isFin, isFullUserBuf, isAllDataCopy;

		// 受信
		rest = recvData(sock, RECEIVE_TIMEOUT);
		if (rest < 0){
			return rest;
		}
		ipBuf = refIpBuf(sock->recvBuf);
		ip = &ipBuf->ip;
		tcp = (TCP_HEADER*)ip->data;

		// ユーザーバッファにコピー
		tcpDataSize = getTcpDataSize(ip);
		dataSize = tcpDataSize - ipBuf->offset;
		data = ipBuf->ip.data + getTcpSize(ip) - dataSize;
		cpSize = copyIovec(data, dataSize, msg->msg_iov, msg->msg_iovlen, &iovArrey, &iovOffset);
		allSize += cpSize;
		ipBuf->offset += cpSize;

		//FINフラグを受信しているか
		if (tcp->flag & TCP_FLG_FIN){
			isFin = (0 < dataSize)? 1 : 2;
		}
		else{
			isFin = 0;
		}
		// ユーザーバッファがいっぱいか？
		isFullUserBuf = (iovArrey == msg->msg_iovlen);
		// 全データをユーザーに渡したか？
		isAllDataCopy = (ipBuf->offset == tcpDataSize);

		ASSERT((isFullUserBuf == 1) || (isAllDataCopy == 1));

		if (isSend[isFin][isFullUserBuf][isAllDataCopy]){
			uint8_t  flag = tcp->flag;
			
			// IPバッファの開放
			detachRecvBuf(ipBuf, (IP_BUFFER**)&sock->recvBuf, &sock->lockGate);
			freeIpBuf(ipBuf);

			// 応答送信する
			sock->acknum += tcpDataSize;
			if ((flag & (TCP_FLG_PSH | TCP_FLG_FIN)) || (refIpBuf(sock->recvBuf) == NULL)){
				if (flag & TCP_FLG_FIN){
					sendFinAck(sock);
				}
				else{
					transSegment(sock, TCP_FLG_ACK, NULL, 0, NULL, 0, TCP_WIN_SIZE);
				}
			}
		}
		if (isReturn[isFin][isFullUserBuf][isAllDataCopy][refIpBuf(sock->recvBuf) != NULL]){
			// 終了
			break;
		}
	}

	return allSize;
}


STATIC int shutdown(SOCKET *sock,int flag)
{
	if ((sock->stat & SOCK_CNCT_ON) == 0)
		return -ENOTCONN;

	switch(flag){
		case SHUT_RD:
			sock->stat |= SOCK_DISCON_RECV;
			break;
		case SHUT_WR:
			sock->stat |= SOCK_DISCON_SEND;
			break;
		case SHUT_RDWR:
			sock->stat |= SOCK_DISCON_RECV | SOCK_DISCON_SEND;
			break;
	}

	if ((sock->stat & (SOCK_DISCON_RECV | SOCK_DISCON_SEND)) && (sock->stat & SOCK_CNCT_TRANS_FIN) == 0){
		disconnect(sock);
	}

	return 0;
}


STATIC int connect(SOCKET *sock)
{
	if (sock->stat & SOCK_CNCT_ON)
		return -EISCONN;

	/* Set connect structure. */
	sock->next = sock->prev = sock;
	sock->stat = SOCK_LINK_ON;
	sock->seqnum = getSeqNumber();
	sock->acknum = 0;

	/* コネクションの確立。 */
	return connectTo(sock);
}


STATIC int listen(SOCKET *sock,int fd)
{
	if (sock->stat & SOCK_LISTEN)
		return -EADDRINUSE;

	if (searchListenSocket(sock->srcport) != NULL)
		return -EADDRINUSE;

	sock->next = sock->prev = sock;
	sock->stat = SOCK_LINK_ON | SOCK_LISTEN;
	sock->waitProc = get_current_task();
	
	/* リッスンスレッドの開始 */
	makeListenThread(sock,fd);
	
	return 0;
}


STATIC int accept(SOCKET *sock,SOCKET **o_newSock,uint32_t *o_srcIp)
{
	SOCKET *newSock;
	IP_BUFFER *ipBuf;
	TCP_HEADER *tcp;
	int rest;
	
	for (;;){
		for (;;){
			/* シグナル割り込みが起きたか？ */
			doSignalRestart();
			if (isSigint() == TRUE){
				return -EINTR;
			}

			newSock = getFromListenSocket(sock);
			if (newSock != NULL){
				break;
			}

			/* 受信待ち */
			if (sys_sleep(-1) == 0){		/* Time out. */
				newSock = getFromListenSocket(sock);
				if (newSock == NULL){
					return -ETIMEDOUT;
				}
				else{
					break;
				}
			}
		}

		ipBuf = refIpBuf(newSock->recvBuf);
		for (;;){
			/* 受信の確認 */
			tcp = (TCP_HEADER*)ipBuf->ip.data;
			switch (isAck(tcp,newSock->seqnum,newSock->acknum)){
				case -1:
					/* 下へ */
				case ACK_LW_SEQ_EQ:
					detachRecvBuf(ipBuf, (IP_BUFFER**)&newSock->recvBuf, &newSock->lockGate);
					if (ipBuf->next == NULL){
						freeIpBuf(ipBuf);
						kfree(newSock);
						goto NEXT;
					}
					else{
						IP_BUFFER *cpIpBuf = ipBuf;

						ipBuf = ipBuf->next;
						freeIpBuf(cpIpBuf);
					}
					break;
				case ACK_EQ_SEQ_GR:
					/* 受信セグメントのシーク番号が大きいときは、後のセグメントが先に到着した可能性がある */
					if (ipBuf->next == NULL){
						goto NEXT;
					}
					else{
						ipBuf = ipBuf->next;
					}
					break;
				default:
					/* 相手方から切断要求 */
					if (tcp->flag & TCP_FLG_RST){
						detachRecvBuf(ipBuf, (IP_BUFFER**)&newSock->recvBuf, &newSock->lockGate);
						freeIpBuf(ipBuf);
						kfree(newSock);
						goto NEXT;
					}
					else{
						goto OUT;
					}
			}
		}
NEXT:	;
	}
OUT:
	detachRecvBuf(ipBuf, (IP_BUFFER**)&newSock->recvBuf, &newSock->lockGate);
	freeIpBuf(ipBuf);

	newSock->stat |= SOCK_CNCT_ON;
	newSock->seqnum += 1;

	newSock->sendBuf.buf = kmalloc(newSock->mss);
	if (newSock->sendBuf.buf == NULL){
		return -ENOMEM;
	}
	newSock->sendBuf.curLen = 0;
	rest = allocRingBuf(SEND_BUF_SIZE, newSock->seqnum, &newSock->ringBuf);
	if (rest < 0){
		return rest;
	}

	*o_srcIp = newSock->dstip;
	*o_newSock = newSock;

	return 0;
}


STATIC int poll(SOCKET *sock)
{
	// コネクションの確認 。
	if (((sock->stat & SOCK_CNCT_ON) == 0) && ((sock->stat & SOCK_LISTEN) == 0)){
		return -ENOTCONN;
	}

	// 送信バッファの残りを送信する
	sendRestData(sock, TCP_FLG_PSH | TCP_FLG_ACK);

	if (sock->stat & SOCK_LISTEN){
		if (sock->newsc_next != NULL){
			return POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM;
		}
	}
	else{
		if (refIpBuf(sock->recvBuf) != NULL){
			return POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM;
		}
	}

	sock->waitProc = get_current_task();

	return POLLOUT | POLLWRNORM;
}


/**************************************************************************
 *
 * 初期化
 *
 **************************************************************************/


static SOCKET_INFO sockInfo = {send, recv, connect, shutdown, listen, accept, poll};


/*================================== グローバル ========================================*/


/*
 * Init TCP.
 */
int initTcp()
{
	registSocket(&sockInfo,IPPROTO_TCP);
	initReceive();

	return 0;
}

/***************************************************************************/
void test_tcp()
{
	printk("waitNext=%x\n",*(uint*)0x16be64);
}
/****************************************************************************/
