diff --git a/l2tpns.c b/l2tpns.c index a001823..bc215e2 100644 --- a/l2tpns.c +++ b/l2tpns.c @@ -3483,14 +3483,15 @@ static void controlnull(tunnelidt t) } // add a control message to a tunnel, and send if within window -static void controladd(controlt *c, sessionidt far, tunnelidt t) +static uint16_t controladd(controlt *c, sessionidt far, tunnelidt t) { uint16_t *pint16 = (uint16_t *) (c->buf + 2); + uint16_t ns; pint16[0] = htons(c->length); // length pint16[1] = htons(tunnel[t].far); // tunnel pint16[2] = htons(far); // session - pint16[3] = htons(tunnel[t].ns); // sequence - tunnel[t].ns++; // advance sequence + ns = tunnel[t].ns++; // advance sequence + pint16[3] = htons(ns); // sequence // link in message in to queue if (tunnel[t].controlc) tunnel[t].controle->next = c; @@ -3506,6 +3507,7 @@ static void controladd(controlt *c, sessionidt far, tunnelidt t) tunnel[t].try = 0; // first send tunnelsend(c->buf, c->length, t); } + return ns; } // @@ -3904,6 +3906,7 @@ static void tunnelclear(tunnelidt t) tunn_local[t].l2tp_fd = -1; tunnel[t].state = TUNNELFREE; + tunn_local[t].scccn = -1; } static void bundleclear(bundleidt b) @@ -4279,6 +4282,15 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexu if (!tunnel[t].controlc) tunnel[t].retry = 0; // caught up } + { + // Handle ack (possibly just a ZLB) + if (tunn_local[t].scccn >= 0 && ((uint16_t) tunn_local[t].scccn) - nr >= 0x8000u) + { + LOG(3, s, t, "REMOTE LNS acked our SCCCN %d\n", tunn_local[t].scccn); + tunn_local[t].scccn = -1; + tunnel[t].state = TUNNELOPEN; + } + } if (l) { // if not a null message int result = 0; @@ -4750,7 +4762,6 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexu } break; case 2: // SCCRP - tunnel[t].state = TUNNELOPEN; tunnel[t].lastrec = time_now; LOG(3, s, t, "Received SCCRP\n"); if (main_quit != QUIT_SHUTDOWN) @@ -4772,7 +4783,8 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexu control32(c, 3, 3, 1); // framing Capabilities if (sendchalresponse) controlb(c, 13, sendchalresponse, 16, 1); // Challenge response control16(c, 9, t, 1); // assigned tunnel - controladd(c, 0, t); // send + tunn_local[t].scccn = controladd(c, 0, t); // send + LOG(3, s, t, "sent SCCCN as %d\n", tunn_local[t].scccn); } else { diff --git a/l2tpns.h b/l2tpns.h index 0ca23be..d468d22 100644 --- a/l2tpns.h +++ b/l2tpns.h @@ -517,6 +517,7 @@ tunnelt; typedef struct { + int32_t scccn; // seq number of last sccn waiting for an ack (-1 if none) controlt *controlr; // queue of OoO-received messages int l2tp_fd; // kernel acceleration UDP socket }