slcompress.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592
  1. /*-
  2. * SPDX-License-Identifier: BSD-3-Clause
  3. *
  4. * Copyright (c) 1989, 1993, 1994
  5. * The Regents of the University of California. All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. * 3. Neither the name of the University nor the names of its contributors
  16. * may be used to endorse or promote products derived from this software
  17. * without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  20. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  21. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  22. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  23. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  24. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  25. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  26. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  27. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  28. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  29. * SUCH DAMAGE.
  30. *
  31. * @(#)slcompress.c 8.2 (Berkeley) 4/16/94
  32. * $FreeBSD$
  33. */
  34. /*
  35. * Routines to compress and uncompess tcp packets (for transmission
  36. * over low speed serial lines.
  37. *
  38. * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
  39. * - Initial distribution.
  40. *
  41. */
  42. #include <sys/param.h>
  43. #include <sys/mbuf.h>
  44. #include <sys/systm.h>
  45. #include <netinet/in.h>
  46. #include <netinet/in_systm.h>
  47. #include <netinet/ip.h>
  48. #include <netinet/tcp.h>
  49. #include <net/slcompress.h>
  50. #ifndef SL_NO_STATS
  51. #define INCR(counter) ++comp->counter;
  52. #else
  53. #define INCR(counter)
  54. #endif
  55. #define BCMP(p1, p2, n) bcmp((void *)(p1), (void *)(p2), (int)(n))
  56. #define BCOPY(p1, p2, n) bcopy((void *)(p1), (void *)(p2), (int)(n))
  57. void
  58. sl_compress_init(struct slcompress *comp, int max_state)
  59. {
  60. u_int i;
  61. struct cstate *tstate = comp->tstate;
  62. if (max_state == -1) {
  63. max_state = MAX_STATES - 1;
  64. bzero((char *)comp, sizeof(*comp));
  65. } else {
  66. /* Don't reset statistics */
  67. bzero((char *)comp->tstate, sizeof(comp->tstate));
  68. bzero((char *)comp->rstate, sizeof(comp->rstate));
  69. }
  70. for (i = max_state; i > 0; --i) {
  71. tstate[i].cs_id = i;
  72. tstate[i].cs_next = &tstate[i - 1];
  73. }
  74. tstate[0].cs_next = &tstate[max_state];
  75. tstate[0].cs_id = 0;
  76. comp->last_cs = &tstate[0];
  77. comp->last_recv = 255;
  78. comp->last_xmit = 255;
  79. comp->flags = SLF_TOSS;
  80. }
  81. /* ENCODE encodes a number that is known to be non-zero. ENCODEZ
  82. * checks for zero (since zero has to be encoded in the long, 3 byte
  83. * form).
  84. */
  85. #define ENCODE(n) { \
  86. if ((u_int16_t)(n) >= 256) { \
  87. *cp++ = 0; \
  88. cp[1] = (n); \
  89. cp[0] = (n) >> 8; \
  90. cp += 2; \
  91. } else { \
  92. *cp++ = (n); \
  93. } \
  94. }
  95. #define ENCODEZ(n) { \
  96. if ((u_int16_t)(n) >= 256 || (u_int16_t)(n) == 0) { \
  97. *cp++ = 0; \
  98. cp[1] = (n); \
  99. cp[0] = (n) >> 8; \
  100. cp += 2; \
  101. } else { \
  102. *cp++ = (n); \
  103. } \
  104. }
  105. #define DECODEL(f) { \
  106. if (*cp == 0) {\
  107. (f) = htonl(ntohl(f) + ((cp[1] << 8) | cp[2])); \
  108. cp += 3; \
  109. } else { \
  110. (f) = htonl(ntohl(f) + (u_int32_t)*cp++); \
  111. } \
  112. }
  113. #define DECODES(f) { \
  114. if (*cp == 0) {\
  115. (f) = htons(ntohs(f) + ((cp[1] << 8) | cp[2])); \
  116. cp += 3; \
  117. } else { \
  118. (f) = htons(ntohs(f) + (u_int32_t)*cp++); \
  119. } \
  120. }
  121. #define DECODEU(f) { \
  122. if (*cp == 0) {\
  123. (f) = htons((cp[1] << 8) | cp[2]); \
  124. cp += 3; \
  125. } else { \
  126. (f) = htons((u_int32_t)*cp++); \
  127. } \
  128. }
  129. /*
  130. * Attempt to compress an outgoing TCP packet and return the type of
  131. * the result. The caller must have already verified that the protocol
  132. * is TCP. The first mbuf must contain the complete IP and TCP headers,
  133. * and "ip" must be == mtod(m, struct ip *). "comp" supplies the
  134. * compression state, and "compress_cid" tells us whether it is OK
  135. * to leave out the CID field when feasible.
  136. *
  137. * The caller is responsible for adjusting m->m_pkthdr.len upon return,
  138. * if m is an M_PKTHDR mbuf.
  139. */
  140. u_int
  141. sl_compress_tcp(struct mbuf *m, struct ip *ip, struct slcompress *comp,
  142. int compress_cid)
  143. {
  144. struct cstate *cs = comp->last_cs->cs_next;
  145. u_int hlen = ip->ip_hl;
  146. struct tcphdr *oth;
  147. struct tcphdr *th;
  148. u_int deltaS, deltaA;
  149. u_int changes = 0;
  150. u_char new_seq[16];
  151. u_char *cp = new_seq;
  152. /*
  153. * Bail if this is an IP fragment or if the TCP packet isn't
  154. * `compressible' (i.e., ACK isn't set or some other control bit is
  155. * set). (We assume that the caller has already made sure the
  156. * packet is IP proto TCP).
  157. */
  158. if ((ip->ip_off & htons(0x3fff)) || m->m_len < 40)
  159. return (TYPE_IP);
  160. th = (struct tcphdr *)&((int32_t *)ip)[hlen];
  161. if ((th->th_flags & (TH_SYN|TH_FIN|TH_RST|TH_ACK)) != TH_ACK)
  162. return (TYPE_IP);
  163. /*
  164. * Packet is compressible -- we're going to send either a
  165. * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way we need
  166. * to locate (or create) the connection state. Special case the
  167. * most recently used connection since it's most likely to be used
  168. * again & we don't have to do any reordering if it's used.
  169. */
  170. INCR(sls_packets)
  171. if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr ||
  172. ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr ||
  173. *(int32_t *)th != ((int32_t *)&cs->cs_ip)[cs->cs_ip.ip_hl]) {
  174. /*
  175. * Wasn't the first -- search for it.
  176. *
  177. * States are kept in a circularly linked list with
  178. * last_cs pointing to the end of the list. The
  179. * list is kept in lru order by moving a state to the
  180. * head of the list whenever it is referenced. Since
  181. * the list is short and, empirically, the connection
  182. * we want is almost always near the front, we locate
  183. * states via linear search. If we don't find a state
  184. * for the datagram, the oldest state is (re-)used.
  185. */
  186. struct cstate *lcs;
  187. struct cstate *lastcs = comp->last_cs;
  188. do {
  189. lcs = cs; cs = cs->cs_next;
  190. INCR(sls_searches)
  191. if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr
  192. && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr
  193. && *(int32_t *)th ==
  194. ((int32_t *)&cs->cs_ip)[cs->cs_ip.ip_hl])
  195. goto found;
  196. } while (cs != lastcs);
  197. /*
  198. * Didn't find it -- re-use oldest cstate. Send an
  199. * uncompressed packet that tells the other side what
  200. * connection number we're using for this conversation.
  201. * Note that since the state list is circular, the oldest
  202. * state points to the newest and we only need to set
  203. * last_cs to update the lru linkage.
  204. */
  205. INCR(sls_misses)
  206. comp->last_cs = lcs;
  207. hlen += th->th_off;
  208. hlen <<= 2;
  209. if (hlen > m->m_len)
  210. return TYPE_IP;
  211. goto uncompressed;
  212. found:
  213. /*
  214. * Found it -- move to the front on the connection list.
  215. */
  216. if (cs == lastcs)
  217. comp->last_cs = lcs;
  218. else {
  219. lcs->cs_next = cs->cs_next;
  220. cs->cs_next = lastcs->cs_next;
  221. lastcs->cs_next = cs;
  222. }
  223. }
  224. /*
  225. * Make sure that only what we expect to change changed. The first
  226. * line of the `if' checks the IP protocol version, header length &
  227. * type of service. The 2nd line checks the "Don't fragment" bit.
  228. * The 3rd line checks the time-to-live and protocol (the protocol
  229. * check is unnecessary but costless). The 4th line checks the TCP
  230. * header length. The 5th line checks IP options, if any. The 6th
  231. * line checks TCP options, if any. If any of these things are
  232. * different between the previous & current datagram, we send the
  233. * current datagram `uncompressed'.
  234. */
  235. oth = (struct tcphdr *)&((int32_t *)&cs->cs_ip)[hlen];
  236. deltaS = hlen;
  237. hlen += th->th_off;
  238. hlen <<= 2;
  239. if (hlen > m->m_len)
  240. return TYPE_IP;
  241. if (((u_int16_t *)ip)[0] != ((u_int16_t *)&cs->cs_ip)[0] ||
  242. ((u_int16_t *)ip)[3] != ((u_int16_t *)&cs->cs_ip)[3] ||
  243. ((u_int16_t *)ip)[4] != ((u_int16_t *)&cs->cs_ip)[4] ||
  244. th->th_off != oth->th_off ||
  245. (deltaS > 5 &&
  246. BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) ||
  247. (th->th_off > 5 &&
  248. BCMP(th + 1, oth + 1, (th->th_off - 5) << 2)))
  249. goto uncompressed;
  250. /*
  251. * Figure out which of the changing fields changed. The
  252. * receiver expects changes in the order: urgent, window,
  253. * ack, seq (the order minimizes the number of temporaries
  254. * needed in this section of code).
  255. */
  256. if (th->th_flags & TH_URG) {
  257. deltaS = ntohs(th->th_urp);
  258. ENCODEZ(deltaS);
  259. changes |= NEW_U;
  260. } else if (th->th_urp != oth->th_urp)
  261. /* argh! URG not set but urp changed -- a sensible
  262. * implementation should never do this but RFC793
  263. * doesn't prohibit the change so we have to deal
  264. * with it. */
  265. goto uncompressed;
  266. deltaS = (u_int16_t)(ntohs(th->th_win) - ntohs(oth->th_win));
  267. if (deltaS) {
  268. ENCODE(deltaS);
  269. changes |= NEW_W;
  270. }
  271. deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack);
  272. if (deltaA) {
  273. if (deltaA > 0xffff)
  274. goto uncompressed;
  275. ENCODE(deltaA);
  276. changes |= NEW_A;
  277. }
  278. deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq);
  279. if (deltaS) {
  280. if (deltaS > 0xffff)
  281. goto uncompressed;
  282. ENCODE(deltaS);
  283. changes |= NEW_S;
  284. }
  285. switch(changes) {
  286. case 0:
  287. /*
  288. * Nothing changed. If this packet contains data and the
  289. * last one didn't, this is probably a data packet following
  290. * an ack (normal on an interactive connection) and we send
  291. * it compressed. Otherwise it's probably a retransmit,
  292. * retransmitted ack or window probe. Send it uncompressed
  293. * in case the other side missed the compressed version.
  294. */
  295. if (ip->ip_len != cs->cs_ip.ip_len &&
  296. ntohs(cs->cs_ip.ip_len) == hlen)
  297. break;
  298. /* FALLTHROUGH */
  299. case SPECIAL_I:
  300. case SPECIAL_D:
  301. /*
  302. * actual changes match one of our special case encodings --
  303. * send packet uncompressed.
  304. */
  305. goto uncompressed;
  306. case NEW_S|NEW_A:
  307. if (deltaS == deltaA &&
  308. deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
  309. /* special case for echoed terminal traffic */
  310. changes = SPECIAL_I;
  311. cp = new_seq;
  312. }
  313. break;
  314. case NEW_S:
  315. if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
  316. /* special case for data xfer */
  317. changes = SPECIAL_D;
  318. cp = new_seq;
  319. }
  320. break;
  321. }
  322. deltaS = ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id);
  323. if (deltaS != 1) {
  324. ENCODEZ(deltaS);
  325. changes |= NEW_I;
  326. }
  327. if (th->th_flags & TH_PUSH)
  328. changes |= TCP_PUSH_BIT;
  329. /*
  330. * Grab the cksum before we overwrite it below. Then update our
  331. * state with this packet's header.
  332. */
  333. deltaA = ntohs(th->th_sum);
  334. BCOPY(ip, &cs->cs_ip, hlen);
  335. /*
  336. * We want to use the original packet as our compressed packet.
  337. * (cp - new_seq) is the number of bytes we need for compressed
  338. * sequence numbers. In addition we need one byte for the change
  339. * mask, one for the connection id and two for the tcp checksum.
  340. * So, (cp - new_seq) + 4 bytes of header are needed. hlen is how
  341. * many bytes of the original packet to toss so subtract the two to
  342. * get the new packet size.
  343. */
  344. deltaS = cp - new_seq;
  345. cp = (u_char *)ip;
  346. if (compress_cid == 0 || comp->last_xmit != cs->cs_id) {
  347. comp->last_xmit = cs->cs_id;
  348. hlen -= deltaS + 4;
  349. cp += hlen;
  350. *cp++ = changes | NEW_C;
  351. *cp++ = cs->cs_id;
  352. } else {
  353. hlen -= deltaS + 3;
  354. cp += hlen;
  355. *cp++ = changes;
  356. }
  357. m->m_len -= hlen;
  358. m->m_data += hlen;
  359. *cp++ = deltaA >> 8;
  360. *cp++ = deltaA;
  361. BCOPY(new_seq, cp, deltaS);
  362. INCR(sls_compressed)
  363. return (TYPE_COMPRESSED_TCP);
  364. /*
  365. * Update connection state cs & send uncompressed packet ('uncompressed'
  366. * means a regular ip/tcp packet but with the 'conversation id' we hope
  367. * to use on future compressed packets in the protocol field).
  368. */
  369. uncompressed:
  370. BCOPY(ip, &cs->cs_ip, hlen);
  371. ip->ip_p = cs->cs_id;
  372. comp->last_xmit = cs->cs_id;
  373. return (TYPE_UNCOMPRESSED_TCP);
  374. }
  375. int
  376. sl_uncompress_tcp(u_char **bufp, int len, u_int type, struct slcompress *comp)
  377. {
  378. u_char *hdr, *cp;
  379. int hlen, vjlen;
  380. cp = bufp? *bufp: NULL;
  381. vjlen = sl_uncompress_tcp_core(cp, len, len, type, comp, &hdr, &hlen);
  382. if (vjlen < 0)
  383. return (0); /* error */
  384. if (vjlen == 0)
  385. return (len); /* was uncompressed already */
  386. cp += vjlen;
  387. len -= vjlen;
  388. /*
  389. * At this point, cp points to the first byte of data in the
  390. * packet. If we're not aligned on a 4-byte boundary, copy the
  391. * data down so the ip & tcp headers will be aligned. Then back up
  392. * cp by the tcp/ip header length to make room for the reconstructed
  393. * header (we assume the packet we were handed has enough space to
  394. * prepend 128 bytes of header).
  395. */
  396. if ((intptr_t)cp & 3) {
  397. if (len > 0)
  398. BCOPY(cp, ((intptr_t)cp &~ 3), len);
  399. cp = (u_char *)((intptr_t)cp &~ 3);
  400. }
  401. cp -= hlen;
  402. len += hlen;
  403. BCOPY(hdr, cp, hlen);
  404. *bufp = cp;
  405. return (len);
  406. }
  407. /*
  408. * Uncompress a packet of total length total_len. The first buflen
  409. * bytes are at buf; this must include the entire (compressed or
  410. * uncompressed) TCP/IP header. This procedure returns the length
  411. * of the VJ header, with a pointer to the uncompressed IP header
  412. * in *hdrp and its length in *hlenp.
  413. */
  414. int
  415. sl_uncompress_tcp_core(u_char *buf, int buflen, int total_len, u_int type,
  416. struct slcompress *comp, u_char **hdrp, u_int *hlenp)
  417. {
  418. u_char *cp;
  419. u_int hlen, changes;
  420. struct tcphdr *th;
  421. struct cstate *cs;
  422. struct ip *ip;
  423. u_int16_t *bp;
  424. u_int vjlen;
  425. switch (type) {
  426. case TYPE_UNCOMPRESSED_TCP:
  427. ip = (struct ip *) buf;
  428. if (ip->ip_p >= MAX_STATES)
  429. goto bad;
  430. cs = &comp->rstate[comp->last_recv = ip->ip_p];
  431. comp->flags &=~ SLF_TOSS;
  432. ip->ip_p = IPPROTO_TCP;
  433. /*
  434. * Calculate the size of the TCP/IP header and make sure that
  435. * we don't overflow the space we have available for it.
  436. */
  437. hlen = ip->ip_hl << 2;
  438. if (hlen + sizeof(struct tcphdr) > buflen)
  439. goto bad;
  440. hlen += ((struct tcphdr *)&((char *)ip)[hlen])->th_off << 2;
  441. if (hlen > MAX_HDR || hlen > buflen)
  442. goto bad;
  443. BCOPY(ip, &cs->cs_ip, hlen);
  444. cs->cs_hlen = hlen;
  445. INCR(sls_uncompressedin)
  446. *hdrp = (u_char *) &cs->cs_ip;
  447. *hlenp = hlen;
  448. return (0);
  449. default:
  450. goto bad;
  451. case TYPE_COMPRESSED_TCP:
  452. break;
  453. }
  454. /* We've got a compressed packet. */
  455. INCR(sls_compressedin)
  456. cp = buf;
  457. changes = *cp++;
  458. if (changes & NEW_C) {
  459. /* Make sure the state index is in range, then grab the state.
  460. * If we have a good state index, clear the 'discard' flag. */
  461. if (*cp >= MAX_STATES)
  462. goto bad;
  463. comp->flags &=~ SLF_TOSS;
  464. comp->last_recv = *cp++;
  465. } else {
  466. /* this packet has an implicit state index. If we've
  467. * had a line error since the last time we got an
  468. * explicit state index, we have to toss the packet. */
  469. if (comp->flags & SLF_TOSS) {
  470. INCR(sls_tossed)
  471. return (-1);
  472. }
  473. }
  474. cs = &comp->rstate[comp->last_recv];
  475. hlen = cs->cs_ip.ip_hl << 2;
  476. th = (struct tcphdr *)&((u_char *)&cs->cs_ip)[hlen];
  477. th->th_sum = htons((*cp << 8) | cp[1]);
  478. cp += 2;
  479. if (changes & TCP_PUSH_BIT)
  480. th->th_flags |= TH_PUSH;
  481. else
  482. th->th_flags &=~ TH_PUSH;
  483. switch (changes & SPECIALS_MASK) {
  484. case SPECIAL_I:
  485. {
  486. u_int i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen;
  487. th->th_ack = htonl(ntohl(th->th_ack) + i);
  488. th->th_seq = htonl(ntohl(th->th_seq) + i);
  489. }
  490. break;
  491. case SPECIAL_D:
  492. th->th_seq = htonl(ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len)
  493. - cs->cs_hlen);
  494. break;
  495. default:
  496. if (changes & NEW_U) {
  497. th->th_flags |= TH_URG;
  498. DECODEU(th->th_urp)
  499. } else
  500. th->th_flags &=~ TH_URG;
  501. if (changes & NEW_W)
  502. DECODES(th->th_win)
  503. if (changes & NEW_A)
  504. DECODEL(th->th_ack)
  505. if (changes & NEW_S)
  506. DECODEL(th->th_seq)
  507. break;
  508. }
  509. if (changes & NEW_I) {
  510. DECODES(cs->cs_ip.ip_id)
  511. } else
  512. cs->cs_ip.ip_id = htons(ntohs(cs->cs_ip.ip_id) + 1);
  513. /*
  514. * At this point, cp points to the first byte of data in the
  515. * packet. Fill in the IP total length and update the IP
  516. * header checksum.
  517. */
  518. vjlen = cp - buf;
  519. buflen -= vjlen;
  520. if (buflen < 0)
  521. /* we must have dropped some characters (crc should detect
  522. * this but the old slip framing won't) */
  523. goto bad;
  524. total_len += cs->cs_hlen - vjlen;
  525. cs->cs_ip.ip_len = htons(total_len);
  526. /* recompute the ip header checksum */
  527. bp = (u_int16_t *) &cs->cs_ip;
  528. cs->cs_ip.ip_sum = 0;
  529. for (changes = 0; hlen > 0; hlen -= 2)
  530. changes += *bp++;
  531. changes = (changes & 0xffff) + (changes >> 16);
  532. changes = (changes & 0xffff) + (changes >> 16);
  533. cs->cs_ip.ip_sum = ~ changes;
  534. *hdrp = (u_char *) &cs->cs_ip;
  535. *hlenp = cs->cs_hlen;
  536. return vjlen;
  537. bad:
  538. comp->flags |= SLF_TOSS;
  539. INCR(sls_errorin)
  540. return (-1);
  541. }