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