📄 tcp_send.c
字号:
/* * Roadrunner/pk * Copyright (C) 1989-2002 Cornfed Systems, Inc. * * The Roadrunner/pk operating system is free software; you can * redistribute and/or modify it under the terms of the GNU General * Public License, version 2, as published by the Free Software * Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * More information about the Roadrunner/pk operating system of * which this file is a part is available on the World-Wide Web * at: http://www.cornfed.com. * */#include <net/ether.h>#include <net/tcp.h>#if _DEBUG_TCP#include <stdio.h>#endif#include <stdlib.h>#include <sys/intr.h>#include <sys/timer.h>u_short cksum(void *buf, int len);#if _DEBUG_RETRvoid tcp_dump_retr(char *s, buf_t b);#endifstatic voidtcp_send_segment(char *s, tcb_t tcb, buf_t b, int iplen, ipaddr src, ipaddr dst){ etherhdr_t eh; iphdr_t ih; tcphdr_t th; tcpiphdr_t ti; eh = (etherhdr_t) bstart(b); ih = (iphdr_t) eh->data; th = (tcphdr_t) (((char *) ih) + sizeof(struct iphdr)); ti = (tcpiphdr_t) (((char *) th) - sizeof(struct ipovly)); /* Convert to network order */ th->sport = HS2NET(th->sport); th->dport = HS2NET(th->dport); th->seq = HL2NET(th->seq); th->ack = HL2NET(th->ack); th->win = HS2NET(th->win); th->urp = HS2NET(th->urp); /* Compute checksum */ ti->iv.src = HL2NET(src); ti->iv.dst = HL2NET(dst); ti->iv.zero = 0; ti->iv.pr = IP_PROTOCOL_TCP; ti->iv.len = HS2NET(iplen); th->cksum = cksum(ti, sizeof(struct ipovly) + iplen); /* * Insert segment in retransmission queue unless it is an ACK with * no data. iplen is the size of the IP packet payload so subtracting * off the size of the TCP hdr gives the data length. Create a * duplicate buffer descriptor that points to the segment and send * it to the IP layer. */ { int datalen = iplen - sizeof(struct tcphdr); if (datalen > 0 || th->flags & (TF_SYN | TF_FIN)) { buf_t h = balloc(); b->blk->refcnt++; h->blk = b->blk; bstart(h) = bstart(b); blen(h) = blen(b); disable; benq(h, &(tcb->retr)); enable; } } /* Send the segment */ ip_send(b, iplen, IP_PROTOCOL_TCP, src, dst);}static voidtcp_retransmit(tcb_t tcb){ /* Resend the first segment in the retransmission queue */ if (tcb->retr.h != NULL) { buf_t b, h; etherhdr_t eh; iphdr_t ih; tcphdr_t th; ipaddr dst, src; int iplen; b = tcb->retr.h; eh = (etherhdr_t) bstart(b); ih = (iphdr_t) eh->data; th = (tcphdr_t) (((char *) ih) + sizeof(struct iphdr)); iplen = blen(b) - ETHER_HDR_LEN - IP_HLEN(ih); src = NET2HL(ih->src); dst = NET2HL(ih->dst); h = balloc(); b->blk->refcnt++; h->blk = b->blk; bstart(h) = bstart(b); blen(h) = blen(b);#if _DEBUG_RETR tcp_dump_retr("tcp_retransmit", h);#endif /* Send the segment */ ip_send(h, iplen, IP_PROTOCOL_TCP, src, dst); } /* Restart retransmission timer */ if (tcb->flags & TCPF_RETRANSMIT) { struct timeval tv; tv.tv_sec = TCP_RETRANSMIT_SEC; tv.tv_usec = TCP_RETRANSMIT_USEC; timer_start("tcp retransmit", &tv, (timer_func_t) tcp_retransmit, tcb); }}voidtcp_send_syn(tcb_t tcb){ socket_t socket = tcb->socket; buf_t b; etherhdr_t eh; iphdr_t ih; tcphdr_t th; b = _bget(ETHER_PKT_LEN); if (b == NULL) return; blen(b) = ETHER_HDR_LEN + sizeof(struct iphdr) + sizeof(struct tcphdr); eh = (etherhdr_t) bstart(b); ih = (iphdr_t) eh->data; th = (tcphdr_t) (((char *) ih) + sizeof(struct iphdr)); /* Format and send TCP segment header */ th->sport = socket->sport; th->dport = socket->dport; th->seq = tcb->snd_nxt++; th->ack = tcb->rcv_nxt; th->off = sizeof(struct tcphdr) << 2; th->flags = TF_SYN; if (tcb->state == TCPS_SYN_RECEIVED) th->flags |= TF_ACK; th->win = RCV_WND; th->cksum = 0; th->urp = th->seq; tcp_send_segment("tcp_send_syn", tcb, b, sizeof(struct tcphdr), socket->src, socket->dst);}voidtcp_send_ack(tcb_t tcb){ socket_t socket = tcb->socket; buf_t b; etherhdr_t eh; iphdr_t ih; tcphdr_t th; b = _bget(ETHER_PKT_LEN); if (b == NULL) return; blen(b) = ETHER_HDR_LEN + sizeof(struct iphdr) + sizeof(struct tcphdr); eh = (etherhdr_t) bstart(b); ih = (iphdr_t) eh->data; th = (tcphdr_t) (((char *) ih) + sizeof(struct iphdr)); /* Format TCP segment header */ th->sport = socket->sport; th->dport = socket->dport; th->seq = tcb->snd_nxt; th->ack = tcb->rcv_nxt; th->off = sizeof(struct tcphdr) << 2; th->flags = TF_ACK; th->win = tcb->rcv_wnd; th->cksum = 0; th->urp = th->seq; tcp_send_segment("tcp_send_ack", tcb, b, sizeof(struct tcphdr), socket->src, socket->dst);}voidtcp_send_fin(tcb_t tcb){ socket_t socket = tcb->socket; buf_t b; etherhdr_t eh; iphdr_t ih; tcphdr_t th; b = _bget(ETHER_PKT_LEN); if (b == NULL) return; blen(b) = ETHER_HDR_LEN + sizeof(struct iphdr) + sizeof(struct tcphdr); eh = (etherhdr_t) bstart(b); ih = (iphdr_t) eh->data; th = (tcphdr_t) (((char *) ih) + sizeof(struct iphdr)); /* Format TCP segment header */ th->sport = socket->sport; th->dport = socket->dport; th->seq = tcb->snd_nxt++; th->ack = tcb->rcv_nxt; th->off = sizeof(struct tcphdr) << 2; th->flags = TF_FIN; th->win = tcb->rcv_wnd; th->cksum = 0; th->urp = th->seq; tcp_send_segment("tcp_send_fin", tcb, b, sizeof(struct tcphdr), socket->src, socket->dst);}voidtcp_send(tcb_t tcb){ socket_t socket = tcb->socket; buf_t b; etherhdr_t eh; iphdr_t ih; tcphdr_t th; int bytecnt = 0, hdrlen, len; hdrlen = ETHER_HDR_LEN + sizeof(struct iphdr) + sizeof(struct tcphdr); for (;;) { disable; b = bdeq(&(tcb->socket->sndq)); enable; if (b == NULL) break; tcb->socket->snd_cc -= blen(b) - hdrlen; eh = (etherhdr_t) bstart(b); ih = (iphdr_t) eh->data; th = (tcphdr_t) (((char *) ih) + sizeof(struct iphdr)); /* Format TCP segment header */ th->sport = socket->sport; th->dport = socket->dport; th->seq = tcb->snd_nxt; tcb->snd_nxt += blen(b) - hdrlen; th->ack = tcb->rcv_nxt; th->off = sizeof(struct tcphdr) << 2; th->flags = TF_ACK; th->win = tcb->rcv_wnd; th->cksum = 0; th->urp = th->seq; len = blen(b) - ETHER_HDR_LEN - sizeof(struct iphdr); tcp_send_segment("tcp_send", tcb, b, len, socket->src, socket->dst); bytecnt += len; } /* Set retransmission timer */ if (!(tcb->flags & TCPF_RETRANSMIT) && bytecnt > 0) { struct timeval tv; tv.tv_sec = TCP_RETRANSMIT_SEC; tv.tv_usec = TCP_RETRANSMIT_USEC; timer_start("tcp retransmit", &tv, (timer_func_t) tcp_retransmit, tcb); tcb->flags |= TCPF_RETRANSMIT; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -