1/*	$OpenBSD: name2id.c,v 1.2 2007/06/19 16:45:15 reyk 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 "ospfd.h"
29
30#define	IDVAL_MAX	50000
31
32u_int16_t	 _name2id(struct n2id_labels *, const char *);
33const char	*_id2name(struct n2id_labels *, u_int16_t);
34u_int32_t	 _id2tag(struct n2id_labels *, u_int16_t);
35u_int16_t	 _tag2id(struct n2id_labels *, u_int32_t);
36void		 _tag(struct n2id_labels *, u_int16_t, u_int32_t);
37void		 _unref(struct n2id_labels *, u_int16_t);
38void		 _ref(struct n2id_labels *, u_int16_t);
39
40struct n2id_labels	rt_labels = TAILQ_HEAD_INITIALIZER(rt_labels);
41
42u_int16_t
43rtlabel_name2id(const char *name)
44{
45	return (_name2id(&rt_labels, name));
46}
47
48const char *
49rtlabel_id2name(u_int16_t id)
50{
51	return (_id2name(&rt_labels, id));
52}
53
54u_int32_t
55rtlabel_id2tag(u_int16_t id)
56{
57	return (_id2tag(&rt_labels, id));
58}
59
60u_int16_t
61rtlabel_tag2id(u_int32_t tag)
62{
63	return (_tag2id(&rt_labels, tag));
64}
65
66void
67rtlabel_tag(u_int16_t id, u_int32_t tag)
68{
69	_tag(&rt_labels, id, tag);
70}
71
72void
73rtlabel_unref(u_int16_t id)
74{
75	_unref(&rt_labels, id);
76}
77
78/*
79void
80rtlabel_ref(u_int16_t id)
81{
82	_ref(&rt_labels, id);
83}
84*/
85
86u_int16_t
87_name2id(struct n2id_labels *head, const char *name)
88{
89	struct n2id_label	*label, *p = NULL;
90	u_int16_t		 new_id = 1;
91
92	if (!name[0]) {
93		errno = EINVAL;
94		return (0);
95	}
96
97	TAILQ_FOREACH(label, head, entry)
98		if (strcmp(name, label->name) == 0) {
99			label->ref++;
100			return (label->id);
101		}
102
103	/*
104	 * to avoid fragmentation, we do a linear search from the beginning
105	 * and take the first free slot we find. if there is none or the list
106	 * is empty, append a new entry at the end.
107	 */
108
109	if (!TAILQ_EMPTY(head))
110		for (p = TAILQ_FIRST(head); p != NULL &&
111		    p->id == new_id; p = TAILQ_NEXT(p, entry))
112			new_id = p->id + 1;
113
114	if (new_id > IDVAL_MAX) {
115		errno = ERANGE;
116		return (0);
117	}
118
119	if ((label = calloc(1, sizeof(struct n2id_label))) == NULL)
120		return (0);
121	if ((label->name = strdup(name)) == NULL) {
122		free(label);
123		return (0);
124	}
125	label->id = new_id;
126	label->ref++;
127
128	if (p != NULL)	/* insert new entry before p */
129		TAILQ_INSERT_BEFORE(p, label, entry);
130	else		/* either list empty or no free slot in between */
131		TAILQ_INSERT_TAIL(head, label, entry);
132
133	return (label->id);
134}
135
136const char *
137_id2name(struct n2id_labels *head, u_int16_t id)
138{
139	struct n2id_label	*label;
140
141	if (id == 0)
142		return ("");
143
144	TAILQ_FOREACH(label, head, entry)
145		if (label->id == id)
146			return (label->name);
147
148	return ("");
149}
150
151u_int32_t
152_id2tag(struct n2id_labels *head, u_int16_t id)
153{
154	struct n2id_label	*label;
155
156	if (id == 0)
157		return (0);
158
159	TAILQ_FOREACH(label, head, entry)
160		if (label->id == id)
161			return (label->ext_tag);
162
163	return (0);
164}
165
166u_int16_t
167_tag2id(struct n2id_labels *head, u_int32_t tag)
168{
169	struct n2id_label	*label;
170
171	if (tag == 0)
172		return (0);
173
174	TAILQ_FOREACH(label, head, entry)
175		if (label->ext_tag == tag)
176			return (label->id);
177
178	return (0);
179}
180
181void
182_tag(struct n2id_labels *head, u_int16_t id, u_int32_t tag)
183{
184	struct n2id_label	*label;
185
186	if (id == 0)
187		return;
188
189	TAILQ_FOREACH(label, head, entry)
190		if (label->id == id)
191			label->ext_tag = tag;
192}
193
194void
195_unref(struct n2id_labels *head, u_int16_t id)
196{
197	struct n2id_label	*p, *next;
198
199	if (id == 0)
200		return;
201
202	for (p = TAILQ_FIRST(head); p != NULL; p = next) {
203		next = TAILQ_NEXT(p, entry);
204		if (id == p->id) {
205			if (--p->ref == 0) {
206				TAILQ_REMOVE(head, p, entry);
207				free(p->name);
208				free(p);
209			}
210			break;
211		}
212	}
213}
214
215void
216_ref(struct n2id_labels *head, u_int16_t id)
217{
218	struct n2id_label	*label;
219
220	if (id == 0)
221		return;
222
223	TAILQ_FOREACH(label, head, entry)
224		if (label->id == id) {
225			++label->ref;
226			break;
227		}
228}
229