📄 isdn_bsdcomp.c
字号:
struct bsd_dict *dictp; unsigned char c; int hval,disp,ilen,mxcode; unsigned char *rptr = skb_in->data; int isize = skb_in->len;#define OUTPUT(ent) \ { \ bitno -= n_bits; \ accm |= ((ent) << bitno); \ do { \ if(skb_out && skb_tailroom(skb_out) > 0) \ *(skb_put(skb_out,1)) = (unsigned char) (accm>>24); \ accm <<= 8; \ bitno += 8; \ } while (bitno <= 24); \ } /* * If the protocol is not in the range we're interested in, * just return without compressing the packet. If it is, * the protocol becomes the first byte to compress. */ printk(KERN_DEBUG "bsd_compress called with %x\n",proto); ent = proto; if (proto < 0x21 || proto > 0xf9 || !(proto & 0x1) ) return 0; db = (struct bsd_db *) state; hshift = db->hshift; max_ent = db->max_ent; n_bits = db->n_bits; bitno = 32; accm = 0; mxcode = MAXCODE (n_bits); /* This is the PPP header information */ if(skb_out && skb_tailroom(skb_out) >= 2) { char *v = skb_put(skb_out,2); /* we only push our own data on the header, AC,PC and protos is pushed by caller */ v[0] = db->seqno >> 8; v[1] = db->seqno; } ilen = ++isize; /* This is off by one, but that is what is in draft! */ while (--ilen > 0) { c = *rptr++; fcode = BSD_KEY (ent, c); hval = BSD_HASH (ent, c, hshift); dictp = dict_ptr (db, hval); /* Validate and then check the entry. */ if (dictp->codem1 >= max_ent) goto nomatch; if (dictp->fcode == fcode) { ent = dictp->codem1 + 1; continue; /* found (prefix,suffix) */ } /* continue probing until a match or invalid entry */ disp = (hval == 0) ? 1 : hval; do { hval += disp; if (hval >= db->hsize) hval -= db->hsize; dictp = dict_ptr (db, hval); if (dictp->codem1 >= max_ent) goto nomatch; } while (dictp->fcode != fcode); ent = dictp->codem1 + 1; /* finally found (prefix,suffix) */ continue; nomatch: OUTPUT(ent); /* output the prefix */ /* code -> hashtable */ if (max_ent < db->maxmaxcode) { struct bsd_dict *dictp2; struct bsd_dict *dictp3; int indx; /* expand code size if needed */ if (max_ent >= mxcode) { db->n_bits = ++n_bits; mxcode = MAXCODE (n_bits); } /* * Invalidate old hash table entry using * this code, and then take it over. */ dictp2 = dict_ptr (db, max_ent + 1); indx = dictp2->cptr; dictp3 = dict_ptr (db, indx); if (dictp3->codem1 == max_ent) dictp3->codem1 = BADCODEM1; dictp2->cptr = hval; dictp->codem1 = max_ent; dictp->fcode = fcode; db->max_ent = ++max_ent; if (db->lens) { unsigned short *len1 = lens_ptr (db, max_ent); unsigned short *len2 = lens_ptr (db, ent); *len1 = *len2 + 1; } } ent = c; } OUTPUT(ent); /* output the last code */ if(skb_out) db->bytes_out += skb_out->len; /* Do not count bytes from here */ db->uncomp_bytes += isize; db->in_count += isize; ++db->uncomp_count; ++db->seqno; if (bitno < 32) ++db->bytes_out; /* must be set before calling bsd_check */ /* * Generate the clear command if needed */ if (bsd_check(db)) OUTPUT (CLEAR); /* * Pad dribble bits of last code with ones. * Do not emit a completely useless byte of ones. */ if (bitno < 32 && skb_out && skb_tailroom(skb_out) > 0) *(skb_put(skb_out,1)) = (unsigned char) ((accm | (0xff << (bitno-8))) >> 24); /* * Increase code size if we would have without the packet * boundary because the decompressor will do so. */ if (max_ent >= mxcode && max_ent < db->maxmaxcode) db->n_bits++; /* If output length is too large then this is an incompressible frame. */ if (!skb_out || (skb_out && skb_out->len >= skb_in->len) ) { ++db->incomp_count; db->incomp_bytes += isize; return 0; } /* Count the number of compressed frames */ ++db->comp_count; db->comp_bytes += skb_out->len; return skb_out->len;#undef OUTPUT}/* * Update the "BSD Compress" dictionary on the receiver for * incompressible data by pretending to compress the incoming data. */static void bsd_incomp (void *state, struct sk_buff *skb_in,int proto){ bsd_compress (state, skb_in, NULL, proto);}/* * Decompress "BSD Compress". */static int bsd_decompress (void *state, struct sk_buff *skb_in, struct sk_buff *skb_out, struct isdn_ppp_resetparams *rsparm){ struct bsd_db *db; unsigned int max_ent; unsigned long accm; unsigned int bitno; /* 1st valid bit in accm */ unsigned int n_bits; unsigned int tgtbitno; /* bitno when we have a code */ struct bsd_dict *dictp; int seq; unsigned int incode; unsigned int oldcode; unsigned int finchar; unsigned char *p,*ibuf; int ilen; int codelen; int extra; db = (struct bsd_db *) state; max_ent = db->max_ent; accm = 0; bitno = 32; /* 1st valid bit in accm */ n_bits = db->n_bits; tgtbitno = 32 - n_bits; /* bitno when we have a code */ printk(KERN_DEBUG "bsd_decompress called\n"); if(!skb_in || !skb_out) { printk(KERN_ERR "bsd_decompress called with NULL parameter\n"); return DECOMP_ERROR; } /* * Get the sequence number. */ if( (p = skb_pull(skb_in,2)) == NULL) { return DECOMP_ERROR; } p-=2; seq = (p[0] << 8) + p[1]; ilen = skb_in->len; ibuf = skb_in->data; /* * Check the sequence number and give up if it differs from * the value we're expecting. */ if (seq != db->seqno) { if (db->debug) { printk(KERN_DEBUG "bsd_decomp%d: bad sequence # %d, expected %d\n", db->unit, seq, db->seqno - 1); } return DECOMP_ERROR; } ++db->seqno; db->bytes_out += ilen; if(skb_tailroom(skb_out) > 0) *(skb_put(skb_out,1)) = 0; else return DECOMP_ERR_NOMEM; oldcode = CLEAR; /* * Keep the checkpoint correctly so that incompressible packets * clear the dictionary at the proper times. */ for (;;) { if (ilen-- <= 0) { db->in_count += (skb_out->len - 1); /* don't count the header */ break; } /* * Accumulate bytes until we have a complete code. * Then get the next code, relying on the 32-bit, * unsigned accm to mask the result. */ bitno -= 8; accm |= *ibuf++ << bitno; if (tgtbitno < bitno) continue; incode = accm >> tgtbitno; accm <<= n_bits; bitno += n_bits; /* * The dictionary must only be cleared at the end of a packet. */ if (incode == CLEAR) { if (ilen > 0) { if (db->debug) printk(KERN_DEBUG "bsd_decomp%d: bad CLEAR\n", db->unit); return DECOMP_FATALERROR; /* probably a bug */ } bsd_clear(db); break; } if ((incode > max_ent + 2) || (incode > db->maxmaxcode) || (incode > max_ent && oldcode == CLEAR)) { if (db->debug) { printk(KERN_DEBUG "bsd_decomp%d: bad code 0x%x oldcode=0x%x ", db->unit, incode, oldcode); printk(KERN_DEBUG "max_ent=0x%x skb->Len=%d seqno=%d\n", max_ent, skb_out->len, db->seqno); } return DECOMP_FATALERROR; /* probably a bug */ } /* Special case for KwKwK string. */ if (incode > max_ent) { finchar = oldcode; extra = 1; } else { finchar = incode; extra = 0; } codelen = *(lens_ptr (db, finchar)); if( skb_tailroom(skb_out) < codelen + extra) { if (db->debug) { printk(KERN_DEBUG "bsd_decomp%d: ran out of mru\n", db->unit);#ifdef DEBUG printk(KERN_DEBUG " len=%d, finchar=0x%x, codelen=%d,skblen=%d\n", ilen, finchar, codelen, skb_out->len);#endif } return DECOMP_FATALERROR; } /* * Decode this code and install it in the decompressed buffer. */ p = skb_put(skb_out,codelen); p += codelen; while (finchar > LAST) { struct bsd_dict *dictp2 = dict_ptr (db, finchar); dictp = dict_ptr (db, dictp2->cptr);#ifdef DEBUG if (--codelen <= 0 || dictp->codem1 != finchar-1) { if (codelen <= 0) { printk(KERN_ERR "bsd_decomp%d: fell off end of chain ", db->unit); printk(KERN_ERR "0x%x at 0x%x by 0x%x, max_ent=0x%x\n", incode, finchar, dictp2->cptr, max_ent); } else { if (dictp->codem1 != finchar-1) { printk(KERN_ERR "bsd_decomp%d: bad code chain 0x%x finchar=0x%x ",db->unit, incode, finchar); printk(KERN_ERR "oldcode=0x%x cptr=0x%x codem1=0x%x\n", oldcode, dictp2->cptr, dictp->codem1); } } return DECOMP_FATALERROR; }#endif { u32 fcode = dictp->fcode; *--p = (fcode >> 16) & 0xff; finchar = fcode & 0xffff; } } *--p = finchar; #ifdef DEBUG if (--codelen != 0) printk(KERN_ERR "bsd_decomp%d: short by %d after code 0x%x, max_ent=0x%x\n", db->unit, codelen, incode, max_ent);#endif if (extra) /* the KwKwK case again */ *(skb_put(skb_out,1)) = finchar; /* * If not first code in a packet, and * if not out of code space, then allocate a new code. * * Keep the hash table correct so it can be used * with uncompressed packets. */ if (oldcode != CLEAR && max_ent < db->maxmaxcode) { struct bsd_dict *dictp2, *dictp3; u16 *lens1, *lens2; unsigned long fcode; int hval, disp, indx; fcode = BSD_KEY(oldcode,finchar); hval = BSD_HASH(oldcode,finchar,db->hshift); dictp = dict_ptr (db, hval); /* look for a free hash table entry */ if (dictp->codem1 < max_ent) { disp = (hval == 0) ? 1 : hval; do { hval += disp; if (hval >= db->hsize) hval -= db->hsize; dictp = dict_ptr (db, hval); } while (dictp->codem1 < max_ent); } /* * Invalidate previous hash table entry * assigned this code, and then take it over */ dictp2 = dict_ptr (db, max_ent + 1); indx = dictp2->cptr; dictp3 = dict_ptr (db, indx); if (dictp3->codem1 == max_ent) dictp3->codem1 = BADCODEM1; dictp2->cptr = hval; dictp->codem1 = max_ent; dictp->fcode = fcode; db->max_ent = ++max_ent; /* Update the length of this string. */ lens1 = lens_ptr (db, max_ent); lens2 = lens_ptr (db, oldcode); *lens1 = *lens2 + 1; /* Expand code size if needed. */ if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) { db->n_bits = ++n_bits; tgtbitno = 32-n_bits; } } oldcode = incode; } ++db->comp_count; ++db->uncomp_count; db->comp_bytes += skb_in->len - BSD_OVHD; db->uncomp_bytes += skb_out->len; if (bsd_check(db)) { if (db->debug) printk(KERN_DEBUG "bsd_decomp%d: peer should have cleared dictionary on %d\n", db->unit, db->seqno - 1); } return skb_out->len;}/************************************************************* * Table of addresses for the BSD compression module *************************************************************/static struct isdn_ppp_compressor ippp_bsd_compress = { .owner = THIS_MODULE, .num = CI_BSD_COMPRESS, .alloc = bsd_alloc, .free = bsd_free, .init = bsd_init, .reset = bsd_reset, .compress = bsd_compress, .decompress = bsd_decompress, .incomp = bsd_incomp, .stat = bsd_stats,};/************************************************************* * Module support routines *************************************************************/static int __init isdn_bsdcomp_init(void){ int answer = isdn_ppp_register_compressor (&ippp_bsd_compress); if (answer == 0) printk (KERN_INFO "PPP BSD Compression module registered\n"); return answer;}static void __exit isdn_bsdcomp_exit(void){ isdn_ppp_unregister_compressor (&ippp_bsd_compress);}module_init(isdn_bsdcomp_init);module_exit(isdn_bsdcomp_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -