1 /* $OpenBSD: name2id.c,v 1.9 2009/06/04 04:46:42 claudio Exp $ */ 2 3 /* 4 * Copyright (c) 2004, 2005 Henning Brauer <henning@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN 15 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 16 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/socket.h> 21 22 #include <net/route.h> 23 24 #include <errno.h> 25 #include <stdlib.h> 26 #include <string.h> 27 28 #include "bgpd.h" 29 30 #define IDVAL_MAX 50000 31 32 struct n2id_label { 33 TAILQ_ENTRY(n2id_label) entry; 34 char *name; 35 u_int16_t id; 36 int ref; 37 }; 38 39 TAILQ_HEAD(n2id_labels, n2id_label); 40 41 u_int16_t _name2id(struct n2id_labels *, const char *); 42 const char *_id2name(struct n2id_labels *, u_int16_t); 43 void _unref(struct n2id_labels *, u_int16_t); 44 void _ref(struct n2id_labels *, u_int16_t); 45 46 struct n2id_labels rt_labels = TAILQ_HEAD_INITIALIZER(rt_labels); 47 struct n2id_labels pftable_labels = TAILQ_HEAD_INITIALIZER(pftable_labels); 48 49 u_int16_t 50 rtlabel_name2id(const char *name) 51 { 52 return (_name2id(&rt_labels, name)); 53 } 54 55 const char * 56 rtlabel_id2name(u_int16_t id) 57 { 58 return (_id2name(&rt_labels, id)); 59 } 60 61 void 62 rtlabel_unref(u_int16_t id) 63 { 64 _unref(&rt_labels, id); 65 } 66 67 void 68 rtlabel_ref(u_int16_t id) 69 { 70 _ref(&rt_labels, id); 71 } 72 73 u_int16_t 74 pftable_name2id(const char *name) 75 { 76 return (_name2id(&pftable_labels, name)); 77 } 78 79 const char * 80 pftable_id2name(u_int16_t id) 81 { 82 return (_id2name(&pftable_labels, id)); 83 } 84 85 void 86 pftable_unref(u_int16_t id) 87 { 88 _unref(&pftable_labels, id); 89 } 90 91 void 92 pftable_ref(u_int16_t id) 93 { 94 _ref(&pftable_labels, id); 95 } 96 97 u_int16_t 98 _name2id(struct n2id_labels *head, const char *name) 99 { 100 struct n2id_label *label, *p = NULL; 101 u_int16_t new_id = 1; 102 103 if (!name[0]) { 104 errno = EINVAL; 105 return (0); 106 } 107 108 TAILQ_FOREACH(label, head, entry) 109 if (strcmp(name, label->name) == 0) { 110 label->ref++; 111 return (label->id); 112 } 113 114 /* 115 * to avoid fragmentation, we do a linear search from the beginning 116 * and take the first free slot we find. if there is none or the list 117 * is empty, append a new entry at the end. 118 */ 119 120 if (!TAILQ_EMPTY(head)) 121 for (p = TAILQ_FIRST(head); p != NULL && 122 p->id == new_id; p = TAILQ_NEXT(p, entry)) 123 new_id = p->id + 1; 124 125 if (new_id > IDVAL_MAX) { 126 errno = ERANGE; 127 return (0); 128 } 129 130 if ((label = calloc(1, sizeof(struct n2id_label))) == NULL) 131 return (0); 132 if ((label->name = strdup(name)) == NULL) { 133 free(label); 134 return (0); 135 } 136 label->id = new_id; 137 label->ref++; 138 139 if (p != NULL) /* insert new entry before p */ 140 TAILQ_INSERT_BEFORE(p, label, entry); 141 else /* either list empty or no free slot in between */ 142 TAILQ_INSERT_TAIL(head, label, entry); 143 144 return (label->id); 145 } 146 147 const char * 148 _id2name(struct n2id_labels *head, u_int16_t id) 149 { 150 struct n2id_label *label; 151 152 if (id == 0) 153 return (""); 154 155 TAILQ_FOREACH(label, head, entry) 156 if (label->id == id) 157 return (label->name); 158 159 return (""); 160 } 161 162 void 163 _unref(struct n2id_labels *head, u_int16_t id) 164 { 165 struct n2id_label *p, *next; 166 167 if (id == 0) 168 return; 169 170 for (p = TAILQ_FIRST(head); p != NULL; p = next) { 171 next = TAILQ_NEXT(p, entry); 172 if (id == p->id) { 173 if (--p->ref == 0) { 174 TAILQ_REMOVE(head, p, entry); 175 free(p->name); 176 free(p); 177 } 178 break; 179 } 180 } 181 } 182 183 void 184 _ref(struct n2id_labels *head, u_int16_t id) 185 { 186 struct n2id_label *label; 187 188 if (id == 0) 189 return; 190 191 TAILQ_FOREACH(label, head, entry) 192 if (label->id == id) { 193 ++label->ref; 194 break; 195 } 196 } 197