0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053 #include <linux/module.h>
0054 #include <linux/slab.h>
0055 #include <linux/types.h>
0056 #include <linux/string.h>
0057 #include <linux/errno.h>
0058 #include <linux/kernel.h>
0059 #include <net/slhc_vj.h>
0060
0061 #ifdef CONFIG_INET
0062
0063 #include <linux/mm.h>
0064 #include <linux/socket.h>
0065 #include <linux/sockios.h>
0066 #include <linux/termios.h>
0067 #include <linux/in.h>
0068 #include <linux/fcntl.h>
0069 #include <linux/inet.h>
0070 #include <linux/netdevice.h>
0071 #include <net/ip.h>
0072 #include <net/protocol.h>
0073 #include <net/icmp.h>
0074 #include <net/tcp.h>
0075 #include <linux/skbuff.h>
0076 #include <net/sock.h>
0077 #include <linux/timer.h>
0078 #include <linux/uaccess.h>
0079 #include <net/checksum.h>
0080 #include <asm/unaligned.h>
0081
0082 static unsigned char *encode(unsigned char *cp, unsigned short n);
0083 static long decode(unsigned char **cpp);
0084 static unsigned char * put16(unsigned char *cp, unsigned short x);
0085 static unsigned short pull16(unsigned char **cpp);
0086
0087
0088
0089
0090
0091 struct slcompress *
0092 slhc_init(int rslots, int tslots)
0093 {
0094 short i;
0095 struct cstate *ts;
0096 struct slcompress *comp;
0097
0098 if (rslots < 0 || rslots > 255 || tslots < 0 || tslots > 255)
0099 return ERR_PTR(-EINVAL);
0100
0101 comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL);
0102 if (! comp)
0103 goto out_fail;
0104
0105 if (rslots > 0) {
0106 size_t rsize = rslots * sizeof(struct cstate);
0107 comp->rstate = kzalloc(rsize, GFP_KERNEL);
0108 if (! comp->rstate)
0109 goto out_free;
0110 comp->rslot_limit = rslots - 1;
0111 }
0112
0113 if (tslots > 0) {
0114 size_t tsize = tslots * sizeof(struct cstate);
0115 comp->tstate = kzalloc(tsize, GFP_KERNEL);
0116 if (! comp->tstate)
0117 goto out_free2;
0118 comp->tslot_limit = tslots - 1;
0119 }
0120
0121 comp->xmit_oldest = 0;
0122 comp->xmit_current = 255;
0123 comp->recv_current = 255;
0124
0125
0126
0127
0128
0129
0130 comp->flags |= SLF_TOSS;
0131
0132 if ( tslots > 0 ) {
0133 ts = comp->tstate;
0134 for(i = comp->tslot_limit; i > 0; --i){
0135 ts[i].cs_this = i;
0136 ts[i].next = &(ts[i - 1]);
0137 }
0138 ts[0].next = &(ts[comp->tslot_limit]);
0139 ts[0].cs_this = 0;
0140 }
0141 return comp;
0142
0143 out_free2:
0144 kfree(comp->rstate);
0145 out_free:
0146 kfree(comp);
0147 out_fail:
0148 return ERR_PTR(-ENOMEM);
0149 }
0150
0151
0152
0153 void
0154 slhc_free(struct slcompress *comp)
0155 {
0156 if ( IS_ERR_OR_NULL(comp) )
0157 return;
0158
0159 if ( comp->tstate != NULLSLSTATE )
0160 kfree( comp->tstate );
0161
0162 if ( comp->rstate != NULLSLSTATE )
0163 kfree( comp->rstate );
0164
0165 kfree( comp );
0166 }
0167
0168
0169
0170 static inline unsigned char *
0171 put16(unsigned char *cp, unsigned short x)
0172 {
0173 *cp++ = x >> 8;
0174 *cp++ = x;
0175
0176 return cp;
0177 }
0178
0179
0180
0181 static unsigned char *
0182 encode(unsigned char *cp, unsigned short n)
0183 {
0184 if(n >= 256 || n == 0){
0185 *cp++ = 0;
0186 cp = put16(cp,n);
0187 } else {
0188 *cp++ = n;
0189 }
0190 return cp;
0191 }
0192
0193
0194 static unsigned short
0195 pull16(unsigned char **cpp)
0196 {
0197 short rval;
0198
0199 rval = *(*cpp)++;
0200 rval <<= 8;
0201 rval |= *(*cpp)++;
0202 return rval;
0203 }
0204
0205
0206 static long
0207 decode(unsigned char **cpp)
0208 {
0209 int x;
0210
0211 x = *(*cpp)++;
0212 if(x == 0){
0213 return pull16(cpp) & 0xffff;
0214 } else {
0215 return x & 0xff;
0216 }
0217 }
0218
0219
0220
0221
0222
0223
0224
0225
0226 int
0227 slhc_compress(struct slcompress *comp, unsigned char *icp, int isize,
0228 unsigned char *ocp, unsigned char **cpp, int compress_cid)
0229 {
0230 struct cstate *ocs = &(comp->tstate[comp->xmit_oldest]);
0231 struct cstate *lcs = ocs;
0232 struct cstate *cs = lcs->next;
0233 unsigned long deltaS, deltaA;
0234 short changes = 0;
0235 int nlen, hlen;
0236 unsigned char new_seq[16];
0237 unsigned char *cp = new_seq;
0238 struct iphdr *ip;
0239 struct tcphdr *th, *oth;
0240 __sum16 csum;
0241
0242
0243
0244
0245
0246
0247 if(isize<sizeof(struct iphdr))
0248 return isize;
0249
0250 ip = (struct iphdr *) icp;
0251 if (ip->version != 4 || ip->ihl < 5)
0252 return isize;
0253
0254
0255 if (ip->protocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x3fff)) {
0256
0257 if(ip->protocol != IPPROTO_TCP)
0258 comp->sls_o_nontcp++;
0259 else
0260 comp->sls_o_tcp++;
0261 return isize;
0262 }
0263 nlen = ip->ihl * 4;
0264 if (isize < nlen + sizeof(*th))
0265 return isize;
0266
0267 th = (struct tcphdr *)(icp + nlen);
0268 if (th->doff < sizeof(struct tcphdr) / 4)
0269 return isize;
0270 hlen = nlen + th->doff * 4;
0271
0272
0273
0274
0275
0276 if(hlen > isize || th->syn || th->fin || th->rst ||
0277 ! (th->ack)){
0278
0279 comp->sls_o_tcp++;
0280 return isize;
0281 }
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296 for ( ; ; ) {
0297 if( ip->saddr == cs->cs_ip.saddr
0298 && ip->daddr == cs->cs_ip.daddr
0299 && th->source == cs->cs_tcp.source
0300 && th->dest == cs->cs_tcp.dest)
0301 goto found;
0302
0303
0304 if ( cs == ocs )
0305 break;
0306 lcs = cs;
0307 cs = cs->next;
0308 comp->sls_o_searches++;
0309 }
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319 comp->sls_o_misses++;
0320 comp->xmit_oldest = lcs->cs_this;
0321 goto uncompressed;
0322
0323 found:
0324
0325
0326
0327 if(lcs == ocs) {
0328
0329 } else if (cs == ocs) {
0330
0331 comp->xmit_oldest = lcs->cs_this;
0332 } else {
0333
0334 lcs->next = cs->next;
0335 cs->next = ocs->next;
0336 ocs->next = cs;
0337 }
0338
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349
0350
0351 oth = &cs->cs_tcp;
0352
0353 if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl
0354 || ip->tos != cs->cs_ip.tos
0355 || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000))
0356 || ip->ttl != cs->cs_ip.ttl
0357 || th->doff != cs->cs_tcp.doff
0358 || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0)
0359 || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){
0360 goto uncompressed;
0361 }
0362
0363
0364
0365
0366
0367
0368
0369 if(th->urg){
0370 deltaS = ntohs(th->urg_ptr);
0371 cp = encode(cp,deltaS);
0372 changes |= NEW_U;
0373 } else if(th->urg_ptr != oth->urg_ptr){
0374
0375
0376
0377
0378 goto uncompressed;
0379 }
0380 if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){
0381 cp = encode(cp,deltaS);
0382 changes |= NEW_W;
0383 }
0384 if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){
0385 if(deltaA > 0x0000ffff)
0386 goto uncompressed;
0387 cp = encode(cp,deltaA);
0388 changes |= NEW_A;
0389 }
0390 if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){
0391 if(deltaS > 0x0000ffff)
0392 goto uncompressed;
0393 cp = encode(cp,deltaS);
0394 changes |= NEW_S;
0395 }
0396
0397 switch(changes){
0398 case 0:
0399
0400
0401
0402
0403
0404
0405 if(ip->tot_len != cs->cs_ip.tot_len &&
0406 ntohs(cs->cs_ip.tot_len) == hlen)
0407 break;
0408 goto uncompressed;
0409 case SPECIAL_I:
0410 case SPECIAL_D:
0411
0412
0413
0414 goto uncompressed;
0415 case NEW_S|NEW_A:
0416 if(deltaS == deltaA &&
0417 deltaS == ntohs(cs->cs_ip.tot_len) - hlen){
0418
0419 changes = SPECIAL_I;
0420 cp = new_seq;
0421 }
0422 break;
0423 case NEW_S:
0424 if(deltaS == ntohs(cs->cs_ip.tot_len) - hlen){
0425
0426 changes = SPECIAL_D;
0427 cp = new_seq;
0428 }
0429 break;
0430 }
0431 deltaS = ntohs(ip->id) - ntohs(cs->cs_ip.id);
0432 if(deltaS != 1){
0433 cp = encode(cp,deltaS);
0434 changes |= NEW_I;
0435 }
0436 if(th->psh)
0437 changes |= TCP_PUSH_BIT;
0438
0439
0440
0441 csum = th->check;
0442 memcpy(&cs->cs_ip,ip,20);
0443 memcpy(&cs->cs_tcp,th,20);
0444
0445
0446
0447
0448
0449
0450 deltaS = cp - new_seq;
0451 if(compress_cid == 0 || comp->xmit_current != cs->cs_this){
0452 cp = ocp;
0453 *cpp = ocp;
0454 *cp++ = changes | NEW_C;
0455 *cp++ = cs->cs_this;
0456 comp->xmit_current = cs->cs_this;
0457 } else {
0458 cp = ocp;
0459 *cpp = ocp;
0460 *cp++ = changes;
0461 }
0462 *(__sum16 *)cp = csum;
0463 cp += 2;
0464
0465 memcpy(cp,new_seq,deltaS);
0466 memcpy(cp+deltaS,icp+hlen,isize-hlen);
0467 comp->sls_o_compressed++;
0468 ocp[0] |= SL_TYPE_COMPRESSED_TCP;
0469 return isize - hlen + deltaS + (cp - ocp);
0470
0471
0472
0473
0474
0475 uncompressed:
0476 memcpy(&cs->cs_ip,ip,20);
0477 memcpy(&cs->cs_tcp,th,20);
0478 if (ip->ihl > 5)
0479 memcpy(cs->cs_ipopt, ip+1, ((ip->ihl) - 5) * 4);
0480 if (th->doff > 5)
0481 memcpy(cs->cs_tcpopt, th+1, ((th->doff) - 5) * 4);
0482 comp->xmit_current = cs->cs_this;
0483 comp->sls_o_uncompressed++;
0484 memcpy(ocp, icp, isize);
0485 *cpp = ocp;
0486 ocp[9] = cs->cs_this;
0487 ocp[0] |= SL_TYPE_UNCOMPRESSED_TCP;
0488 return isize;
0489 }
0490
0491
0492 int
0493 slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
0494 {
0495 int changes;
0496 long x;
0497 struct tcphdr *thp;
0498 struct iphdr *ip;
0499 struct cstate *cs;
0500 int len, hdrlen;
0501 unsigned char *cp = icp;
0502
0503
0504 comp->sls_i_compressed++;
0505 if(isize < 3){
0506 comp->sls_i_error++;
0507 return 0;
0508 }
0509 changes = *cp++;
0510 if(changes & NEW_C){
0511
0512
0513
0514 x = *cp++;
0515 if(x < 0 || x > comp->rslot_limit)
0516 goto bad;
0517
0518
0519 if (!comp->rstate[x].initialized)
0520 goto bad;
0521
0522 comp->flags &=~ SLF_TOSS;
0523 comp->recv_current = x;
0524 } else {
0525
0526
0527
0528 if(comp->flags & SLF_TOSS){
0529 comp->sls_i_tossed++;
0530 return 0;
0531 }
0532 }
0533 cs = &comp->rstate[comp->recv_current];
0534 thp = &cs->cs_tcp;
0535 ip = &cs->cs_ip;
0536
0537 thp->check = *(__sum16 *)cp;
0538 cp += 2;
0539
0540 thp->psh = (changes & TCP_PUSH_BIT) ? 1 : 0;
0541
0542
0543
0544
0545
0546
0547 hdrlen = ip->ihl * 4 + thp->doff * 4;
0548
0549 switch(changes & SPECIALS_MASK){
0550 case SPECIAL_I:
0551 {
0552 short i;
0553 i = ntohs(ip->tot_len) - hdrlen;
0554 thp->ack_seq = htonl( ntohl(thp->ack_seq) + i);
0555 thp->seq = htonl( ntohl(thp->seq) + i);
0556 }
0557 break;
0558
0559 case SPECIAL_D:
0560 thp->seq = htonl( ntohl(thp->seq) +
0561 ntohs(ip->tot_len) - hdrlen);
0562 break;
0563
0564 default:
0565 if(changes & NEW_U){
0566 thp->urg = 1;
0567 if((x = decode(&cp)) == -1) {
0568 goto bad;
0569 }
0570 thp->urg_ptr = htons(x);
0571 } else
0572 thp->urg = 0;
0573 if(changes & NEW_W){
0574 if((x = decode(&cp)) == -1) {
0575 goto bad;
0576 }
0577 thp->window = htons( ntohs(thp->window) + x);
0578 }
0579 if(changes & NEW_A){
0580 if((x = decode(&cp)) == -1) {
0581 goto bad;
0582 }
0583 thp->ack_seq = htonl( ntohl(thp->ack_seq) + x);
0584 }
0585 if(changes & NEW_S){
0586 if((x = decode(&cp)) == -1) {
0587 goto bad;
0588 }
0589 thp->seq = htonl( ntohl(thp->seq) + x);
0590 }
0591 break;
0592 }
0593 if(changes & NEW_I){
0594 if((x = decode(&cp)) == -1) {
0595 goto bad;
0596 }
0597 ip->id = htons (ntohs (ip->id) + x);
0598 } else
0599 ip->id = htons (ntohs (ip->id) + 1);
0600
0601
0602
0603
0604
0605
0606
0607 len = isize - (cp - icp);
0608 if (len < 0)
0609 goto bad;
0610 len += hdrlen;
0611 ip->tot_len = htons(len);
0612 ip->check = 0;
0613
0614 memmove(icp + hdrlen, cp, len - hdrlen);
0615
0616 cp = icp;
0617 memcpy(cp, ip, 20);
0618 cp += 20;
0619
0620 if (ip->ihl > 5) {
0621 memcpy(cp, cs->cs_ipopt, (ip->ihl - 5) * 4);
0622 cp += (ip->ihl - 5) * 4;
0623 }
0624
0625 put_unaligned(ip_fast_csum(icp, ip->ihl),
0626 &((struct iphdr *)icp)->check);
0627
0628 memcpy(cp, thp, 20);
0629 cp += 20;
0630
0631 if (thp->doff > 5) {
0632 memcpy(cp, cs->cs_tcpopt, ((thp->doff) - 5) * 4);
0633 cp += ((thp->doff) - 5) * 4;
0634 }
0635
0636 return len;
0637 bad:
0638 comp->sls_i_error++;
0639 return slhc_toss( comp );
0640 }
0641
0642
0643 int
0644 slhc_remember(struct slcompress *comp, unsigned char *icp, int isize)
0645 {
0646 struct cstate *cs;
0647 unsigned ihl;
0648
0649 unsigned char index;
0650
0651 if(isize < 20) {
0652
0653 comp->sls_i_runt++;
0654 return slhc_toss( comp );
0655 }
0656
0657 ihl = icp[0] & 0xf;
0658 if(ihl < 20 / 4){
0659
0660 comp->sls_i_runt++;
0661 return slhc_toss( comp );
0662 }
0663 index = icp[9];
0664 icp[9] = IPPROTO_TCP;
0665
0666 if (ip_fast_csum(icp, ihl)) {
0667
0668 comp->sls_i_badcheck++;
0669 return slhc_toss( comp );
0670 }
0671 if(index > comp->rslot_limit) {
0672 comp->sls_i_error++;
0673 return slhc_toss(comp);
0674 }
0675
0676
0677 cs = &comp->rstate[comp->recv_current = index];
0678 comp->flags &=~ SLF_TOSS;
0679 memcpy(&cs->cs_ip,icp,20);
0680 memcpy(&cs->cs_tcp,icp + ihl*4,20);
0681 if (ihl > 5)
0682 memcpy(cs->cs_ipopt, icp + sizeof(struct iphdr), (ihl - 5) * 4);
0683 if (cs->cs_tcp.doff > 5)
0684 memcpy(cs->cs_tcpopt, icp + ihl*4 + sizeof(struct tcphdr), (cs->cs_tcp.doff - 5) * 4);
0685 cs->cs_hsize = ihl*2 + cs->cs_tcp.doff*2;
0686 cs->initialized = true;
0687
0688
0689
0690 comp->sls_i_uncompressed++;
0691 return isize;
0692 }
0693
0694 int
0695 slhc_toss(struct slcompress *comp)
0696 {
0697 if ( comp == NULLSLCOMPR )
0698 return 0;
0699
0700 comp->flags |= SLF_TOSS;
0701 return 0;
0702 }
0703
0704 #else
0705
0706 int
0707 slhc_toss(struct slcompress *comp)
0708 {
0709 printk(KERN_DEBUG "Called IP function on non IP-system: slhc_toss");
0710 return -EINVAL;
0711 }
0712 int
0713 slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
0714 {
0715 printk(KERN_DEBUG "Called IP function on non IP-system: slhc_uncompress");
0716 return -EINVAL;
0717 }
0718 int
0719 slhc_compress(struct slcompress *comp, unsigned char *icp, int isize,
0720 unsigned char *ocp, unsigned char **cpp, int compress_cid)
0721 {
0722 printk(KERN_DEBUG "Called IP function on non IP-system: slhc_compress");
0723 return -EINVAL;
0724 }
0725
0726 int
0727 slhc_remember(struct slcompress *comp, unsigned char *icp, int isize)
0728 {
0729 printk(KERN_DEBUG "Called IP function on non IP-system: slhc_remember");
0730 return -EINVAL;
0731 }
0732
0733 void
0734 slhc_free(struct slcompress *comp)
0735 {
0736 printk(KERN_DEBUG "Called IP function on non IP-system: slhc_free");
0737 }
0738 struct slcompress *
0739 slhc_init(int rslots, int tslots)
0740 {
0741 printk(KERN_DEBUG "Called IP function on non IP-system: slhc_init");
0742 return NULL;
0743 }
0744
0745 #endif
0746
0747
0748 EXPORT_SYMBOL(slhc_init);
0749 EXPORT_SYMBOL(slhc_free);
0750 EXPORT_SYMBOL(slhc_remember);
0751 EXPORT_SYMBOL(slhc_compress);
0752 EXPORT_SYMBOL(slhc_uncompress);
0753 EXPORT_SYMBOL(slhc_toss);
0754
0755 MODULE_LICENSE("Dual BSD/GPL");