Module Name: src Committed By: yamaguchi Date: Wed Nov 25 09:16:20 UTC 2020
Modified Files: src/sys/net: if_spppsubr.c Log Message: Refactoring functions for RCR and RCN To generate a diff of this commit: cvs rdiff -u -r1.192 -r1.193 src/sys/net/if_spppsubr.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/net/if_spppsubr.c diff -u src/sys/net/if_spppsubr.c:1.192 src/sys/net/if_spppsubr.c:1.193 --- src/sys/net/if_spppsubr.c:1.192 Wed Nov 25 09:12:50 2020 +++ src/sys/net/if_spppsubr.c Wed Nov 25 09:16:20 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: if_spppsubr.c,v 1.192 2020/11/25 09:12:50 yamaguchi Exp $ */ +/* $NetBSD: if_spppsubr.c,v 1.193 2020/11/25 09:16:20 yamaguchi Exp $ */ /* * Synchronous PPP/Cisco link level subroutines. @@ -41,7 +41,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_spppsubr.c,v 1.192 2020/11/25 09:12:50 yamaguchi Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_spppsubr.c,v 1.193 2020/11/25 09:16:20 yamaguchi Exp $"); #if defined(_KERNEL_OPT) #include "opt_inet.h" @@ -2294,21 +2294,30 @@ sppp_lcp_TO(void *cookie) * transition decision in the state automaton.) */ static int -sppp_lcp_RCR(struct sppp *sp, struct lcp_header *h, int len) +sppp_lcp_RCR(struct sppp *sp, struct lcp_header *h, int origlen) { STDDCL; - u_char *buf, *r, *p, l, blen; - int origlen, rlen; + u_char *buf, *r, *p, l, blen, type; + int len, rlen; uint32_t nmagic; u_short authproto; KASSERT(SPPP_WLOCKED(sp)); - len -= 4; - origlen = len; - buf = r = malloc (blen = len, M_TEMP, M_NOWAIT); - if (! buf) - return (0); + if (origlen < sizeof(*h)) + return 0; + + origlen -= sizeof(*h); + type = 0; + + if (origlen <= 0) + return 0; + else + blen = origlen; + + buf = kmem_intr_alloc(blen, KM_NOSLEEP); + if (buf == NULL) + return 0; if (debug) log(LOG_DEBUG, "%s: lcp parse opts:", @@ -2316,7 +2325,13 @@ sppp_lcp_RCR(struct sppp *sp, struct lcp /* pass 1: check for things that need to be rejected */ p = (void *)(h + 1); - for (rlen = 0; len > 1 && (l = p[1]) != 0; len -= l, p += l) { + r = buf; + rlen = 0; + for (len = origlen; len > 1; len-= l, p += l) { + l = p[1]; + if (l == 0) + break; + /* Sanity check option length */ if (l > len) { /* @@ -2326,11 +2341,12 @@ sppp_lcp_RCR(struct sppp *sp, struct lcp addlog("%s: received malicious LCP option 0x%02x, " "length 0x%02x, (len: 0x%02x) dropping.\n", ifp->if_xname, p[0], l, len); - goto drop; + rlen = -1; + goto end; } if (debug) addlog(" %s", sppp_lcp_opt_name(*p)); - switch (*p) { + switch (p[0]) { case LCP_OPT_MAGIC: /* Magic number. */ /* fall through, both are same length */ @@ -2418,12 +2434,13 @@ sppp_lcp_RCR(struct sppp *sp, struct lcp r += l; rlen += l; } - if (rlen) { - if (debug) - addlog(" send conf-rej\n"); - sppp_cp_send(sp, PPP_LCP, CONF_REJ, h->ident, rlen, buf); + + if (rlen > 0) { + type = CONF_REJ; goto end; - } else if (debug) + } + + if (debug) addlog("\n"); /* @@ -2435,11 +2452,16 @@ sppp_lcp_RCR(struct sppp *sp, struct lcp ifp->if_xname); p = (void *)(h + 1); - len = origlen; - for (rlen = 0; len > 1 && (l = p[1]) != 0; len -= l, p += l) { + r = buf; + rlen = 0; + for (len = origlen; len > 0; len -= l, p += l) { + l = p[1]; + if (l == 0) + break; + if (debug) addlog(" %s", sppp_lcp_opt_name(*p)); - switch (*p) { + switch (p[0]) { case LCP_OPT_MAGIC: /* Magic number -- extract. */ nmagic = (uint32_t)p[2] << 24 | @@ -2560,34 +2582,41 @@ sppp_lcp_RCR(struct sppp *sp, struct lcp r += l; rlen += l; } - if (rlen) { + + if (rlen > 0) { if (++sp->scp[IDX_LCP].fail_counter >= sp->lcp.max_failure) { if (debug) - addlog(" max_failure (%d) exceeded, " - "send conf-rej\n", - sp->lcp.max_failure); - sppp_cp_send(sp, PPP_LCP, CONF_REJ, h->ident, rlen, buf); + addlog(" max_failure (%d) exceeded, ", + sp->lcp.max_failure); + type = CONF_REJ; } else { - if (debug) - addlog(" send conf-nak\n"); - sppp_cp_send(sp, PPP_LCP, CONF_NAK, h->ident, rlen, buf); + type = CONF_NAK; } - goto end; } else { - if (debug) - addlog(" send conf-ack\n"); + type = CONF_ACK; + rlen = origlen; + memcpy(r, h + 1, rlen); sp->scp[IDX_LCP].fail_counter = 0; sp->pp_loopcnt = 0; - sppp_cp_send(sp, PPP_LCP, CONF_ACK, h->ident, origlen, h + 1); } - end: - free(buf, M_TEMP); - return (rlen == 0); +end: + if (rlen > 0) { + if (debug) + addlog("send %s", sppp_cp_type_name(type)); + sppp_cp_send(sp, PPP_LCP, type, h->ident, rlen, buf); + } + + if (debug) + addlog("\n"); + + kmem_free(buf, blen); - drop: - free(buf, M_TEMP); - return -1; + if (rlen > 0) + return -1; + if (type != CONF_ACK) + return 0; + return 1; } /* @@ -2598,15 +2627,15 @@ static void sppp_lcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len) { STDDCL; - u_char *buf, *p, l; + u_char *p, l; KASSERT(SPPP_WLOCKED(sp)); - len -= 4; - buf = malloc (len, M_TEMP, M_NOWAIT); - if (!buf) + if (len <= sizeof(*h)) return; + len -= sizeof(*h); + if (debug) log(LOG_DEBUG, "%s: lcp rej opts:", ifp->if_xname); @@ -2621,11 +2650,11 @@ sppp_lcp_RCN_rej(struct sppp *sp, struct */ addlog("%s: received malicious LCP option, " "dropping.\n", ifp->if_xname); - goto drop; + goto end; } if (debug) addlog(" %s", sppp_lcp_opt_name(*p)); - switch (*p) { + switch (p[0]) { case LCP_OPT_MAGIC: /* Magic number -- can't use it, use 0 */ sp->lcp.opts &= ~(1 << LCP_OPT_MAGIC); @@ -2668,8 +2697,7 @@ sppp_lcp_RCN_rej(struct sppp *sp, struct } if (debug) addlog("\n"); -drop: - free(buf, M_TEMP); +end: return; } @@ -2681,15 +2709,14 @@ static void sppp_lcp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len) { STDDCL; - u_char *buf, *p, l, blen; + u_char *p, l; uint32_t magic; KASSERT(SPPP_WLOCKED(sp)); - len -= 4; - buf = malloc (blen = len, M_TEMP, M_NOWAIT); - if (!buf) + if (len <= sizeof(*h)) return; + len -= sizeof(*h); if (debug) log(LOG_DEBUG, "%s: lcp nak opts:", @@ -2705,11 +2732,11 @@ sppp_lcp_RCN_nak(struct sppp *sp, struct */ addlog("%s: received malicious LCP option, " "dropping.\n", ifp->if_xname); - goto drop; + goto end; } if (debug) addlog(" %s", sppp_lcp_opt_name(*p)); - switch (*p) { + switch (p[0]) { case LCP_OPT_MAGIC: /* Magic number -- renegotiate */ if ((sp->lcp.opts & (1 << LCP_OPT_MAGIC)) && @@ -2761,8 +2788,7 @@ sppp_lcp_RCN_nak(struct sppp *sp, struct } if (debug) addlog("\n"); -drop: - free(buf, M_TEMP); +end: return; } @@ -3092,42 +3118,54 @@ sppp_ipcp_TO(void *cookie) * transition decision in the state automaton.) */ static int -sppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int len) +sppp_ipcp_RCR(struct sppp *sp, struct lcp_header *h, int origlen) { - u_char *buf, *r, *p, l, blen; + u_char *buf, *r, *p, l, blen, type; struct ifnet *ifp = &sp->pp_if; - int rlen, origlen, debug = ifp->if_flags & IFF_DEBUG; + int rlen, len, debug = ifp->if_flags & IFF_DEBUG; uint32_t hisaddr, desiredaddr; KASSERT(SPPP_WLOCKED(sp)); - len -= 4; - origlen = len; + if (origlen < sizeof(*h)) + return 0; + + origlen -= sizeof(*h); + type = 0; + /* * Make sure to allocate a buf that can at least hold a * conf-nak with an `address' option. We might need it below. */ - blen = len < 6 ? 6 : len; - buf = r = malloc (blen, M_TEMP, M_NOWAIT); - if (! buf) - return (0); + blen = MAX(6, origlen); + + buf = kmem_intr_alloc(blen, KM_NOSLEEP); + if (buf == NULL) + return 0; /* pass 1: see if we can recognize them */ if (debug) log(LOG_DEBUG, "%s: ipcp parse opts:", ifp->if_xname); p = (void *)(h + 1); - for (rlen = 0; len > 1 && (l = p[1]) != 0; len -= l, p += l) { + r = buf; + rlen = 0; + for (len = origlen; len > 1; len -= l, p += l) { + l = p[1]; + if (l == 0) + break; + /* Sanity check option length */ if (l > len) { /* XXX should we just RXJ? */ addlog("%s: malicious IPCP option received, dropping\n", ifp->if_xname); - goto drop; + rlen = -1; + goto end; } if (debug) addlog(" %s", sppp_ipcp_opt_name(*p)); - switch (*p) { + switch (p[0]) { #ifdef notyet case IPCP_OPT_COMPRESSION: if (len >= 6 && l >= 6) { @@ -3162,12 +3200,13 @@ sppp_ipcp_RCR(struct sppp *sp, struct lc r += l; rlen += l; } - if (rlen) { - if (debug) - addlog(" send conf-rej\n"); - sppp_cp_send(sp, PPP_IPCP, CONF_REJ, h->ident, rlen, buf); + + if (rlen > 0) { + type = CONF_REJ; goto end; - } else if (debug) + } + + if (debug) addlog("\n"); /* pass 2: parse option values */ @@ -3183,11 +3222,16 @@ sppp_ipcp_RCR(struct sppp *sp, struct lc log(LOG_DEBUG, "%s: ipcp parse opt values: ", ifp->if_xname); p = (void *)(h + 1); - len = origlen; - for (rlen=0; len > 1 && (l = p[1]) != 0; len -= l, p += l) { + r = buf; + rlen = 0; + for (len = origlen; len > 1; len -= l, p += l) { + l = p[1]; + if (l == 0) + break; + if (debug) addlog(" %s", sppp_ipcp_opt_name(*p)); - switch (*p) { + switch (p[0]) { #ifdef notyet case IPCP_OPT_COMPRESSION: continue; @@ -3243,26 +3287,34 @@ sppp_ipcp_RCR(struct sppp *sp, struct lc rlen += l; } - /* - * If we are about to conf-ack the request, but haven't seen - * his address so far, gonna conf-nak it instead, with the - * `address' option present and our idea of his address being - * filled in there, to request negotiation of both addresses. - * - * XXX This can result in an endless req - nak loop if peer - * doesn't want to send us his address. Q: What should we do - * about it? XXX A: implement the max-failure counter. - */ - if (rlen == 0 && !(sp->ipcp.flags & IPCP_HISADDR_SEEN)) { - buf[0] = IPCP_OPT_ADDRESS; - buf[1] = 6; - buf[2] = hisaddr >> 24; - buf[3] = hisaddr >> 16; - buf[4] = hisaddr >> 8; - buf[5] = hisaddr; - rlen = 6; - if (debug) - addlog(" still need hisaddr"); + if (rlen > 0) { + type = CONF_NAK; + } else { + type = CONF_ACK; + rlen = origlen; + memcpy(r, h + 1, rlen); + + if ((sp->ipcp.flags & IPCP_HISADDR_SEEN) == 0) { + /* + * If we are about to conf-ack the request, but haven't seen + * his address so far, gonna conf-nak it instead, with the + * `address' option present and our idea of his address being + * filled in there, to request negotiation of both addresses. + * + * XXX This can result in an endless req - nak loop if peer + * doesn't want to send us his address. Q: What should we do + * about it? XXX A: implement the max-failure counter. + */ + buf[0] = IPCP_OPT_ADDRESS; + buf[1] = 6; + buf[2] = hisaddr >> 24; + buf[3] = hisaddr >> 16; + buf[4] = hisaddr >> 8; + buf[5] = hisaddr; + rlen = 6; + if (debug) + addlog(" still need hisaddr"); + } } if (rlen) { @@ -3275,13 +3327,20 @@ sppp_ipcp_RCR(struct sppp *sp, struct lc sppp_cp_send(sp, PPP_IPCP, CONF_ACK, h->ident, origlen, h + 1); } - end: - free(buf, M_TEMP); - return (rlen == 0); - - drop: - free(buf, M_TEMP); - return -1; +end: + if (rlen > 0) { + if (debug) + addlog(" send %s\n", sppp_cp_type_name(type)); + sppp_cp_send(sp, PPP_IPCP, type, h->ident, rlen, buf); + } + + kmem_free(buf, blen); + + if (rlen < 0) + return -1; + if (type != CONF_ACK) + return 0; + return 1; } /* @@ -3291,33 +3350,37 @@ sppp_ipcp_RCR(struct sppp *sp, struct lc static void sppp_ipcp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len) { - u_char *buf, *p, l, blen; + u_char *p, l; struct ifnet *ifp = &sp->pp_if; int debug = ifp->if_flags & IFF_DEBUG; KASSERT(SPPP_WLOCKED(sp)); - len -= 4; - buf = malloc (blen = len, M_TEMP, M_NOWAIT); - if (!buf) + if (len <= sizeof(*h)) return; + len -= sizeof(*h); + if (debug) log(LOG_DEBUG, "%s: ipcp rej opts:", ifp->if_xname); p = (void *)(h + 1); - for (; len > 1 && (l = p[1]) != 0; len -= l, p += l) { + for (; len > 1; len -= l, p += l) { + l = p[1]; + if (l == 0) + break; + /* Sanity check option length */ if (l > len) { /* XXX should we just RXJ? */ addlog("%s: malicious IPCP option received, dropping\n", ifp->if_xname); - goto drop; + goto end; } if (debug) addlog(" %s", sppp_ipcp_opt_name(*p)); - switch (*p) { + switch (p[0]) { case IPCP_OPT_ADDRESS: /* * Peer doesn't grok address option. This is @@ -3334,8 +3397,7 @@ sppp_ipcp_RCN_rej(struct sppp *sp, struc } if (debug) addlog("\n"); -drop: - free(buf, M_TEMP); +end: return; } @@ -3353,14 +3415,18 @@ sppp_ipcp_RCN_nak(struct sppp *sp, struc KASSERT(SPPP_WLOCKED(sp)); - len -= 4; + len -= sizeof(*h); if (debug) log(LOG_DEBUG, "%s: ipcp nak opts:", ifp->if_xname); p = (void *)(h + 1); - for (; len > 1 && (l = p[1]) != 0; len -= l, p += l) { + for (; len > 1; len -= l, p += l) { + l = p[1]; + if (l == 0) + break; + /* Sanity check option length */ if (l > len) { /* XXX should we just RXJ? */ @@ -3619,11 +3685,11 @@ sppp_ipv6cp_TO(void *cookie) * transition decision in the state automaton.) */ static int -sppp_ipv6cp_RCR(struct sppp *sp, struct lcp_header *h, int len) +sppp_ipv6cp_RCR(struct sppp *sp, struct lcp_header *h, int origlen) { u_char *buf, *r, *p, l, blen; struct ifnet *ifp = &sp->pp_if; - int rlen, origlen, debug = ifp->if_flags & IFF_DEBUG; + int rlen, len, debug = ifp->if_flags & IFF_DEBUG; struct in6_addr myaddr, desiredaddr, suggestaddr; int ifidcount; int type; @@ -3632,34 +3698,46 @@ sppp_ipv6cp_RCR(struct sppp *sp, struct KASSERT(SPPP_WLOCKED(sp)); - len -= 4; - origlen = len; + if (origlen <= 0) + return 0; + + origlen -= sizeof(*h); + type = 0; + /* * Make sure to allocate a buf that can at least hold a * conf-nak with an `address' option. We might need it below. */ - blen = len < 6 ? 6 : len; - buf = r = malloc (blen, M_TEMP, M_NOWAIT); - if (! buf) - return (0); + blen = MAX(6, origlen); + + buf = kmem_intr_alloc(blen, KM_NOSLEEP); + if (buf == NULL) + return 0; /* pass 1: see if we can recognize them */ if (debug) log(LOG_DEBUG, "%s: ipv6cp parse opts:", ifp->if_xname); p = (void *)(h + 1); + r = buf; + rlen = 0; ifidcount = 0; - for (rlen = 0; len > 1 && (l = p[1]) != 0; len -= l, p += l) { + for (len = origlen; len > 1; len -= l, p += l) { + l = p[1]; + if (l == 0) + break; + /* Sanity check option length */ if (l > len) { /* XXX just RXJ? */ addlog("%s: received malicious IPCPv6 option, " "dropping\n", ifp->if_xname); - goto drop; + rlen = -1; + goto end; } if (debug) addlog(" %s", sppp_ipv6cp_opt_name(*p)); - switch (*p) { + switch (p[0]) { case IPV6CP_OPT_IFID: if (len >= 10 && l == 10 && ifidcount == 0) { /* correctly formed address option */ @@ -3695,12 +3773,13 @@ sppp_ipv6cp_RCR(struct sppp *sp, struct r += l; rlen += l; } - if (rlen) { - if (debug) - addlog(" send conf-rej\n"); - sppp_cp_send(sp, PPP_IPV6CP, CONF_REJ, h->ident, rlen, buf); + + if (rlen > 0) { + type = CONF_REJ; goto end; - } else if (debug) + } + + if (debug) addlog("\n"); /* pass 2: parse option values */ @@ -3709,12 +3788,17 @@ sppp_ipv6cp_RCR(struct sppp *sp, struct log(LOG_DEBUG, "%s: ipv6cp parse opt values: ", ifp->if_xname); p = (void *)(h + 1); - len = origlen; + r = buf; + rlen = 0; type = CONF_ACK; - for (rlen = 0; len > 1 && (l = p[1]) != 0; len -= l, p += l) { + for (len = origlen; len > 1; len -= l, p += l) { + l = p[1]; + if (l == 0) + break; + if (debug) addlog(" %s", sppp_ipv6cp_opt_name(*p)); - switch (*p) { + switch (p[0]) { #ifdef notyet case IPV6CP_OPT_COMPRESSION: continue; @@ -3772,30 +3856,41 @@ sppp_ipv6cp_RCR(struct sppp *sp, struct rlen += l; } - if (rlen == 0 && type == CONF_ACK) { - if (debug) - addlog(" send %s\n", sppp_cp_type_name(type)); - sppp_cp_send(sp, PPP_IPV6CP, type, h->ident, origlen, h + 1); - } else { + if (rlen > 0) { + if (type != CONF_ACK) { + if (debug) { + addlog(" send %s suggest %s\n", + sppp_cp_type_name(type), + IN6_PRINT(ip6buf, &suggestaddr)); + } + } #ifdef notdef if (type == CONF_ACK) panic("IPv6CP RCR: CONF_ACK with non-zero rlen"); #endif - - if (debug) { - addlog(" send %s suggest %s\n", - sppp_cp_type_name(type), IN6_PRINT(ip6buf, &suggestaddr)); + } else { + if (type == CONF_ACK) { + rlen = origlen; + memcpy(r, h + 1, rlen); } + } +end: + if (rlen > 0) { + if (debug) + addlog("send %s", sppp_cp_type_name(type)); sppp_cp_send(sp, PPP_IPV6CP, type, h->ident, rlen, buf); } - end: - free(buf, M_TEMP); - return (rlen == 0); - - drop: - free(buf, M_TEMP); - return -1; + if (debug) + addlog("\n"); + + kmem_free(buf, blen); + + if (rlen < 0) + return -1; + if (type != CONF_ACK) + return 0; + return 0; } /* @@ -3805,32 +3900,36 @@ sppp_ipv6cp_RCR(struct sppp *sp, struct static void sppp_ipv6cp_RCN_rej(struct sppp *sp, struct lcp_header *h, int len) { - u_char *buf, *p, l, blen; + u_char *p, l; struct ifnet *ifp = &sp->pp_if; int debug = ifp->if_flags & IFF_DEBUG; KASSERT(SPPP_WLOCKED(sp)); - len -= 4; - buf = malloc (blen = len, M_TEMP, M_NOWAIT); - if (!buf) + if (len <= sizeof(*h)) return; + len -= sizeof(*h); + if (debug) log(LOG_DEBUG, "%s: ipv6cp rej opts:", ifp->if_xname); p = (void *)(h + 1); - for (; len > 1 && (l = p[1]) != 0; len -= l, p += l) { + for (; len > 1; len -= l, p += l) { + l = p[1]; + if (l == 0) + break; + if (l > len) { /* XXX just RXJ? */ addlog("%s: received malicious IPCPv6 option, " "dropping\n", ifp->if_xname); - goto drop; + goto end; } if (debug) addlog(" %s", sppp_ipv6cp_opt_name(*p)); - switch (*p) { + switch (p[0]) { case IPV6CP_OPT_IFID: /* * Peer doesn't grok address option. This is @@ -3847,8 +3946,7 @@ sppp_ipv6cp_RCN_rej(struct sppp *sp, str } if (debug) addlog("\n"); -drop: - free(buf, M_TEMP); +end: return; } @@ -3859,7 +3957,7 @@ drop: static void sppp_ipv6cp_RCN_nak(struct sppp *sp, struct lcp_header *h, int len) { - u_char *buf, *p, l, blen; + u_char *p, l; struct ifnet *ifp = &sp->pp_if; int debug = ifp->if_flags & IFF_DEBUG; struct in6_addr suggestaddr; @@ -3867,26 +3965,30 @@ sppp_ipv6cp_RCN_nak(struct sppp *sp, str KASSERT(SPPP_WLOCKED(sp)); - len -= 4; - buf = malloc (blen = len, M_TEMP, M_NOWAIT); - if (!buf) + if (len <= sizeof(*h)) return; + len -= sizeof(*h); + if (debug) log(LOG_DEBUG, "%s: ipv6cp nak opts:", ifp->if_xname); p = (void *)(h + 1); - for (; len > 1 && (l = p[1]) != 0; len -= l, p += l) { + for (; len > 1; len -= l, p += l) { + l = p[1]; + if (l == 0) + break; + if (l > len) { /* XXX just RXJ? */ addlog("%s: received malicious IPCPv6 option, " "dropping\n", ifp->if_xname); - goto drop; + goto end; } if (debug) addlog(" %s", sppp_ipv6cp_opt_name(*p)); - switch (*p) { + switch (p[0]) { case IPV6CP_OPT_IFID: /* * Peer doesn't like our local ifid. See @@ -3954,8 +4056,7 @@ sppp_ipv6cp_RCN_nak(struct sppp *sp, str } if (debug) addlog("\n"); -drop: - free(buf, M_TEMP); +end: return; }