URI:
       tpacket.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tpacket.c (15872B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 #include <venti.h>
            4 #include <libsec.h>
            5 
            6 typedef struct Mem Mem;
            7 typedef struct Frag Frag;
            8 
            9 enum {
           10         BigMemSize = MaxFragSize,
           11         SmallMemSize = BigMemSize/8,
           12         NLocalFrag = 2
           13 };
           14 
           15 /* position to carve out of a Mem */
           16 enum {
           17         PFront,
           18         PMiddle,
           19         PEnd
           20 };
           21 
           22 struct Mem
           23 {
           24         Lock lk;
           25         int ref;
           26         uchar *bp;
           27         uchar *ep;
           28         uchar *rp;
           29         uchar *wp;
           30         Mem *next;
           31 };
           32 
           33 enum {
           34         FragLocalFree,
           35         FragLocalAlloc,
           36         FragGlobal
           37 };
           38 
           39 struct Frag
           40 {
           41         int state;
           42         Mem *mem;
           43         uchar *rp;
           44         uchar *wp;
           45         Frag *next;
           46         void (*free)(void*);
           47         void *a;
           48         Packet *p;        /* parent packet, for debugging only */
           49 };
           50 
           51 struct Packet
           52 {
           53         int size;
           54         int asize;  /* allocated memory - greater than size unless foreign frags */
           55         ulong pc;
           56 
           57         Packet *next;
           58 
           59         Frag *first;
           60         Frag *last;
           61 
           62         Frag local[NLocalFrag];
           63 };
           64 
           65 static Frag *fragalloc(Packet*, int n, int pos, Frag *next);
           66 static Frag *fragdup(Packet*, Frag*);
           67 static void fragfree(Frag*);
           68 
           69 static Mem *memalloc(int, int);
           70 static void memfree(Mem*);
           71 static int memhead(Mem *m, uchar *rp, int n);
           72 static int memtail(Mem *m, uchar *wp, int n);
           73 
           74 static char EPacketSize[] = "bad packet size";
           75 static char EPacketOffset[] = "bad packet offset";
           76 static char EBadSize[] = "bad size";
           77 
           78 #ifdef NOTDEF
           79 static void checkpacket(Packet*);
           80 #endif
           81 
           82 /*
           83  * the free list is primarily for speed, but it is
           84  * also necessary for packetsplit that packets
           85  * are never freed -- a packet can contain a different
           86  * packet's local fragments, thanks to packetsplit!
           87  */
           88 static struct {
           89         Lock lk;
           90         Packet *packet;
           91         int npacket;
           92         Frag *frag;
           93         int nfrag;
           94         Mem *bigmem;
           95         int nbigmem;
           96         Mem *smallmem;
           97         int nsmallmem;
           98 } freelist;
           99 
          100 #define FRAGSIZE(f) ((f)->wp - (f)->rp)
          101 #define FRAGASIZE(f) ((f)->mem ? (f)->mem->ep - (f)->mem->bp : 0)
          102 
          103 #define NOTFREE(p) assert((p)->size>=0)/*; checkpacket(p)*/
          104 
          105 Packet *
          106 packetalloc(void)
          107 {
          108         Packet *p;
          109 
          110         lock(&freelist.lk);
          111         p = freelist.packet;
          112         if(p != nil)
          113                 freelist.packet = p->next;
          114         else
          115                 freelist.npacket++;
          116         unlock(&freelist.lk);
          117 
          118         if(p == nil)
          119                 p = vtbrk(sizeof(Packet));
          120         else
          121                 assert(p->size == -1);
          122         p->size = 0;
          123         p->asize = 0;
          124         p->first = nil;
          125         p->last = nil;
          126         p->next = nil;
          127         p->pc = getcallerpc((char*)&p+8);        /* might not work, but fine */
          128 
          129         NOTFREE(p);
          130         return p;
          131 }
          132 
          133 void
          134 packetfree(Packet *p)
          135 {
          136         Frag *f, *ff;
          137 
          138         if(p == nil)
          139                 return;
          140 
          141         NOTFREE(p);
          142         p->pc = getcallerpc(&p);
          143 
          144         for(f=p->first; f!=nil; f=ff) {
          145                 ff = f->next;
          146                 fragfree(f);
          147         }
          148         p->first = (void*)0xDeadBeef;
          149         p->last = (void*)0xDeadBeef;
          150         p->size = -1;
          151 
          152         lock(&freelist.lk);
          153         p->next = freelist.packet;
          154         freelist.packet = p;
          155         unlock(&freelist.lk);
          156 }
          157 
          158 Packet *
          159 packetdup(Packet *p, int offset, int n)
          160 {
          161         Frag *f, *ff;
          162         Packet *pp;
          163 
          164         NOTFREE(p);
          165         if(offset < 0 || n < 0 || offset+n > p->size) {
          166                 werrstr(EBadSize);
          167                 return nil;
          168         }
          169 
          170         pp = packetalloc();
          171         pp->pc = getcallerpc(&p);
          172         if(n == 0){
          173                 NOTFREE(pp);
          174                 return pp;
          175         }
          176 
          177         pp->size = n;
          178 
          179         /* skip offset */
          180         for(f=p->first; offset >= FRAGSIZE(f); f=f->next)
          181                 offset -= FRAGSIZE(f);
          182 
          183         /* first frag */
          184         ff = fragdup(pp, f);
          185         ff->rp += offset;
          186         pp->first = ff;
          187         n -= FRAGSIZE(ff);
          188         pp->asize += FRAGASIZE(ff);
          189 
          190         /* the remaining */
          191         while(n > 0) {
          192                 f = f->next;
          193                 ff->next = fragdup(pp, f);
          194                 ff = ff->next;
          195                 n -= FRAGSIZE(ff);
          196                 pp->asize += FRAGASIZE(ff);
          197         }
          198 
          199         /* fix up last frag: note n <= 0 */
          200         ff->wp += n;
          201         ff->next = nil;
          202         pp->last = ff;
          203 
          204         NOTFREE(pp);
          205         NOTFREE(p);
          206         return pp;
          207 }
          208 
          209 Packet *
          210 packetsplit(Packet *p, int n)
          211 {
          212         Packet *pp;
          213         Frag *f, *ff;
          214 
          215         NOTFREE(p);
          216         if(n < 0 || n > p->size) {
          217                 werrstr(EPacketSize);
          218                 return nil;
          219         }
          220 
          221         pp = packetalloc();
          222         pp->pc = getcallerpc(&p);
          223         if(n == 0){
          224                 NOTFREE(pp);
          225                 return pp;
          226         }
          227 
          228         pp->size = n;
          229         p->size -= n;
          230         ff = nil;
          231         for(f=p->first; n > 0 && n >= FRAGSIZE(f); f=f->next) {
          232                 n -= FRAGSIZE(f);
          233                 p->asize -= FRAGASIZE(f);
          234                 pp->asize += FRAGASIZE(f);
          235                 f->p = pp;
          236                 ff = f;
          237         }
          238 
          239         /* split shared frag */
          240         if(n > 0) {
          241                 f->p = pp;
          242                 ff = f;
          243                 f = fragdup(p, ff);
          244                 pp->asize += FRAGASIZE(ff);
          245                 ff->wp = ff->rp + n;
          246                 f->rp += n;
          247         }
          248 
          249         pp->first = p->first;
          250         pp->last = ff;
          251         ff->next = nil;
          252         p->first = f;
          253         if(f == nil || f->next == nil)
          254                 p->last = f;
          255         NOTFREE(pp);
          256         NOTFREE(p);
          257         return pp;
          258 }
          259 
          260 int
          261 packetconsume(Packet *p, uchar *buf, int n)
          262 {
          263         NOTFREE(p);
          264         if(buf && packetcopy(p, buf, 0, n) < 0)
          265                 return -1;
          266         return packettrim(p, n, p->size-n);
          267 }
          268 
          269 int
          270 packettrim(Packet *p, int offset, int n)
          271 {
          272         Frag *f, *ff;
          273 
          274         NOTFREE(p);
          275         if(offset < 0 || offset > p->size) {
          276                 werrstr(EPacketOffset);
          277                 return -1;
          278         }
          279 
          280         if(n < 0 || offset + n > p->size) {
          281                 werrstr(EPacketOffset);
          282                 return -1;
          283         }
          284 
          285         p->size = n;
          286 
          287         /* easy case */
          288         if(n == 0) {
          289                 for(f=p->first; f != nil; f=ff) {
          290                         ff = f->next;
          291                         fragfree(f);
          292                 }
          293                 p->first = p->last = nil;
          294                 p->asize = 0;
          295                 NOTFREE(p);
          296                 return 0;
          297         }
          298 
          299         /* free before offset */
          300         for(f=p->first; offset >= FRAGSIZE(f); f=ff) {
          301                 p->asize -= FRAGASIZE(f);
          302                 offset -= FRAGSIZE(f);
          303                 ff = f->next;
          304                 fragfree(f);
          305         }
          306 
          307         /* adjust frag */
          308         f->rp += offset;
          309         p->first = f;
          310 
          311         /* skip middle */
          312         for(; n > 0 && n > FRAGSIZE(f); f=f->next)
          313                 n -= FRAGSIZE(f);
          314 
          315         /* adjust end */
          316         f->wp = f->rp + n;
          317         p->last = f;
          318         ff = f->next;
          319         f->next = nil;
          320 
          321         /* free after */
          322         for(f=ff; f != nil; f=ff) {
          323                 p->asize -= FRAGASIZE(f);
          324                 ff = f->next;
          325                 fragfree(f);
          326         }
          327         NOTFREE(p);
          328         return 0;
          329 }
          330 
          331 uchar *
          332 packetheader(Packet *p, int n)
          333 {
          334         Frag *f;
          335         Mem *m;
          336 
          337         NOTFREE(p);
          338         if(n <= 0 || n > MaxFragSize) {
          339                 werrstr(EPacketSize);
          340                 return nil;
          341         }
          342 
          343         p->size += n;
          344 
          345         /* try and fix in current frag */
          346         f = p->first;
          347         if(f != nil) {
          348                 m = f->mem;
          349                 if(n <= f->rp - m->bp)
          350                 if(m->ref == 1 || memhead(m, f->rp, n) >= 0) {
          351                         f->rp -= n;
          352                         NOTFREE(p);
          353                         return f->rp;
          354                 }
          355         }
          356 
          357         /* add frag to front */
          358         f = fragalloc(p, n, PEnd, p->first);
          359         p->asize += FRAGASIZE(f);
          360         if(p->first == nil)
          361                 p->last = f;
          362         p->first = f;
          363         NOTFREE(p);
          364         return f->rp;
          365 }
          366 
          367 uchar *
          368 packettrailer(Packet *p, int n)
          369 {
          370         Mem *m;
          371         Frag *f;
          372 
          373         NOTFREE(p);
          374         if(n <= 0 || n > MaxFragSize) {
          375                 werrstr(EPacketSize);
          376                 return nil;
          377         }
          378 
          379         p->size += n;
          380 
          381         /* try and fix in current frag */
          382         if(p->first != nil) {
          383                 f = p->last;
          384                 m = f->mem;
          385                 if(n <= m->ep - f->wp)
          386                 if(m->ref == 1 || memtail(m, f->wp, n) >= 0) {
          387                         f->wp += n;
          388                         NOTFREE(p);
          389                         return f->wp - n;
          390                 }
          391         }
          392 
          393         /* add frag to end */
          394         f = fragalloc(p, n, (p->first == nil)?PMiddle:PFront, nil);
          395         p->asize += FRAGASIZE(f);
          396         if(p->first == nil)
          397                 p->first = f;
          398         else
          399                 p->last->next = f;
          400         p->last = f;
          401         NOTFREE(p);
          402         return f->rp;
          403 }
          404 
          405 void
          406 packetprefix(Packet *p, uchar *buf, int n)
          407 {
          408         Frag *f;
          409         int nn;
          410         Mem *m;
          411 
          412         NOTFREE(p);
          413         if(n <= 0)
          414                 return;
          415 
          416         p->size += n;
          417 
          418         /* try and fix in current frag */
          419         f = p->first;
          420         if(f != nil) {
          421                 m = f->mem;
          422                 nn = f->rp - m->bp;
          423                 if(nn > n)
          424                         nn = n;
          425                 if(m->ref == 1 || memhead(m, f->rp, nn) >= 0) {
          426                         f->rp -= nn;
          427                         n -= nn;
          428                         memmove(f->rp, buf+n, nn);
          429                 }
          430         }
          431 
          432         while(n > 0) {
          433                 nn = n;
          434                 if(nn > MaxFragSize)
          435                         nn = MaxFragSize;
          436                 f = fragalloc(p, nn, PEnd, p->first);
          437                 p->asize += FRAGASIZE(f);
          438                 if(p->first == nil)
          439                         p->last = f;
          440                 p->first = f;
          441                 n -= nn;
          442                 memmove(f->rp, buf+n, nn);
          443         }
          444         NOTFREE(p);
          445 }
          446 
          447 void
          448 packetappend(Packet *p, uchar *buf, int n)
          449 {
          450         Frag *f;
          451         int nn;
          452         Mem *m;
          453 
          454         NOTFREE(p);
          455         if(n <= 0)
          456                 return;
          457 
          458         p->size += n;
          459         /* try and fix in current frag */
          460         if(p->first != nil) {
          461                 f = p->last;
          462                 m = f->mem;
          463                 nn = m->ep - f->wp;
          464                 if(nn > n)
          465                         nn = n;
          466                 if(m->ref == 1 || memtail(m, f->wp, nn) >= 0) {
          467                         memmove(f->wp, buf, nn);
          468                         f->wp += nn;
          469                         buf += nn;
          470                         n -= nn;
          471                 }
          472         }
          473 
          474         while(n > 0) {
          475                 nn = n;
          476                 if(nn > MaxFragSize)
          477                         nn = MaxFragSize;
          478                 f = fragalloc(p, nn, (p->first == nil)?PMiddle:PFront, nil);
          479                 p->asize += FRAGASIZE(f);
          480                 if(p->first == nil)
          481                         p->first = f;
          482                 else
          483                         p->last->next = f;
          484                 p->last = f;
          485                 memmove(f->rp, buf, nn);
          486                 buf += nn;
          487                 n -= nn;
          488         }
          489         NOTFREE(p);
          490 }
          491 
          492 void
          493 packetconcat(Packet *p, Packet *pp)
          494 {
          495         Frag *f;
          496 
          497         NOTFREE(p);
          498         NOTFREE(pp);
          499         if(pp->size == 0)
          500                 return;
          501         p->size += pp->size;
          502         p->asize += pp->asize;
          503         for(f=pp->first; f; f=f->next)
          504                 f->p = p;
          505 
          506         if(p->first != nil)
          507                 p->last->next = pp->first;
          508         else
          509                 p->first = pp->first;
          510 
          511         p->last = pp->last;
          512         pp->size = 0;
          513         pp->asize = 0;
          514         pp->first = nil;
          515         pp->last = nil;
          516         NOTFREE(p);
          517         NOTFREE(pp);
          518 }
          519 
          520 uchar *
          521 packetpeek(Packet *p, uchar *buf, int offset, int n)
          522 {
          523         Frag *f;
          524         int nn;
          525         uchar *b;
          526 
          527         NOTFREE(p);
          528         if(n == 0)
          529                 return buf;
          530 
          531         if(offset < 0 || offset >= p->size) {
          532                 werrstr(EPacketOffset);
          533                 return nil;
          534         }
          535 
          536         if(n < 0 || offset + n > p->size) {
          537                 werrstr(EPacketSize);
          538                 return nil;
          539         }
          540 
          541         /* skip up to offset */
          542         for(f=p->first; offset >= FRAGSIZE(f); f=f->next)
          543                 offset -= FRAGSIZE(f);
          544 
          545         /* easy case */
          546         if(offset + n <= FRAGSIZE(f)){
          547                 NOTFREE(p);
          548                 return f->rp + offset;
          549         }
          550 
          551         for(b=buf; n>0; n -= nn) {
          552                 nn = FRAGSIZE(f) - offset;
          553                 if(nn > n)
          554                         nn = n;
          555                 memmove(b, f->rp+offset, nn);
          556                 offset = 0;
          557                 f = f->next;
          558                 b += nn;
          559         }
          560 
          561         NOTFREE(p);
          562         return buf;
          563 }
          564 
          565 int
          566 packetcopy(Packet *p, uchar *buf, int offset, int n)
          567 {
          568         uchar *b;
          569 
          570         NOTFREE(p);
          571         b = packetpeek(p, buf, offset, n);
          572         if(b == nil)
          573                 return -1;
          574         if(b != buf)
          575                 memmove(buf, b, n);
          576         return 0;
          577 }
          578 
          579 int
          580 packetfragments(Packet *p, IOchunk *io, int nio, int offset)
          581 {
          582         Frag *f;
          583         int size;
          584         IOchunk *eio;
          585 
          586         NOTFREE(p);
          587         if(p->size == 0 || nio <= 0)
          588                 return 0;
          589 
          590         if(offset < 0 || offset > p->size) {
          591                 werrstr(EPacketOffset);
          592                 return -1;
          593         }
          594 
          595         for(f=p->first; offset >= FRAGSIZE(f); f=f->next)
          596                 offset -= FRAGSIZE(f);
          597 
          598         size = 0;
          599         eio = io + nio;
          600         for(; f != nil && io < eio; f=f->next) {
          601                 io->addr = f->rp + offset;
          602                 io->len = f->wp - (f->rp + offset);
          603                 offset = 0;
          604                 size += io->len;
          605                 io++;
          606         }
          607         for(; io < eio; io++){
          608                 io->addr = nil;
          609                 io->len = 0;
          610         }
          611         return size;
          612 }
          613 
          614 void
          615 packetstats(void)
          616 {
          617         Packet *p;
          618         Frag *f;
          619         Mem *m;
          620 
          621         int np, nf, nsm, nbm;
          622 
          623         lock(&freelist.lk);
          624         np = 0;
          625         for(p=freelist.packet; p; p=p->next)
          626                 np++;
          627         nf = 0;
          628         for(f=freelist.frag; f; f=f->next)
          629                 nf++;
          630         nsm = 0;
          631         for(m=freelist.smallmem; m; m=m->next)
          632                 nsm++;
          633         nbm = 0;
          634         for(m=freelist.bigmem; m; m=m->next)
          635                 nbm++;
          636 
          637         fprint(2, "packet: %d/%d frag: %d/%d small mem: %d/%d big mem: %d/%d\n",
          638                 np, freelist.npacket,
          639                 nf, freelist.nfrag,
          640                 nsm, freelist.nsmallmem,
          641                 nbm, freelist.nbigmem);
          642 
          643         unlock(&freelist.lk);
          644 }
          645 
          646 
          647 uint
          648 packetsize(Packet *p)
          649 {
          650         NOTFREE(p);
          651         if(1) {
          652                 Frag *f;
          653                 int size = 0;
          654 
          655                 for(f=p->first; f; f=f->next)
          656                         size += FRAGSIZE(f);
          657                 if(size != p->size)
          658                         fprint(2, "packetsize %d %d\n", size, p->size);
          659                 assert(size == p->size);
          660         }
          661         return p->size;
          662 }
          663 
          664 uint
          665 packetasize(Packet *p)
          666 {
          667         NOTFREE(p);
          668         if(0) {
          669                 Frag *f;
          670                 int asize = 0;
          671 
          672                 for(f=p->first; f; f=f->next)
          673                         asize += FRAGASIZE(f);
          674                 if(asize != p->asize)
          675                         fprint(2, "packetasize %d %d\n", asize, p->asize);
          676                 assert(asize == p->asize);
          677         }
          678         return p->asize;
          679 }
          680 
          681 void
          682 packetsha1(Packet *p, uchar digest[VtScoreSize])
          683 {
          684         DigestState ds;
          685         Frag *f;
          686         int size;
          687 
          688         NOTFREE(p);
          689         memset(&ds, 0, sizeof ds);
          690         size = p->size;
          691         for(f=p->first; f; f=f->next) {
          692                 sha1(f->rp, FRAGSIZE(f), nil, &ds);
          693                 size -= FRAGSIZE(f);
          694         }
          695         assert(size == 0);
          696         sha1(nil, 0, digest, &ds);
          697 }
          698 
          699 int
          700 packetcmp(Packet *pkt0, Packet *pkt1)
          701 {
          702         Frag *f0, *f1;
          703         int n0, n1, x;
          704 
          705         NOTFREE(pkt0);
          706         NOTFREE(pkt1);
          707         f0 = pkt0->first;
          708         f1 = pkt1->first;
          709 
          710         if(f0 == nil)
          711                 return (f1 == nil)?0:-1;
          712         if(f1 == nil)
          713                 return 1;
          714         n0 = FRAGSIZE(f0);
          715         n1 = FRAGSIZE(f1);
          716 
          717         for(;;) {
          718                 if(n0 < n1) {
          719                         x = memcmp(f0->wp - n0, f1->wp - n1, n0);
          720                         if(x != 0)
          721                                 return x;
          722                         n1 -= n0;
          723                         f0 = f0->next;
          724                         if(f0 == nil)
          725                                 return -1;
          726                         n0 = FRAGSIZE(f0);
          727                 } else if (n0 > n1) {
          728                         x = memcmp(f0->wp - n0, f1->wp - n1, n1);
          729                         if(x != 0)
          730                                 return x;
          731                         n0 -= n1;
          732                         f1 = f1->next;
          733                         if(f1 == nil)
          734                                 return 1;
          735                         n1 = FRAGSIZE(f1);
          736                 } else { /* n0 == n1 */
          737                         x = memcmp(f0->wp - n0, f1->wp - n1, n0);
          738                         if(x != 0)
          739                                 return x;
          740                         f0 = f0->next;
          741                         f1 = f1->next;
          742                         if(f0 == nil)
          743                                 return (f1 == nil)?0:-1;
          744                         if(f1 == nil)
          745                                 return 1;
          746                         n0 = FRAGSIZE(f0);
          747                         n1 = FRAGSIZE(f1);
          748                 }
          749         }
          750 }
          751 
          752 static Frag *
          753 fragalloc(Packet *p, int n, int pos, Frag *next)
          754 {
          755         Frag *f, *ef;
          756         Mem *m;
          757 
          758         /* look for local frag */
          759         f = &p->local[0];
          760         ef = &p->local[NLocalFrag];
          761         for(;f<ef; f++) {
          762                 if(f->state == FragLocalFree) {
          763                         f->state = FragLocalAlloc;
          764                         goto Found;
          765                 }
          766         }
          767         lock(&freelist.lk);
          768         f = freelist.frag;
          769         if(f != nil)
          770                 freelist.frag = f->next;
          771         else
          772                 freelist.nfrag++;
          773         unlock(&freelist.lk);
          774 
          775         if(f == nil) {
          776                 f = vtbrk(sizeof(Frag));
          777                 f->state = FragGlobal;
          778         }
          779 
          780 Found:
          781         f->next = next;
          782         f->p = p;
          783 
          784         if(n == 0){
          785                 f->mem = 0;
          786                 f->rp = 0;
          787                 f->wp = 0;
          788                 return f;
          789         }
          790 
          791         if(pos == PEnd && next == nil)
          792                 pos = PMiddle;
          793         m = memalloc(n, pos);
          794         f->mem = m;
          795         f->rp = m->rp;
          796         f->wp = m->wp;
          797         return f;
          798 }
          799 
          800 Packet*
          801 packetforeign(uchar *buf, int n, void (*free)(void *a), void *a)
          802 {
          803         Packet *p;
          804         Frag *f;
          805 
          806         p = packetalloc();
          807         p->pc = getcallerpc(&buf);
          808         f = fragalloc(p, 0, 0, nil);
          809         f->free = free;
          810         f->a = a;
          811         f->next = nil;
          812         f->rp = buf;
          813         f->wp = buf+n;
          814 
          815         p->first = f;
          816         p->last = f;
          817         p->size = n;
          818         NOTFREE(p);
          819         return p;
          820 }
          821 
          822 static Frag *
          823 fragdup(Packet *p, Frag *f)
          824 {
          825         Frag *ff;
          826         Mem *m;
          827 
          828         m = f->mem;
          829 
          830         /*
          831          * m->rp && m->wp can be out of date when ref == 1
          832          * also, potentially reclaims space from previous frags
          833          */
          834         if(m && m->ref == 1) {
          835                 m->rp = f->rp;
          836                 m->wp = f->wp;
          837         }
          838 
          839         ff = fragalloc(p, 0, 0, nil);
          840         ff->mem = f->mem;
          841         ff->rp = f->rp;
          842         ff->wp = f->wp;
          843         ff->next = f->next;
          844 
          845         /*
          846          * We can't duplicate these -- there's no dup function.
          847          */
          848         assert(f->free==nil && f->a==nil);
          849 
          850         if(m){
          851                 lock(&m->lk);
          852                 m->ref++;
          853                 unlock(&m->lk);
          854         }
          855 
          856 
          857         return ff;
          858 }
          859 
          860 
          861 static void
          862 fragfree(Frag *f)
          863 {
          864         if(f->mem == nil){
          865                 if(f->free)
          866                         (*f->free)(f->a);
          867         }else{
          868                 memfree(f->mem);
          869                 f->mem = 0;
          870         }
          871 
          872         if(f->state == FragLocalAlloc) {
          873                 f->state = FragLocalFree;
          874                 return;
          875         }
          876 
          877         lock(&freelist.lk);
          878         f->next = freelist.frag;
          879         freelist.frag = f;
          880         unlock(&freelist.lk);
          881 }
          882 
          883 static Mem *
          884 memalloc(int n, int pos)
          885 {
          886         Mem *m;
          887         int nn;
          888 
          889         if(n < 0 || n > MaxFragSize) {
          890                 werrstr(EPacketSize);
          891                 return nil;
          892         }
          893         if(n <= SmallMemSize) {
          894                 lock(&freelist.lk);
          895                 m = freelist.smallmem;
          896                 if(m != nil)
          897                         freelist.smallmem = m->next;
          898                 else
          899                         freelist.nsmallmem++;
          900                 unlock(&freelist.lk);
          901                 nn = SmallMemSize;
          902         } else {
          903                 lock(&freelist.lk);
          904                 m = freelist.bigmem;
          905                 if(m != nil)
          906                         freelist.bigmem = m->next;
          907                 else
          908                         freelist.nbigmem++;
          909                 unlock(&freelist.lk);
          910                 nn = BigMemSize;
          911         }
          912 
          913         if(m == nil) {
          914                 m = vtbrk(sizeof(Mem));
          915                 m->bp = vtbrk(nn);
          916                 m->ep = m->bp + nn;
          917         }
          918         assert(m->ref == 0);
          919         m->ref = 1;
          920 
          921         switch(pos) {
          922         default:
          923                 assert(0);
          924         case PFront:
          925                 m->rp = m->bp;
          926                 break;
          927         case PMiddle:
          928                 /* leave a little bit at end */
          929                 m->rp = m->ep - n - 32;
          930                 break;
          931         case PEnd:
          932                 m->rp = m->ep - n;
          933                 break;
          934         }
          935         /* check we did not blow it */
          936         if(m->rp < m->bp)
          937                 m->rp = m->bp;
          938         m->wp = m->rp + n;
          939         assert(m->rp >= m->bp && m->wp <= m->ep);
          940         return m;
          941 }
          942 
          943 static void
          944 memfree(Mem *m)
          945 {
          946         lock(&m->lk);
          947         m->ref--;
          948         if(m->ref > 0) {
          949                 unlock(&m->lk);
          950                 return;
          951         }
          952         unlock(&m->lk);
          953         assert(m->ref == 0);
          954 
          955 /*        memset(m->bp, 0xEF, m->ep-m->bp); */
          956         switch(m->ep - m->bp) {
          957         default:
          958                 assert(0);
          959         case SmallMemSize:
          960                 lock(&freelist.lk);
          961                 m->next = freelist.smallmem;
          962                 freelist.smallmem = m;
          963                 unlock(&freelist.lk);
          964                 break;
          965         case BigMemSize:
          966                 lock(&freelist.lk);
          967                 m->next = freelist.bigmem;
          968                 freelist.bigmem = m;
          969                 unlock(&freelist.lk);
          970                 break;
          971         }
          972 }
          973 
          974 static int
          975 memhead(Mem *m, uchar *rp, int n)
          976 {
          977         fprint(2, "memhead called\n");
          978         abort();
          979         lock(&m->lk);
          980         if(m->rp != rp) {
          981                 unlock(&m->lk);
          982                 return -1;
          983         }
          984         m->rp -= n;
          985         unlock(&m->lk);
          986         return 0;
          987 }
          988 
          989 static int
          990 memtail(Mem *m, uchar *wp, int n)
          991 {
          992         fprint(2, "memtail called\n");
          993         abort();
          994         lock(&m->lk);
          995         if(m->wp != wp) {
          996                 unlock(&m->lk);
          997                 return -1;
          998         }
          999         m->wp += n;
         1000         unlock(&m->lk);
         1001         return 0;
         1002 }
         1003 
         1004 #ifdef NOTDEF
         1005 static void
         1006 checkpacket(Packet *p)
         1007 {
         1008         int s, as;
         1009         Frag *f;
         1010         Frag *ff;
         1011 
         1012         s = 0;
         1013         as = 0;
         1014         ff=p->first;
         1015         for(f=p->first; f; ff=f,f=f->next){
         1016                 assert(f->p == p);
         1017                 s += FRAGSIZE(f);
         1018                 as += FRAGASIZE(f);
         1019         }
         1020         assert(s == p->size);
         1021         assert(as == p->asize);
         1022         if(p->first)
         1023                 assert(ff==p->last);
         1024 }
         1025 #endif