+void lcp_open(tunnelidt t, sessionidt s)
+{
+ // transition to Authentication or Network phase:
+ session[s].ppp.phase = sess_local[s].lcp_authtype ? Authenticate : Network;
+
+ // LCP now Opened
+ change_state(s, lcp, Opened);
+
+ if (session[s].ppp.phase == Authenticate)
+ {
+ if (sess_local[s].lcp_authtype == AUTHCHAP)
+ sendchap(t, s);
+ }
+ else
+ {
+ // This-Layer-Up
+ sendipcp(t, s);
+ change_state(s, ipcp, RequestSent);
+ // move to passive state for IPv6 (if configured), CCP
+ if (config->ipv6_prefix.s6_addr[0])
+ change_state(s, ipv6cp, Stopped);
+ else
+ change_state(s, ipv6cp, Closed);
+
+ change_state(s, ccp, Stopped);
+ }
+}
+
+static void lcp_restart(sessionidt s)
+{
+ session[s].ppp.phase = Establish;
+ // This-Layer-Down
+ change_state(s, ipcp, Dead);
+ change_state(s, ipv6cp, Dead);
+ change_state(s, ccp, Dead);
+}
+
+static uint8_t *ppp_rej(sessionidt s, uint8_t *buf, size_t blen, uint16_t mtype,
+ uint8_t **response, uint8_t *queued, uint8_t *packet, uint8_t *option)
+{
+ if (!*response || **response != ConfigRej)
+ {
+ queued = *response = makeppp(buf, blen, packet, 2, session[s].tunnel, s, mtype);
+ if (!queued)
+ return 0;
+
+ *queued = ConfigRej;
+ queued += 4;
+ }
+
+ if ((queued - buf + option[1]) > blen)
+ {
+ LOG(2, s, session[s].tunnel, "PPP overflow for ConfigRej (proto %u, option %u).\n", mtype, *option);
+ return 0;
+ }
+
+ memcpy(queued, option, option[1]);
+ return queued + option[1];
+}
+
+static uint8_t *ppp_nak(sessionidt s, uint8_t *buf, size_t blen, uint16_t mtype,
+ uint8_t **response, uint8_t *queued, uint8_t *packet, uint8_t *option,
+ uint8_t *value, size_t vlen)
+{
+ int *nak_sent;
+ switch (mtype)
+ {
+ case PPPLCP: nak_sent = &sess_local[s].lcp.nak_sent; break;
+ case PPPIPCP: nak_sent = &sess_local[s].ipcp.nak_sent; break;
+ case PPPIPV6CP: nak_sent = &sess_local[s].ipv6cp.nak_sent; break;
+ default: return 0; // ?
+ }
+
+ if (*response && **response != ConfigNak)
+ {
+ if (*nak_sent < config->ppp_max_failure) // reject queued
+ return queued;
+
+ return ppp_rej(s, buf, blen, mtype, response, 0, packet, option);
+ }
+
+ if (!*response)
+ {
+ if (*nak_sent >= config->ppp_max_failure)
+ return ppp_rej(s, buf, blen, mtype, response, 0, packet, option);
+
+ queued = *response = makeppp(buf, blen, packet, 2, session[s].tunnel, s, mtype);
+ if (!queued)
+ return 0;
+
+ *nak_sent++;
+ *queued = ConfigNak;
+ queued += 4;
+ }
+
+ if ((queued - buf + vlen + 2) > blen)
+ {
+ LOG(2, s, session[s].tunnel, "PPP overflow for ConfigNak (proto %u, option %u).\n", mtype, *option);
+ return 0;
+ }
+
+ *queued++ = *option;
+ *queued++ = vlen + 2;
+ memcpy(queued, value, vlen);
+ return queued + vlen;
+}
+