ruby-radix 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/ext/radixlib.c ADDED
@@ -0,0 +1,677 @@
1
+ /*
2
+ * Copyright (c) 1999-2000
3
+ *
4
+ * The Regents of the University of Michigan ("The Regents") and
5
+ * Merit Network, Inc. All rights reserved. Redistribution and use
6
+ * in source and binary forms, with or without modification, are
7
+ * permitted provided that the following conditions are met:
8
+ *
9
+ * 1. Redistributions of source code must retain the above
10
+ * copyright notice, this list of conditions and the
11
+ * following disclaimer.
12
+ *
13
+ * 2. Redistributions in binary form must reproduce the above
14
+ * copyright notice, this list of conditions and the
15
+ * following disclaimer in the documentation and/or other
16
+ * materials provided with the distribution.
17
+ *
18
+ * 3. All advertising materials mentioning features or use of
19
+ * this software must display the following acknowledgement:
20
+ *
21
+ * This product includes software developed by the University of
22
+ * Michigan, Merit Network, Inc., and their contributors.
23
+ *
24
+ * 4. Neither the name of the University, Merit Network, nor the
25
+ * names of their contributors may be used to endorse or
26
+ * promote products derived from this software without
27
+ * specific prior written permission.
28
+ *
29
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS"
30
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
31
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
32
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TH E REGENTS
33
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
36
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HO WEVER CAUSED
37
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
39
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
40
+ * POSSIBILITY OF SUCH DAMAGE.
41
+ */
42
+ /*
43
+ * Portions Copyright (c) 2004,2005 Damien Miller <djm@mindrot.org>
44
+ *
45
+ * Permission to use, copy, modify, and distribute this software for any
46
+ * purpose with or without fee is hereby granted, provided that the above
47
+ * copyright notice and this permission notice appear in all copies.
48
+ *
49
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
50
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
51
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
52
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
53
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
54
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
55
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
56
+ */
57
+
58
+ #include <sys/types.h>
59
+ #include <stdlib.h>
60
+ #include <stdio.h>
61
+ #include <string.h>
62
+
63
+ #include "radixlib.h"
64
+ #include "ruby.h"
65
+
66
+ /* $Id: radix.c,v 1.17 2007/10/24 06:04:31 djm Exp $ */
67
+
68
+ /*
69
+ * Originally from MRT include/defs.h
70
+ * $MRTId: defs.h,v 1.1.1.1 2000/08/14 18:46:10 labovit Exp $
71
+ */
72
+ #define BIT_TEST(f, b) ((f) & (b))
73
+
74
+ /*
75
+ * Originally from MRT include/mrt.h
76
+ * $MRTId: mrt.h,v 1.1.1.1 2000/08/14 18:46:10 labovit Exp $
77
+ */
78
+ #define prefix_tochar(prefix) ((char *)&(prefix)->add)
79
+ #define prefix_touchar(prefix) ((u_char *)&(prefix)->add)
80
+
81
+ /*
82
+ * Originally from MRT lib/mrt/prefix.c
83
+ * $MRTId: prefix.c,v 1.1.1.1 2000/08/14 18:46:11 labovit Exp $
84
+ */
85
+
86
+ #define MALLOC xmalloc
87
+ #define FREE xfree
88
+
89
+ static int
90
+ comp_with_mask(u_char *addr, u_char *dest, u_int mask)
91
+ {
92
+ if (memcmp(addr, dest, mask / 8) == 0) {
93
+ u_int n = mask / 8;
94
+ u_int m = ((~0) << (8 - (mask % 8)));
95
+
96
+ if (mask % 8 == 0 || (addr[n] & m) == (dest[n] & m))
97
+ return (1);
98
+ }
99
+ return (0);
100
+ }
101
+
102
+ static prefix_t
103
+ *New_Prefix2(int family, void *dest, int bitlen, prefix_t *prefix)
104
+ {
105
+ int dynamic_allocated = 0;
106
+ int default_bitlen = 32;
107
+
108
+ if (family == AF_INET6) {
109
+ default_bitlen = 128;
110
+ if (prefix == NULL) {
111
+ if ((prefix = MALLOC(sizeof(*prefix))) == NULL)
112
+ return (NULL);
113
+ memset(prefix, '\0', sizeof(*prefix));
114
+ dynamic_allocated++;
115
+ }
116
+ memcpy(&prefix->add.sin6, dest, 16);
117
+ } else if (family == AF_INET) {
118
+ if (prefix == NULL) {
119
+ if ((prefix = MALLOC(sizeof(*prefix))) == NULL)
120
+ return (NULL);
121
+ memset(prefix, '\0', sizeof(*prefix));
122
+ dynamic_allocated++;
123
+ }
124
+ memcpy(&prefix->add.sin, dest, 4);
125
+ } else
126
+ return (NULL);
127
+
128
+ prefix->bitlen = (bitlen >= 0) ? bitlen : default_bitlen;
129
+ prefix->family = family;
130
+ prefix->ref_count = 0;
131
+ if (dynamic_allocated)
132
+ prefix->ref_count++;
133
+ return (prefix);
134
+ }
135
+
136
+
137
+ static prefix_t
138
+ *Ref_Prefix(prefix_t *prefix)
139
+ {
140
+ if (prefix == NULL)
141
+ return (NULL);
142
+ if (prefix->ref_count == 0) {
143
+ /* make a copy in case of a static prefix */
144
+ return (New_Prefix2(prefix->family, &prefix->add,
145
+ prefix->bitlen, NULL));
146
+ }
147
+ prefix->ref_count++;
148
+ return (prefix);
149
+ }
150
+
151
+
152
+ void
153
+ Deref_Prefix(prefix_t *prefix)
154
+ {
155
+ if (prefix == NULL)
156
+ return;
157
+ prefix->ref_count--;
158
+ if (prefix->ref_count <= 0) {
159
+ FREE(prefix);
160
+ return;
161
+ }
162
+ }
163
+
164
+ /*
165
+ * Originally from MRT lib/radix/radix.c
166
+ * $MRTId: radix.c,v 1.1.1.1 2000/08/14 18:46:13 labovit Exp $
167
+ */
168
+
169
+ /* these routines support continuous mask only */
170
+
171
+ radix_tree_t
172
+ *New_Radix(void)
173
+ {
174
+ radix_tree_t *radix;
175
+
176
+ if ((radix = MALLOC(sizeof(*radix))) == NULL)
177
+ return (NULL);
178
+ memset(radix, '\0', sizeof(*radix));
179
+
180
+ radix->maxbits = 128;
181
+ radix->head = NULL;
182
+ radix->num_active_node = 0;
183
+ return (radix);
184
+ }
185
+
186
+ /*
187
+ * if func is supplied, it will be called as func(node->data)
188
+ * before deleting the node
189
+ */
190
+ static void
191
+ Clear_Radix(radix_tree_t *radix, rdx_cb_t func, void *cbctx)
192
+ {
193
+ if (radix->head) {
194
+ radix_node_t *Xstack[RADIX_MAXBITS + 1];
195
+ radix_node_t **Xsp = Xstack;
196
+ radix_node_t *Xrn = radix->head;
197
+
198
+ while (Xrn) {
199
+ radix_node_t *l = Xrn->l;
200
+ radix_node_t *r = Xrn->r;
201
+
202
+ if (Xrn->prefix) {
203
+ Deref_Prefix(Xrn->prefix);
204
+ if (Xrn->data && func)
205
+ func(Xrn, cbctx);
206
+ }
207
+ FREE(Xrn);
208
+ radix->num_active_node--;
209
+
210
+ if (l) {
211
+ if (r)
212
+ *Xsp++ = r;
213
+ Xrn = l;
214
+ } else if (r) {
215
+ Xrn = r;
216
+ } else if (Xsp != Xstack) {
217
+ Xrn = *(--Xsp);
218
+ } else {
219
+ Xrn = (radix_node_t *) 0;
220
+ }
221
+ }
222
+ }
223
+ }
224
+
225
+ void
226
+ Destroy_Radix(radix_tree_t *radix, rdx_cb_t func, void *cbctx)
227
+ {
228
+ Clear_Radix(radix, func, cbctx);
229
+ FREE(radix);
230
+ }
231
+
232
+ /*
233
+ * if func is supplied, it will be called as func(node->prefix, node->data)
234
+ */
235
+ void
236
+ radix_process(radix_tree_t *radix, rdx_cb_t func, void *cbctx)
237
+ {
238
+ radix_node_t *node;
239
+
240
+ RADIX_WALK(radix->head, node) {
241
+ func(node, cbctx);
242
+ } RADIX_WALK_END;
243
+ }
244
+
245
+ radix_node_t
246
+ *radix_search_exact(radix_tree_t *radix, prefix_t *prefix)
247
+ {
248
+ radix_node_t *node;
249
+ u_char *addr;
250
+ u_int bitlen;
251
+
252
+ if (radix->head == NULL)
253
+ return (NULL);
254
+
255
+ node = radix->head;
256
+ addr = prefix_touchar(prefix);
257
+ bitlen = prefix->bitlen;
258
+
259
+ while (node->bit < bitlen) {
260
+ if (BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07)))
261
+ node = node->r;
262
+ else
263
+ node = node->l;
264
+
265
+ if (node == NULL)
266
+ return (NULL);
267
+ }
268
+
269
+ if (node->bit > bitlen || node->prefix == NULL)
270
+ return (NULL);
271
+
272
+ if (comp_with_mask(prefix_tochar(node->prefix),
273
+ prefix_tochar(prefix), bitlen))
274
+ return (node);
275
+
276
+ return (NULL);
277
+ }
278
+
279
+
280
+ /* if inclusive != 0, "best" may be the given prefix itself */
281
+ static radix_node_t
282
+ *radix_search_best2(radix_tree_t *radix, prefix_t *prefix, int inclusive)
283
+ {
284
+ radix_node_t *node;
285
+ radix_node_t *stack[RADIX_MAXBITS + 1];
286
+ u_char *addr;
287
+ u_int bitlen;
288
+ int cnt = 0;
289
+
290
+ if (radix->head == NULL)
291
+ return (NULL);
292
+
293
+ node = radix->head;
294
+ addr = prefix_touchar(prefix);
295
+ bitlen = prefix->bitlen;
296
+
297
+ while (node->bit < bitlen) {
298
+ if (node->prefix)
299
+ stack[cnt++] = node;
300
+ if (BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07)))
301
+ node = node->r;
302
+ else
303
+ node = node->l;
304
+
305
+ if (node == NULL)
306
+ break;
307
+ }
308
+
309
+ if (inclusive && node && node->prefix)
310
+ stack[cnt++] = node;
311
+
312
+
313
+ if (cnt <= 0)
314
+ return (NULL);
315
+
316
+ while (--cnt >= 0) {
317
+ node = stack[cnt];
318
+ if (comp_with_mask(prefix_tochar(node->prefix),
319
+ prefix_tochar(prefix), node->prefix->bitlen))
320
+ return (node);
321
+ }
322
+ return (NULL);
323
+ }
324
+
325
+
326
+ radix_node_t
327
+ *radix_search_best(radix_tree_t *radix, prefix_t *prefix)
328
+ {
329
+ return (radix_search_best2(radix, prefix, 1));
330
+ }
331
+
332
+
333
+ radix_node_t
334
+ *radix_lookup(radix_tree_t *radix, prefix_t *prefix)
335
+ {
336
+ radix_node_t *node, *new_node, *parent, *glue;
337
+ u_char *addr, *test_addr;
338
+ u_int bitlen, check_bit, differ_bit;
339
+ u_int i, j, r;
340
+
341
+ if (radix->head == NULL) {
342
+ if ((node = MALLOC(sizeof(*node))) == NULL)
343
+ return (NULL);
344
+ memset(node, '\0', sizeof(*node));
345
+ node->bit = prefix->bitlen;
346
+ node->prefix = Ref_Prefix(prefix);
347
+ node->parent = NULL;
348
+ node->l = node->r = NULL;
349
+ node->data = NULL;
350
+ radix->head = node;
351
+ radix->num_active_node++;
352
+ return (node);
353
+ }
354
+ addr = prefix_touchar(prefix);
355
+ bitlen = prefix->bitlen;
356
+ node = radix->head;
357
+
358
+ while (node->bit < bitlen || node->prefix == NULL) {
359
+ if (node->bit < radix->maxbits && BIT_TEST(addr[node->bit >> 3],
360
+ 0x80 >> (node->bit & 0x07))) {
361
+ if (node->r == NULL)
362
+ break;
363
+ node = node->r;
364
+ } else {
365
+ if (node->l == NULL)
366
+ break;
367
+ node = node->l;
368
+ }
369
+ }
370
+
371
+ test_addr = prefix_touchar(node->prefix);
372
+ /* find the first bit different */
373
+ check_bit = (node->bit < bitlen) ? node->bit : bitlen;
374
+ differ_bit = 0;
375
+ for (i = 0; i * 8 < check_bit; i++) {
376
+ if ((r = (addr[i] ^ test_addr[i])) == 0) {
377
+ differ_bit = (i + 1) * 8;
378
+ continue;
379
+ }
380
+ /* I know the better way, but for now */
381
+ for (j = 0; j < 8; j++) {
382
+ if (BIT_TEST(r, (0x80 >> j)))
383
+ break;
384
+ }
385
+ /* must be found */
386
+ differ_bit = i * 8 + j;
387
+ break;
388
+ }
389
+ if (differ_bit > check_bit)
390
+ differ_bit = check_bit;
391
+
392
+ parent = node->parent;
393
+ while (parent && parent->bit >= differ_bit) {
394
+ node = parent;
395
+ parent = node->parent;
396
+ }
397
+
398
+ if (differ_bit == bitlen && node->bit == bitlen) {
399
+ if (node->prefix == NULL)
400
+ node->prefix = Ref_Prefix(prefix);
401
+ return (node);
402
+ }
403
+ if ((new_node = MALLOC(sizeof(*new_node))) == NULL)
404
+ return (NULL);
405
+ memset(new_node, '\0', sizeof(*new_node));
406
+ new_node->bit = prefix->bitlen;
407
+ new_node->prefix = Ref_Prefix(prefix);
408
+ new_node->parent = NULL;
409
+ new_node->l = new_node->r = NULL;
410
+ new_node->data = NULL;
411
+ radix->num_active_node++;
412
+
413
+ if (node->bit == differ_bit) {
414
+ new_node->parent = node;
415
+ if (node->bit < radix->maxbits && BIT_TEST(addr[node->bit >> 3],
416
+ 0x80 >> (node->bit & 0x07)))
417
+ node->r = new_node;
418
+ else
419
+ node->l = new_node;
420
+
421
+ return (new_node);
422
+ }
423
+ if (bitlen == differ_bit) {
424
+ if (bitlen < radix->maxbits && BIT_TEST(test_addr[bitlen >> 3],
425
+ 0x80 >> (bitlen & 0x07)))
426
+ new_node->r = node;
427
+ else
428
+ new_node->l = node;
429
+
430
+ new_node->parent = node->parent;
431
+ if (node->parent == NULL)
432
+ radix->head = new_node;
433
+ else if (node->parent->r == node)
434
+ node->parent->r = new_node;
435
+ else
436
+ node->parent->l = new_node;
437
+
438
+ node->parent = new_node;
439
+ } else {
440
+ if ((glue = MALLOC(sizeof(*glue))) == NULL)
441
+ return (NULL);
442
+ memset(glue, '\0', sizeof(*glue));
443
+ glue->bit = differ_bit;
444
+ glue->prefix = NULL;
445
+ glue->parent = node->parent;
446
+ glue->data = NULL;
447
+ radix->num_active_node++;
448
+ if (differ_bit < radix->maxbits &&
449
+ BIT_TEST(addr[differ_bit >> 3],
450
+ 0x80 >> (differ_bit & 0x07))) {
451
+ glue->r = new_node;
452
+ glue->l = node;
453
+ } else {
454
+ glue->r = node;
455
+ glue->l = new_node;
456
+ }
457
+ new_node->parent = glue;
458
+
459
+ if (node->parent == NULL)
460
+ radix->head = glue;
461
+ else if (node->parent->r == node)
462
+ node->parent->r = glue;
463
+ else
464
+ node->parent->l = glue;
465
+
466
+ node->parent = glue;
467
+ }
468
+ return (new_node);
469
+ }
470
+
471
+
472
+ void
473
+ radix_remove(radix_tree_t *radix, radix_node_t *node)
474
+ {
475
+ radix_node_t *parent, *child;
476
+
477
+ if (node->r && node->l) {
478
+ /*
479
+ * this might be a placeholder node -- have to check and make
480
+ * sure there is a prefix aossciated with it !
481
+ */
482
+ if (node->prefix != NULL)
483
+ Deref_Prefix(node->prefix);
484
+ node->prefix = NULL;
485
+ /* Also I needed to clear data pointer -- masaki */
486
+ node->data = NULL;
487
+ return;
488
+ }
489
+ if (node->r == NULL && node->l == NULL) {
490
+ parent = node->parent;
491
+ Deref_Prefix(node->prefix);
492
+ FREE(node);
493
+ radix->num_active_node--;
494
+
495
+ if (parent == NULL) {
496
+ radix->head = NULL;
497
+ return;
498
+ }
499
+ if (parent->r == node) {
500
+ parent->r = NULL;
501
+ child = parent->l;
502
+ } else {
503
+ parent->l = NULL;
504
+ child = parent->r;
505
+ }
506
+
507
+ if (parent->prefix)
508
+ return;
509
+
510
+ /* we need to remove parent too */
511
+ if (parent->parent == NULL)
512
+ radix->head = child;
513
+ else if (parent->parent->r == parent)
514
+ parent->parent->r = child;
515
+ else
516
+ parent->parent->l = child;
517
+
518
+ child->parent = parent->parent;
519
+ FREE(parent);
520
+ radix->num_active_node--;
521
+ return;
522
+ }
523
+ if (node->r)
524
+ child = node->r;
525
+ else
526
+ child = node->l;
527
+
528
+ parent = node->parent;
529
+ child->parent = parent;
530
+
531
+ Deref_Prefix(node->prefix);
532
+ FREE(node);
533
+ radix->num_active_node--;
534
+
535
+ if (parent == NULL) {
536
+ radix->head = child;
537
+ return;
538
+ }
539
+ if (parent->r == node)
540
+ parent->r = child;
541
+ else
542
+ parent->l = child;
543
+ }
544
+
545
+ /* Local additions */
546
+ static void
547
+ sanitise_mask(u_char *addr, u_int masklen, u_int maskbits)
548
+ {
549
+ u_int i = masklen / 8;
550
+ u_int j = masklen % 8;
551
+
552
+ if (j != 0) {
553
+ addr[i] &= (~0) << (8 - j);
554
+ i++;
555
+ }
556
+ for (; i < maskbits / 8; i++)
557
+ addr[i] = 0;
558
+ }
559
+
560
+ prefix_t
561
+ *prefix_pton(const char *string, long len, const char **errmsg)
562
+ {
563
+ char save[256], *cp, *ep;
564
+ struct addrinfo hints, *ai;
565
+ void *addr;
566
+ prefix_t *ret;
567
+ size_t slen;
568
+ int r;
569
+
570
+ ret = NULL;
571
+
572
+ /* Copy the string to parse, because we modify it */
573
+ if ((slen = strlen(string) + 1) > sizeof(save)) {
574
+ *errmsg = "string too long";
575
+ return (NULL);
576
+ }
577
+ memcpy(save, string, slen);
578
+
579
+ if ((cp = strchr(save, '/')) != NULL) {
580
+ if (len != -1 ) {
581
+ *errmsg = "masklen specified twice";
582
+ return (NULL);
583
+ }
584
+ *cp++ = '\0';
585
+ len = strtol(cp, &ep, 10);
586
+ if (*cp == '\0' || *ep != '\0' || len < 0) {
587
+ *errmsg = "could not parse masklen";
588
+ return (NULL);
589
+ }
590
+ /* More checks below */
591
+ }
592
+ memset(&hints, '\0', sizeof(hints));
593
+ hints.ai_flags = AI_NUMERICHOST;
594
+
595
+ if ((r = getaddrinfo(save, NULL, &hints, &ai)) != 0) {
596
+ snprintf(save, sizeof(save), "getaddrinfo: %s:",
597
+ gai_strerror(r));
598
+ *errmsg = save;
599
+ return NULL;
600
+ }
601
+ if (ai == NULL || ai->ai_addr == NULL) {
602
+ *errmsg = "getaddrinfo returned no result";
603
+ goto out;
604
+ }
605
+ switch (ai->ai_addr->sa_family) {
606
+ case AF_INET:
607
+ if (len == -1)
608
+ len = 32;
609
+ else if (len < 0 || len > 32)
610
+ goto out;
611
+ addr = &((struct sockaddr_in *) ai->ai_addr)->sin_addr;
612
+ sanitise_mask(addr, len, 32);
613
+ break;
614
+ case AF_INET6:
615
+ if (len == -1)
616
+ len = 128;
617
+ else if (len < 0 || len > 128)
618
+ goto out;
619
+ addr = &((struct sockaddr_in6 *) ai->ai_addr)->sin6_addr;
620
+ sanitise_mask(addr, len, 128);
621
+ break;
622
+ default:
623
+ goto out;
624
+ }
625
+
626
+ ret = New_Prefix2(ai->ai_addr->sa_family, addr, len, NULL);
627
+ if (ret == NULL)
628
+ *errmsg = "New_Prefix2 failed";
629
+ out:
630
+ freeaddrinfo(ai);
631
+ return (ret);
632
+ }
633
+
634
+ prefix_t
635
+ *prefix_from_blob(u_char *blob, int len, int prefixlen)
636
+ {
637
+ int family, maxprefix;
638
+
639
+ switch (len) {
640
+ case 4:
641
+ /* Assume AF_INET */
642
+ family = AF_INET;
643
+ maxprefix = 32;
644
+ break;
645
+ case 16:
646
+ /* Assume AF_INET6 */
647
+ family = AF_INET6;
648
+ maxprefix = 128;
649
+ break;
650
+ default:
651
+ /* Who knows? */
652
+ return NULL;
653
+ }
654
+ if (prefixlen == -1)
655
+ prefixlen = maxprefix;
656
+ if (prefixlen < 0 || prefixlen > maxprefix)
657
+ return NULL;
658
+ return (New_Prefix2(family, blob, prefixlen, NULL));
659
+ }
660
+
661
+ const char *
662
+ prefix_addr_ntop(prefix_t *prefix, char *buf, size_t len)
663
+ {
664
+ return (inet_ntop(prefix->family, &prefix->add, buf, len));
665
+ }
666
+
667
+ const char *
668
+ prefix_ntop(prefix_t *prefix, char *buf, size_t len)
669
+ {
670
+ char addrbuf[128];
671
+
672
+ if (prefix_addr_ntop(prefix, addrbuf, sizeof(addrbuf)) == NULL)
673
+ return (NULL);
674
+ snprintf(buf, len, "%s/%d", addrbuf, prefix->bitlen);
675
+
676
+ return (buf);
677
+ }