+// adjust tcp mss to avoid fragmentation (called only for tcp packets with syn set)
+void adjust_tcp_mss(sessionidt s, tunnelidt t, uint8_t *buf, int len, uint8_t *tcp)
+{
+ int d = (tcp[12] >> 4) * 4;
+ uint8_t *mss = 0;
+ uint8_t *data;
+
+ if ((tcp[13] & 0x3f) & ~(TCP_FLAG_SYN|TCP_FLAG_ACK)) // only want SYN and SYN,ACK
+ return;
+
+ if (tcp + d > buf + len) // short?
+ return;
+
+ data = tcp + d;
+ tcp += 20;
+
+ while (tcp < data)
+ {
+ if (*tcp == 2 && tcp[1] == 4) // mss option (2), length 4
+ {
+ mss = tcp + 2;
+ if (mss + 2 > data) return; // short?
+ break;
+ }
+
+ if (*tcp == 0) return; // end of options
+ if (*tcp == 1 || !tcp[1]) // no op (one byte), or no length (prevent loop)
+ tcp++;
+ else
+ tcp += tcp[1]; // skip over option
+ }
+
+ if (!mss) return; // not found
+ if (ntohl(*(uint16_t *) mss) <= MSS) return; // mss OK
+
+ LOG(5, s, t, "TCP: %s:%u -> %s:%u SYN%s, adjusted mss from %u to %u\n",
+ fmtaddr(*(in_addr_t *)(buf + 12), 0), *(uint16_t *)tcp,
+ fmtaddr(*(in_addr_t *)(buf + 16), 1), *(uint16_t *)(tcp + 2),
+ (tcp[13] & TCP_FLAG_ACK) ? ",ACK" : "",
+ ntohl(*(uint16_t *) mss), MSS);
+
+ // FIXME
+}
+