This source file includes following definitions.
- slhc_init
- slhc_free
- put16
- encode
- pull16
- decode
- slhc_compress
- slhc_uncompress
- slhc_remember
- slhc_toss
- slhc_i_status
- slhc_o_status
- export_slhc_syms
- init_module
- cleanup_module
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53 #include <linux/config.h>
54 #ifdef CONFIG_INET
55
56 #include <linux/module.h>
57
58 #include <linux/types.h>
59 #include <linux/sched.h>
60 #include <linux/mm.h>
61 #include <linux/string.h>
62 #include <linux/socket.h>
63 #include <linux/sockios.h>
64 #include <linux/termios.h>
65 #include <linux/in.h>
66 #include <linux/fcntl.h>
67 #include <linux/inet.h>
68 #include <linux/netdevice.h>
69 #include <net/ip.h>
70 #include <net/protocol.h>
71 #include <net/icmp.h>
72 #include <net/tcp.h>
73 #include <linux/skbuff.h>
74 #include <net/sock.h>
75 #include <linux/errno.h>
76 #include <linux/timer.h>
77 #include <asm/system.h>
78 #include <asm/segment.h>
79 #include <linux/mm.h>
80 #include <net/checksum.h>
81 #include "slhc.h"
82
83 #ifdef __alpha__
84 # include <asm/unaligned.h>
85 #endif
86
87 int last_retran;
88
89 static unsigned char *encode(unsigned char *cp, unsigned short n);
90 static long decode(unsigned char **cpp);
91 static unsigned char * put16(unsigned char *cp, unsigned short x);
92 static unsigned short pull16(unsigned char **cpp);
93 static void export_slhc_syms(void);
94 static has_exported = 0;
95
96
97
98
99 struct slcompress *
100 slhc_init(int rslots, int tslots)
101 {
102 register short i;
103 register struct cstate *ts;
104 struct slcompress *comp;
105
106 if (!has_exported)
107 export_slhc_syms();
108
109 comp = (struct slcompress *)kmalloc(sizeof(struct slcompress),
110 GFP_KERNEL);
111 if (! comp)
112 return NULL;
113
114 memset(comp, 0, sizeof(struct slcompress));
115
116 if ( rslots > 0 && rslots < 256 ) {
117 comp->rstate =
118 (struct cstate *)kmalloc(rslots * sizeof(struct cstate),
119 GFP_KERNEL);
120 if (! comp->rstate)
121 {
122 kfree((unsigned char *)comp);
123 return NULL;
124 }
125 memset(comp->rstate, 0, rslots * sizeof(struct cstate));
126 comp->rslot_limit = rslots - 1;
127 }
128
129 if ( tslots > 0 && tslots < 256 ) {
130 comp->tstate =
131 (struct cstate *)kmalloc(tslots * sizeof(struct cstate),
132 GFP_KERNEL);
133 if (! comp->tstate)
134 {
135 kfree((unsigned char *)comp->rstate);
136 kfree((unsigned char *)comp);
137 return NULL;
138 }
139 memset(comp->tstate, 0, tslots * sizeof(struct cstate));
140 comp->tslot_limit = tslots - 1;
141 }
142
143 comp->xmit_oldest = 0;
144 comp->xmit_current = 255;
145 comp->recv_current = 255;
146
147
148
149
150
151
152 comp->flags |= SLF_TOSS;
153
154 if ( tslots > 0 ) {
155 ts = comp->tstate;
156 for(i = comp->tslot_limit; i > 0; --i){
157 ts[i].cs_this = i;
158 ts[i].next = &(ts[i - 1]);
159 }
160 ts[0].next = &(ts[comp->tslot_limit]);
161 ts[0].cs_this = 0;
162 }
163 MOD_INC_USE_COUNT;
164 return comp;
165 }
166
167
168
169 void
170 slhc_free(struct slcompress *comp)
171 {
172 if ( comp == NULLSLCOMPR )
173 return;
174
175 if ( comp->rstate != NULLSLSTATE )
176 kfree( comp->rstate );
177
178 if ( comp->tstate != NULLSLSTATE )
179 kfree( comp->tstate );
180
181 MOD_DEC_USE_COUNT;
182 kfree( comp );
183 }
184
185
186
187 static inline unsigned char *
188 put16(unsigned char *cp, unsigned short x)
189 {
190 *cp++ = x >> 8;
191 *cp++ = x;
192
193 return cp;
194 }
195
196
197
198 unsigned char *
199 encode(unsigned char *cp, unsigned short n)
200 {
201 if(n >= 256 || n == 0){
202 *cp++ = 0;
203 cp = put16(cp,n);
204 } else {
205 *cp++ = n;
206 }
207 return cp;
208 }
209
210
211 static unsigned short
212 pull16(unsigned char **cpp)
213 {
214 short rval;
215
216 rval = *(*cpp)++;
217 rval <<= 8;
218 rval |= *(*cpp)++;
219 return rval;
220 }
221
222
223 long
224 decode(unsigned char **cpp)
225 {
226 register int x;
227
228 x = *(*cpp)++;
229 if(x == 0){
230 return pull16(cpp) & 0xffff;
231 } else {
232 return x & 0xff;
233 }
234 }
235
236
237
238
239
240
241
242
243 int
244 slhc_compress(struct slcompress *comp, unsigned char *icp, int isize,
245 unsigned char *ocp, unsigned char **cpp, int compress_cid)
246 {
247 register struct cstate *ocs = &(comp->tstate[comp->xmit_oldest]);
248 register struct cstate *lcs = ocs;
249 register struct cstate *cs = lcs->next;
250 register unsigned long deltaS, deltaA;
251 register short changes = 0;
252 int hlen;
253 unsigned char new_seq[16];
254 register unsigned char *cp = new_seq;
255 struct iphdr *ip;
256 struct tcphdr *th, *oth;
257
258 ip = (struct iphdr *) icp;
259
260
261 if(ip->protocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x1fff) ||
262 (ip->frag_off & 32)){
263
264 if(ip->protocol != IPPROTO_TCP)
265 comp->sls_o_nontcp++;
266 else
267 comp->sls_o_tcp++;
268 return isize;
269 }
270
271
272 th = (struct tcphdr *)(((unsigned char *)ip) + ip->ihl*4);
273 hlen = ip->ihl*4 + th->doff*4;
274
275
276
277
278 if(th->syn || th->fin || th->rst ||
279 ! (th->ack)){
280
281 comp->sls_o_tcp++;
282 return isize;
283 }
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298 for ( ; ; ) {
299 if( ip->saddr == cs->cs_ip.saddr
300 && ip->daddr == cs->cs_ip.daddr
301 && th->source == cs->cs_tcp.source
302 && th->dest == cs->cs_tcp.dest)
303 goto found;
304
305
306 if ( cs == ocs )
307 break;
308 lcs = cs;
309 cs = cs->next;
310 comp->sls_o_searches++;
311 };
312
313
314
315
316
317
318
319
320
321 comp->sls_o_misses++;
322 comp->xmit_oldest = lcs->cs_this;
323 goto uncompressed;
324
325 found:
326
327
328
329 if(lcs == ocs) {
330
331 } else if (cs == ocs) {
332
333 comp->xmit_oldest = lcs->cs_this;
334 } else {
335
336 lcs->next = cs->next;
337 cs->next = ocs->next;
338 ocs->next = cs;
339 }
340
341
342
343
344
345
346
347
348
349
350
351
352
353 oth = &cs->cs_tcp;
354
355 if(last_retran
356 || ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl
357 || ip->tos != cs->cs_ip.tos
358 || (ip->frag_off & 64) != (cs->cs_ip.frag_off & 64)
359 || ip->ttl != cs->cs_ip.ttl
360 || th->doff != cs->cs_tcp.doff
361 || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0)
362 || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){
363 goto uncompressed;
364 }
365
366
367
368
369
370
371
372 if(th->urg){
373 deltaS = ntohs(th->urg_ptr);
374 cp = encode(cp,deltaS);
375 changes |= NEW_U;
376 } else if(th->urg_ptr != oth->urg_ptr){
377
378
379
380
381 goto uncompressed;
382 }
383 if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){
384 cp = encode(cp,deltaS);
385 changes |= NEW_W;
386 }
387 if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){
388 if(deltaA > 0x0000ffff)
389 goto uncompressed;
390 cp = encode(cp,deltaA);
391 changes |= NEW_A;
392 }
393 if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){
394 if(deltaS > 0x0000ffff)
395 goto uncompressed;
396 cp = encode(cp,deltaS);
397 changes |= NEW_S;
398 }
399
400 switch(changes){
401 case 0:
402
403
404
405
406
407
408 if(ip->tot_len != cs->cs_ip.tot_len &&
409 ntohs(cs->cs_ip.tot_len) == hlen)
410 break;
411 goto uncompressed;
412 break;
413 case SPECIAL_I:
414 case SPECIAL_D:
415
416
417
418 goto uncompressed;
419 case NEW_S|NEW_A:
420 if(deltaS == deltaA &&
421 deltaS == ntohs(cs->cs_ip.tot_len) - hlen){
422
423 changes = SPECIAL_I;
424 cp = new_seq;
425 }
426 break;
427 case NEW_S:
428 if(deltaS == ntohs(cs->cs_ip.tot_len) - hlen){
429
430 changes = SPECIAL_D;
431 cp = new_seq;
432 }
433 break;
434 }
435 deltaS = ntohs(ip->id) - ntohs(cs->cs_ip.id);
436 if(deltaS != 1){
437 cp = encode(cp,deltaS);
438 changes |= NEW_I;
439 }
440 if(th->psh)
441 changes |= TCP_PUSH_BIT;
442
443
444
445 deltaA = ntohs(th->check);
446 memcpy(&cs->cs_ip,ip,20);
447 memcpy(&cs->cs_tcp,th,20);
448
449
450
451
452
453
454 deltaS = cp - new_seq;
455 if(compress_cid == 0 || comp->xmit_current != cs->cs_this){
456 cp = ocp;
457 *cpp = ocp;
458 *cp++ = changes | NEW_C;
459 *cp++ = cs->cs_this;
460 comp->xmit_current = cs->cs_this;
461 } else {
462 cp = ocp;
463 *cpp = ocp;
464 *cp++ = changes;
465 }
466 cp = put16(cp,(short)deltaA);
467
468 memcpy(cp,new_seq,deltaS);
469 memcpy(cp+deltaS,icp+hlen,isize-hlen);
470 comp->sls_o_compressed++;
471 ocp[0] |= SL_TYPE_COMPRESSED_TCP;
472 return isize - hlen + deltaS + (cp - ocp);
473
474
475
476
477
478 uncompressed:
479 memcpy(&cs->cs_ip,ip,20);
480 memcpy(&cs->cs_tcp,th,20);
481 if (ip->ihl > 5)
482 memcpy(cs->cs_ipopt, ip+1, ((ip->ihl) - 5) * 4);
483 if (th->doff > 5)
484 memcpy(cs->cs_tcpopt, th+1, ((th->doff) - 5) * 4);
485 comp->xmit_current = cs->cs_this;
486 comp->sls_o_uncompressed++;
487 memcpy(ocp, icp, isize);
488 *cpp = ocp;
489 ocp[9] = cs->cs_this;
490 ocp[0] |= SL_TYPE_UNCOMPRESSED_TCP;
491 return isize;
492 }
493
494
495 int
496 slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
497 {
498 register int changes;
499 long x;
500 register struct tcphdr *thp;
501 register struct iphdr *ip;
502 register struct cstate *cs;
503 int len, hdrlen;
504 unsigned char *cp = icp;
505
506
507 comp->sls_i_compressed++;
508 if(isize < 3){
509 comp->sls_i_error++;
510 return 0;
511 }
512 changes = *cp++;
513 if(changes & NEW_C){
514
515
516
517 x = *cp++;
518 if(x < 0 || x > comp->rslot_limit)
519 goto bad;
520
521 comp->flags &=~ SLF_TOSS;
522 comp->recv_current = x;
523 } else {
524
525
526
527 if(comp->flags & SLF_TOSS){
528 comp->sls_i_tossed++;
529 return 0;
530 }
531 }
532 cs = &comp->rstate[comp->recv_current];
533 thp = &cs->cs_tcp;
534 ip = &cs->cs_ip;
535
536 if((x = pull16(&cp)) == -1) {
537 goto bad;
538 }
539 thp->check = htons(x);
540
541 thp->psh = (changes & TCP_PUSH_BIT) ? 1 : 0;
542
543
544
545
546
547
548 hdrlen = ip->ihl * 4 + thp->doff * 4;
549
550 switch(changes & SPECIALS_MASK){
551 case SPECIAL_I:
552 {
553 register short i;
554 i = ntohs(ip->tot_len) - hdrlen;
555 thp->ack_seq = htonl( ntohl(thp->ack_seq) + i);
556 thp->seq = htonl( ntohl(thp->seq) + i);
557 }
558 break;
559
560 case SPECIAL_D:
561 thp->seq = htonl( ntohl(thp->seq) +
562 ntohs(ip->tot_len) - hdrlen);
563 break;
564
565 default:
566 if(changes & NEW_U){
567 thp->urg = 1;
568 if((x = decode(&cp)) == -1) {
569 goto bad;
570 }
571 thp->urg_ptr = htons(x);
572 } else
573 thp->urg = 0;
574 if(changes & NEW_W){
575 if((x = decode(&cp)) == -1) {
576 goto bad;
577 }
578 thp->window = htons( ntohs(thp->window) + x);
579 }
580 if(changes & NEW_A){
581 if((x = decode(&cp)) == -1) {
582 goto bad;
583 }
584 thp->ack_seq = htonl( ntohl(thp->ack_seq) + x);
585 }
586 if(changes & NEW_S){
587 if((x = decode(&cp)) == -1) {
588 goto bad;
589 }
590 thp->seq = htonl( ntohl(thp->seq) + x);
591 }
592 break;
593 }
594 if(changes & NEW_I){
595 if((x = decode(&cp)) == -1) {
596 goto bad;
597 }
598 ip->id = htons (ntohs (ip->id) + x);
599 } else
600 ip->id = htons (ntohs (ip->id) + 1);
601
602
603
604
605
606
607
608 len = isize - (cp - icp);
609 if (len < 0)
610 goto bad;
611 len += hdrlen;
612 ip->tot_len = htons(len);
613 ip->check = 0;
614
615 memmove(icp + hdrlen, cp, len - hdrlen);
616
617 cp = icp;
618 memcpy(cp, ip, 20);
619 cp += 20;
620
621 if (ip->ihl > 5) {
622 memcpy(cp, cs->cs_ipopt, (ip->ihl - 5) * 4);
623 cp += (ip->ihl - 5) * 4;
624 }
625
626 #ifdef __alpha__
627 stw_u(ip_fast_csum(icp, ip->ihl), &((struct iphdr *)icp)->check);
628 #else
629 ((struct iphdr *)icp)->check = ip_fast_csum(icp, ((struct iphdr*)icp)->ihl);
630 #endif
631
632 memcpy(cp, thp, 20);
633 cp += 20;
634
635 if (thp->doff > 5) {
636 memcpy(cp, cs->cs_tcpopt, ((thp->doff) - 5) * 4);
637 cp += ((thp->doff) - 5) * 4;
638 }
639
640 return len;
641 bad:
642 comp->sls_i_error++;
643 return slhc_toss( comp );
644 }
645
646
647 int
648 slhc_remember(struct slcompress *comp, unsigned char *icp, int isize)
649 {
650 register struct cstate *cs;
651 unsigned ihl;
652
653 unsigned char index;
654
655 if(isize < 20) {
656
657 comp->sls_i_runt++;
658 return slhc_toss( comp );
659 }
660
661 ihl = icp[0] & 0xf;
662 if(ihl < 20 / 4){
663
664 comp->sls_i_runt++;
665 return slhc_toss( comp );
666 }
667 index = icp[9];
668 icp[9] = IPPROTO_TCP;
669
670 if (ip_fast_csum(icp, ihl)) {
671
672 comp->sls_i_badcheck++;
673 return slhc_toss( comp );
674 }
675 if(index > comp->rslot_limit) {
676 comp->sls_i_error++;
677 return slhc_toss(comp);
678 }
679
680
681 cs = &comp->rstate[comp->recv_current = index];
682 comp->flags &=~ SLF_TOSS;
683 memcpy(&cs->cs_ip,icp,20);
684 memcpy(&cs->cs_tcp,icp + ihl*4,20);
685 if (ihl > 5)
686 memcpy(cs->cs_ipopt, icp + sizeof(struct iphdr), (ihl - 5) * 4);
687 if (cs->cs_tcp.doff > 5)
688 memcpy(cs->cs_tcpopt, icp + ihl*4 + sizeof(struct tcphdr), (cs->cs_tcp.doff - 5) * 4);
689 cs->cs_hsize = ihl*2 + cs->cs_tcp.doff*2;
690
691
692
693 comp->sls_i_uncompressed++;
694 return isize;
695 }
696
697
698 int
699 slhc_toss(struct slcompress *comp)
700 {
701 if ( comp == NULLSLCOMPR )
702 return 0;
703
704 comp->flags |= SLF_TOSS;
705 return 0;
706 }
707
708
709 void slhc_i_status(struct slcompress *comp)
710 {
711 if (comp != NULLSLCOMPR) {
712 printk("\t%ld Cmp, %ld Uncmp, %ld Bad, %ld Tossed\n",
713 comp->sls_i_compressed,
714 comp->sls_i_uncompressed,
715 comp->sls_i_error,
716 comp->sls_i_tossed);
717 }
718 }
719
720
721 void slhc_o_status(struct slcompress *comp)
722 {
723 if (comp != NULLSLCOMPR) {
724 printk("\t%ld Cmp, %ld Uncmp, %ld AsIs, %ld NotTCP\n",
725 comp->sls_o_compressed,
726 comp->sls_o_uncompressed,
727 comp->sls_o_tcp,
728 comp->sls_o_nontcp);
729 printk("\t%10ld Searches, %10ld Misses\n",
730 comp->sls_o_searches,
731 comp->sls_o_misses);
732 }
733 }
734
735 static struct symbol_table slhc_syms = {
736
737 #include <linux/symtab_begin.h>
738
739 X(slhc_init),
740 X(slhc_free),
741 X(slhc_remember),
742 X(slhc_compress),
743 X(slhc_uncompress),
744 X(slhc_toss),
745 #include <linux/symtab_end.h>
746 };
747
748 static void export_slhc_syms(void)
749 {
750 register_symtab(&slhc_syms);
751 has_exported = 1;
752 }
753
754 #ifdef MODULE
755
756 int init_module(void)
757 {
758 printk("CSLIP: code copyright 1989 Regents of the University of California\n");
759 export_slhc_syms();
760 return 0;
761 }
762
763 void cleanup_module(void)
764 {
765 return;
766 }
767 #endif
768 #endif