📄 tcp.c
字号:
}voidtcpackproc(void *a){ Tcptimer *t, *tp, *timeo; Proto *tcp; Tcppriv *priv; int loop; tcp = a; priv = tcp->priv; for(;;) { tsleep(&up->sleep, return0, 0, MSPTICK); qlock(&priv->tl); timeo = nil; loop = 0; for(t = priv->timers; t != nil; t = tp) { if(loop++ > 10000) panic("tcpackproc1"); tp = t->next; if(t->state == TcptimerON) { t->count--; if(t->count == 0) { timerstate(priv, t, TcptimerDONE); t->readynext = timeo; timeo = t; } } } qunlock(&priv->tl); loop = 0; for(t = timeo; t != nil; t = t->readynext) { if(loop++ > 10000) panic("tcpackproc2"); if(t->state == TcptimerDONE && t->func != nil && !waserror()){ (*t->func)(t->arg); poperror(); } } limborexmit(tcp); }}voidtcpgo(Tcppriv *priv, Tcptimer *t){ if(t == nil || t->start == 0) return; qlock(&priv->tl); t->count = t->start; timerstate(priv, t, TcptimerON); qunlock(&priv->tl);}voidtcphalt(Tcppriv *priv, Tcptimer *t){ if(t == nil) return; qlock(&priv->tl); timerstate(priv, t, TcptimerOFF); qunlock(&priv->tl);}intbackoff(int n){ return 1 << n;}voidlocalclose(Conv *s, char *reason) /* called with tcb locked */{ Tcpctl *tcb; Reseq *rp,*rp1; Tcppriv *tpriv; tpriv = s->p->priv; tcb = (Tcpctl*)s->ptcl; iphtrem(&tpriv->ht, s); tcphalt(tpriv, &tcb->timer); tcphalt(tpriv, &tcb->rtt_timer); tcphalt(tpriv, &tcb->acktimer); tcphalt(tpriv, &tcb->katimer); /* Flush reassembly queue; nothing more can arrive */ for(rp = tcb->reseq; rp != nil; rp = rp1) { rp1 = rp->next; freeblist(rp->bp); free(rp); } tcb->reseq = nil; if(tcb->state == Syn_sent) Fsconnected(s, reason); if(s->state == Announced) wakeup(&s->listenr); qhangup(s->rq, reason); qhangup(s->wq, reason); tcpsetstate(s, Closed);}/* mtu (- TCP + IP hdr len) of 1st hop */inttcpmtu(Proto *tcp, uchar *addr, int version, int *scale){ Ipifc *ifc; int mtu; ifc = findipifc(tcp->f, addr, 0); switch(version){ default: case V4: mtu = DEF_MSS; if(ifc != nil) mtu = ifc->maxtu - ifc->m->hsize - (TCP4_PKT + TCP4_HDRSIZE); break; case V6: mtu = DEF_MSS6; if(ifc != nil) mtu = ifc->maxtu - ifc->m->hsize - (TCP6_PKT + TCP6_HDRSIZE); break; } if(ifc != nil){ if(ifc->mbps > 100) *scale = HaveWS | 3; else if(ifc->mbps > 10) *scale = HaveWS | 1; else *scale = HaveWS | 0; } else *scale = HaveWS | 0; return mtu;}voidinittcpctl(Conv *s, int mode){ Tcpctl *tcb; Tcp4hdr* h4; Tcp6hdr* h6; int mss; tcb = (Tcpctl*)s->ptcl; memset(tcb, 0, sizeof(Tcpctl)); tcb->ssthresh = 65535; tcb->srtt = tcp_irtt<<LOGAGAIN; tcb->mdev = 0; /* setup timers */ tcb->timer.start = tcp_irtt / MSPTICK; tcb->timer.func = tcptimeout; tcb->timer.arg = s; tcb->rtt_timer.start = MAX_TIME; tcb->acktimer.start = TCP_ACK / MSPTICK; tcb->acktimer.func = tcpacktimer; tcb->acktimer.arg = s; tcb->katimer.start = DEF_KAT / MSPTICK; tcb->katimer.func = tcpkeepalive; tcb->katimer.arg = s; mss = DEF_MSS; /* create a prototype(pseudo) header */ if(mode != TCP_LISTEN){ if(ipcmp(s->laddr, IPnoaddr) == 0) findlocalip(s->p->f, s->laddr, s->raddr); switch(s->ipversion){ case V4: h4 = &tcb->protohdr.tcp4hdr; memset(h4, 0, sizeof(*h4)); h4->proto = IP_TCPPROTO; hnputs(h4->tcpsport, s->lport); hnputs(h4->tcpdport, s->rport); v6tov4(h4->tcpsrc, s->laddr); v6tov4(h4->tcpdst, s->raddr); break; case V6: h6 = &tcb->protohdr.tcp6hdr; memset(h6, 0, sizeof(*h6)); h6->proto = IP_TCPPROTO; hnputs(h6->tcpsport, s->lport); hnputs(h6->tcpdport, s->rport); ipmove(h6->tcpsrc, s->laddr); ipmove(h6->tcpdst, s->raddr); mss = DEF_MSS6; break; default: panic("inittcpctl: version %d", s->ipversion); } } tcb->mss = tcb->cwind = mss; /* default is no window scaling */ tcb->window = QMAX; tcb->rcv.wnd = QMAX; tcb->rcv.scale = 0; tcb->snd.scale = 0; qsetlimit(s->rq, QMAX);}/* * called with s qlocked */voidtcpstart(Conv *s, int mode){ Tcpctl *tcb; Tcppriv *tpriv; char kpname[KNAMELEN]; tpriv = s->p->priv; if(tpriv->ackprocstarted == 0){ qlock(&tpriv->apl); if(tpriv->ackprocstarted == 0){ sprint(kpname, "#I%dtcpack", s->p->f->dev); kproc(kpname, tcpackproc, s->p); tpriv->ackprocstarted = 1; } qunlock(&tpriv->apl); } tcb = (Tcpctl*)s->ptcl; inittcpctl(s, mode); iphtadd(&tpriv->ht, s); switch(mode) { case TCP_LISTEN: tpriv->stats[PassiveOpens]++; tcb->flags |= CLONE; tcpsetstate(s, Listen); break; case TCP_CONNECT: tpriv->stats[ActiveOpens]++; tcb->flags |= ACTIVE; tcpsndsyn(s, tcb); tcpsetstate(s, Syn_sent); tcpoutput(s); break; }}static char*tcpflag(ushort flag){ static char buf[128]; sprint(buf, "%d", flag>>10); /* Head len */ if(flag & URG) strcat(buf, " URG"); if(flag & ACK) strcat(buf, " ACK"); if(flag & PSH) strcat(buf, " PSH"); if(flag & RST) strcat(buf, " RST"); if(flag & SYN) strcat(buf, " SYN"); if(flag & FIN) strcat(buf, " FIN"); return buf;}Block *htontcp6(Tcp *tcph, Block *data, Tcp6hdr *ph, Tcpctl *tcb){ int dlen; Tcp6hdr *h; ushort csum; ushort hdrlen, optpad = 0; uchar *opt; hdrlen = TCP6_HDRSIZE; if(tcph->flags & SYN){ if(tcph->mss) hdrlen += MSS_LENGTH; if(tcph->ws) hdrlen += WS_LENGTH; optpad = hdrlen & 3; if(optpad) optpad = 4 - optpad; hdrlen += optpad; } if(data) { dlen = blocklen(data); data = padblock(data, hdrlen + TCP6_PKT); if(data == nil) return nil; } else { dlen = 0; data = allocb(hdrlen + TCP6_PKT + 64); /* the 64 pad is to meet mintu's */ if(data == nil) return nil; data->wp += hdrlen + TCP6_PKT; } /* copy in pseudo ip header plus port numbers */ h = (Tcp6hdr *)(data->rp); memmove(h, ph, TCP6_TCBPHDRSZ); /* compose pseudo tcp header, do cksum calculation */ hnputl(h->vcf, hdrlen + dlen); h->ploadlen[0] = h->ploadlen[1] = h->proto = 0; h->ttl = ph->proto; /* copy in variable bits */ hnputl(h->tcpseq, tcph->seq); hnputl(h->tcpack, tcph->ack); hnputs(h->tcpflag, (hdrlen<<10) | tcph->flags); hnputs(h->tcpwin, tcph->wnd>>(tcb != nil ? tcb->snd.scale : 0)); hnputs(h->tcpurg, tcph->urg); if(tcph->flags & SYN){ opt = h->tcpopt; if(tcph->mss != 0){ *opt++ = MSSOPT; *opt++ = MSS_LENGTH; hnputs(opt, tcph->mss); opt += 2; } if(tcph->ws != 0){ *opt++ = WSOPT; *opt++ = WS_LENGTH; *opt++ = tcph->ws; } while(optpad-- > 0) *opt++ = NOOPOPT; } if(tcb != nil && tcb->nochecksum){ h->tcpcksum[0] = h->tcpcksum[1] = 0; } else { csum = ptclcsum(data, TCP6_IPLEN, hdrlen+dlen+TCP6_PHDRSIZE); hnputs(h->tcpcksum, csum); } /* move from pseudo header back to normal ip header */ memset(h->vcf, 0, 4); h->vcf[0] = IP_VER6; hnputs(h->ploadlen, hdrlen+dlen); h->proto = ph->proto; return data;}Block *htontcp4(Tcp *tcph, Block *data, Tcp4hdr *ph, Tcpctl *tcb){ int dlen; Tcp4hdr *h; ushort csum; ushort hdrlen, optpad = 0; uchar *opt; hdrlen = TCP4_HDRSIZE; if(tcph->flags & SYN){ if(tcph->mss) hdrlen += MSS_LENGTH; if(tcph->ws) hdrlen += WS_LENGTH; optpad = hdrlen & 3; if(optpad) optpad = 4 - optpad; hdrlen += optpad; } if(data) { dlen = blocklen(data); data = padblock(data, hdrlen + TCP4_PKT); if(data == nil) return nil; } else { dlen = 0; data = allocb(hdrlen + TCP4_PKT + 64); /* the 64 pad is to meet mintu's */ if(data == nil) return nil; data->wp += hdrlen + TCP4_PKT; } /* copy in pseudo ip header plus port numbers */ h = (Tcp4hdr *)(data->rp); memmove(h, ph, TCP4_TCBPHDRSZ); /* copy in variable bits */ hnputs(h->tcplen, hdrlen + dlen); hnputl(h->tcpseq, tcph->seq); hnputl(h->tcpack, tcph->ack); hnputs(h->tcpflag, (hdrlen<<10) | tcph->flags); hnputs(h->tcpwin, tcph->wnd>>(tcb != nil ? tcb->snd.scale : 0)); hnputs(h->tcpurg, tcph->urg); if(tcph->flags & SYN){ opt = h->tcpopt; if(tcph->mss != 0){ *opt++ = MSSOPT; *opt++ = MSS_LENGTH; hnputs(opt, tcph->mss); opt += 2; } if(tcph->ws != 0){ *opt++ = WSOPT; *opt++ = WS_LENGTH; *opt++ = tcph->ws; } while(optpad-- > 0) *opt++ = NOOPOPT; } if(tcb != nil && tcb->nochecksum){ h->tcpcksum[0] = h->tcpcksum[1] = 0; } else { csum = ptclcsum(data, TCP4_IPLEN, hdrlen+dlen+TCP4_PHDRSIZE); hnputs(h->tcpcksum, csum); } return data;}intntohtcp6(Tcp *tcph, Block **bpp){ Tcp6hdr *h; uchar *optr; ushort hdrlen; ushort optlen; int n; *bpp = pullupblock(*bpp, TCP6_PKT+TCP6_HDRSIZE); if(*bpp == nil) return -1; h = (Tcp6hdr *)((*bpp)->rp); tcph->source = nhgets(h->tcpsport); tcph->dest = nhgets(h->tcpdport); tcph->seq = nhgetl(h->tcpseq); tcph->ack = nhgetl(h->tcpack); hdrlen = (h->tcpflag[0]>>2) & ~3; if(hdrlen < TCP6_HDRSIZE) { freeblist(*bpp); return -1; } tcph->flags = h->tcpflag[1]; tcph->wnd = nhgets(h->tcpwin); tcph->urg = nhgets(h->tcpurg); tcph->mss = 0; tcph->ws = 0; tcph->len = nhgets(h->ploadlen) - hdrlen; *bpp = pullupblock(*bpp, hdrlen+TCP6_PKT); if(*bpp == nil) return -1; optr = h->tcpopt; n = hdrlen - TCP6_HDRSIZE; while(n > 0 && *optr != EOLOPT) { if(*optr == NOOPOPT) { n--; optr++; continue; } optlen = optr[1]; if(optlen < 2 || optlen > n) break; switch(*optr) { case MSSOPT: if(optlen == MSS_LENGTH) tcph->mss = nhgets(optr+2); break; case WSOPT: if(optlen == WS_LENGTH && *(optr+2) <= 14) tcph->ws = HaveWS | *(optr+2); break; } n -= optlen; optr += optlen; } return hdrlen;}intntohtcp4(Tcp *tcph, Block **bpp){ Tcp4hdr *h; uchar *optr; ushort hdrlen; ushort optlen; int n; *bpp = pullupblock(*bpp, TCP4_PKT+TCP4_HDRSIZE); if(*bpp == nil) return -1; h = (Tcp4hdr *)((*bpp)->rp); tcph->source = nhgets(h->tcpsport); tcph->dest = nhgets(h->tcpdport); tcph->seq = nhgetl(h->tcpseq); tcph->ack = nhgetl(h->tcpack); hdrlen = (h->tcpflag[0]>>2) & ~3; if(hdrlen < TCP4_HDRSIZE) { freeblist(*bpp); return -1; } tcph->flags = h->tcpflag[1]; tcph->wnd = nhgets(h->tcpwin); tcph->urg = nhgets(h->tcpurg); tcph->mss = 0; tcph->ws = 0; tcph->len = nhgets(h->length) - (hdrlen + TCP4_PKT); *bpp = pullupblock(*bpp, hdrlen+TCP4_PKT); if(*bpp == nil) return -1; optr = h->tcpopt; n = hdrlen - TCP4_HDRSIZE; while(n > 0 && *optr != EOLOPT) { if(*optr == NOOPOPT) { n--; optr++; continue; } optlen = optr[1]; if(optlen < 2 || optlen > n) break; switch(*optr) { case MSSOPT: if(optlen == MSS_LENGTH) tcph->mss = nhgets(optr+2); break; case WSOPT: if(optlen == WS_LENGTH && *(optr+2) <= 14) tcph->ws = HaveWS | *(optr+2); break; } n -= optlen; optr += optlen; } return hdrlen;}/* * For outgiing calls, generate an initial sequence * number and put a SYN on the send queue */voidtcpsndsyn(Conv *s, Tcpctl *tcb){ tcb->iss = (nrand(1<<16)<<16)|nrand(1<<16); tcb->rttseq = tcb->iss; tcb->snd.wl2 = tcb->iss; tcb->snd.una = tcb->iss; tcb->snd.ptr = tcb->rttseq; tcb->snd.nxt = tcb->rttseq; tcb->flgcnt++; tcb->flags |= FORCE; tcb->sndsyntime = NOW; /* set desired mss and scale */ tcb->mss = tcpmtu(s->p, s->laddr, s->ipversion, &tcb->scale);}voidsndrst(Proto *tcp, uchar *source, uchar *dest, ushort length, Tcp *seg, uchar version, char *reason){ Block *hbp; uchar rflags; Tcppriv *tpriv; Tcp4hdr ph4; Tcp6hdr ph6; netlog(tcp->f, Logtcp, "sndrst: %s", reason); tpriv = tcp->priv; if(seg->flags & RST) return; /* make pseudo header */ switch(version) { case V4: memset(&ph4, 0, sizeof(ph4)); ph4.vihl = IP_VER4; v6tov4(ph4.tcpsrc, dest); v6tov4(ph4.tcpdst, source); ph4.proto = IP_TCPPROTO; hnputs(ph4.tcplen, TCP4_HDRSIZE); hnputs(ph4.tcpsport, seg->dest); hnputs(ph4.tcpdport, seg->source); break; case V6: memset(&ph6, 0, sizeof(ph6)); ph6.vcf[0] = IP_VER6; ipmove(ph6.tcpsrc, dest); ipmove(ph6.tcpdst, source); ph6.proto = IP_TCPPROTO; hnputs(ph6.ploadlen, TCP6_HDRSIZE); hnputs(ph6.tcpsport, seg->dest); hnputs(ph6.tcpdport, seg->source); break; default: panic("sndrst: version %d", version); } tpriv->stats[OutRsts]++; rflags = RST; /* convince the other end that this reset is in band */ if(seg->flags & ACK) { seg->seq = seg->ack;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -