MSL2 = 10,
MSPTICK = 50, /* Milliseconds per timer tick */
DEF_MSS = 1460, /* Default maximum segment */
- DEF_MSS6 = 1280, /* Default maximum segment (min) for v6 */
+ DEF_MSS6 = 1220, /* Default maximum segment (min) for v6 */
DEF_RTT = 500, /* Default round trip */
DEF_KAT = 120000, /* Default time (ms) between keep alives */
TCP_LISTEN = 0, /* Listen connection */
/* mtu (- TCP + IP hdr len) of 1st hop */
static int
-tcpmtu(Proto *tcp, uchar *addr, int version, uint *scale)
+tcpmtu(Route *r, int version, uint *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;
- }
/*
* set the ws. it doesn't commit us to anything.
* ws is the ultimate limit to the bandwidth-delay product.
*/
*scale = Defadvscale;
- return mtu;
+ /*
+ * currently we do not implement path MTU discovery
+ * so use interface MTU *only* if directly reachable
+ * or when we use V4 which allows routers to fragment.
+ * otherwise, we use the default MSS which assumes a
+ * safe minimum MTU of 1280 bytes for V6.
+ */
+ if(r != nil){
+ ifc = r->ifc;
+ mtu = ifc->maxtu - ifc->m->hsize;
+ if(version == V4)
+ return mtu - (TCP4_PKT + TCP4_HDRSIZE);
+ mtu -= TCP6_PKT + TCP6_HDRSIZE;
+ if((r->type & (Rifc|Runi)) != 0 || mtu <= DEF_MSS6)
+ return mtu;
+ }
+ if(version == V6)
+ return DEF_MSS6;
+ else
+ return DEF_MSS;
}
static void
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;
}
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;
}
tcb->sndsyntime = NOW;
/* set desired mss and scale */
- tcb->mss = tcpmtu(s->p, s->laddr, s->ipversion, &tcb->scale);
+ tcb->mss = tcpmtu(v6lookup(s->p->f, s->raddr, s), s->ipversion, &tcb->scale);
tpriv = s->p->priv;
tpriv->stats[Mss] = tcb->mss;
}
seg.ack = lp->irs+1;
seg.flags = SYN|ACK;
seg.urg = 0;
- seg.mss = tcpmtu(tcp, lp->laddr, lp->version, &scale);
+ seg.mss = tcpmtu(v6lookup(tcp->f, lp->raddr, nil), lp->version, &scale);
seg.wnd = QMAX;
/* if the other side set scale, we should too */
tcb->flgcnt = 0;
tcb->flags |= SYNACK;
+ /* set desired mss and scale */
+ tcb->mss = tcpmtu(v6lookup(s->p->f, src, s), version, &tcb->scale);
+
/* our sending max segment size cannot be bigger than what he asked for */
- if(lp->mss != 0 && lp->mss < tcb->mss) {
+ if(lp->mss != 0 && lp->mss < tcb->mss)
tcb->mss = lp->mss;
- tpriv->stats[Mss] = tcb->mss;
- }
+ tpriv->stats[Mss] = tcb->mss;
/* window scaling */
tcpsetscale(new, tcb, lp->rcvscale, lp->sndscale);
* receive queue
*/
if(bp) {
- bp = packblock(bp);
- if(bp == nil)
- panic("tcp packblock");
- qpassnolim(s->rq, bp);
+ qpassnolim(s->rq, packblock(bp));
bp = nil;
}
tcb->rcv.nxt += length;
if(tcb->state != Closed)
if(ipcmp(s->raddr, dest) == 0)
if(ipcmp(s->laddr, source) == 0){
+ if(s->ignoreadvice)
+ break;
qlock(s);
qunlock(tcp);
switch(tcb->state){
static char*
tcpctl(Conv* c, char** f, int n)
{
+ if(n == 1 && strcmp(f[0], "close") == 0)
+ return tcpclose(c), nil;
if(n == 1 && strcmp(f[0], "hangup") == 0)
return tcphangup(c);
if(n >= 1 && strcmp(f[0], "keepalive") == 0)