+ if(type == ETH_P_8021Q) {
+ start += 4;
+ type = DATA(packet)[16] << 8 | DATA(packet)[17];
+ }
+
+ if(type == ETH_P_IP && DATA(packet)[start + 9] == 6)
+ start += (DATA(packet)[start] & 0xf) * 4;
+ else if(type == ETH_P_IPV6 && DATA(packet)[start + 6] == 6)
+ start += 40;
+ else
+ return;
+
+ if(packet->len <= start + 20)
+ return;
+
+ /* Use data offset field to calculate length of options field */
+ int len = ((DATA(packet)[start + 12] >> 4) - 5) * 4;
+
+ if(packet->len < start + 20 + len)
+ return;
+
+ /* Search for MSS option header */
+ for(int i = 0; i < len;) {
+ if(DATA(packet)[start + 20 + i] == 0)
+ break;
+
+ if(DATA(packet)[start + 20 + i] == 1) {
+ i++;
+ continue;
+ }
+
+ if(i > len - 2 || i > len - DATA(packet)[start + 21 + i])
+ break;
+
+ if(DATA(packet)[start + 20 + i] != 2) {
+ if(DATA(packet)[start + 21 + i] < 2)
+ break;
+ i += DATA(packet)[start + 21 + i];
+ continue;
+ }
+
+ if(DATA(packet)[start + 21] != 4)
+ break;
+
+ /* Found it */
+ uint16_t oldmss = DATA(packet)[start + 22 + i] << 8 | DATA(packet)[start + 23 + i];
+ uint16_t newmss = mtu - start - 20;
+ uint16_t csum = DATA(packet)[start + 16] << 8 | DATA(packet)[start + 17];
+
+ if(oldmss <= newmss)
+ break;
+
+ logger(DEBUG_TRAFFIC, LOG_INFO, "Clamping MSS of packet from %s to %s to %d", source->name, via->name, newmss);
+
+ /* Update the MSS value and the checksum */
+ DATA(packet)[start + 22 + i] = newmss >> 8;
+ DATA(packet)[start + 23 + i] = newmss & 0xff;
+ csum ^= 0xffff;
+ csum -= oldmss;
+ csum += newmss;
+ csum ^= 0xffff;
+ DATA(packet)[start + 16] = csum >> 8;
+ DATA(packet)[start + 17] = csum & 0xff;
+ break;
+ }
+}
+
+static void swap_mac_addresses(vpn_packet_t *packet) {
+ mac_t tmp;
+ memcpy(&tmp, &DATA(packet)[0], sizeof tmp);
+ memcpy(&DATA(packet)[0], &DATA(packet)[6], sizeof tmp);
+ memcpy(&DATA(packet)[6], &tmp, sizeof tmp);
+}
+
+static void age_subnets(void *data) {
+ bool left = false;
+
+ for splay_each(subnet_t, s, myself->subnet_tree) {
+ if(s->expires && s->expires < now.tv_sec) {
+ if(debug_level >= DEBUG_TRAFFIC) {
+ char netstr[MAXNETSTR];
+ if(net2str(netstr, sizeof netstr, s))
+ logger(DEBUG_TRAFFIC, LOG_INFO, "Subnet %s expired", netstr);
+ }
+
+ for list_each(connection_t, c, connection_list)
+ if(c->edge)
+ send_del_subnet(c, s);
+
+ subnet_del(myself, s);
+ } else {
+ if(s->expires)
+ left = true;
+ }
+ }
+
+ if(left)
+ timeout_set(&age_subnets_timeout, &(struct timeval){10, rand() % 100000});
+}