+// Process IPV6CP messages
+void processipv6cp(tunnelidt t, sessionidt s, uint8_t *p, uint16_t l)
+{
+
+ CSTAT(processipv6cp);
+
+ LOG_HEX(5, "IPV6CP", p, l);
+ if (l < 4)
+ {
+ LOG(1, s, t, "Short IPV6CP %d bytes\n", l);
+ STAT(tunnel_rx_errors);
+ return ;
+ }
+ if (*p == ConfigAck)
+ {
+ // happy with our IPV6CP
+ session[s].flags |= SF_IPV6CP_ACKED;
+
+ LOG(3, s, t, "IPV6CP Acked, IPv6 is now active\n");
+ // Add a routed block if configured.
+ if (session[s].ipv6prefixlen)
+ {
+ route6set(s, session[s].ipv6route, session[s].ipv6prefixlen, 1);
+ session[s].flags |= SF_IPV6_ROUTED;
+ }
+
+ // Send an initial RA (TODO: Should we send these regularly?)
+ send_ipv6_ra(t, s, NULL);
+ return;
+ }
+ if (*p != ConfigReq)
+ {
+ LOG(1, s, t, "Unexpected IPV6CP code %d\n", *p);
+ STAT(tunnel_rx_errors);
+ return;
+ }
+
+ LOG(4, s, t, "IPV6CP ConfigReq received\n");
+ if (ntohs(*(uint16_t *) (p + 2)) > l)
+ {
+ LOG(1, s, t, "Length mismatch IPV6CP %d/%d\n", ntohs(*(uint16_t *) (p + 2)), l);
+ STAT(tunnel_rx_errors);
+ return ;
+ }
+ if (!session[s].ip)
+ {
+ LOG(3, s, t, "Waiting on radius reply\n");
+ return; // have to wait on RADIUS reply
+ }
+ // form a config reply quoting the IP in the session
+ {
+ uint8_t b[MAXCONTROL];
+ uint8_t *i,
+ *q;
+
+ l = ntohs(*(uint16_t *) (p + 2)); // We must use length from IPV6CP len field
+ q = p + 4;
+ i = p + l;
+ while (q < i && q[1])
+ {
+ if (*q != 1)
+ break;
+ q += q[1];
+ }
+ if (q < i)
+ {
+ // reject
+ uint16_t n = 4;
+ i = p + l;
+ if (!(q = makeppp(b, sizeof(b), p, l, t, s, PPPIPV6CP)))
+ {
+ LOG(2, s, t, "Failed to send IPV6CP ConfigRej\n");
+ return;
+ }
+ *q = ConfigRej;
+ p += 4;
+ while (p < i && p[1])
+ {
+ if (*p != 1)
+ {
+ LOG(2, s, t, "IPV6CP reject %d\n", *p);
+ memcpy(q + n, p, p[1]);
+ n += p[1];
+ }
+ p += p[1];
+ }
+ *(uint16_t *) (q + 2) = htons(n);
+ LOG(4, s, t, "Sending ConfigRej\n");
+ tunnelsend(b, n + (q - b), t); // send it
+ }
+ else
+ {
+ LOG(4, s, t, "Sending ConfigAck\n");
+ *p = ConfigAck;
+ i = findppp(p, 1); // IP address
+ if (!i || i[1] != 10)
+ {
+ LOG(1, s, t, "No IP in IPV6CP request\n");
+ STAT(tunnel_rx_errors);
+ return ;
+ }
+ if ((*(uint32_t *) (i + 2) != htonl(session[s].ip)) ||
+ (*(uint32_t *) (i + 6) != 0))
+ {
+ *(uint32_t *) (i + 2) = htonl(session[s].ip);
+ *(uint32_t *) (i + 6) = 0;
+ *p = ConfigNak;
+ LOG(4, s, t,
+ " No, a ConfigNak, client is "
+ "requesting IP - sending %s\n",
+ fmtaddr(htonl(session[s].ip), 0));
+ }
+ if (!(q = makeppp(b, sizeof(b), p, l, t, s, PPPIPV6CP)))
+ {
+ LOG(2, s, t, " Failed to send IPV6CP packet.\n");
+ return;
+ }
+ tunnelsend(b, l + (q - b), t); // send it
+ }
+ }
+}
+