/* * Copyright (C) 2001-2004 by egnite Software GmbH * * 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. Neither the name of the copyright holders nor the names of * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * For additional information see http://www.ethernut.de/ * */ /*! * \file net/pppdebug.c * \brief PPP debug helper functions. * * \verbatim * $Id: pppdebug.c 5101 2013-04-30 13:14:20Z olereinhardt $ * \endverbatim */ #include #include #include #include #include #include #include FILE *__ppp_trs; /*!< \brief PPP trace output stream. */ uint_fast8_t __ppp_trf; /*!< \brief PPP trace flags. */ static uint8_t ppp_header_sz; /* Size of the PPP header. */ static const char dbg_confreq[] PROGMEM = "[CONFREQ]"; static const char dbg_confack[] PROGMEM = "[CONFACK]"; static const char dbg_confnak[] PROGMEM = "[CONFNAK]"; static const char dbg_confrej[] PROGMEM = "[CONFREJ]"; static const char dbg_termreq[] PROGMEM = "[TERMREQ]"; static const char dbg_termack[] PROGMEM = "[TERMACK]"; static const char dbg_coderej[] PROGMEM = "[CODEREJ]"; static const char dbg_protrej[] PROGMEM = "[PROTREJ]"; static const char dbg_echoreq[] PROGMEM = "[ECHOREQ]"; static const char dbg_echorsp[] PROGMEM = "[ECHORSP]"; static const char dbg_discreq[] PROGMEM = "[DISCREQ]"; void NutDumpLcpOption(FILE * stream, NETBUF * nb) { XCPOPT *xcpo; uint16_t len; if ((len = nb->nb_ap.sz) != 0) xcpo = nb->nb_ap.vp; else { len = nb->nb_dl.sz - ppp_header_sz - sizeof(XCPHDR); xcpo = (XCPOPT *) (((char *) nb->nb_dl.vp) + ppp_header_sz + sizeof(XCPHDR)); } fprintf(stream, "[OPT(%u)]", len); while (len) { switch (xcpo->xcpo_type) { case LCP_MRU: fprintf(stream, "[MRU=%u]", ntohs(xcpo->xcpo_.us)); break; case LCP_ASYNCMAP: fprintf(stream, "[ACCM=0x%08lX]", ntohl(xcpo->xcpo_.ul)); break; case LCP_AUTHTYPE: fprintf(stream, "[AUTH=0x%04X]", ntohs(xcpo->xcpo_.us)); break; case LCP_MAGICNUMBER: fprintf(stream, "[MAGIC=0x%08lX]", ntohl(xcpo->xcpo_.ul)); break; case LCP_PCOMPRESSION: fputs("[PCOMP]", stream); break; case LCP_ACCOMPRESSION: fputs("[ACOMP]", stream); break; default: fprintf(stream, "[OPT%u?]", xcpo->xcpo_type); break; } if (len < xcpo->xcpo_len) { fputs("[LEN?]", stream); break; } len -= xcpo->xcpo_len; xcpo = (XCPOPT *) ((char *) xcpo + xcpo->xcpo_len); } } void NutDumpLcp(FILE * stream, NETBUF * nb) { XCPHDR *lcp; uint16_t len; if ((len = nb->nb_nw.sz) != 0) { len = nb->nb_nw.sz + nb->nb_ap.sz; lcp = nb->nb_nw.vp; } else { len = nb->nb_dl.sz - ppp_header_sz; lcp = (XCPHDR *) (((char *) nb->nb_dl.vp) + ppp_header_sz); } fprintf(stream, "[LCP-%03u(%u)]", lcp->xch_id, ntohs(lcp->xch_len)); if (len < sizeof(XCPHDR)) { fputs("[LEN?]", stream); return; } switch (lcp->xch_code) { case XCP_CONFREQ: fputs_P(dbg_confreq, stream); NutDumpLcpOption(stream, nb); break; case XCP_CONFACK: fputs_P(dbg_confack, stream); NutDumpLcpOption(stream, nb); break; case XCP_CONFNAK: fputs_P(dbg_confnak, stream); NutDumpLcpOption(stream, nb); break; case XCP_CONFREJ: fputs_P(dbg_confrej, stream); NutDumpLcpOption(stream, nb); break; case XCP_TERMREQ: fputs_P(dbg_termreq, stream); break; case XCP_TERMACK: fputs_P(dbg_termack, stream); break; case XCP_CODEREJ: fputs_P(dbg_coderej, stream); break; case LCP_PROTREJ: fputs_P(dbg_protrej, stream); break; case LCP_ERQ: fputs_P(dbg_echoreq, stream); break; case LCP_ERP: fputs_P(dbg_echorsp, stream); break; case LCP_DRQ: fputs_P(dbg_discreq, stream); break; default: fprintf(stream, "[CODE%u?]", lcp->xch_code); break; } } void NutDumpPapOption(FILE * stream, NETBUF * nb) { char *xcpo; uint16_t len; uint8_t i; if ((len = nb->nb_ap.sz) != 0) xcpo = nb->nb_ap.vp; else { len = nb->nb_dl.sz - ppp_header_sz - sizeof(XCPHDR); xcpo = ((char *) nb->nb_dl.vp) + ppp_header_sz + sizeof(XCPHDR); } fprintf(stream, "[OPT(%u)]", len); while (len) { if (*xcpo) { fputc('[', stream); for (i = 1; i <= *xcpo; i++) fputc(*(xcpo + i), stream); fputc(']', stream); } if (len < (uint16_t) (*xcpo + 1)) { fputs("[LEN?]", stream); break; } len -= *xcpo + 1; xcpo = xcpo + *xcpo + 1; } } void NutDumpPap(FILE * stream, NETBUF * nb) { XCPHDR *pap; uint16_t len; if ((len = nb->nb_nw.sz) != 0) pap = nb->nb_nw.vp; else { len = nb->nb_dl.sz - ppp_header_sz; pap = (XCPHDR *) (((char *) nb->nb_dl.vp) + ppp_header_sz); } fprintf(stream, "[PAP-%03u(%u)]", pap->xch_id, ntohs(pap->xch_len)); if (len < sizeof(XCPHDR)) { fputs("[LEN?]", stream); return; } switch (pap->xch_code) { case XCP_CONFREQ: fputs_P(dbg_confreq, stream); NutDumpPapOption(stream, nb); break; case XCP_CONFACK: fputs_P(dbg_confack, stream); break; case XCP_CONFNAK: fputs_P(dbg_confnak, stream); break; default: fprintf(stream, "[CODE%u?]", pap->xch_code); break; } } void NutDumpIpcpOption(FILE * stream, NETBUF * nb) { XCPOPT *xcpo = NULL; uint16_t len; if ((len = nb->nb_ap.sz) != 0) xcpo = nb->nb_ap.vp; else { if ((nb->nb_dl.sz)>(ppp_header_sz + sizeof(XCPHDR))) { len = nb->nb_dl.sz - ppp_header_sz - sizeof(XCPHDR); xcpo = (XCPOPT *) (((char *) nb->nb_dl.vp) + ppp_header_sz + sizeof(XCPHDR)); } else len=0; } fprintf(stream, "[OPT(%u)]", len); while (len) { switch (xcpo->xcpo_type) { case IPCP_ADDR: fprintf(stream, "[ADDR=%s]", inet_ntoa(xcpo->xcpo_.ul)); break; case IPCP_COMPRESSTYPE: fputs("[COMP]", stream); break; case IPCP_MS_DNS1: fprintf(stream, "[DNS1=%s]", inet_ntoa(xcpo->xcpo_.ul)); break; case IPCP_MS_DNS2: fprintf(stream, "[DNS2=%s]", inet_ntoa(xcpo->xcpo_.ul)); break; default: fprintf(stream, "[OPT%u?]", xcpo->xcpo_type); break; } if (len < xcpo->xcpo_len) { fputs("[LEN?]", stream); break; } len -= xcpo->xcpo_len; xcpo = (XCPOPT *) ((char *) xcpo + xcpo->xcpo_len); } } void NutDumpIpcp(FILE * stream, NETBUF * nb) { XCPHDR *ipcp; uint16_t len; if ((len = nb->nb_nw.sz) != 0) ipcp = nb->nb_nw.vp; else { len = nb->nb_dl.sz - ppp_header_sz; ipcp = (XCPHDR *) (((char *) nb->nb_dl.vp) + ppp_header_sz); } fprintf(stream, "[IPCP-%03u(%u)]", ipcp->xch_id, ntohs(ipcp->xch_len)); if (len < sizeof(XCPHDR)) { fputs("[LEN?]", stream); return; } switch (ipcp->xch_code) { case XCP_CONFREQ: fputs_P(dbg_confreq, stream); NutDumpIpcpOption(stream, nb); break; case XCP_CONFACK: fputs_P(dbg_confack, stream); NutDumpIpcpOption(stream, nb); break; case XCP_CONFNAK: fputs_P(dbg_confnak, stream); NutDumpIpcpOption(stream, nb); break; case XCP_CONFREJ: fputs_P(dbg_confrej, stream); NutDumpIpcpOption(stream, nb); break; case XCP_TERMREQ: fputs_P(dbg_termreq, stream); break; case XCP_TERMACK: fputs_P(dbg_termack, stream); break; case XCP_CODEREJ: fputs_P(dbg_coderej, stream); break; default: fprintf(stream, "[CODE%u?]", ipcp->xch_code); break; } } void NutDumpPpp(FILE * stream, NETBUF * nb) { PPPHDR *ph = (PPPHDR *) nb->nb_dl.vp; uint16_t protocol; fprintf(stream, "(%u)", nb->nb_dl.sz + nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz); /* * Check if the address and control field is compressed. * Thanks to Francois Rademeyer. */ if (ph->address != AHDLC_ALLSTATIONS) { /* * Check for protocol compression. * LSB of 2nd octet for protocol is always 1. */ if (((uint8_t *) nb->nb_dl.vp)[0] & 0x01) { ppp_header_sz = 1; protocol = *(uint8_t *) nb->nb_dl.vp; } else { char *cp = (char *)nb->nb_dl.vp; ppp_header_sz = 2; protocol = ntohs(((uint16_t)cp[0] << 8) | cp[1]); } } else { ppp_header_sz = sizeof(PPPHDR); protocol = ntohs(ph->prot_type); } if (nb->nb_dl.sz < ppp_header_sz) { fputs("[LEN?]", stream); return; } switch (protocol) { case PPP_IP: break; case PPP_LCP: NutDumpLcp(stream, nb); break; case PPP_IPCP: NutDumpIpcp(stream, nb); break; case PPP_PAP: NutDumpPap(stream, nb); break; default: fprintf(stream, "[TYPE 0x%04X?]", ntohs(ph->prot_type)); break; } } /*! * \brief Control PPP tracing. * * \param stream Pointer to a previously opened stream or null to * disable trace output. * \param flags Flags to enable specific traces. */ void NutTracePPP(FILE * stream, uint8_t flags) { if (stream) __ppp_trs = stream; if (__ppp_trs) __ppp_trf = flags; else __ppp_trf = 0; }