diff options
| author | Alexander Motin <mav@FreeBSD.org> | 2007-07-25 14:03:46 +0000 |
|---|---|---|
| committer | Alexander Motin <mav@FreeBSD.org> | 2007-07-25 14:03:46 +0000 |
| commit | 9b0e4d54a4d1ba9b43eaafed87a2c663444b2fc2 (patch) | |
| tree | 2a661dc526a199f0dd1499c873caa949758b198f /sys/netgraph | |
| parent | 80ef4001e9c839600f7753c129ad6d5c96fcdddc (diff) | |
Notes
Diffstat (limited to 'sys/netgraph')
| -rw-r--r-- | sys/netgraph/ng_mppc.c | 210 |
1 files changed, 124 insertions, 86 deletions
diff --git a/sys/netgraph/ng_mppc.c b/sys/netgraph/ng_mppc.c index 55b021a6b564..0cf1e7272b9a 100644 --- a/sys/netgraph/ng_mppc.c +++ b/sys/netgraph/ng_mppc.c @@ -113,6 +113,8 @@ MALLOC_DEFINE(M_NETGRAPH_MPPC, "netgraph_mppc", "netgraph mppc node "); #define MPPC_FLAG_ENCRYPTED 0x1000 /* packet is encrypted */ #define MPPC_CCOUNT_MASK 0x0fff /* sequence number mask */ +#define MPPC_CCOUNT_INC(d) ((d) = (((d) + 1) & MPPC_CCOUNT_MASK)) + #define MPPE_UPDATE_MASK 0xff /* coherency count when we're */ #define MPPE_UPDATE_FLAG 0xff /* supposed to update key */ @@ -152,12 +154,14 @@ static ng_disconnect_t ng_mppc_disconnect; /* Helper functions */ static int ng_mppc_compress(node_p node, - struct mbuf *m, struct mbuf **resultp); + struct mbuf **datap); static int ng_mppc_decompress(node_p node, - struct mbuf *m, struct mbuf **resultp); + struct mbuf **datap); +#ifdef NETGRAPH_MPPC_ENCRYPTION static void ng_mppc_getkey(const u_char *h, u_char *h2, int len); static void ng_mppc_updatekey(u_int32_t bits, u_char *key0, u_char *key, struct rc4_state *rc4); +#endif static void ng_mppc_reset_req(node_p node); /* Node type descriptor */ @@ -354,7 +358,6 @@ ng_mppc_rcvdata(hook_p hook, item_p item) { const node_p node = NG_HOOK_NODE(hook); const priv_p priv = NG_NODE_PRIVATE(node); - struct mbuf *out; int error; struct mbuf *m; @@ -366,13 +369,11 @@ ng_mppc_rcvdata(hook_p hook, item_p item) NG_FREE_ITEM(item); return (ENXIO); } - if ((error = ng_mppc_compress(node, m, &out)) != 0) { - NG_FREE_M(m); + if ((error = ng_mppc_compress(node, &m)) != 0) { NG_FREE_ITEM(item); return(error); } - NG_FREE_M(m); - NG_FWD_NEW_DATA(error, item, priv->xmit.hook, out); + NG_FWD_NEW_DATA(error, item, priv->xmit.hook, m); return (error); } @@ -383,8 +384,7 @@ ng_mppc_rcvdata(hook_p hook, item_p item) NG_FREE_ITEM(item); return (ENXIO); } - if ((error = ng_mppc_decompress(node, m, &out)) != 0) { - NG_FREE_M(m); + if ((error = ng_mppc_decompress(node, &m)) != 0) { NG_FREE_ITEM(item); if (error == EINVAL && priv->ctrlnode != 0) { struct ng_mesg *msg; @@ -399,8 +399,7 @@ ng_mppc_rcvdata(hook_p hook, item_p item) } return (error); } - NG_FREE_M(m); - NG_FWD_NEW_DATA(error, item, priv->recv.hook, out); + NG_FWD_NEW_DATA(error, item, priv->recv.hook, m); return (error); } @@ -464,51 +463,54 @@ ng_mppc_disconnect(hook_p hook) * The original mbuf is not free'd. */ static int -ng_mppc_compress(node_p node, struct mbuf *m, struct mbuf **resultp) +ng_mppc_compress(node_p node, struct mbuf **datap) { const priv_p priv = NG_NODE_PRIVATE(node); struct ng_mppc_dir *const d = &priv->xmit; - u_char *inbuf, *outbuf; - int outlen, inlen; u_int16_t header; + struct mbuf *m = *datap; /* Initialize */ - *resultp = NULL; header = d->cc; - if (d->flushed) { + + /* Always set the flushed bit in stateless mode */ + if (d->flushed || ((d->cfg.bits & MPPE_STATELESS) != 0)) { header |= MPPC_FLAG_FLUSHED; d->flushed = 0; } - /* Work with contiguous regions of memory */ - inlen = m->m_pkthdr.len; - MALLOC(inbuf, u_char *, inlen, M_NETGRAPH_MPPC, M_NOWAIT); - if (inbuf == NULL) - return (ENOMEM); - m_copydata(m, 0, inlen, (caddr_t)inbuf); - if ((d->cfg.bits & MPPC_BIT) != 0) - outlen = MPPC_MAX_BLOWUP(inlen); - else - outlen = MPPC_HDRLEN + inlen; - MALLOC(outbuf, u_char *, outlen, M_NETGRAPH_MPPC, M_NOWAIT); - if (outbuf == NULL) { - FREE(inbuf, M_NETGRAPH_MPPC); - return (ENOMEM); - } - - /* Compress "inbuf" into "outbuf" (if compression enabled) */ + /* Compress packet (if compression enabled) */ #ifdef NETGRAPH_MPPC_COMPRESSION if ((d->cfg.bits & MPPC_BIT) != 0) { u_short flags = MPPC_MANDATORY_COMPRESS_FLAGS; + u_char *inbuf, *outbuf; + int outlen, inlen; u_char *source, *dest; u_long sourceCnt, destCnt; int rtn; + /* Work with contiguous regions of memory. */ + inlen = m->m_pkthdr.len; + inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT); + if (inbuf == NULL) { + m_freem(m); + return (ENOMEM); + } + m_copydata(m, 0, inlen, (caddr_t)inbuf); + + outlen = MPPC_MAX_BLOWUP(inlen); + outbuf = malloc(outlen, M_NETGRAPH_MPPC, M_NOWAIT); + if (outbuf == NULL) { + m_freem(m); + free(inbuf, M_NETGRAPH_MPPC); + return (ENOMEM); + } + /* Prepare to compress */ source = inbuf; sourceCnt = inlen; - dest = outbuf + MPPC_HDRLEN; - destCnt = outlen - MPPC_HDRLEN; + dest = outbuf; + destCnt = outlen; if ((d->cfg.bits & MPPE_STATELESS) == 0) flags |= MPPC_SAVE_HISTORY; @@ -524,55 +526,67 @@ ng_mppc_compress(node_p node, struct mbuf *m, struct mbuf **resultp) header |= MPPC_FLAG_COMPRESSED; if ((rtn & MPPC_RESTART_HISTORY) != 0) header |= MPPC_FLAG_RESTART; + + /* Replace m by the compresed one. */ + m_freem(m); + m = m_devget((caddr_t)outbuf, outlen, 0, NULL, NULL); } d->flushed = (rtn & MPPC_EXPANDED) != 0 || (flags & MPPC_SAVE_HISTORY) == 0; - } -#endif - /* If we did not compress this packet, copy it to output buffer */ - if ((header & MPPC_FLAG_COMPRESSED) == 0) { - bcopy(inbuf, outbuf + MPPC_HDRLEN, inlen); - outlen = MPPC_HDRLEN + inlen; - } - FREE(inbuf, M_NETGRAPH_MPPC); + free(inbuf, M_NETGRAPH_MPPC); + free(outbuf, M_NETGRAPH_MPPC); - /* Always set the flushed bit in stateless mode */ - if ((d->cfg.bits & MPPE_STATELESS) != 0) - header |= MPPC_FLAG_FLUSHED; + /* Check m_devget() result. */ + if (m == NULL) + return (ENOMEM); + } +#endif /* Now encrypt packet (if encryption enabled) */ #ifdef NETGRAPH_MPPC_ENCRYPTION if ((d->cfg.bits & MPPE_BITS) != 0) { + struct mbuf *m1; - /* Set header bits; need to reset key if we say we did */ + /* Set header bits */ header |= MPPC_FLAG_ENCRYPTED; - if ((header & MPPC_FLAG_FLUSHED) != 0) - rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits)); /* Update key if it's time */ if ((d->cfg.bits & MPPE_STATELESS) != 0 || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) { - ng_mppc_updatekey(d->cfg.bits, - d->cfg.startkey, d->key, &d->rc4); + ng_mppc_updatekey(d->cfg.bits, + d->cfg.startkey, d->key, &d->rc4); + } else if ((header & MPPC_FLAG_FLUSHED) != 0) { + /* Need to reset key if we say we did + and ng_mppc_updatekey wasn't called to do it also. */ + rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits)); } + /* We must own the mbuf chain exclusively to modify it. */ + m = m_unshare(m, M_DONTWAIT); + if (m == NULL) + return (ENOMEM); + /* Encrypt packet */ - rc4_crypt(&d->rc4, outbuf + MPPC_HDRLEN, - outbuf + MPPC_HDRLEN, outlen - MPPC_HDRLEN); + m1 = m; + while (m1) { + rc4_crypt(&d->rc4, mtod(m1, u_char *), + mtod(m1, u_char *), m1->m_len); + m1 = m1->m_next; + } } #endif - /* Update sequence number */ - d->cc++; + /* Update coherency count for next time (12 bit arithmetic) */ + MPPC_CCOUNT_INC(d->cc); /* Install header */ - *((u_int16_t *)outbuf) = htons(header); + M_PREPEND(m, MPPC_HDRLEN, M_DONTWAIT); + if (m != NULL) + *(mtod(m, uint16_t *)) = htons(header); - /* Return packet in an mbuf */ - *resultp = m_devget((caddr_t)outbuf, outlen, 0, NULL, NULL); - FREE(outbuf, M_NETGRAPH_MPPC); - return (*resultp == NULL ? ENOBUFS : 0); + *datap = m; + return (*datap == NULL ? ENOBUFS : 0); } /* @@ -580,28 +594,23 @@ ng_mppc_compress(node_p node, struct mbuf *m, struct mbuf **resultp) * The original mbuf is not free'd. */ static int -ng_mppc_decompress(node_p node, struct mbuf *m, struct mbuf **resultp) +ng_mppc_decompress(node_p node, struct mbuf **datap) { const priv_p priv = NG_NODE_PRIVATE(node); struct ng_mppc_dir *const d = &priv->recv; u_int16_t header, cc; u_int numLost; - u_char *buf; - int len; + struct mbuf *m = *datap; /* Pull off header */ - if (m->m_pkthdr.len < MPPC_HDRLEN) + if (m->m_pkthdr.len < MPPC_HDRLEN) { + m_freem(m); return (EINVAL); + } m_copydata(m, 0, MPPC_HDRLEN, (caddr_t)&header); header = ntohs(header); cc = (header & MPPC_CCOUNT_MASK); - - /* Copy payload into a contiguous region of memory */ - len = m->m_pkthdr.len - MPPC_HDRLEN; - MALLOC(buf, u_char *, len, M_NETGRAPH_MPPC, M_NOWAIT); - if (buf == NULL) - return (ENOMEM); - m_copydata(m, MPPC_HDRLEN, len, (caddr_t)buf); + m_adj(m, MPPC_HDRLEN); /* Check for an unexpected jump in the sequence number */ numLost = ((cc - d->cc) & MPPC_CCOUNT_MASK); @@ -635,7 +644,7 @@ ng_mppc_decompress(node_p node, struct mbuf *m, struct mbuf **resultp) ng_mppc_updatekey(d->cfg.bits, d->cfg.startkey, d->key, &d->rc4); } - d->cc++; + MPPC_CCOUNT_INC(d->cc); } /* Reset key (except in stateless mode, see below) */ @@ -653,6 +662,9 @@ ng_mppc_decompress(node_p node, struct mbuf *m, struct mbuf **resultp) /* Decrypt packet */ if ((header & MPPC_FLAG_ENCRYPTED) != 0) { +#ifdef NETGRAPH_MPPC_ENCRYPTION + struct mbuf *m1; +#endif /* Are we not expecting encryption? */ if ((d->cfg.bits & MPPE_BITS) == 0) { @@ -669,8 +681,18 @@ ng_mppc_decompress(node_p node, struct mbuf *m, struct mbuf **resultp) d->cfg.startkey, d->key, &d->rc4); } + /* We must own the mbuf chain exclusively to modify it. */ + m = m_unshare(m, M_DONTWAIT); + if (m == NULL) + return (ENOMEM); + /* Decrypt packet */ - rc4_crypt(&d->rc4, buf, buf, len); + m1 = m; + while (m1 != NULL) { + rc4_crypt(&d->rc4, mtod(m1, u_char *), + mtod(m1, u_char *), m1->m_len); + m1 = m1->m_next; + } #endif } else { @@ -683,7 +705,7 @@ ng_mppc_decompress(node_p node, struct mbuf *m, struct mbuf **resultp) } /* Update coherency count for next time (12 bit arithmetic) */ - d->cc++; + MPPC_CCOUNT_INC(d->cc); /* Check for unexpected compressed packet */ if ((header & MPPC_FLAG_COMPRESSED) != 0 @@ -691,7 +713,7 @@ ng_mppc_decompress(node_p node, struct mbuf *m, struct mbuf **resultp) log(LOG_ERR, "%s: rec'd unexpectedly %s packet", __func__, "compressed"); failed: - FREE(buf, M_NETGRAPH_MPPC); + m_freem(m); return (EINVAL); } @@ -702,12 +724,24 @@ failed: u_char *decompbuf, *source, *dest; u_long sourceCnt, destCnt; int decomplen, rtn; + u_char *buf; + int len; + + /* Copy payload into a contiguous region of memory. */ + len = m->m_pkthdr.len; + buf = malloc(len, M_NETGRAPH_MPPC, M_NOWAIT); + if (buf == NULL) { + m_freem(m); + return (ENOMEM); + } + m_copydata(m, 0, len, (caddr_t)buf); /* Allocate a buffer for decompressed data */ - MALLOC(decompbuf, u_char *, MPPC_DECOMP_BUFSIZE - + MPPC_DECOMP_SAFETY, M_NETGRAPH_MPPC, M_NOWAIT); + decompbuf = malloc(MPPC_DECOMP_BUFSIZE + MPPC_DECOMP_SAFETY, + M_NETGRAPH_MPPC, M_NOWAIT); if (decompbuf == NULL) { - FREE(buf, M_NETGRAPH_MPPC); + m_freem(m); + free(buf, M_NETGRAPH_MPPC); return (ENOMEM); } decomplen = MPPC_DECOMP_BUFSIZE; @@ -730,21 +764,24 @@ failed: || (rtn & MPPC_DECOMP_OK) != MPPC_DECOMP_OK) { log(LOG_ERR, "%s: decomp returned 0x%x", __func__, rtn); - FREE(decompbuf, M_NETGRAPH_MPPC); + free(buf, M_NETGRAPH_MPPC); + free(decompbuf, M_NETGRAPH_MPPC); goto failed; } /* Replace compressed data with decompressed data */ - FREE(buf, M_NETGRAPH_MPPC); - buf = decompbuf; + free(buf, M_NETGRAPH_MPPC); len = decomplen - destCnt; + + m_freem(m); + m = m_devget((caddr_t)decompbuf, len, 0, NULL, NULL); + free(decompbuf, M_NETGRAPH_MPPC); } #endif /* Return result in an mbuf */ - *resultp = m_devget((caddr_t)buf, len, 0, NULL, NULL); - FREE(buf, M_NETGRAPH_MPPC); - return (*resultp == NULL ? ENOBUFS : 0); + *datap = m; + return (*datap == NULL ? ENOBUFS : 0); } /* @@ -767,6 +804,7 @@ ng_mppc_reset_req(node_p node) d->flushed = 1; } +#ifdef NETGRAPH_MPPC_ENCRYPTION /* * Generate a new encryption key */ @@ -781,11 +819,10 @@ ng_mppc_getkey(const u_char *h, u_char *h2, int len) SHA1_CTX c; int k; - bzero(&hash, sizeof(hash)); SHA1Init(&c); SHA1Update(&c, h, len); for (k = 0; k < 4; k++) - SHA1Update(&c, pad1, sizeof(pad2)); + SHA1Update(&c, pad1, sizeof(pad1)); SHA1Update(&c, h2, len); for (k = 0; k < 4; k++) SHA1Update(&c, pad2, sizeof(pad2)); @@ -811,4 +848,5 @@ ng_mppc_updatekey(u_int32_t bits, bcopy(&ng_mppe_weakenkey, key, 1); rc4_init(rc4, key, keylen); } +#endif |
