Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

950 lines
29 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. vjslip.c
  5. Abstract:
  6. Author:
  7. Thomas J. Dimitri (TommyD)
  8. Environment:
  9. Revision History:
  10. --*/
  11. #include "wan.h"
  12. #define __FILE_SIG__ VJ_FILESIG
  13. #if 0
  14. NPAGED_LOOKASIDE_LIST VJCtxList; // List of free vj context descs
  15. #endif
  16. #define INCR(counter) ++comp->counter;
  17. // A.2 Compression
  18. //
  19. // This routine looks daunting but isn't really. The code splits into four
  20. // approximately equal sized sections: The first quarter manages a
  21. // circularly linked, least-recently-used list of `active' TCP
  22. // connections./47/ The second figures out the sequence/ack/window/urg
  23. // changes and builds the bulk of the compressed packet. The third handles
  24. // the special-case encodings. The last quarter does packet ID and
  25. // connection ID encoding and replaces the original packet header with the
  26. // compressed header.
  27. //
  28. // The arguments to this routine are a pointer to a packet to be
  29. // compressed, a pointer to the compression state data for the serial line,
  30. // and a flag which enables or disables connection id (C bit) compression.
  31. //
  32. // Compression is done `in-place' so, if a compressed packet is created,
  33. // both the start address and length of the incoming packet (the off and
  34. // len fields of m) will be updated to reflect the removal of the original
  35. // header and its replacement by the compressed header. If either a
  36. // compressed or uncompressed packet is created, the compression state is
  37. // updated. This routines returns the packet type for the transmit framer
  38. // (TYPE_IP, TYPE_UNCOMPRESSED_TCP or TYPE_COMPRESSED_TCP).
  39. //
  40. // Because 16 and 32 bit arithmetic is done on various header fields, the
  41. // incoming IP packet must be aligned appropriately (e.g., on a SPARC, the
  42. // IP header is aligned on a 32-bit boundary). Substantial changes would
  43. // have to be made to the code below if this were not true (and it would
  44. // probably be cheaper to byte copy the incoming header to somewhere
  45. // correctly aligned than to make those changes).
  46. //
  47. // Note that the outgoing packet will be aligned arbitrarily (e.g., it
  48. // could easily start on an odd-byte boundary).
  49. //
  50. UCHAR
  51. sl_compress_tcp(
  52. PUUCHAR UNALIGNED *m_off, // Frame start (points to IP header)
  53. ULONG *m_len, // Length of entire frame
  54. ULONG *precomph_len, // Length of TCP/IP header pre-comp
  55. ULONG *postcomph_len, // Length of TCP/IP header post-comp
  56. struct slcompress *comp, // Compression struct for this link
  57. ULONG compress_cid) { // Compress connection id boolean
  58. struct cstate *cs = comp->last_cs->cs_next;
  59. struct ip_v4 UNALIGNED *ip = (struct ip_v4 UNALIGNED *)*m_off;
  60. struct ip_v4 UNALIGNED *csip;
  61. ULONG hlen = ip->ip_hl & 0x0F; // last 4 bits are the length
  62. struct tcphdr UNALIGNED *oth; /* last TCP header */
  63. struct tcphdr UNALIGNED *th; /* current TCP header */
  64. // ----------------------------
  65. // 47. The two most common operations on the connection list are a `find'
  66. // that terminates at the first entry (a new packet for the most recently
  67. // used connection) and moving the last entry on the list to the head of
  68. // the list (the first packet from a new connection). A circular list
  69. // efficiently handles these two operations.
  70. ULONG deltaS, deltaA; /* general purpose temporaries */
  71. ULONG changes = 0; /* change mask */
  72. UCHAR new_seq[16]; /* changes from last to current */
  73. UCHAR UNALIGNED *cp = new_seq;
  74. USHORT ip_len;
  75. /*
  76. * Bail if this is an IP fragment or if the TCP packet isn't
  77. * `compressible' (i.e., ACK isn't set or some other control bit is
  78. * set). Or if it does not contain the TCP protocol.
  79. */
  80. if ((ip->ip_off & 0xff3f) || *m_len < 40 || ip->ip_p != IPPROTO_TCP)
  81. return (TYPE_IP);
  82. th = (struct tcphdr UNALIGNED *) & ((ULONG UNALIGNED *) ip)[hlen];
  83. if ((th->th_flags & (TH_SYN | TH_FIN | TH_RST | TH_ACK)) != TH_ACK)
  84. return (TYPE_IP);
  85. //
  86. // The TCP/IP stack is propagating the padding bytes that it
  87. // is receiving off of the LAN. This shows up here as a
  88. // packet that has a length that is greater than the IP datagram
  89. // length. We will add this work around for now.
  90. //
  91. if (*m_len > ntohs(ip->ip_len)) {
  92. *m_len = ntohs(ip->ip_len);
  93. }
  94. /*
  95. * Packet is compressible -- we're going to send either a
  96. * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way we need to
  97. * locate (or create) the connection state. Special case the most
  98. * recently used connection since it's most likely to be used again &
  99. * we don't have to do any reordering if it's used.
  100. */
  101. //
  102. // Keep stats here
  103. //
  104. INCR(OutPackets);
  105. csip = (struct ip_v4 UNALIGNED*)&cs->cs_ip;
  106. if (ip->ip_src.s_addr != csip->ip_src.s_addr ||
  107. ip->ip_dst.s_addr != csip->ip_dst.s_addr ||
  108. *(ULONG UNALIGNED *) th != ((ULONG UNALIGNED *) csip)[csip->ip_hl & 0x0F]) {
  109. /*
  110. * Wasn't the first -- search for it.
  111. *
  112. * States are kept in a circularly linked list with last_cs
  113. * pointing to the end of the list. The list is kept in lru
  114. * order by moving a state to the head of the list whenever
  115. * it is referenced. Since the list is short and,
  116. * empirically, the connection we want is almost always near
  117. * the front, we locate states via linear search. If we
  118. * don't find a state for the datagram, the oldest state is
  119. * (re-)used.
  120. */
  121. struct cstate *lcs;
  122. struct cstate *lastcs = comp->last_cs;
  123. do {
  124. lcs = cs;
  125. cs = cs->cs_next;
  126. INCR(OutSearches);
  127. csip = (struct ip_v4 UNALIGNED*)&cs->cs_ip;
  128. if (ip->ip_src.s_addr == csip->ip_src.s_addr &&
  129. ip->ip_dst.s_addr == csip->ip_dst.s_addr &&
  130. *(ULONG UNALIGNED *) th == ((ULONG UNALIGNED *) csip)[cs->cs_ip.ip_hl & 0x0F])
  131. goto found;
  132. } while (cs != lastcs);
  133. /*
  134. * Didn't find it -- re-use oldest cstate. Send an
  135. * uncompressed packet that tells the other side what
  136. * connection number we're using for this conversation. Note
  137. * that since the state list is circular, the oldest state
  138. * points to the newest and we only need to set last_cs to
  139. * update the lru linkage.
  140. */
  141. INCR(OutMisses);
  142. //
  143. // A miss!
  144. //
  145. comp->last_cs = lcs;
  146. hlen += (th->th_off >> 4);
  147. hlen <<= 2;
  148. if (hlen > *m_len) {
  149. return(TYPE_IP);
  150. }
  151. goto uncompressed;
  152. found:
  153. /* Found it -- move to the front on the connection list. */
  154. if (cs == lastcs)
  155. comp->last_cs = lcs;
  156. else {
  157. lcs->cs_next = cs->cs_next;
  158. cs->cs_next = lastcs->cs_next;
  159. lastcs->cs_next = cs;
  160. }
  161. }
  162. /*
  163. * Make sure that only what we expect to change changed. The first
  164. * line of the `if' checks the IP protocol version, header length &
  165. * type of service. The 2nd line checks the "Don't fragment" bit.
  166. * The 3rd line checks the time-to-live and protocol (the protocol
  167. * check is unnecessary but costless). The 4th line checks the TCP
  168. * header length. The 5th line checks IP options, if any. The 6th
  169. * line checks TCP options, if any. If any of these things are
  170. * different between the previous & current datagram, we send the
  171. * current datagram `uncompressed'.
  172. */
  173. oth = (struct tcphdr UNALIGNED *) & ((ULONG UNALIGNED *) csip)[hlen];
  174. deltaS = hlen;
  175. hlen += (th->th_off >> 4);
  176. hlen <<= 2;
  177. //
  178. // Bug fix? It's in cslip.tar.Z
  179. //
  180. if (hlen > *m_len) {
  181. NdisWanDbgOut(DBG_FAILURE, DBG_VJ,("Bad TCP packet length"));
  182. return(TYPE_IP);
  183. }
  184. if (((USHORT UNALIGNED *) ip)[0] != ((USHORT UNALIGNED *) csip)[0] ||
  185. ((USHORT UNALIGNED *) ip)[3] != ((USHORT UNALIGNED *) csip)[3] ||
  186. ((USHORT UNALIGNED *) ip)[4] != ((USHORT UNALIGNED *) csip)[4] ||
  187. (th->th_off >> 4) != (oth->th_off >> 4) ||
  188. (deltaS > 5 &&
  189. memcmp((UCHAR UNALIGNED *)(ip + 1), (UCHAR UNALIGNED *)(csip + 1), (deltaS - 5) << 2)) ||
  190. ((th->th_off >> 4) > 5 &&
  191. memcmp((UCHAR UNALIGNED *)(th + 1), (UCHAR UNALIGNED *)(oth + 1), ((th->th_off >> 4) - 5) << 2))) {
  192. goto uncompressed;
  193. }
  194. /*
  195. * Figure out which of the changing fields changed. The receiver
  196. * expects changes in the order: urgent, window, ack, seq.
  197. */
  198. if (th->th_flags & TH_URG) {
  199. deltaS = ntohs(th->th_urp);
  200. ENCODEZ(deltaS);
  201. changes |= NEW_U;
  202. } else if (th->th_urp != oth->th_urp) {
  203. /*
  204. * argh! URG not set but urp changed -- a sensible
  205. * implementation should never do this but RFC793 doesn't
  206. * prohibit the change so we have to deal with it.
  207. */
  208. goto uncompressed;
  209. }
  210. if (deltaS = (USHORT) (ntohs(th->th_win) - ntohs(oth->th_win))) {
  211. ENCODE(deltaS);
  212. changes |= NEW_W;
  213. }
  214. if (deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack)) {
  215. if (deltaA > 0xffff) {
  216. goto uncompressed;
  217. }
  218. ENCODE(deltaA);
  219. changes |= NEW_A;
  220. }
  221. if (deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq)) {
  222. if (deltaS > 0xffff) {
  223. goto uncompressed;
  224. }
  225. ENCODE(deltaS);
  226. changes |= NEW_S;
  227. }
  228. ip_len = ntohs(csip->ip_len);
  229. /*
  230. * Look for the special-case encodings.
  231. */
  232. switch (changes) {
  233. case 0:
  234. /*
  235. * Nothing changed. If this packet contains data and the last
  236. * one didn't, this is probably a data packet following an
  237. * ack (normal on an interactive connection) and we send it
  238. * compressed. Otherwise it's probably a retransmit,
  239. * retransmitted ack or window probe. Send it uncompressed
  240. * in case the other side missed the compressed version.
  241. */
  242. if (ip->ip_len != csip->ip_len &&
  243. ip_len == hlen)
  244. break;
  245. /* (fall through) */
  246. case SPECIAL_I:
  247. case SPECIAL_D:
  248. /*
  249. * Actual changes match one of our special case encodings --
  250. * send packet uncompressed.
  251. */
  252. goto uncompressed;
  253. case NEW_S | NEW_A:
  254. if (deltaS == deltaA &&
  255. deltaS == (ip_len - hlen)) {
  256. /* special case for echoed terminal traffic */
  257. changes = SPECIAL_I;
  258. cp = new_seq;
  259. }
  260. break;
  261. case NEW_S:
  262. if (deltaS == (ip_len - hlen)) {
  263. /* special case for data xfer */
  264. changes = SPECIAL_D;
  265. cp = new_seq;
  266. }
  267. break;
  268. }
  269. deltaS = ntohs(ip->ip_id) - ntohs(csip->ip_id);
  270. if (deltaS != 1) {
  271. ENCODEZ(deltaS);
  272. changes |= NEW_I;
  273. }
  274. if (th->th_flags & TH_PUSH)
  275. changes |= TCP_PUSH_BIT;
  276. /*
  277. * Grab the cksum before we overwrite it below. Then update our
  278. * state with this packet's header.
  279. */
  280. deltaA = (th->th_sumhi << 8) + th->th_sumlo;
  281. NdisMoveMemory((UCHAR UNALIGNED *)csip,
  282. (UCHAR UNALIGNED *)ip,
  283. hlen);
  284. /*
  285. * We want to use the original packet as our compressed packet. (cp -
  286. * new_seq) is the number of bytes we need for compressed sequence
  287. * numbers. In addition we need one byte for the change mask, one
  288. * for the connection id and two for the tcp checksum. So, (cp -
  289. * new_seq) + 4 bytes of header are needed. hlen is how many bytes
  290. * of the original packet to toss so subtract the two to get the new
  291. * packet size.
  292. */
  293. deltaS = (ULONG)(cp - new_seq);
  294. cp = (UCHAR UNALIGNED *) ip;
  295. *precomph_len = hlen;
  296. if (compress_cid == 0 || comp->last_xmit != cs->cs_id) {
  297. comp->last_xmit = cs->cs_id;
  298. hlen -= deltaS + 4;
  299. *postcomph_len = deltaS + 4;
  300. cp += hlen;
  301. *cp++ = (UCHAR)(changes | NEW_C);
  302. *cp++ = cs->cs_id;
  303. } else {
  304. hlen -= deltaS + 3;
  305. *postcomph_len = deltaS + 3;
  306. cp += hlen;
  307. *cp++ = (UCHAR)changes;
  308. }
  309. *m_len -= hlen;
  310. *m_off += hlen;
  311. *cp++ = (UCHAR)(deltaA >> 8);
  312. *cp++ = (UCHAR)(deltaA);
  313. NdisMoveMemory((UCHAR UNALIGNED *)cp,
  314. (UCHAR UNALIGNED *)new_seq,
  315. deltaS);
  316. INCR(OutCompressed);
  317. return (TYPE_COMPRESSED_TCP);
  318. uncompressed:
  319. /*
  320. * Update connection state cs & send uncompressed packet
  321. * ('uncompressed' means a regular ip/tcp packet but with the
  322. * 'conversation id' we hope to use on future compressed packets in
  323. * the protocol field).
  324. */
  325. NdisMoveMemory((UCHAR UNALIGNED *)csip,
  326. (UCHAR UNALIGNED *)ip,
  327. hlen);
  328. ip->ip_p = cs->cs_id;
  329. comp->last_xmit = cs->cs_id;
  330. return (TYPE_UNCOMPRESSED_TCP);
  331. }
  332. // A.3 Decompression
  333. //
  334. // This routine decompresses a received packet. It is called with a
  335. // pointer to the packet, the packet length and type, and a pointer to the
  336. // compression state structure for the incoming serial line. It returns a
  337. // pointer to the resulting packet or zero if there were errors in the
  338. // incoming packet. If the packet is COMPRESSED_TCP or UNCOMPRESSED_TCP,
  339. // the compression state will be updated.
  340. //
  341. // The new packet will be constructed in-place. That means that there must
  342. // be 128 bytes of free space in front of bufp to allow room for the
  343. // reconstructed IP and TCP headers. The reconstructed packet will be
  344. // aligned on a 32-bit boundary.
  345. //
  346. //LONG
  347. //sl_uncompress_tcp(
  348. // PUUCHAR UNALIGNED *bufp,
  349. // LONG len,
  350. // UCHAR type,
  351. // struct slcompress *comp) {
  352. LONG
  353. sl_uncompress_tcp(
  354. PUUCHAR UNALIGNED *InBuffer,
  355. PLONG InLength,
  356. UCHAR UNALIGNED *OutBuffer,
  357. PLONG OutLength,
  358. UCHAR type,
  359. struct slcompress *comp
  360. )
  361. {
  362. UCHAR UNALIGNED *cp;
  363. LONG inlen;
  364. LONG hlen, changes;
  365. struct tcphdr UNALIGNED *th;
  366. struct cstate *cs;
  367. struct ip_v4 UNALIGNED *ip;
  368. inlen = *InLength;
  369. switch (type) {
  370. case TYPE_ERROR:
  371. default:
  372. NdisWanDbgOut(DBG_FAILURE, DBG_VJ, ("Packet transmission error type 0x%.2x",type));
  373. goto bad;
  374. case TYPE_IP:
  375. break;
  376. case TYPE_UNCOMPRESSED_TCP:
  377. /*
  378. * Locate the saved state for this connection. If the state
  379. * index is legal, clear the 'discard' flag.
  380. */
  381. ip = (struct ip_v4 UNALIGNED *) *InBuffer;
  382. if (ip->ip_p >= comp->MaxStates) {
  383. NdisWanDbgOut(DBG_FAILURE, DBG_VJ, ("Max state exceeded %u", ip->ip_p));
  384. goto bad;
  385. }
  386. cs = &comp->rstate[comp->last_recv = ip->ip_p];
  387. comp->flags &= ~SLF_TOSS;
  388. /*
  389. * Restore the IP protocol field then save a copy of this
  390. * packet header. (The checksum is zeroed in the copy so we
  391. * don't have to zero it each time we process a compressed
  392. * packet.
  393. */
  394. hlen = ip->ip_hl & 0x0F;
  395. hlen += ((struct tcphdr UNALIGNED *) & ((ULONG UNALIGNED *) ip)[hlen])->th_off >> 4;
  396. hlen <<= 2;
  397. if (hlen > inlen) {
  398. NdisWanDbgOut(DBG_FAILURE, DBG_VJ, ("recv'd runt uncompressed packet %d %d", hlen, inlen));
  399. goto bad;
  400. }
  401. NdisMoveMemory((PUCHAR)&cs->cs_ip,
  402. (PUCHAR)ip,
  403. hlen);
  404. cs->cs_ip.ip_p = IPPROTO_TCP;
  405. NdisMoveMemory((PUCHAR)OutBuffer,
  406. (PUCHAR)&cs->cs_ip,
  407. hlen);
  408. cs->cs_ip.ip_sum = 0;
  409. cs->cs_hlen = (USHORT)hlen;
  410. *InBuffer = (PUCHAR)ip + hlen;
  411. *InLength = inlen - hlen;
  412. *OutLength = hlen;
  413. INCR(InUncompressed);
  414. return (inlen);
  415. case TYPE_COMPRESSED_TCP:
  416. break;
  417. }
  418. /* We've got a compressed packet. */
  419. INCR(InCompressed);
  420. cp = *InBuffer;
  421. changes = *cp++;
  422. if (changes & NEW_C) {
  423. /*
  424. * Make sure the state index is in range, then grab the
  425. * state. If we have a good state index, clear the 'discard'
  426. * flag.
  427. */
  428. if (*cp >= comp->MaxStates) {
  429. NdisWanDbgOut(DBG_FAILURE, DBG_VJ, ("MaxState of %u too big", *cp));
  430. goto bad;
  431. }
  432. comp->flags &= ~SLF_TOSS;
  433. comp->last_recv = *cp++;
  434. } else {
  435. /*
  436. * This packet has an implicit state index. If we've had a
  437. * line error since the last time we got an explicit state
  438. * index, we have to toss the packet.
  439. */
  440. if (comp->flags & SLF_TOSS) {
  441. NdisWanDbgOut(DBG_FAILURE, DBG_VJ,("Packet has state index, have to toss it"));
  442. INCR(InTossed);
  443. return (0);
  444. }
  445. }
  446. /*
  447. * Find the state then fill in the TCP checksum and PUSH bit.
  448. */
  449. cs = &comp->rstate[comp->last_recv];
  450. //
  451. // If there was a line error and we did not get notified we could
  452. // miss a TYPE_UNCOMPRESSED_TCP which would leave us with an
  453. // un-init'd cs!
  454. //
  455. if (cs->cs_hlen == 0) {
  456. NdisWanDbgOut(DBG_FAILURE, DBG_VJ,("Un-Init'd state!"));
  457. goto bad;
  458. }
  459. hlen = (cs->cs_ip.ip_hl & 0x0F) << 2;
  460. th = (struct tcphdr UNALIGNED *) & ((UCHAR UNALIGNED *) &cs->cs_ip)[hlen];
  461. th->th_sumhi = cp[0];
  462. th->th_sumlo = cp[1];
  463. cp += 2;
  464. if (changes & TCP_PUSH_BIT)
  465. th->th_flags |= TH_PUSH;
  466. else
  467. th->th_flags &= ~TH_PUSH;
  468. /*
  469. * Fix up the state's ack, seq, urg and win fields based on the
  470. * changemask.
  471. */
  472. switch (changes & SPECIALS_MASK) {
  473. case SPECIAL_I:
  474. {
  475. UCHAR UNALIGNED * piplen=(UCHAR UNALIGNED *)&(cs->cs_ip.ip_len);
  476. UCHAR UNALIGNED * ptcplen;
  477. ULONG tcplen;
  478. ULONG i;
  479. i = ((piplen[0] << 8) + piplen[1]) - cs->cs_hlen;
  480. // th->th_ack = htonl(ntohl(th->th_ack) + i);
  481. ptcplen=(UCHAR UNALIGNED *)&(th->th_ack);
  482. tcplen=(ptcplen[0] << 24) + (ptcplen[1] << 16) +
  483. (ptcplen[2] << 8) + ptcplen[3] + i;
  484. ptcplen[3]=(UCHAR)(tcplen);
  485. ptcplen[2]=(UCHAR)(tcplen >> 8);
  486. ptcplen[1]=(UCHAR)(tcplen >> 16);
  487. ptcplen[0]=(UCHAR)(tcplen >> 24);
  488. // th->th_seq = htonl(ntohl(th->th_seq) + i);
  489. ptcplen=(UCHAR UNALIGNED *)&(th->th_seq);
  490. tcplen=(ptcplen[0] << 24) + (ptcplen[1] << 16) +
  491. (ptcplen[2] << 8) + ptcplen[3] + i;
  492. ptcplen[3]=(UCHAR)(tcplen);
  493. ptcplen[2]=(UCHAR)(tcplen >> 8);
  494. ptcplen[1]=(UCHAR)(tcplen >> 16);
  495. ptcplen[0]=(UCHAR)(tcplen >> 24);
  496. }
  497. break;
  498. case SPECIAL_D:
  499. {
  500. // th->th_seq = htonl(ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len)
  501. // - cs->cs_hlen);
  502. UCHAR UNALIGNED *piplen=(UCHAR UNALIGNED *)&(cs->cs_ip.ip_len);
  503. UCHAR UNALIGNED *ptcplen;
  504. ULONG tcplen;
  505. ULONG i;
  506. i = ((piplen[0] << 8) + piplen[1]) - cs->cs_hlen;
  507. ptcplen=(UCHAR UNALIGNED *)&(th->th_seq);
  508. tcplen=(ptcplen[0] << 24) + (ptcplen[1] << 16) +
  509. (ptcplen[2] << 8) + ptcplen[3] + i;
  510. ptcplen[3]=(UCHAR)(tcplen);
  511. ptcplen[2]=(UCHAR)(tcplen >> 8);
  512. ptcplen[1]=(UCHAR)(tcplen >> 16);
  513. ptcplen[0]=(UCHAR)(tcplen >> 24);
  514. }
  515. break;
  516. default:
  517. if (changes & NEW_U) {
  518. th->th_flags |= TH_URG;
  519. DECODEU(th->th_urp)
  520. } else
  521. th->th_flags &= ~TH_URG;
  522. if (changes & NEW_W)
  523. DECODES(th->th_win);
  524. if (changes & NEW_A)
  525. DECODEL(th->th_ack)
  526. if (changes & NEW_S)
  527. DECODEL(th->th_seq)
  528. break;
  529. }
  530. /* Update the IP ID */
  531. if (changes & NEW_I) {
  532. DECODES(cs->cs_ip.ip_id)
  533. } else {
  534. USHORT id;
  535. UCHAR UNALIGNED *pid = (UCHAR UNALIGNED *)&(cs->cs_ip.ip_id);
  536. // cs->cs_ip.ip_id = htons(ntohs(cs->cs_ip.ip_id) + 1);
  537. id=(pid[0] << 8) + pid[1] + 1;
  538. pid[0]=(UCHAR)(id >> 8);
  539. pid[1]=(UCHAR)(id);
  540. }
  541. /*
  542. * At this point, cp points to the first byte of data in the packet.
  543. * If we're not aligned on a 4-byte boundary, copy the data down so
  544. * the IP & TCP headers will be aligned. Then back up cp by the
  545. * TCP/IP header length to make room for the reconstructed header (we
  546. * assume the packet we were handed has enough space to prepend 128
  547. * bytes of header). Adjust the lenth to account for the new header
  548. * & fill in the IP total length.
  549. */
  550. // len -= (cp - *bufp);
  551. inlen -= (ULONG)(cp - *InBuffer);
  552. if (inlen < 0) {
  553. /*
  554. * we must have dropped some characters (crc should detect
  555. * this but the old slip framing won't)
  556. */
  557. NdisWanDbgOut(DBG_FAILURE, DBG_VJ,("len has dropped below 0!"));
  558. goto bad;
  559. }
  560. //
  561. // Who Cares about 4 byte alignement! It's just a useless big copy!
  562. //
  563. // if ((ULONG) cp & 3) {
  564. // if (len > 0)
  565. // //
  566. // // BUG BUG we want OVBCOPY..
  567. // //
  568. // NdisMoveMemory(
  569. // (PUCHAR)((ULONG) cp & ~3),
  570. // cp,
  571. // len);
  572. // cp = (PUCHAR) ((ULONG) cp & ~3);
  573. // }
  574. // cp -= cs->cs_hlen;
  575. // len += cs->cs_hlen;
  576. // cs->cs_ip.ip_len = htons(len);
  577. cs->cs_ip.ip_len = htons(inlen + cs->cs_hlen);
  578. // NdisMoveMemory(
  579. // (PUCHAR)cp,
  580. // (PUCHAR)&cs->cs_ip,
  581. // cs->cs_hlen);
  582. NdisMoveMemory((PUCHAR)OutBuffer,
  583. (PUCHAR)&cs->cs_ip,
  584. cs->cs_hlen);
  585. // *bufp = cp;
  586. *InBuffer = cp;
  587. *InLength = inlen;
  588. *OutLength = cs->cs_hlen;
  589. /* recompute the ip header checksum */
  590. {
  591. // USHORT UNALIGNED * bp = (USHORT UNALIGNED *) cp;
  592. USHORT UNALIGNED * bp = (USHORT UNALIGNED *) OutBuffer;
  593. for (changes = 0; hlen > 0; hlen -= 2)
  594. changes += *bp++;
  595. changes = (changes & 0xffff) + (changes >> 16);
  596. changes = (changes & 0xffff) + (changes >> 16);
  597. // ((struct ip_v4 UNALIGNED *) cp)->ip_sum = (USHORT)~changes;
  598. ((struct ip_v4 UNALIGNED *) OutBuffer)->ip_sum = (USHORT)~changes;
  599. }
  600. return (inlen + cs->cs_hlen);
  601. bad:
  602. comp->flags |= SLF_TOSS;
  603. INCR(InErrors);
  604. return (0);
  605. }
  606. // A.4 Initialization
  607. //
  608. // This routine initializes the state structure for both the transmit and
  609. // receive halves of some serial line. It must be called each time the
  610. // line is brought up.
  611. //
  612. VOID
  613. WanInitVJ(
  614. VOID
  615. )
  616. {
  617. #if 0
  618. NdisInitializeNPagedLookasideList(&VJCtxList,
  619. NULL,
  620. NULL,
  621. 0,
  622. sizeof(slcompress),
  623. VJCTX_TAG,
  624. 0);
  625. #endif
  626. }
  627. VOID
  628. WanDeleteVJ(
  629. VOID
  630. )
  631. {
  632. #if 0
  633. NdisDeleteNPagedLookasideList(&VJCtxList);
  634. #endif
  635. }
  636. NDIS_STATUS
  637. sl_compress_init(
  638. struct slcompress **retcomp,
  639. UCHAR MaxStates
  640. )
  641. {
  642. ULONG i;
  643. struct cstate *tstate; // = comp->tstate;
  644. struct slcompress *comp;
  645. comp = *retcomp;
  646. //
  647. // Do we need to allocate memory for this bundle
  648. //
  649. if (comp == NULL) {
  650. NdisWanAllocateMemory(&comp, sizeof(slcompress), VJCOMPRESS_TAG);
  651. //
  652. // If there was no memory to allocate
  653. //
  654. if (comp == NULL) {
  655. return(NDIS_STATUS_RESOURCES);
  656. }
  657. }
  658. tstate = comp->tstate;
  659. /*
  660. * Clean out any junk left from the last time line was used.
  661. */
  662. NdisZeroMemory(
  663. (PUCHAR) comp,
  664. sizeof(*comp));
  665. /*
  666. * Link the transmit states into a circular list.
  667. */
  668. for (i = MaxStates - 1; i > 0; --i) {
  669. tstate[i].cs_id = (UCHAR)i;
  670. tstate[i].cs_next = &tstate[i - 1];
  671. }
  672. tstate[0].cs_next = &tstate[MaxStates - 1];
  673. tstate[0].cs_id = 0;
  674. comp->last_cs = &tstate[0];
  675. /*
  676. * Make sure we don't accidentally do CID compression
  677. * (assumes MAX_VJ_STATES < 255).
  678. */
  679. comp->last_recv = 255;
  680. comp->last_xmit = 255;
  681. comp->flags = SLF_TOSS;
  682. comp->MaxStates=MaxStates;
  683. *retcomp = comp;
  684. return (NDIS_STATUS_SUCCESS);
  685. }
  686. VOID
  687. sl_compress_terminate(
  688. struct slcompress **comp
  689. )
  690. {
  691. if (*comp != NULL) {
  692. NdisWanFreeMemory(*comp);
  693. *comp = NULL;
  694. }
  695. }
  696. // A.5 Berkeley Unix dependencies
  697. //
  698. // Note: The following is of interest only if you are trying to bring the
  699. // sample code up on a system that is not derived from 4BSD (Berkeley
  700. // Unix).
  701. //
  702. // The code uses the normal Berkeley Unix header files (from
  703. // /usr/include/netinet) for definitions of the structure of IP and TCP
  704. // headers. The structure tags tend to follow the protocol RFCs closely
  705. // and should be obvious even if you do not have access to a 4BSD
  706. // system./48/
  707. //
  708. // ----------------------------
  709. // 48. In the event they are not obvious, the header files (and all the
  710. // Berkeley networking code) can be anonymous ftp'd from host
  711. //
  712. //
  713. // The macro BCOPY(src, dst, amt) is invoked to copy amt bytes from src to
  714. // dst. In BSD, it translates into a call to BCOPY. If you have the
  715. // misfortune to be running System-V Unix, it can be translated into a call
  716. // to memcpy. The macro OVBCOPY(src, dst, amt) is used to copy when src
  717. // and dst overlap (i.e., when doing the 4-byte alignment copy). In the
  718. // BSD kernel, it translates into a call to ovbcopy. Since AT&T botched
  719. // the definition of memcpy, this should probably translate into a copy
  720. // loop under System-V.
  721. //
  722. // The macro BCMP(src, dst, amt) is invoked to compare amt bytes of src and
  723. // dst for equality. In BSD, it translates into a call to bcmp. In
  724. // System-V, it can be translated into a call to memcmp or you can write a
  725. // routine to do the compare. The routine should return zero if all bytes
  726. // of src and dst are equal and non-zero otherwise.
  727. //
  728. // The routine ntohl(dat) converts (4 byte) long dat from network byte
  729. // order to host byte order. On a reasonable cpu this can be the no-op
  730. // macro:
  731. // #define ntohl(dat) (dat)
  732. //
  733. // On a Vax or IBM PC (or anything with Intel byte order), you will have to
  734. // define a macro or routine to rearrange bytes.
  735. //
  736. // The routine ntohs(dat) is like ntohl but converts (2 byte) shorts
  737. // instead of longs. The routines htonl(dat) and htons(dat) do the inverse
  738. // transform (host to network byte order) for longs and shorts.
  739. //
  740. // A struct mbuf is used in the call to sl_compress_tcp because that
  741. // routine needs to modify both the start address and length if the
  742. // incoming packet is compressed. In BSD, an mbuf is the kernel's buffer
  743. // management structure. If other systems, the following definition should
  744. // be sufficient:
  745. //
  746. // struct mbuf {
  747. // UCHAR *m_off; /* pointer to start of data */
  748. // int m_len; /* length of data */
  749. // };
  750. //
  751. // #define mtod(m, t) ((t)(m->m_off))
  752. //
  753. //
  754. // B Compatibility with past mistakes
  755. //
  756. //
  757. // When combined with the modern PPP serial line protocol[9], the use of
  758. // header compression is automatic and invisible to the user.
  759. // Unfortunately, many sites have existing users of the SLIP described in
  760. // [12] which doesn't allow for different protocol types to distinguish
  761. // header compressed packets from IP packets or for version numbers or an
  762. // option exchange that could be used to automatically negotiate header
  763. // compression.
  764. //
  765. // The author has used the following tricks to allow header compressed SLIP
  766. // to interoperate with the existing servers and clients. Note that these
  767. // are hacks for compatibility with past mistakes and should be offensive
  768. // to any right thinking person. They are offered solely to ease the pain
  769. // of running SLIP while users wait patiently for vendors to release PPP.
  770. //
  771. //
  772. // B.1 Living without a framing `type' byte
  773. //
  774. // The bizarre packet type numbers in sec. A.1 were chosen to allow a
  775. // `packet type' to be sent on lines where it is undesirable or impossible
  776. // to add an explicit type byte. Note that the first byte of an IP packet
  777. // always contains `4' (the IP protocol version) in the top four bits. And
  778. // that the most significant bit of the first byte of the compressed header
  779. // is ignored. Using the packet types in sec. A.1, the type can be encoded
  780. // in the most significant bits of the outgoing packet using the code
  781. //
  782. // p->dat[0] |= sl_compress_tcp(p, comp);
  783. //
  784. // and decoded on the receive side by
  785. //
  786. // if (p->dat[0] & 0x80)
  787. // type = TYPE_COMPRESSED_TCP;
  788. // else if (p->dat[0] >= 0x70) {
  789. // type = TYPE_UNCOMPRESSED_TCP;
  790. // p->dat[0] &=~ 0x30;
  791. // } else
  792. // type = TYPE_IP;
  793. // status = sl_uncompress_tcp(p, type, comp);