]> git.proxmox.com Git - mirror_iproute2.git/blame - lib/rt_names.c
vdpa: add .gitignore
[mirror_iproute2.git] / lib / rt_names.c
CommitLineData
aba5acdf
SH
1/*
2 * rt_names.c rtnetlink names DB.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10 */
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <unistd.h>
aba5acdf
SH
15#include <fcntl.h>
16#include <string.h>
17#include <sys/time.h>
b88fd9f4 18#include <sys/socket.h>
13ada95d 19#include <dirent.h>
4a36b4c2 20#include <limits.h>
b88fd9f4
SH
21
22#include <asm/types.h>
23#include <linux/rtnetlink.h>
24
25#include "rt_names.h"
f6793eec 26#include "utils.h"
fb72129b 27
f00073e8 28#define NAME_MAX_LEN 512
29
ca697cee
HL
30int numeric;
31
9c47d877 32struct rtnl_hash_entry {
68ef5072
SH
33 struct rtnl_hash_entry *next;
34 const char *name;
9c47d877
PM
35 unsigned int id;
36};
37
f00073e8 38static int fread_id_name(FILE *fp, int *id, char *namebuf)
39{
40 char buf[NAME_MAX_LEN];
41
42 while (fgets(buf, sizeof(buf), fp)) {
43 char *p = buf;
44
45 while (*p == ' ' || *p == '\t')
46 p++;
47
48 if (*p == '#' || *p == '\n' || *p == 0)
49 continue;
50
51 if (sscanf(p, "0x%x %s\n", id, namebuf) != 2 &&
52 sscanf(p, "0x%x %s #", id, namebuf) != 2 &&
53 sscanf(p, "%d %s\n", id, namebuf) != 2 &&
54 sscanf(p, "%d %s #", id, namebuf) != 2) {
55 strcpy(namebuf, p);
56 return -1;
57 }
58 return 1;
59 }
60 return 0;
61}
62
9c47d877 63static void
46ac8a55 64rtnl_hash_initialize(const char *file, struct rtnl_hash_entry **hash, int size)
9c47d877
PM
65{
66 struct rtnl_hash_entry *entry;
9c47d877 67 FILE *fp;
f00073e8 68 int id;
69 char namebuf[NAME_MAX_LEN] = {0};
70 int ret;
9c47d877
PM
71
72 fp = fopen(file, "r");
73 if (!fp)
74 return;
9c47d877 75
f00073e8 76 while ((ret = fread_id_name(fp, &id, &namebuf[0]))) {
77 if (ret == -1) {
9c47d877 78 fprintf(stderr, "Database %s is corrupted at %s\n",
f00073e8 79 file, namebuf);
97c13582 80 fclose(fp);
9c47d877
PM
81 return;
82 }
83
68ef5072 84 if (id < 0)
9c47d877 85 continue;
f00073e8 86
9c47d877
PM
87 entry = malloc(sizeof(*entry));
88 entry->id = id;
89 entry->name = strdup(namebuf);
90 entry->next = hash[id & (size - 1)];
91 hash[id & (size - 1)] = entry;
92 }
93 fclose(fp);
94}
95
46ac8a55 96static void rtnl_tab_initialize(const char *file, char **tab, int size)
aba5acdf 97{
aba5acdf 98 FILE *fp;
f00073e8 99 int id;
100 char namebuf[NAME_MAX_LEN] = {0};
101 int ret;
aba5acdf
SH
102
103 fp = fopen(file, "r");
104 if (!fp)
105 return;
aba5acdf 106
f00073e8 107 while ((ret = fread_id_name(fp, &id, &namebuf[0]))) {
108 if (ret == -1) {
aba5acdf 109 fprintf(stderr, "Database %s is corrupted at %s\n",
f00073e8 110 file, namebuf);
97c13582 111 fclose(fp);
aba5acdf
SH
112 return;
113 }
68ef5072 114 if (id < 0 || id > size)
aba5acdf
SH
115 continue;
116
117 tab[id] = strdup(namebuf);
118 }
119 fclose(fp);
120}
121
68ef5072 122static char *rtnl_rtprot_tab[256] = {
30f3beea
AC
123 [RTPROT_UNSPEC] = "unspec",
124 [RTPROT_REDIRECT] = "redirect",
125 [RTPROT_KERNEL] = "kernel",
126 [RTPROT_BOOT] = "boot",
127 [RTPROT_STATIC] = "static",
128
129 [RTPROT_GATED] = "gated",
130 [RTPROT_RA] = "ra",
131 [RTPROT_MRT] = "mrt",
132 [RTPROT_ZEBRA] = "zebra",
133 [RTPROT_BIRD] = "bird",
134 [RTPROT_BABEL] = "babel",
135 [RTPROT_DNROUTED] = "dnrouted",
136 [RTPROT_XORP] = "xorp",
137 [RTPROT_NTK] = "ntk",
138 [RTPROT_DHCP] = "dhcp",
139 [RTPROT_KEEPALIVED] = "keepalived",
140 [RTPROT_BGP] = "bgp",
141 [RTPROT_ISIS] = "isis",
142 [RTPROT_OSPF] = "ospf",
143 [RTPROT_RIP] = "rip",
144 [RTPROT_EIGRP] = "eigrp",
aba5acdf
SH
145};
146
147
aba5acdf
SH
148static int rtnl_rtprot_init;
149
150static void rtnl_rtprot_initialize(void)
151{
719e331f
DA
152 struct dirent *de;
153 DIR *d;
154
aba5acdf 155 rtnl_rtprot_init = 1;
fb72129b 156 rtnl_tab_initialize(CONFDIR "/rt_protos",
aba5acdf 157 rtnl_rtprot_tab, 256);
719e331f
DA
158
159 d = opendir(CONFDIR "/rt_protos.d");
160 if (!d)
161 return;
162
163 while ((de = readdir(d)) != NULL) {
164 char path[PATH_MAX];
165 size_t len;
166
167 if (*de->d_name == '.')
168 continue;
169
170 /* only consider filenames ending in '.conf' */
171 len = strlen(de->d_name);
172 if (len <= 5)
173 continue;
174 if (strcmp(de->d_name + len - 5, ".conf"))
175 continue;
176
177 snprintf(path, sizeof(path), CONFDIR "/rt_protos.d/%s",
178 de->d_name);
179 rtnl_tab_initialize(path, rtnl_rtprot_tab, 256);
180 }
181 closedir(d);
aba5acdf
SH
182}
183
68ef5072 184const char *rtnl_rtprot_n2a(int id, char *buf, int len)
aba5acdf 185{
ca697cee 186 if (id < 0 || id >= 256 || numeric) {
46ac8a55 187 snprintf(buf, len, "%u", id);
aba5acdf
SH
188 return buf;
189 }
190 if (!rtnl_rtprot_tab[id]) {
191 if (!rtnl_rtprot_init)
192 rtnl_rtprot_initialize();
193 }
194 if (rtnl_rtprot_tab[id])
195 return rtnl_rtprot_tab[id];
46ac8a55 196 snprintf(buf, len, "%u", id);
aba5acdf
SH
197 return buf;
198}
199
46ac8a55 200int rtnl_rtprot_a2n(__u32 *id, const char *arg)
aba5acdf 201{
68ef5072 202 static char *cache;
aba5acdf
SH
203 static unsigned long res;
204 char *end;
205 int i;
206
207 if (cache && strcmp(cache, arg) == 0) {
208 *id = res;
209 return 0;
210 }
211
212 if (!rtnl_rtprot_init)
213 rtnl_rtprot_initialize();
214
68ef5072 215 for (i = 0; i < 256; i++) {
aba5acdf
SH
216 if (rtnl_rtprot_tab[i] &&
217 strcmp(rtnl_rtprot_tab[i], arg) == 0) {
218 cache = rtnl_rtprot_tab[i];
219 res = i;
220 *id = res;
221 return 0;
222 }
223 }
224
225 res = strtoul(arg, &end, 0);
226 if (!end || end == arg || *end || res > 255)
227 return -1;
228 *id = res;
229 return 0;
230}
231
68ef5072
SH
232
233static char *rtnl_rtscope_tab[256] = {
234 [RT_SCOPE_UNIVERSE] = "global",
235 [RT_SCOPE_NOWHERE] = "nowhere",
236 [RT_SCOPE_HOST] = "host",
237 [RT_SCOPE_LINK] = "link",
238 [RT_SCOPE_SITE] = "site",
aba5acdf
SH
239};
240
241static int rtnl_rtscope_init;
242
243static void rtnl_rtscope_initialize(void)
244{
245 rtnl_rtscope_init = 1;
fb72129b 246 rtnl_tab_initialize(CONFDIR "/rt_scopes",
aba5acdf
SH
247 rtnl_rtscope_tab, 256);
248}
249
46ac8a55 250const char *rtnl_rtscope_n2a(int id, char *buf, int len)
aba5acdf 251{
ca697cee 252 if (id < 0 || id >= 256 || numeric) {
aba5acdf
SH
253 snprintf(buf, len, "%d", id);
254 return buf;
255 }
68ef5072 256
aba5acdf
SH
257 if (!rtnl_rtscope_tab[id]) {
258 if (!rtnl_rtscope_init)
259 rtnl_rtscope_initialize();
260 }
68ef5072 261
aba5acdf
SH
262 if (rtnl_rtscope_tab[id])
263 return rtnl_rtscope_tab[id];
68ef5072 264
aba5acdf
SH
265 snprintf(buf, len, "%d", id);
266 return buf;
267}
268
46ac8a55 269int rtnl_rtscope_a2n(__u32 *id, const char *arg)
aba5acdf 270{
68ef5072 271 static const char *cache;
aba5acdf
SH
272 static unsigned long res;
273 char *end;
274 int i;
275
276 if (cache && strcmp(cache, arg) == 0) {
277 *id = res;
278 return 0;
279 }
280
281 if (!rtnl_rtscope_init)
282 rtnl_rtscope_initialize();
283
68ef5072 284 for (i = 0; i < 256; i++) {
aba5acdf
SH
285 if (rtnl_rtscope_tab[i] &&
286 strcmp(rtnl_rtscope_tab[i], arg) == 0) {
287 cache = rtnl_rtscope_tab[i];
288 res = i;
289 *id = res;
290 return 0;
291 }
292 }
293
294 res = strtoul(arg, &end, 0);
295 if (!end || end == arg || *end || res > 255)
296 return -1;
297 *id = res;
298 return 0;
299}
300
301
68ef5072 302static char *rtnl_rtrealm_tab[256] = {
aba5acdf
SH
303 "unknown",
304};
305
306static int rtnl_rtrealm_init;
307
308static void rtnl_rtrealm_initialize(void)
309{
310 rtnl_rtrealm_init = 1;
fb72129b 311 rtnl_tab_initialize(CONFDIR "/rt_realms",
aba5acdf
SH
312 rtnl_rtrealm_tab, 256);
313}
314
46ac8a55 315const char *rtnl_rtrealm_n2a(int id, char *buf, int len)
aba5acdf 316{
ca697cee 317 if (id < 0 || id >= 256 || numeric) {
aba5acdf
SH
318 snprintf(buf, len, "%d", id);
319 return buf;
320 }
321 if (!rtnl_rtrealm_tab[id]) {
322 if (!rtnl_rtrealm_init)
323 rtnl_rtrealm_initialize();
324 }
325 if (rtnl_rtrealm_tab[id])
326 return rtnl_rtrealm_tab[id];
327 snprintf(buf, len, "%d", id);
328 return buf;
329}
330
331
46ac8a55 332int rtnl_rtrealm_a2n(__u32 *id, const char *arg)
aba5acdf 333{
68ef5072 334 static char *cache;
aba5acdf
SH
335 static unsigned long res;
336 char *end;
337 int i;
338
339 if (cache && strcmp(cache, arg) == 0) {
340 *id = res;
341 return 0;
342 }
343
344 if (!rtnl_rtrealm_init)
345 rtnl_rtrealm_initialize();
346
68ef5072 347 for (i = 0; i < 256; i++) {
aba5acdf
SH
348 if (rtnl_rtrealm_tab[i] &&
349 strcmp(rtnl_rtrealm_tab[i], arg) == 0) {
350 cache = rtnl_rtrealm_tab[i];
351 res = i;
352 *id = res;
353 return 0;
354 }
355 }
356
357 res = strtoul(arg, &end, 0);
358 if (!end || end == arg || *end || res > 255)
359 return -1;
360 *id = res;
361 return 0;
362}
363
364
81ebcb2a
MY
365static struct rtnl_hash_entry dflt_table_entry = { .name = "default" };
366static struct rtnl_hash_entry main_table_entry = { .name = "main" };
367static struct rtnl_hash_entry local_table_entry = { .name = "local" };
aba5acdf 368
68ef5072 369static struct rtnl_hash_entry *rtnl_rttable_hash[256] = {
81ebcb2a
MY
370 [RT_TABLE_DEFAULT] = &dflt_table_entry,
371 [RT_TABLE_MAIN] = &main_table_entry,
372 [RT_TABLE_LOCAL] = &local_table_entry,
aba5acdf
SH
373};
374
375static int rtnl_rttable_init;
376
377static void rtnl_rttable_initialize(void)
378{
13ada95d
DA
379 struct dirent *de;
380 DIR *d;
81ebcb2a
MY
381 int i;
382
aba5acdf 383 rtnl_rttable_init = 1;
81ebcb2a
MY
384 for (i = 0; i < 256; i++) {
385 if (rtnl_rttable_hash[i])
386 rtnl_rttable_hash[i]->id = i;
387 }
fb72129b 388 rtnl_hash_initialize(CONFDIR "/rt_tables",
9c47d877 389 rtnl_rttable_hash, 256);
13ada95d
DA
390
391 d = opendir(CONFDIR "/rt_tables.d");
392 if (!d)
393 return;
394
395 while ((de = readdir(d)) != NULL) {
396 char path[PATH_MAX];
397 size_t len;
398
399 if (*de->d_name == '.')
400 continue;
401
402 /* only consider filenames ending in '.conf' */
403 len = strlen(de->d_name);
404 if (len <= 5)
405 continue;
406 if (strcmp(de->d_name + len - 5, ".conf"))
407 continue;
408
68ef5072
SH
409 snprintf(path, sizeof(path),
410 CONFDIR "/rt_tables.d/%s", de->d_name);
13ada95d
DA
411 rtnl_hash_initialize(path, rtnl_rttable_hash, 256);
412 }
413 closedir(d);
aba5acdf
SH
414}
415
68ef5072 416const char *rtnl_rttable_n2a(__u32 id, char *buf, int len)
aba5acdf 417{
9c47d877
PM
418 struct rtnl_hash_entry *entry;
419
9c47d877
PM
420 if (!rtnl_rttable_init)
421 rtnl_rttable_initialize();
422 entry = rtnl_rttable_hash[id & 255];
423 while (entry && entry->id != id)
424 entry = entry->next;
ca697cee 425 if (!numeric && entry)
9c47d877
PM
426 return entry->name;
427 snprintf(buf, len, "%u", id);
aba5acdf
SH
428 return buf;
429}
430
46ac8a55 431int rtnl_rttable_a2n(__u32 *id, const char *arg)
aba5acdf 432{
68ef5072 433 static const char *cache;
aba5acdf 434 static unsigned long res;
9c47d877 435 struct rtnl_hash_entry *entry;
aba5acdf 436 char *end;
5ffbf450 437 unsigned long i;
aba5acdf
SH
438
439 if (cache && strcmp(cache, arg) == 0) {
440 *id = res;
441 return 0;
442 }
443
444 if (!rtnl_rttable_init)
445 rtnl_rttable_initialize();
446
68ef5072 447 for (i = 0; i < 256; i++) {
9c47d877
PM
448 entry = rtnl_rttable_hash[i];
449 while (entry && strcmp(entry->name, arg))
450 entry = entry->next;
451 if (entry) {
452 cache = entry->name;
453 res = entry->id;
aba5acdf
SH
454 *id = res;
455 return 0;
456 }
457 }
458
459 i = strtoul(arg, &end, 0);
9c47d877 460 if (!end || end == arg || *end || i > RT_TABLE_MAX)
aba5acdf
SH
461 return -1;
462 *id = i;
463 return 0;
464}
465
466
68ef5072 467static char *rtnl_rtdsfield_tab[256] = {
aba5acdf
SH
468 "0",
469};
470
471static int rtnl_rtdsfield_init;
472
473static void rtnl_rtdsfield_initialize(void)
474{
475 rtnl_rtdsfield_init = 1;
fb72129b 476 rtnl_tab_initialize(CONFDIR "/rt_dsfield",
aba5acdf
SH
477 rtnl_rtdsfield_tab, 256);
478}
479
46ac8a55 480const char *rtnl_dsfield_n2a(int id, char *buf, int len)
aba5acdf 481{
bf244ee6
PM
482 const char *name;
483
68ef5072 484 if (id < 0 || id >= 256) {
aba5acdf
SH
485 snprintf(buf, len, "%d", id);
486 return buf;
487 }
bf244ee6
PM
488 if (!numeric) {
489 name = rtnl_dsfield_get_name(id);
490 if (name != NULL)
491 return name;
492 }
493 snprintf(buf, len, "0x%02x", id);
494 return buf;
495}
496
497const char *rtnl_dsfield_get_name(int id)
498{
499 if (id < 0 || id >= 256)
500 return NULL;
aba5acdf
SH
501 if (!rtnl_rtdsfield_tab[id]) {
502 if (!rtnl_rtdsfield_init)
503 rtnl_rtdsfield_initialize();
504 }
bf244ee6 505 return rtnl_rtdsfield_tab[id];
aba5acdf
SH
506}
507
508
46ac8a55 509int rtnl_dsfield_a2n(__u32 *id, const char *arg)
aba5acdf 510{
68ef5072 511 static char *cache;
aba5acdf
SH
512 static unsigned long res;
513 char *end;
514 int i;
515
516 if (cache && strcmp(cache, arg) == 0) {
517 *id = res;
518 return 0;
519 }
520
521 if (!rtnl_rtdsfield_init)
522 rtnl_rtdsfield_initialize();
523
68ef5072 524 for (i = 0; i < 256; i++) {
aba5acdf
SH
525 if (rtnl_rtdsfield_tab[i] &&
526 strcmp(rtnl_rtdsfield_tab[i], arg) == 0) {
527 cache = rtnl_rtdsfield_tab[i];
528 res = i;
529 *id = res;
530 return 0;
531 }
532 }
533
534 res = strtoul(arg, &end, 16);
535 if (!end || end == arg || *end || res > 255)
536 return -1;
537 *id = res;
538 return 0;
539}
540
ac694c33 541
68ef5072
SH
542static struct rtnl_hash_entry dflt_group_entry = {
543 .id = 0, .name = "default"
544};
ac694c33 545
68ef5072 546static struct rtnl_hash_entry *rtnl_group_hash[256] = {
ac694c33
VD
547 [0] = &dflt_group_entry,
548};
549
550static int rtnl_group_init;
551
552static void rtnl_group_initialize(void)
553{
554 rtnl_group_init = 1;
4e5615b3 555 rtnl_hash_initialize(CONFDIR "/group",
ac694c33
VD
556 rtnl_group_hash, 256);
557}
558
46ac8a55 559int rtnl_group_a2n(int *id, const char *arg)
ac694c33 560{
68ef5072 561 static const char *cache;
ac694c33
VD
562 static unsigned long res;
563 struct rtnl_hash_entry *entry;
564 char *end;
565 int i;
566
567 if (cache && strcmp(cache, arg) == 0) {
568 *id = res;
569 return 0;
570 }
571
572 if (!rtnl_group_init)
573 rtnl_group_initialize();
574
68ef5072 575 for (i = 0; i < 256; i++) {
ac694c33
VD
576 entry = rtnl_group_hash[i];
577 while (entry && strcmp(entry->name, arg))
578 entry = entry->next;
579 if (entry) {
580 cache = entry->name;
581 res = entry->id;
582 *id = res;
583 return 0;
584 }
585 }
586
587 i = strtol(arg, &end, 0);
588 if (!end || end == arg || *end || i < 0)
589 return -1;
590 *id = i;
591 return 0;
592}
c4fdf75d
ST
593
594const char *rtnl_group_n2a(int id, char *buf, int len)
595{
596 struct rtnl_hash_entry *entry;
597 int i;
598
599 if (!rtnl_group_init)
600 rtnl_group_initialize();
601
ca697cee 602 for (i = 0; !numeric && i < 256; i++) {
c4fdf75d 603 entry = rtnl_group_hash[i];
2d98dd48
ZS
604
605 while (entry) {
606 if (entry->id == id)
607 return entry->name;
608 entry = entry->next;
609 }
c4fdf75d
ST
610 }
611
612 snprintf(buf, len, "%d", id);
613 return buf;
614}
eef43b50 615
616static char *nl_proto_tab[256] = {
617 [NETLINK_ROUTE] = "rtnl",
618 [NETLINK_UNUSED] = "unused",
619 [NETLINK_USERSOCK] = "usersock",
620 [NETLINK_FIREWALL] = "fw",
621 [NETLINK_SOCK_DIAG] = "tcpdiag",
622 [NETLINK_NFLOG] = "nflog",
623 [NETLINK_XFRM] = "xfrm",
624 [NETLINK_SELINUX] = "selinux",
625 [NETLINK_ISCSI] = "iscsi",
626 [NETLINK_AUDIT] = "audit",
627 [NETLINK_FIB_LOOKUP] = "fiblookup",
628 [NETLINK_CONNECTOR] = "connector",
629 [NETLINK_NETFILTER] = "nft",
630 [NETLINK_IP6_FW] = "ip6fw",
631 [NETLINK_DNRTMSG] = "dec-rt",
632 [NETLINK_KOBJECT_UEVENT] = "uevent",
633 [NETLINK_GENERIC] = "genl",
634 [NETLINK_SCSITRANSPORT] = "scsi-trans",
635 [NETLINK_ECRYPTFS] = "ecryptfs",
636 [NETLINK_RDMA] = "rdma",
637 [NETLINK_CRYPTO] = "crypto",
638};
639
640static int nl_proto_init;
641
642static void nl_proto_initialize(void)
643{
644 nl_proto_init = 1;
645 rtnl_tab_initialize(CONFDIR "/nl_protos",
646 nl_proto_tab, 256);
647}
648
649const char *nl_proto_n2a(int id, char *buf, int len)
650{
ca697cee
HL
651 if (id < 0 || id >= 256 || numeric) {
652 snprintf(buf, len, "%d", id);
eef43b50 653 return buf;
654 }
655
656 if (!nl_proto_init)
657 nl_proto_initialize();
658
659 if (nl_proto_tab[id])
660 return nl_proto_tab[id];
661
662 snprintf(buf, len, "%u", id);
663 return buf;
664}
665
666int nl_proto_a2n(__u32 *id, const char *arg)
667{
68ef5072 668 static char *cache;
eef43b50 669 static unsigned long res;
670 char *end;
671 int i;
672
673 if (cache && strcmp(cache, arg) == 0) {
674 *id = res;
675 return 0;
676 }
677
678 if (!nl_proto_init)
679 nl_proto_initialize();
680
681 for (i = 0; i < 256; i++) {
682 if (nl_proto_tab[i] &&
683 strcmp(nl_proto_tab[i], arg) == 0) {
684 cache = nl_proto_tab[i];
685 res = i;
686 *id = res;
687 return 0;
688 }
689 }
690
691 res = strtoul(arg, &end, 0);
692 if (!end || end == arg || *end || res > 255)
693 return -1;
694 *id = res;
695 return 0;
696}
6fd53b2a
RP
697
698#define PROTODOWN_REASON_NUM_BITS 32
699static char *protodown_reason_tab[PROTODOWN_REASON_NUM_BITS] = {
700};
701
702static int protodown_reason_init;
703
704static void protodown_reason_initialize(void)
705{
706 struct dirent *de;
707 DIR *d;
708
709 protodown_reason_init = 1;
710
711 d = opendir(CONFDIR "/protodown_reasons.d");
712 if (!d)
713 return;
714
715 while ((de = readdir(d)) != NULL) {
716 char path[PATH_MAX];
717 size_t len;
718
719 if (*de->d_name == '.')
720 continue;
721
722 /* only consider filenames ending in '.conf' */
723 len = strlen(de->d_name);
724 if (len <= 5)
725 continue;
726 if (strcmp(de->d_name + len - 5, ".conf"))
727 continue;
728
729 snprintf(path, sizeof(path), CONFDIR "/protodown_reasons.d/%s",
730 de->d_name);
731 rtnl_tab_initialize(path, protodown_reason_tab,
732 PROTODOWN_REASON_NUM_BITS);
733 }
734 closedir(d);
735}
736
737int protodown_reason_n2a(int id, char *buf, int len)
738{
739 if (id < 0 || id >= PROTODOWN_REASON_NUM_BITS)
740 return -1;
741
742 if (numeric) {
743 snprintf(buf, len, "%d", id);
744 return 0;
745 }
746
747 if (!protodown_reason_init)
748 protodown_reason_initialize();
749
750 if (protodown_reason_tab[id])
751 snprintf(buf, len, "%s", protodown_reason_tab[id]);
752 else
753 snprintf(buf, len, "%d", id);
754
755 return 0;
756}
757
758int protodown_reason_a2n(__u32 *id, const char *arg)
759{
760 static char *cache;
761 static unsigned long res;
762 char *end;
763 int i;
764
765 if (cache && strcmp(cache, arg) == 0) {
766 *id = res;
767 return 0;
768 }
769
770 if (!protodown_reason_init)
771 protodown_reason_initialize();
772
773 for (i = 0; i < PROTODOWN_REASON_NUM_BITS; i++) {
774 if (protodown_reason_tab[i] &&
775 strcmp(protodown_reason_tab[i], arg) == 0) {
776 cache = protodown_reason_tab[i];
777 res = i;
778 *id = res;
779 return 0;
780 }
781 }
782
783 res = strtoul(arg, &end, 0);
784 if (!end || end == arg || *end || res >= PROTODOWN_REASON_NUM_BITS)
785 return -1;
786 *id = res;
787 return 0;
788}