block.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <ip.h>
  4. #include <auth.h>
  5. #include "ppp.h"
  6. enum
  7. {
  8. PAD = 128,
  9. NLIST = (1<<5),
  10. BPOW = 10,
  11. };
  12. typedef struct Barena Barena;
  13. struct Barena
  14. {
  15. QLock;
  16. Block* list[NLIST];
  17. };
  18. static Barena area;
  19. #define ADEBUG if(0)
  20. /*
  21. * allocation tracing
  22. */
  23. enum
  24. {
  25. Npc= 64,
  26. };
  27. typedef struct Arefent Arefent;
  28. struct Arefent
  29. {
  30. uint pc;
  31. uint n;
  32. };
  33. typedef struct Aref Aref;
  34. struct Aref
  35. {
  36. Arefent tab[Npc];
  37. QLock;
  38. };
  39. Aref arefblock;
  40. static ulong callerpc(void*);
  41. static void aref(Aref*, ulong);
  42. static void aunref(Aref*, ulong);
  43. Block*
  44. allocb(int len)
  45. {
  46. int sz;
  47. Block *bp, **l;
  48. len += PAD;
  49. sz = (len>>BPOW)&(NLIST-1);
  50. qlock(&area);
  51. l = &area.list[sz];
  52. for(bp = *l; bp; bp = bp->flist) {
  53. if(bp->bsz >= len) {
  54. *l = bp->flist;
  55. qunlock(&area);
  56. bp->next = nil;
  57. bp->list = nil;
  58. bp->flist = nil;
  59. bp->base = (uchar*)bp+sizeof(Block);
  60. bp->rptr = bp->base+PAD;
  61. bp->wptr = bp->rptr;
  62. bp->lim = bp->base+bp->bsz;
  63. bp->flow = nil;
  64. bp->flags= 0;
  65. ADEBUG {
  66. bp->pc = callerpc(&len);
  67. aref(&arefblock, bp->pc);
  68. }
  69. return bp;
  70. }
  71. l = &bp->flist;
  72. }
  73. qunlock(&area);
  74. bp = mallocz(sizeof(Block)+len, 1);
  75. bp->bsz = len;
  76. bp->base = (uchar*)bp+sizeof(Block);
  77. bp->rptr = bp->base+PAD;
  78. bp->wptr = bp->rptr;
  79. bp->lim = bp->base+len;
  80. ADEBUG {
  81. bp->pc = callerpc(&len);
  82. aref(&arefblock, bp->pc);
  83. }
  84. return bp;
  85. }
  86. void
  87. freeb(Block *bp)
  88. {
  89. int sz;
  90. Block **l, *next;
  91. qlock(&area);
  92. while(bp) {
  93. sz = (bp->bsz>>BPOW)&(NLIST-1);
  94. l = &area.list[sz];
  95. bp->flist = *l;
  96. *l = bp;
  97. next = bp->next;
  98. /* to catch use after free */
  99. bp->rptr = (uchar*)0xdeadbabe;
  100. bp->wptr = (uchar*)0xdeadbabe;
  101. bp->next = (Block*)0xdeadbabe;
  102. bp->list = (Block*)0xdeadbabe;
  103. ADEBUG aunref(&arefblock, bp->pc);
  104. bp = next;
  105. }
  106. qunlock(&area);
  107. }
  108. /*
  109. * concatenate a list of blocks into a single one and make sure
  110. * the result is at least min uchars
  111. */
  112. Block*
  113. concat(Block *bp)
  114. {
  115. int len;
  116. Block *nb, *f;
  117. nb = allocb(blen(bp));
  118. for(f = bp; f; f = f->next) {
  119. len = BLEN(f);
  120. memmove(nb->wptr, f->rptr, len);
  121. nb->wptr += len;
  122. }
  123. freeb(bp);
  124. return nb;
  125. }
  126. int
  127. blen(Block *bp)
  128. {
  129. int len;
  130. len = 0;
  131. while(bp) {
  132. len += BLEN(bp);
  133. bp = bp->next;
  134. }
  135. return len;
  136. }
  137. Block *
  138. pullup(Block *bp, int n)
  139. {
  140. int i;
  141. Block *nbp;
  142. /*
  143. * this should almost always be true, the rest it
  144. * just for to avoid every caller checking.
  145. */
  146. if(BLEN(bp) >= n)
  147. return bp;
  148. /*
  149. * if not enough room in the first block,
  150. * add another to the front of the list.
  151. */
  152. if(bp->lim - bp->rptr < n){
  153. nbp = allocb(n);
  154. nbp->next = bp;
  155. bp = nbp;
  156. }
  157. /*
  158. * copy uchars from the trailing blocks into the first
  159. */
  160. n -= BLEN(bp);
  161. while(nbp = bp->next){
  162. i = BLEN(nbp);
  163. if(i >= n) {
  164. memmove(bp->wptr, nbp->rptr, n);
  165. bp->wptr += n;
  166. nbp->rptr += n;
  167. return bp;
  168. }
  169. else {
  170. memmove(bp->wptr, nbp->rptr, i);
  171. bp->wptr += i;
  172. bp->next = nbp->next;
  173. nbp->next = nil;
  174. freeb(nbp);
  175. n -= i;
  176. }
  177. }
  178. freeb(bp);
  179. return nil;
  180. }
  181. /*
  182. * Pad a block to the front with n uchars. This is used to add protocol
  183. * headers to the front of blocks.
  184. */
  185. Block*
  186. padb(Block *bp, int n)
  187. {
  188. Block *nbp;
  189. if(bp->rptr-bp->base >= n) {
  190. bp->rptr -= n;
  191. return bp;
  192. }
  193. else {
  194. /* fprint(2, "padb: required %d PAD %d\n", n, PAD) = malloc(sizeof(*required %d PAD %d\n", n, PAD))); */
  195. nbp = allocb(n);
  196. nbp->wptr = nbp->lim;
  197. nbp->rptr = nbp->wptr - n;
  198. nbp->next = bp;
  199. return nbp;
  200. }
  201. }
  202. Block *
  203. btrim(Block *bp, int offset, int len)
  204. {
  205. ulong l;
  206. Block *nb, *startb;
  207. if(blen(bp) < offset+len) {
  208. freeb(bp);
  209. return nil;
  210. }
  211. while((l = BLEN(bp)) < offset) {
  212. offset -= l;
  213. nb = bp->next;
  214. bp->next = nil;
  215. freeb(bp);
  216. bp = nb;
  217. }
  218. startb = bp;
  219. bp->rptr += offset;
  220. while((l = BLEN(bp)) < len) {
  221. len -= l;
  222. bp = bp->next;
  223. }
  224. bp->wptr -= (BLEN(bp) - len);
  225. bp->flags |= S_DELIM;
  226. if(bp->next) {
  227. freeb(bp->next);
  228. bp->next = nil;
  229. }
  230. return startb;
  231. }
  232. Block*
  233. copyb(Block *bp, int count)
  234. {
  235. int l;
  236. Block *nb, *head, **p;
  237. p = &head;
  238. head = nil;
  239. while(bp != nil && count != 0) {
  240. l = BLEN(bp);
  241. if(count < l)
  242. l = count;
  243. nb = allocb(l);
  244. memmove(nb->wptr, bp->rptr, l);
  245. nb->wptr += l;
  246. count -= l;
  247. nb->flags = bp->flags;
  248. *p = nb;
  249. p = &nb->next;
  250. bp = bp->next;
  251. }
  252. if(count) {
  253. nb = allocb(count);
  254. memset(nb->wptr, 0, count);
  255. nb->wptr += count;
  256. nb->flags |= S_DELIM;
  257. *p = nb;
  258. }
  259. if(blen(head) == 0)
  260. fprint(2, "copyb: zero length\n");
  261. return head;
  262. }
  263. int
  264. pullb(Block **bph, int count)
  265. {
  266. Block *bp;
  267. int n, uchars;
  268. uchars = 0;
  269. if(bph == nil)
  270. return 0;
  271. while(*bph != nil && count != 0) {
  272. bp = *bph;
  273. n = BLEN(bp);
  274. if(count < n)
  275. n = count;
  276. uchars += n;
  277. count -= n;
  278. bp->rptr += n;
  279. if(BLEN(bp) == 0) {
  280. *bph = bp->next;
  281. bp->next = nil;
  282. freeb(bp);
  283. }
  284. }
  285. return uchars;
  286. }
  287. /*
  288. * handy routines for keeping track of allocations
  289. */
  290. static ulong
  291. callerpc(void *a)
  292. {
  293. return ((ulong*)a)[-1];
  294. }
  295. static void
  296. aref(Aref *ap, ulong pc)
  297. {
  298. Arefent *a, *e;
  299. e = &ap->tab[Npc-1];
  300. qlock(ap);
  301. for(a = ap->tab; a < e; a++)
  302. if(a->pc == pc || a->pc == 0)
  303. break;
  304. a->pc = pc;
  305. a->n++;
  306. qunlock(ap);
  307. }
  308. static void
  309. aunref(Aref *ap, ulong pc)
  310. {
  311. Arefent *a, *e;
  312. e = &ap->tab[Npc-1];
  313. qlock(ap);
  314. for(a = ap->tab; a < e; a++)
  315. if(a->pc == pc || a->pc == 0)
  316. break;
  317. a->n--;
  318. qunlock(ap);
  319. }