Changeset View
Changeset View
Standalone View
Standalone View
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 All 18 Lines | |||||
static int | static int | ||||
ng_deflate_shutdown(node_p node) | ng_deflate_shutdown(node_p node) | ||||
{ | { | ||||
const priv_p priv = NG_NODE_PRIVATE(node); | const priv_p priv = NG_NODE_PRIVATE(node); | ||||
/* Take down netgraph node. */ | /* Take down netgraph node. */ | ||||
if (priv->cfg.enable) { | if (priv->cfg.enable) { | ||||
if (priv->compress) | if (priv->compress) | ||||
deflateEnd(&priv->cx); | deflateEnd(&priv->cx); | ||||
else | else | ||||
inflateEnd(&priv->cx); | inflateEnd(&priv->cx); | ||||
emaste: unrelated whitespace change? | |||||
} | } | ||||
free(priv, M_NETGRAPH_DEFLATE); | free(priv, M_NETGRAPH_DEFLATE); | ||||
NG_NODE_SET_PRIVATE(node, NULL); | NG_NODE_SET_PRIVATE(node, NULL); | ||||
NG_NODE_UNREF(node); /* let the node escape */ | NG_NODE_UNREF(node); /* let the node escape */ | ||||
return (0); | return (0); | ||||
} | } | ||||
Show All 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); | ||||
Done Inline ActionsZ_PACKET_FLUSH is the FreeBSD only and specific implementation. ota_j.email.ne.jp: Z_PACKET_FLUSH is the FreeBSD only and specific implementation. | |||||
/* 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; | |||||
Done Inline Actionsmaybe a kassert that outlen > 4 && the last 4 bytes are the expected 00 00 ff ff? emaste: maybe a kassert that outlen > 4 && the last 4 bytes are the expected 00 00 ff ff? | |||||
/* 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 { | ||||
/* Install header. */ | /* Install header. */ | ||||
Show All 22 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); | |||||
Done Inline ActionsDoes this fnflate() really do a work? ota_j.email.ne.jp: Does this fnflate() really do a work?
Its output buffer begins with priv->outbuf just like… | |||||
Done Inline ActionsYes, this would pass the uncompressed data through inflate engine and update the dictionary, which will be used for later decompression (the first few packets are not compressible normally). delphij: Yes, this would pass the uncompressed data through inflate engine and update the dictionary… | |||||
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 |
unrelated whitespace change?