📄 tcp.c
字号:
//==========================================================================//// net/tcp.c//// Stand-alone TCP networking support for RedBoot////==========================================================================//####COPYRIGHTBEGIN####// // ------------------------------------------- // The contents of this file are subject to the Red Hat eCos Public License // Version 1.1 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at // http://www.redhat.com/ // // Software distributed under the License is distributed on an "AS IS" // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the // License for the specific language governing rights and limitations under // the License. // // The Original Code is eCos - Embedded Configurable Operating System, // released September 30, 1998. // // The Initial Developer of the Original Code is Red Hat. // Portions created by Red Hat are // Copyright (C) 1998, 1999, 2000 Red Hat, Inc. // All Rights Reserved. // ------------------------------------------- // //####COPYRIGHTEND####//==========================================================================//#####DESCRIPTIONBEGIN####//// Author(s): gthomas// Contributors: gthomas// Date: 2000-07-14// Purpose: // Description: // // This code is part of RedBoot (tm).////####DESCRIPTIONEND####////==========================================================================#include <net/net.h>#define MAX_TCP_SEGMENT (ETH_MAX_PKTLEN - (sizeof(eth_header_t) + sizeof(ip_header_t)))#define MAX_TCP_DATA (MAX_TCP_SEGMENT - sizeof(tcp_header_t))/* sequence number comparison macros */#define SEQ_LT(a,b) ((int)((a)-(b)) < 0)#define SEQ_LE(a,b) ((int)((a)-(b)) <= 0)#define SEQ_GT(a,b) ((int)((a)-(b)) > 0)#define SEQ_GE(a,b) ((int)((a)-(b)) >= 0)static void do_retrans(void *p);static void do_close(void *p);#ifdef BSP_LOGstatic char *flags_to_str(octet f){ static char str[7], *p; p = str; if (f & TCP_FLAG_FIN) *p++ = 'F'; if (f & TCP_FLAG_SYN) *p++ = 'S'; if (f & TCP_FLAG_RST) *p++ = 'R'; if (f & TCP_FLAG_PSH) *p++ = 'P'; if (f & TCP_FLAG_ACK) *p++ = 'A'; if (f & TCP_FLAG_URG) *p++ = 'U'; *p = '\0'; return str;}#endif/* * A major assumption is that only a very small number of sockets will * active, so a simple linear search of those sockets is acceptible. */static tcp_socket_t *tcp_list;/* * Format and send an outgoing segment. */static voidtcp_send(tcp_socket_t *s, int flags, int resend){ tcp_header_t *tcp; ip_header_t *ip; pktbuf_t *pkt = &s->pkt; unsigned short cksum; dword tcp_magic; int tcp_magic_size = sizeof(tcp_magic); ip = pkt->ip_hdr; tcp = pkt->tcp_hdr; if (flags & TCP_FLAG_SYN) { /* If SYN, assume no data and send MSS option in tcp header */ pkt->pkt_bytes = sizeof(tcp_header_t) + 4; tcp->hdr_len = 6; tcp_magic = htonl(0x02040000 | MAX_TCP_DATA); memcpy((unsigned char *)(tcp+1), &tcp_magic, tcp_magic_size); s->data_bytes = 0; } else { pkt->pkt_bytes = s->data_bytes + sizeof(tcp_header_t); tcp->hdr_len = 5; } /* tcp header */ tcp->reserved = 0; tcp->seqnum = htonl(s->seq); tcp->acknum = htonl(s->ack); tcp->checksum = 0; if (!resend) { tcp->src_port = htons(s->our_port); tcp->dest_port = htons(s->his_port); tcp->flags = flags; /* always set PUSH flag if sending data */ if (s->data_bytes) tcp->flags |= TCP_FLAG_PSH; tcp->window = htons(MAX_TCP_DATA); tcp->urgent = 0; /* fill in some pseudo-header fields */ memcpy(ip->source, __local_ip_addr, sizeof(ip_addr_t)); memcpy(ip->destination, s->his_addr.ip_addr, sizeof(ip_addr_t)); ip->protocol = IP_PROTO_TCP; } /* another pseudo-header field */ ip->length = htons(pkt->pkt_bytes); /* compute tcp checksum */ cksum = __sum((word *)tcp, pkt->pkt_bytes, __pseudo_sum(ip)); tcp->checksum = htons(cksum); __ip_send(pkt, IP_PROTO_TCP, &s->his_addr); BSPLOG(bsp_log("tcp_send: state[%d] flags[%s] ack[%x] data[%d].\n", s->state, flags_to_str(tcp->flags), s->ack, s->data_bytes)); if (s->state == _TIME_WAIT) __timer_set(&s->timer, 120000, do_close, s); else if ((tcp->flags & (TCP_FLAG_FIN | TCP_FLAG_SYN)) || s->data_bytes) __timer_set(&s->timer, 1000, do_retrans, s);}/* * Send a reset for a bogus incoming segment. */static voidsend_reset(pktbuf_t *pkt, ip_route_t *r){ ip_header_t *ip = pkt->ip_hdr; tcp_header_t *tcp = pkt->tcp_hdr; dword seq, ack; word src, dest; word cksum; seq = ntohl(tcp->acknum); ack = ntohl(tcp->seqnum); src = ntohs(tcp->dest_port); dest = ntohs(tcp->src_port); tcp = (tcp_header_t *)(ip + 1); pkt->pkt_bytes = sizeof(tcp_header_t); /* tcp header */ tcp->hdr_len = 5; tcp->reserved = 0; tcp->seqnum = htonl(seq); tcp->acknum = htonl(ack); tcp->window = htons(1024); tcp->urgent = 0; tcp->checksum = 0; tcp->src_port = htons(src); tcp->dest_port = htons(dest); tcp->flags = TCP_FLAG_RST | TCP_FLAG_ACK; /* fill in some pseudo-header fields */ memcpy(ip->source, __local_ip_addr, sizeof(ip_addr_t)); memcpy(ip->destination, r->ip_addr, sizeof(ip_addr_t)); ip->protocol = IP_PROTO_TCP; ip->length = htons(pkt->pkt_bytes); /* compute tcp checksum */ cksum = __sum((word *)tcp, pkt->pkt_bytes, __pseudo_sum(ip)); tcp->checksum = htons(cksum); __ip_send(pkt, IP_PROTO_TCP, r);}/* * Remove given socket from socket list. */static voidunlink_socket(tcp_socket_t *s){ tcp_socket_t *prev, *tp; for (prev = NULL, tp = tcp_list; tp; prev = tp, tp = tp->next) if (tp == s) { BSPLOG(bsp_log("unlink tcp socket.\n")); if (prev) prev->next = s->next; else tcp_list = s->next; }}/* * Retransmit last packet. */static voiddo_retrans(void *p){ BSPLOG(bsp_log("tcp do_retrans.\n"));//{ int oldConsole = start_console(); printf("do_retrans "); end_console(oldConsole); } tcp_send((tcp_socket_t *)p, 0, 1);}static voiddo_close(void *p){ BSPLOG(bsp_log("tcp do_close.\n")); /* close connection */ ((tcp_socket_t *)p)->state = _CLOSED; unlink_socket(p);}static voidfree_rxlist(tcp_socket_t *s){ pktbuf_t *p; BSPLOG(bsp_log("tcp free_rxlist.\n")); while ((p = s->rxlist) != NULL) { s->rxlist = p->next; __pktbuf_free(p); }}/* * Handle a conection reset. */static voiddo_reset(tcp_socket_t *s){ /* close connection */ s->state = _CLOSED; __timer_cancel(&s->timer); free_rxlist(s); unlink_socket(s);}/* * Extract data from incoming tcp segment. * Returns true if packet is queued on rxlist, false otherwise. */static inthandle_data(tcp_socket_t *s, pktbuf_t *pkt){ tcp_header_t *tcp = pkt->tcp_hdr; unsigned int diff, seq; int data_len; char *data_ptr; pktbuf_t *p; data_len = pkt->pkt_bytes - (tcp->hdr_len << 2); data_ptr = ((char *)tcp) + (tcp->hdr_len << 2); seq = ntohl(tcp->seqnum); BSPLOG(bsp_log("tcp data: seq[%x] len[%d].\n", seq, data_len)); if (SEQ_LE(seq, s->ack)) { /* * Figure difference between which byte we're expecting and which byte * is sent first. Adjust data length and data pointer accordingly. */ diff = s->ack - seq; data_len -= diff; data_ptr += diff; if (data_len > 0) { /* queue the new data */ s->ack += data_len; pkt->next = NULL; if ((p = s->rxlist) != NULL) { while (p->next) p = p->next; p->next = pkt; BSPLOG(bsp_log("tcp data: Add pkt[%x] len[%d].\n",pkt, data_len)); } else { s->rxlist = pkt; s->rxcnt = data_len; s->rxptr = data_ptr; BSPLOG(bsp_log("tcp data: pkt[%x] len[%d].\n", pkt, data_len)); } return 1; } } return 0;}static voidhandle_ack(tcp_socket_t *s, pktbuf_t *pkt){ tcp_header_t *tcp = pkt->tcp_hdr; dword ack; int advance; char *dp; /* process ack value in packet */ ack = ntohl(tcp->acknum); BSPLOG(bsp_log("Rcvd tcp ACK %x\n", ack)); if (SEQ_GT(ack, s->seq)) { __timer_cancel(&s->timer); advance = ack - s->seq; if (advance > s->data_bytes) advance = s->data_bytes; BSPLOG(bsp_log("seq advance %d", advance)); if (advance > 0) { s->seq += advance; s->data_bytes -= advance; if (s->data_bytes) { /* other end ack'd only part of the pkt */ BSPLOG(bsp_log(" %d bytes left", s->data_bytes)); dp = (char *)(s->pkt.tcp_hdr + 1); memcpy(dp, dp + advance, s->data_bytes); } } } BSPLOG(bsp_log("\n"));}/* * Handle incoming TCP packets. */void__tcp_handler(pktbuf_t *pkt, ip_route_t *r){ tcp_header_t *tcp = pkt->tcp_hdr;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -