Changeset View
Changeset View
Standalone View
Standalone View
head/sys/netgraph/ng_deflate.c
| Show All 35 Lines | |||||
| #include <sys/param.h> | #include <sys/param.h> | ||||
| #include <sys/systm.h> | #include <sys/systm.h> | ||||
| #include <sys/kernel.h> | #include <sys/kernel.h> | ||||
| #include <sys/mbuf.h> | #include <sys/mbuf.h> | ||||
| #include <sys/malloc.h> | #include <sys/malloc.h> | ||||
| #include <sys/endian.h> | #include <sys/endian.h> | ||||
| #include <sys/errno.h> | #include <sys/errno.h> | ||||
| #include <sys/syslog.h> | #include <sys/syslog.h> | ||||
| #include <sys/zlib.h> | #include <contrib/zlib/zlib.h> | ||||
| #include <netgraph/ng_message.h> | #include <netgraph/ng_message.h> | ||||
| #include <netgraph/netgraph.h> | #include <netgraph/netgraph.h> | ||||
| #include <netgraph/ng_parse.h> | #include <netgraph/ng_parse.h> | ||||
| #include <netgraph/ng_deflate.h> | #include <netgraph/ng_deflate.h> | ||||
| #include "opt_netgraph.h" | #include "opt_netgraph.h" | ||||
| Show All 24 Lines | |||||
| static ng_constructor_t ng_deflate_constructor; | static ng_constructor_t ng_deflate_constructor; | ||||
| static ng_rcvmsg_t ng_deflate_rcvmsg; | static ng_rcvmsg_t ng_deflate_rcvmsg; | ||||
| static ng_shutdown_t ng_deflate_shutdown; | static ng_shutdown_t ng_deflate_shutdown; | ||||
| static ng_newhook_t ng_deflate_newhook; | static ng_newhook_t ng_deflate_newhook; | ||||
| static ng_rcvdata_t ng_deflate_rcvdata; | static ng_rcvdata_t ng_deflate_rcvdata; | ||||
| static ng_disconnect_t ng_deflate_disconnect; | static ng_disconnect_t ng_deflate_disconnect; | ||||
| /* Helper functions */ | /* Helper functions */ | ||||
| static void *z_alloc(void *, u_int items, u_int size); | static int ng_deflate_compress(node_p, struct mbuf *, struct mbuf **); | ||||
| static void z_free(void *, void *ptr); | static int ng_deflate_decompress(node_p, struct mbuf *, struct mbuf **); | ||||
| static int ng_deflate_compress(node_p node, | static void ng_deflate_reset_req(node_p); | ||||
| struct mbuf *m, struct mbuf **resultp); | |||||
| static int ng_deflate_decompress(node_p node, | |||||
| struct mbuf *m, struct mbuf **resultp); | |||||
| static void ng_deflate_reset_req(node_p node); | |||||
| /* Parse type for struct ng_deflate_config. */ | /* Parse type for struct ng_deflate_config. */ | ||||
| static const struct ng_parse_struct_field ng_deflate_config_type_fields[] | static const struct ng_parse_struct_field ng_deflate_config_type_fields[] | ||||
| = NG_DEFLATE_CONFIG_INFO; | = NG_DEFLATE_CONFIG_INFO; | ||||
| static const struct ng_parse_type ng_deflate_config_type = { | static const struct ng_parse_type ng_deflate_config_type = { | ||||
| &ng_parse_struct_type, | &ng_parse_struct_type, | ||||
| ng_deflate_config_type_fields | ng_deflate_config_type_fields | ||||
| }; | }; | ||||
| ▲ Show 20 Lines • Show All 150 Lines • ▼ Show 20 Lines | if (priv->cfg.enable) { | ||||
| priv->cfg.enable = 0; | priv->cfg.enable = 0; | ||||
| } | } | ||||
| /* Configuration is OK, reset to it. */ | /* Configuration is OK, reset to it. */ | ||||
| priv->cfg = *cfg; | priv->cfg = *cfg; | ||||
| if (priv->cfg.enable) { | if (priv->cfg.enable) { | ||||
| priv->cx.next_in = NULL; | priv->cx.next_in = NULL; | ||||
| priv->cx.zalloc = z_alloc; | |||||
| priv->cx.zfree = z_free; | |||||
| int res; | int res; | ||||
| if (priv->compress) { | if (priv->compress) { | ||||
| if ((res = deflateInit2(&priv->cx, | if ((res = deflateInit2(&priv->cx, | ||||
| Z_DEFAULT_COMPRESSION, Z_DEFLATED, | Z_DEFAULT_COMPRESSION, Z_DEFLATED, | ||||
| -cfg->windowBits, 8, | -cfg->windowBits, 8, | ||||
| Z_DEFAULT_STRATEGY)) != Z_OK) { | Z_DEFAULT_STRATEGY)) != Z_OK) { | ||||
| log(LOG_NOTICE, | log(LOG_NOTICE, | ||||
| "deflateInit2: error %d, %s\n", | "deflateInit2: error %d, %s\n", | ||||
| ▲ Show 20 Lines • Show All 73 Lines • ▼ Show 20 Lines | ng_deflate_rcvdata(hook_p hook, item_p item) | ||||
| NGI_GET_M(item, m); | NGI_GET_M(item, m); | ||||
| /* Compress */ | /* Compress */ | ||||
| if (priv->compress) { | if (priv->compress) { | ||||
| if ((error = ng_deflate_compress(node, m, &out)) != 0) { | if ((error = ng_deflate_compress(node, m, &out)) != 0) { | ||||
| NG_FREE_ITEM(item); | NG_FREE_ITEM(item); | ||||
| log(LOG_NOTICE, "%s: error: %d\n", __func__, error); | log(LOG_NOTICE, "%s: error: %d\n", __func__, error); | ||||
| return (error); | return (error); | ||||
| } | } | ||||
| } else { /* Decompress */ | } else { /* Decompress */ | ||||
| if ((error = ng_deflate_decompress(node, m, &out)) != 0) { | if ((error = ng_deflate_decompress(node, m, &out)) != 0) { | ||||
| NG_FREE_ITEM(item); | NG_FREE_ITEM(item); | ||||
| log(LOG_NOTICE, "%s: error: %d\n", __func__, error); | log(LOG_NOTICE, "%s: error: %d\n", __func__, error); | ||||
| if (priv->ctrlnode != 0) { | if (priv->ctrlnode != 0) { | ||||
| struct ng_mesg *msg; | struct ng_mesg *msg; | ||||
| /* Need to send a reset-request. */ | /* Need to send a reset-request. */ | ||||
| ▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | ng_deflate_disconnect(hook_p hook) | ||||
| return (0); | return (0); | ||||
| } | } | ||||
| /************************************************************************ | /************************************************************************ | ||||
| HELPER STUFF | HELPER STUFF | ||||
| ************************************************************************/ | ************************************************************************/ | ||||
| /* | /* | ||||
| * Space allocation and freeing routines for use by zlib routines. | |||||
| */ | |||||
| static void * | |||||
| z_alloc(void *notused, u_int items, u_int size) | |||||
| { | |||||
| return (malloc(items * size, M_NETGRAPH_DEFLATE, M_NOWAIT)); | |||||
| } | |||||
| static void | |||||
| z_free(void *notused, void *ptr) | |||||
| { | |||||
| free(ptr, M_NETGRAPH_DEFLATE); | |||||
| } | |||||
| /* | |||||
| * Compress/encrypt a packet and put the result in a new mbuf at *resultp. | * Compress/encrypt a packet and put the result in a new mbuf at *resultp. | ||||
| * The original mbuf is not free'd. | * The original mbuf is not free'd. | ||||
| */ | */ | ||||
| static int | static int | ||||
| ng_deflate_compress(node_p node, struct mbuf *m, struct mbuf **resultp) | ng_deflate_compress(node_p node, struct mbuf *m, struct mbuf **resultp) | ||||
| { | { | ||||
| const priv_p priv = NG_NODE_PRIVATE(node); | const priv_p priv = NG_NODE_PRIVATE(node); | ||||
| int outlen, inlen; | int outlen, inlen; | ||||
| Show All 32 Lines | ng_deflate_compress(node_p node, struct mbuf *m, struct mbuf **resultp) | ||||
| } else { | } else { | ||||
| priv->cx.next_in = priv->inbuf + 1; /* compress protocol */ | priv->cx.next_in = priv->inbuf + 1; /* compress protocol */ | ||||
| priv->cx.avail_in = inlen - 1; | priv->cx.avail_in = inlen - 1; | ||||
| } | } | ||||
| priv->cx.next_out = priv->outbuf + 2 + DEFLATE_HDRLEN; | priv->cx.next_out = priv->outbuf + 2 + DEFLATE_HDRLEN; | ||||
| priv->cx.avail_out = outlen - 2 - DEFLATE_HDRLEN; | priv->cx.avail_out = outlen - 2 - DEFLATE_HDRLEN; | ||||
| /* Compress. */ | /* Compress. */ | ||||
| rtn = deflate(&priv->cx, Z_PACKET_FLUSH); | rtn = deflate(&priv->cx, Z_SYNC_FLUSH); | ||||
| /* Check return value. */ | /* Check return value. */ | ||||
| if (rtn != Z_OK) { | if (rtn != Z_OK) { | ||||
| priv->stats.Errors++; | priv->stats.Errors++; | ||||
| log(LOG_NOTICE, "ng_deflate: compression error: %d (%s)\n", | log(LOG_NOTICE, "ng_deflate: compression error: %d (%s)\n", | ||||
| rtn, priv->cx.msg); | rtn, priv->cx.msg); | ||||
| NG_FREE_M(m); | NG_FREE_M(m); | ||||
| return (EINVAL); | return (EINVAL); | ||||
| } | } | ||||
| /* Calculate resulting size. */ | /* Calculate resulting size. */ | ||||
| outlen -= priv->cx.avail_out; | outlen -= priv->cx.avail_out; | ||||
| /* | |||||
| * Z_SYNC_FLUSH completes the current deflate block and follows | |||||
| * it with an empty stored block that is three bits plus filler | |||||
| * bits to the next byte, followed by four bytes (00 00 ff ff). | |||||
| * RFC 1979 Section 2.1, "Data" requires the four bytes be | |||||
| * removed before transmission. | |||||
| */ | |||||
| outlen -= 4; | |||||
| MPASS(outlen > 0); | |||||
| MPASS(priv->outbuf[outlen + 0] == 0x00); | |||||
| MPASS(priv->outbuf[outlen + 1] == 0x00); | |||||
| MPASS(priv->outbuf[outlen + 2] == 0xff); | |||||
| MPASS(priv->outbuf[outlen + 3] == 0xff); | |||||
| /* If we can't compress this packet, send it as-is. */ | /* If we can't compress this packet, send it as-is. */ | ||||
| if (outlen > inlen) { | if (outlen > inlen) { | ||||
| /* Return original packet uncompressed. */ | /* Return original packet uncompressed. */ | ||||
| *resultp = m; | *resultp = m; | ||||
| priv->stats.FramesUncomp++; | priv->stats.FramesUncomp++; | ||||
| priv->stats.OutOctets+=inlen; | priv->stats.OutOctets+=inlen; | ||||
| } else { | } else { | ||||
| Show All 23 Lines | |||||
| /* | /* | ||||
| * Decompress/decrypt packet and put the result in a new mbuf at *resultp. | * Decompress/decrypt packet and put the result in a new mbuf at *resultp. | ||||
| * The original mbuf is not free'd. | * The original mbuf is not free'd. | ||||
| */ | */ | ||||
| static int | static int | ||||
| ng_deflate_decompress(node_p node, struct mbuf *m, struct mbuf **resultp) | ng_deflate_decompress(node_p node, struct mbuf *m, struct mbuf **resultp) | ||||
| { | { | ||||
| const priv_p priv = NG_NODE_PRIVATE(node); | const priv_p priv = NG_NODE_PRIVATE(node); | ||||
| int outlen, inlen; | int outlen, inlen, datalen; | ||||
| int rtn; | int rtn; | ||||
| uint16_t proto; | uint16_t proto; | ||||
| int offset; | int offset; | ||||
| uint16_t rseqnum; | uint16_t rseqnum; | ||||
| u_char headbuf[5]; | |||||
| static u_char EMPTY_BLOCK[4] = { 0x00, 0x00, 0xff, 0xff }; | |||||
| /* Initialize. */ | /* Initialize. */ | ||||
| *resultp = NULL; | *resultp = NULL; | ||||
| inlen = m->m_pkthdr.len; | inlen = m->m_pkthdr.len; | ||||
| if (inlen > DEFLATE_BUF_SIZE) { | if (inlen > DEFLATE_BUF_SIZE) { | ||||
| priv->stats.Errors++; | priv->stats.Errors++; | ||||
| ▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | if (proto == PROT_COMPD) { | ||||
| /* Prepare to decompress. */ | /* Prepare to decompress. */ | ||||
| priv->cx.next_in = priv->inbuf + offset; | priv->cx.next_in = priv->inbuf + offset; | ||||
| priv->cx.avail_in = inlen - offset; | priv->cx.avail_in = inlen - offset; | ||||
| /* Reserve space for protocol decompression. */ | /* Reserve space for protocol decompression. */ | ||||
| priv->cx.next_out = priv->outbuf + 1; | priv->cx.next_out = priv->outbuf + 1; | ||||
| priv->cx.avail_out = outlen - 1; | priv->cx.avail_out = outlen - 1; | ||||
| /* Decompress. */ | /* Decompress. */ | ||||
| rtn = inflate(&priv->cx, Z_PACKET_FLUSH); | rtn = inflate(&priv->cx, Z_SYNC_FLUSH); | ||||
| /* Check return value. */ | /* Check return value. */ | ||||
| if (rtn != Z_OK && rtn != Z_STREAM_END) { | if (rtn != Z_OK && rtn != Z_STREAM_END) { | ||||
| priv->stats.Errors++; | priv->stats.Errors++; | ||||
| NG_FREE_M(m); | NG_FREE_M(m); | ||||
| priv->seqnum = 0; | priv->seqnum = 0; | ||||
| log(LOG_NOTICE, "%s: decompression error: %d (%s)\n", | log(LOG_NOTICE, "%s: decompression error: %d (%s)\n", | ||||
| __func__, rtn, priv->cx.msg); | __func__, rtn, priv->cx.msg); | ||||
| switch (rtn) { | switch (rtn) { | ||||
| case Z_MEM_ERROR: | case Z_MEM_ERROR: | ||||
| return (ENOMEM); | return (ENOMEM); | ||||
| case Z_DATA_ERROR: | case Z_DATA_ERROR: | ||||
| return (EIO); | return (EIO); | ||||
| default: | default: | ||||
| return (EINVAL); | return (EINVAL); | ||||
| } | } | ||||
| } | } | ||||
| /* Handle the EMPTY_BLOCK omitted by sender */ | |||||
| if (inflateSyncPoint(&priv->cx)) { | |||||
| priv->cx.avail_in = 4; | |||||
| priv->cx.next_in = EMPTY_BLOCK; | |||||
| inflate(&priv->cx, Z_SYNC_FLUSH); | |||||
| } | |||||
| /* Calculate resulting size. */ | /* Calculate resulting size. */ | ||||
| outlen -= priv->cx.avail_out; | outlen -= priv->cx.avail_out; | ||||
| /* Decompress protocol. */ | /* Decompress protocol. */ | ||||
| if ((priv->outbuf[1] & 0x01) != 0) { | if ((priv->outbuf[1] & 0x01) != 0) { | ||||
| priv->outbuf[0] = 0; | priv->outbuf[0] = 0; | ||||
| /* Return packet in an mbuf. */ | /* Return packet in an mbuf. */ | ||||
| m_copyback(m, 0, outlen, (caddr_t)priv->outbuf); | m_copyback(m, 0, outlen, (caddr_t)priv->outbuf); | ||||
| } else { | } else { | ||||
| outlen--; | outlen--; | ||||
| /* Return packet in an mbuf. */ | /* Return packet in an mbuf. */ | ||||
| m_copyback(m, 0, outlen, (caddr_t)(priv->outbuf + 1)); | m_copyback(m, 0, outlen, (caddr_t)(priv->outbuf + 1)); | ||||
| } | } | ||||
| if (m->m_pkthdr.len < outlen) { | if (m->m_pkthdr.len < outlen) { | ||||
| m_freem(m); | m_freem(m); | ||||
| priv->stats.Errors++; | priv->stats.Errors++; | ||||
| priv->seqnum = 0; | priv->seqnum = 0; | ||||
| return (ENOMEM); | return (ENOMEM); | ||||
| } else if (outlen < m->m_pkthdr.len) | } else if (outlen < m->m_pkthdr.len) | ||||
| m_adj(m, outlen - m->m_pkthdr.len); | m_adj(m, outlen - m->m_pkthdr.len); | ||||
| *resultp = m; | *resultp = m; | ||||
| priv->stats.FramesPlain++; | priv->stats.FramesPlain++; | ||||
| priv->stats.OutOctets+=outlen; | priv->stats.OutOctets+=outlen; | ||||
| } else { /* Packet is not compressed, just update dictionary. */ | } else { | ||||
| /* Packet is not compressed, just update dictionary. */ | |||||
| priv->stats.FramesUncomp++; | priv->stats.FramesUncomp++; | ||||
| /* | |||||
| * Fake a header for uncompressed data block | |||||
| */ | |||||
| datalen = inlen - offset + 1; | |||||
| headbuf[0] = 0x80; | |||||
| headbuf[1] = datalen & 0xff; | |||||
| headbuf[2] = datalen >> 8; | |||||
| headbuf[3] = (~datalen) & 0xff; | |||||
| headbuf[4] = (~datalen) >> 8; | |||||
| priv->cx.next_in = headbuf; | |||||
| priv->cx.avail_in = sizeof(headbuf); | |||||
| priv->cx.next_out = priv->outbuf; | |||||
| priv->cx.avail_out = DEFLATE_BUF_SIZE; | |||||
| rtn = inflate(&priv->cx, Z_NO_FLUSH); | |||||
| if (priv->inbuf[0] == 0) { | if (priv->inbuf[0] == 0) { | ||||
| priv->cx.next_in = priv->inbuf + 1; /* compress protocol */ | priv->cx.next_in = | ||||
| priv->inbuf + 1; /* compress protocol */ | |||||
| priv->cx.avail_in = inlen - 1; | priv->cx.avail_in = inlen - 1; | ||||
| } else { | } else { | ||||
| priv->cx.next_in = priv->inbuf; | priv->cx.next_in = priv->inbuf; | ||||
| priv->cx.avail_in = inlen; | priv->cx.avail_in = inlen; | ||||
| } | } | ||||
| priv->cx.next_out = priv->outbuf; | |||||
| priv->cx.avail_out = DEFLATE_BUF_SIZE; | |||||
| rtn = inflateIncomp(&priv->cx); | rtn = inflate(&priv->cx, Z_SYNC_FLUSH); | ||||
| /* Check return value */ | /* Check return value */ | ||||
| if (rtn != Z_OK) { | if (rtn != Z_OK) { | ||||
| priv->stats.Errors++; | priv->stats.Errors++; | ||||
| log(LOG_NOTICE, "%s: inflateIncomp error: %d (%s)\n", | log(LOG_NOTICE, "%s: inflate error: %d (%s)\n", | ||||
| __func__, rtn, priv->cx.msg); | __func__, rtn, priv->cx.msg); | ||||
| NG_FREE_M(m); | NG_FREE_M(m); | ||||
| priv->seqnum = 0; | priv->seqnum = 0; | ||||
| return (EINVAL); | return (EINVAL); | ||||
| } | } | ||||
| *resultp = m; | *resultp = m; | ||||
| priv->stats.FramesPlain++; | priv->stats.FramesPlain++; | ||||
| Show All 26 Lines | |||||