summaryrefslogtreecommitdiff
path: root/lwip/src/netif/ppp/upap.c
diff options
context:
space:
mode:
Diffstat (limited to 'lwip/src/netif/ppp/upap.c')
-rw-r--r--lwip/src/netif/ppp/upap.c677
1 files changed, 677 insertions, 0 deletions
diff --git a/lwip/src/netif/ppp/upap.c b/lwip/src/netif/ppp/upap.c
new file mode 100644
index 0000000..3b2399d
--- /dev/null
+++ b/lwip/src/netif/ppp/upap.c
@@ -0,0 +1,677 @@
+/*
+ * upap.c - User/Password Authentication Protocol.
+ *
+ * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any legal
+ * details, please contact
+ * Office of Technology Transfer
+ * Carnegie Mellon University
+ * 5000 Forbes Avenue
+ * Pittsburgh, PA 15213-3890
+ * (412) 268-4387, fax: (412) 268-7395
+ * tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "netif/ppp/ppp_opts.h"
+#if PPP_SUPPORT && PAP_SUPPORT /* don't build if not configured for use in lwipopts.h */
+
+/*
+ * @todo:
+ */
+
+#if 0 /* UNUSED */
+#include <stdio.h>
+#include <string.h>
+#endif /* UNUSED */
+
+#include "netif/ppp/ppp_impl.h"
+
+#include "netif/ppp/upap.h"
+
+#if PPP_OPTIONS
+/*
+ * Command-line options.
+ */
+static option_t pap_option_list[] = {
+ { "hide-password", o_bool, &hide_password,
+ "Don't output passwords to log", OPT_PRIO | 1 },
+ { "show-password", o_bool, &hide_password,
+ "Show password string in debug log messages", OPT_PRIOSUB | 0 },
+
+ { "pap-restart", o_int, &upap[0].us_timeouttime,
+ "Set retransmit timeout for PAP", OPT_PRIO },
+ { "pap-max-authreq", o_int, &upap[0].us_maxtransmits,
+ "Set max number of transmissions for auth-reqs", OPT_PRIO },
+ { "pap-timeout", o_int, &upap[0].us_reqtimeout,
+ "Set time limit for peer PAP authentication", OPT_PRIO },
+
+ { NULL }
+};
+#endif /* PPP_OPTIONS */
+
+/*
+ * Protocol entry points.
+ */
+static void upap_init(ppp_pcb *pcb);
+static void upap_lowerup(ppp_pcb *pcb);
+static void upap_lowerdown(ppp_pcb *pcb);
+static void upap_input(ppp_pcb *pcb, u_char *inpacket, int l);
+static void upap_protrej(ppp_pcb *pcb);
+#if PRINTPKT_SUPPORT
+static int upap_printpkt(const u_char *p, int plen, void (*printer) (void *, const char *, ...), void *arg);
+#endif /* PRINTPKT_SUPPORT */
+
+const struct protent pap_protent = {
+ PPP_PAP,
+ upap_init,
+ upap_input,
+ upap_protrej,
+ upap_lowerup,
+ upap_lowerdown,
+ NULL,
+ NULL,
+#if PRINTPKT_SUPPORT
+ upap_printpkt,
+#endif /* PRINTPKT_SUPPORT */
+#if PPP_DATAINPUT
+ NULL,
+#endif /* PPP_DATAINPUT */
+#if PRINTPKT_SUPPORT
+ "PAP",
+ NULL,
+#endif /* PRINTPKT_SUPPORT */
+#if PPP_OPTIONS
+ pap_option_list,
+ NULL,
+#endif /* PPP_OPTIONS */
+#if DEMAND_SUPPORT
+ NULL,
+ NULL
+#endif /* DEMAND_SUPPORT */
+};
+
+static void upap_timeout(void *arg);
+#if PPP_SERVER
+static void upap_reqtimeout(void *arg);
+static void upap_rauthreq(ppp_pcb *pcb, u_char *inp, int id, int len);
+#endif /* PPP_SERVER */
+static void upap_rauthack(ppp_pcb *pcb, u_char *inp, int id, int len);
+static void upap_rauthnak(ppp_pcb *pcb, u_char *inp, int id, int len);
+static void upap_sauthreq(ppp_pcb *pcb);
+#if PPP_SERVER
+static void upap_sresp(ppp_pcb *pcb, u_char code, u_char id, const char *msg, int msglen);
+#endif /* PPP_SERVER */
+
+
+/*
+ * upap_init - Initialize a UPAP unit.
+ */
+static void upap_init(ppp_pcb *pcb) {
+ pcb->upap.us_user = NULL;
+ pcb->upap.us_userlen = 0;
+ pcb->upap.us_passwd = NULL;
+ pcb->upap.us_passwdlen = 0;
+ pcb->upap.us_clientstate = UPAPCS_INITIAL;
+#if PPP_SERVER
+ pcb->upap.us_serverstate = UPAPSS_INITIAL;
+#endif /* PPP_SERVER */
+ pcb->upap.us_id = 0;
+}
+
+
+/*
+ * upap_authwithpeer - Authenticate us with our peer (start client).
+ *
+ * Set new state and send authenticate's.
+ */
+void upap_authwithpeer(ppp_pcb *pcb, const char *user, const char *password) {
+
+ if(!user || !password)
+ return;
+
+ /* Save the username and password we're given */
+ pcb->upap.us_user = user;
+ pcb->upap.us_userlen = (u8_t)LWIP_MIN(strlen(user), 0xff);
+ pcb->upap.us_passwd = password;
+ pcb->upap.us_passwdlen = (u8_t)LWIP_MIN(strlen(password), 0xff);
+ pcb->upap.us_transmits = 0;
+
+ /* Lower layer up yet? */
+ if (pcb->upap.us_clientstate == UPAPCS_INITIAL ||
+ pcb->upap.us_clientstate == UPAPCS_PENDING) {
+ pcb->upap.us_clientstate = UPAPCS_PENDING;
+ return;
+ }
+
+ upap_sauthreq(pcb); /* Start protocol */
+}
+
+#if PPP_SERVER
+/*
+ * upap_authpeer - Authenticate our peer (start server).
+ *
+ * Set new state.
+ */
+void upap_authpeer(ppp_pcb *pcb) {
+
+ /* Lower layer up yet? */
+ if (pcb->upap.us_serverstate == UPAPSS_INITIAL ||
+ pcb->upap.us_serverstate == UPAPSS_PENDING) {
+ pcb->upap.us_serverstate = UPAPSS_PENDING;
+ return;
+ }
+
+ pcb->upap.us_serverstate = UPAPSS_LISTEN;
+ if (pcb->settings.pap_req_timeout > 0)
+ TIMEOUT(upap_reqtimeout, pcb, pcb->settings.pap_req_timeout);
+}
+#endif /* PPP_SERVER */
+
+/*
+ * upap_timeout - Retransmission timer for sending auth-reqs expired.
+ */
+static void upap_timeout(void *arg) {
+ ppp_pcb *pcb = (ppp_pcb*)arg;
+
+ if (pcb->upap.us_clientstate != UPAPCS_AUTHREQ)
+ return;
+
+ if (pcb->upap.us_transmits >= pcb->settings.pap_max_transmits) {
+ /* give up in disgust */
+ ppp_error("No response to PAP authenticate-requests");
+ pcb->upap.us_clientstate = UPAPCS_BADAUTH;
+ auth_withpeer_fail(pcb, PPP_PAP);
+ return;
+ }
+
+ upap_sauthreq(pcb); /* Send Authenticate-Request */
+}
+
+
+#if PPP_SERVER
+/*
+ * upap_reqtimeout - Give up waiting for the peer to send an auth-req.
+ */
+static void upap_reqtimeout(void *arg) {
+ ppp_pcb *pcb = (ppp_pcb*)arg;
+
+ if (pcb->upap.us_serverstate != UPAPSS_LISTEN)
+ return; /* huh?? */
+
+ auth_peer_fail(pcb, PPP_PAP);
+ pcb->upap.us_serverstate = UPAPSS_BADAUTH;
+}
+#endif /* PPP_SERVER */
+
+
+/*
+ * upap_lowerup - The lower layer is up.
+ *
+ * Start authenticating if pending.
+ */
+static void upap_lowerup(ppp_pcb *pcb) {
+
+ if (pcb->upap.us_clientstate == UPAPCS_INITIAL)
+ pcb->upap.us_clientstate = UPAPCS_CLOSED;
+ else if (pcb->upap.us_clientstate == UPAPCS_PENDING) {
+ upap_sauthreq(pcb); /* send an auth-request */
+ }
+
+#if PPP_SERVER
+ if (pcb->upap.us_serverstate == UPAPSS_INITIAL)
+ pcb->upap.us_serverstate = UPAPSS_CLOSED;
+ else if (pcb->upap.us_serverstate == UPAPSS_PENDING) {
+ pcb->upap.us_serverstate = UPAPSS_LISTEN;
+ if (pcb->settings.pap_req_timeout > 0)
+ TIMEOUT(upap_reqtimeout, pcb, pcb->settings.pap_req_timeout);
+ }
+#endif /* PPP_SERVER */
+}
+
+
+/*
+ * upap_lowerdown - The lower layer is down.
+ *
+ * Cancel all timeouts.
+ */
+static void upap_lowerdown(ppp_pcb *pcb) {
+
+ if (pcb->upap.us_clientstate == UPAPCS_AUTHREQ) /* Timeout pending? */
+ UNTIMEOUT(upap_timeout, pcb); /* Cancel timeout */
+#if PPP_SERVER
+ if (pcb->upap.us_serverstate == UPAPSS_LISTEN && pcb->settings.pap_req_timeout > 0)
+ UNTIMEOUT(upap_reqtimeout, pcb);
+#endif /* PPP_SERVER */
+
+ pcb->upap.us_clientstate = UPAPCS_INITIAL;
+#if PPP_SERVER
+ pcb->upap.us_serverstate = UPAPSS_INITIAL;
+#endif /* PPP_SERVER */
+}
+
+
+/*
+ * upap_protrej - Peer doesn't speak this protocol.
+ *
+ * This shouldn't happen. In any case, pretend lower layer went down.
+ */
+static void upap_protrej(ppp_pcb *pcb) {
+
+ if (pcb->upap.us_clientstate == UPAPCS_AUTHREQ) {
+ ppp_error("PAP authentication failed due to protocol-reject");
+ auth_withpeer_fail(pcb, PPP_PAP);
+ }
+#if PPP_SERVER
+ if (pcb->upap.us_serverstate == UPAPSS_LISTEN) {
+ ppp_error("PAP authentication of peer failed (protocol-reject)");
+ auth_peer_fail(pcb, PPP_PAP);
+ }
+#endif /* PPP_SERVER */
+ upap_lowerdown(pcb);
+}
+
+
+/*
+ * upap_input - Input UPAP packet.
+ */
+static void upap_input(ppp_pcb *pcb, u_char *inpacket, int l) {
+ u_char *inp;
+ u_char code, id;
+ int len;
+
+ /*
+ * Parse header (code, id and length).
+ * If packet too short, drop it.
+ */
+ inp = inpacket;
+ if (l < UPAP_HEADERLEN) {
+ UPAPDEBUG(("pap_input: rcvd short header."));
+ return;
+ }
+ GETCHAR(code, inp);
+ GETCHAR(id, inp);
+ GETSHORT(len, inp);
+ if (len < UPAP_HEADERLEN) {
+ UPAPDEBUG(("pap_input: rcvd illegal length."));
+ return;
+ }
+ if (len > l) {
+ UPAPDEBUG(("pap_input: rcvd short packet."));
+ return;
+ }
+ len -= UPAP_HEADERLEN;
+
+ /*
+ * Action depends on code.
+ */
+ switch (code) {
+ case UPAP_AUTHREQ:
+#if PPP_SERVER
+ upap_rauthreq(pcb, inp, id, len);
+#endif /* PPP_SERVER */
+ break;
+
+ case UPAP_AUTHACK:
+ upap_rauthack(pcb, inp, id, len);
+ break;
+
+ case UPAP_AUTHNAK:
+ upap_rauthnak(pcb, inp, id, len);
+ break;
+
+ default: /* XXX Need code reject */
+ break;
+ }
+}
+
+#if PPP_SERVER
+/*
+ * upap_rauth - Receive Authenticate.
+ */
+static void upap_rauthreq(ppp_pcb *pcb, u_char *inp, int id, int len) {
+ u_char ruserlen, rpasswdlen;
+ char *ruser;
+ char *rpasswd;
+ char rhostname[256];
+ int retcode;
+ const char *msg;
+ int msglen;
+
+ if (pcb->upap.us_serverstate < UPAPSS_LISTEN)
+ return;
+
+ /*
+ * If we receive a duplicate authenticate-request, we are
+ * supposed to return the same status as for the first request.
+ */
+ if (pcb->upap.us_serverstate == UPAPSS_OPEN) {
+ upap_sresp(pcb, UPAP_AUTHACK, id, "", 0); /* return auth-ack */
+ return;
+ }
+ if (pcb->upap.us_serverstate == UPAPSS_BADAUTH) {
+ upap_sresp(pcb, UPAP_AUTHNAK, id, "", 0); /* return auth-nak */
+ return;
+ }
+
+ /*
+ * Parse user/passwd.
+ */
+ if (len < 1) {
+ UPAPDEBUG(("pap_rauth: rcvd short packet."));
+ return;
+ }
+ GETCHAR(ruserlen, inp);
+ len -= sizeof (u_char) + ruserlen + sizeof (u_char);
+ if (len < 0) {
+ UPAPDEBUG(("pap_rauth: rcvd short packet."));
+ return;
+ }
+ ruser = (char *) inp;
+ INCPTR(ruserlen, inp);
+ GETCHAR(rpasswdlen, inp);
+ if (len < rpasswdlen) {
+ UPAPDEBUG(("pap_rauth: rcvd short packet."));
+ return;
+ }
+
+ rpasswd = (char *) inp;
+
+ /*
+ * Check the username and password given.
+ */
+ retcode = UPAP_AUTHNAK;
+ if (auth_check_passwd(pcb, ruser, ruserlen, rpasswd, rpasswdlen, &msg, &msglen)) {
+ retcode = UPAP_AUTHACK;
+ }
+ BZERO(rpasswd, rpasswdlen);
+
+#if 0 /* UNUSED */
+ /*
+ * Check remote number authorization. A plugin may have filled in
+ * the remote number or added an allowed number, and rather than
+ * return an authenticate failure, is leaving it for us to verify.
+ */
+ if (retcode == UPAP_AUTHACK) {
+ if (!auth_number()) {
+ /* We do not want to leak info about the pap result. */
+ retcode = UPAP_AUTHNAK; /* XXX exit value will be "wrong" */
+ warn("calling number %q is not authorized", remote_number);
+ }
+ }
+
+ msglen = strlen(msg);
+ if (msglen > 255)
+ msglen = 255;
+#endif /* UNUSED */
+
+ upap_sresp(pcb, retcode, id, msg, msglen);
+
+ /* Null terminate and clean remote name. */
+ ppp_slprintf(rhostname, sizeof(rhostname), "%.*v", ruserlen, ruser);
+
+ if (retcode == UPAP_AUTHACK) {
+ pcb->upap.us_serverstate = UPAPSS_OPEN;
+ ppp_notice("PAP peer authentication succeeded for %q", rhostname);
+ auth_peer_success(pcb, PPP_PAP, 0, ruser, ruserlen);
+ } else {
+ pcb->upap.us_serverstate = UPAPSS_BADAUTH;
+ ppp_warn("PAP peer authentication failed for %q", rhostname);
+ auth_peer_fail(pcb, PPP_PAP);
+ }
+
+ if (pcb->settings.pap_req_timeout > 0)
+ UNTIMEOUT(upap_reqtimeout, pcb);
+}
+#endif /* PPP_SERVER */
+
+/*
+ * upap_rauthack - Receive Authenticate-Ack.
+ */
+static void upap_rauthack(ppp_pcb *pcb, u_char *inp, int id, int len) {
+ u_char msglen;
+ char *msg;
+ LWIP_UNUSED_ARG(id);
+
+ if (pcb->upap.us_clientstate != UPAPCS_AUTHREQ) /* XXX */
+ return;
+
+ /*
+ * Parse message.
+ */
+ if (len < 1) {
+ UPAPDEBUG(("pap_rauthack: ignoring missing msg-length."));
+ } else {
+ GETCHAR(msglen, inp);
+ if (msglen > 0) {
+ len -= sizeof (u_char);
+ if (len < msglen) {
+ UPAPDEBUG(("pap_rauthack: rcvd short packet."));
+ return;
+ }
+ msg = (char *) inp;
+ PRINTMSG(msg, msglen);
+ }
+ }
+
+ pcb->upap.us_clientstate = UPAPCS_OPEN;
+
+ auth_withpeer_success(pcb, PPP_PAP, 0);
+}
+
+
+/*
+ * upap_rauthnak - Receive Authenticate-Nak.
+ */
+static void upap_rauthnak(ppp_pcb *pcb, u_char *inp, int id, int len) {
+ u_char msglen;
+ char *msg;
+ LWIP_UNUSED_ARG(id);
+
+ if (pcb->upap.us_clientstate != UPAPCS_AUTHREQ) /* XXX */
+ return;
+
+ /*
+ * Parse message.
+ */
+ if (len < 1) {
+ UPAPDEBUG(("pap_rauthnak: ignoring missing msg-length."));
+ } else {
+ GETCHAR(msglen, inp);
+ if (msglen > 0) {
+ len -= sizeof (u_char);
+ if (len < msglen) {
+ UPAPDEBUG(("pap_rauthnak: rcvd short packet."));
+ return;
+ }
+ msg = (char *) inp;
+ PRINTMSG(msg, msglen);
+ }
+ }
+
+ pcb->upap.us_clientstate = UPAPCS_BADAUTH;
+
+ ppp_error("PAP authentication failed");
+ auth_withpeer_fail(pcb, PPP_PAP);
+}
+
+
+/*
+ * upap_sauthreq - Send an Authenticate-Request.
+ */
+static void upap_sauthreq(ppp_pcb *pcb) {
+ struct pbuf *p;
+ u_char *outp;
+ int outlen;
+
+ outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) +
+ pcb->upap.us_userlen + pcb->upap.us_passwdlen;
+ p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +outlen), PPP_CTRL_PBUF_TYPE);
+ if(NULL == p)
+ return;
+ if(p->tot_len != p->len) {
+ pbuf_free(p);
+ return;
+ }
+
+ outp = (u_char*)p->payload;
+ MAKEHEADER(outp, PPP_PAP);
+
+ PUTCHAR(UPAP_AUTHREQ, outp);
+ PUTCHAR(++pcb->upap.us_id, outp);
+ PUTSHORT(outlen, outp);
+ PUTCHAR(pcb->upap.us_userlen, outp);
+ MEMCPY(outp, pcb->upap.us_user, pcb->upap.us_userlen);
+ INCPTR(pcb->upap.us_userlen, outp);
+ PUTCHAR(pcb->upap.us_passwdlen, outp);
+ MEMCPY(outp, pcb->upap.us_passwd, pcb->upap.us_passwdlen);
+
+ ppp_write(pcb, p);
+
+ TIMEOUT(upap_timeout, pcb, pcb->settings.pap_timeout_time);
+ ++pcb->upap.us_transmits;
+ pcb->upap.us_clientstate = UPAPCS_AUTHREQ;
+}
+
+#if PPP_SERVER
+/*
+ * upap_sresp - Send a response (ack or nak).
+ */
+static void upap_sresp(ppp_pcb *pcb, u_char code, u_char id, const char *msg, int msglen) {
+ struct pbuf *p;
+ u_char *outp;
+ int outlen;
+
+ outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen;
+ p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +outlen), PPP_CTRL_PBUF_TYPE);
+ if(NULL == p)
+ return;
+ if(p->tot_len != p->len) {
+ pbuf_free(p);
+ return;
+ }
+
+ outp = (u_char*)p->payload;
+ MAKEHEADER(outp, PPP_PAP);
+
+ PUTCHAR(code, outp);
+ PUTCHAR(id, outp);
+ PUTSHORT(outlen, outp);
+ PUTCHAR(msglen, outp);
+ MEMCPY(outp, msg, msglen);
+
+ ppp_write(pcb, p);
+}
+#endif /* PPP_SERVER */
+
+#if PRINTPKT_SUPPORT
+/*
+ * upap_printpkt - print the contents of a PAP packet.
+ */
+static const char* const upap_codenames[] = {
+ "AuthReq", "AuthAck", "AuthNak"
+};
+
+static int upap_printpkt(const u_char *p, int plen, void (*printer) (void *, const char *, ...), void *arg) {
+ int code, id, len;
+ int mlen, ulen, wlen;
+ const u_char *user, *pwd, *msg;
+ const u_char *pstart;
+
+ if (plen < UPAP_HEADERLEN)
+ return 0;
+ pstart = p;
+ GETCHAR(code, p);
+ GETCHAR(id, p);
+ GETSHORT(len, p);
+ if (len < UPAP_HEADERLEN || len > plen)
+ return 0;
+
+ if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(upap_codenames))
+ printer(arg, " %s", upap_codenames[code-1]);
+ else
+ printer(arg, " code=0x%x", code);
+ printer(arg, " id=0x%x", id);
+ len -= UPAP_HEADERLEN;
+ switch (code) {
+ case UPAP_AUTHREQ:
+ if (len < 1)
+ break;
+ ulen = p[0];
+ if (len < ulen + 2)
+ break;
+ wlen = p[ulen + 1];
+ if (len < ulen + wlen + 2)
+ break;
+ user = (const u_char *) (p + 1);
+ pwd = (const u_char *) (p + ulen + 2);
+ p += ulen + wlen + 2;
+ len -= ulen + wlen + 2;
+ printer(arg, " user=");
+ ppp_print_string(user, ulen, printer, arg);
+ printer(arg, " password=");
+/* FIXME: require ppp_pcb struct as printpkt() argument */
+#if 0
+ if (!pcb->settings.hide_password)
+#endif
+ ppp_print_string(pwd, wlen, printer, arg);
+#if 0
+ else
+ printer(arg, "<hidden>");
+#endif
+ break;
+ case UPAP_AUTHACK:
+ case UPAP_AUTHNAK:
+ if (len < 1)
+ break;
+ mlen = p[0];
+ if (len < mlen + 1)
+ break;
+ msg = (const u_char *) (p + 1);
+ p += mlen + 1;
+ len -= mlen + 1;
+ printer(arg, " ");
+ ppp_print_string(msg, mlen, printer, arg);
+ break;
+ default:
+ break;
+ }
+
+ /* print the rest of the bytes in the packet */
+ for (; len > 0; --len) {
+ GETCHAR(code, p);
+ printer(arg, " %.2x", code);
+ }
+
+ return p - pstart;
+}
+#endif /* PRINTPKT_SUPPORT */
+
+#endif /* PPP_SUPPORT && PAP_SUPPORT */