+ LOG(5, s, t, "Ethernet -> Tunnel (%d bytes)\n", len);
+
+ // Add on L2TP header
+ {
+ uint8_t *p = makeppp(b, sizeof(b), buf, len, t, s, PPPIP);
+ if (!p) return;
+ tunnelsend(b, len + (p-b), t); // send it...
+ }
+
+ // Snooping this session, send it to intercept box
+ if (sp->snoop_ip && sp->snoop_port)
+ snoop_send_packet(buf, len, sp->snoop_ip, sp->snoop_port);
+
+ sp->cout += len; // byte count
+ sp->total_cout += len; // byte count
+ sp->pout++;
+ udp_tx += len;
+ sess_local[s].cout += len; // To send to master..
+}
+
+// process outgoing (to tunnel) IPv6
+//
+static void processipv6out(uint8_t * buf, int len)
+{
+ sessionidt s;
+ sessiont *sp;
+ tunnelidt t;
+ in_addr_t ip;
+ struct in6_addr ip6;
+
+ char *data = buf; // Keep a copy of the originals.
+ int size = len;
+
+ uint8_t b[MAXETHER + 20];
+
+ CSTAT(processipv6out);
+
+ if (len < MIN_IP_SIZE)
+ {
+ LOG(1, 0, 0, "Short IPv6, %d bytes\n", len);
+ STAT(tunnel_tx_errors);
+ return;
+ }
+ if (len >= MAXETHER)
+ {
+ LOG(1, 0, 0, "Oversize IPv6 packet %d bytes\n", len);
+ STAT(tunnel_tx_errors);
+ return;
+ }
+
+ // Skip the tun header
+ buf += 4;
+ len -= 4;
+
+ // Got an IP header now
+ if (*(uint8_t *)(buf) >> 4 != 6)
+ {
+ LOG(1, 0, 0, "IP: Don't understand anything except IPv6\n");
+ return;
+ }
+
+ ip6 = *(struct in6_addr *)(buf+24);
+ s = sessionbyipv6(ip6);
+
+ if (s == 0)
+ {
+ ip = *(uint32_t *)(buf + 32);
+ s = sessionbyip(ip);
+ }
+
+ if (s == 0)
+ {
+ // Is this a packet for a session that doesn't exist?
+ static int rate = 0; // Number of ICMP packets we've sent this second.
+ static int last = 0; // Last time we reset the ICMP packet counter 'rate'.
+
+ if (last != time_now)
+ {
+ last = time_now;
+ rate = 0;
+ }
+
+ if (rate++ < config->icmp_rate) // Only send a max of icmp_rate per second.
+ {
+ // FIXME: Should send icmp6 host unreachable
+ }
+ return;
+ }
+ t = session[s].tunnel;
+ sp = &session[s];
+
+ // FIXME: add DoS prevention/filters?
+
+ if (sp->tbf_out)
+ {
+ // Are we throttling this session?
+ if (config->cluster_iam_master)
+ tbf_queue_packet(sp->tbf_out, data, size);
+ else
+ master_throttle_packet(sp->tbf_out, data, size);
+ return;
+ }
+ else if (sp->walled_garden && !config->cluster_iam_master)
+ {
+ // We are walled-gardening this
+ master_garden_packet(s, data, size);
+ return;
+ }
+
+ LOG(5, s, t, "Ethernet -> Tunnel (%d bytes)\n", len);