source: mainline/uspace/lib/nic/src/nic_addr_db.c@ 2732c94

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 2732c94 was 2732c94, checked in by Adam Hraska <adam.hraska+hos@…>, 13 years ago

Replaced separate uspace hash_set implementation with uspace's hash_table.

  • Property mode set to 100644
File size: 6.6 KB
Line 
1/*
2 * Copyright (c) 2011 Radim Vansa
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/**
30 * @addtogroup libnic
31 * @{
32 */
33/**
34 * @file
35 * @brief Generic hash-set based database of addresses
36 */
37#include <assert.h>
38#include <stdlib.h>
39#include <bool.h>
40#include <errno.h>
41#include <mem.h>
42
43#include "nic_addr_db.h"
44#include "adt/hash_table.h"
45//#include "string.h"
46
47
48/* Couple address bytes into KEY_CNT key fields. Align up to fit all bytes. */
49//#define KEY_CNT ((NIC_ADDR_MAX_LENGTH + sizeof(unsigned long) - 1) / sizeof(unsigned long))
50#define KEY_CNT 1
51
52/**
53 * Maximal length of addresses in the DB (in bytes).
54 */
55#define NIC_ADDR_MAX_LENGTH 16
56
57/**
58 * Helper structure for keeping the address in the hash set.
59 */
60typedef struct nic_addr_entry {
61 link_t link;
62 uint8_t addr[NIC_ADDR_MAX_LENGTH];
63} nic_addr_entry_t;
64
65
66/*
67 * Hash table helper functions
68 */
69
70static bool nic_addr_match(unsigned long *key, size_t key_cnt,
71 const link_t *item)
72{
73 /* Ugly type-punning hack. */
74 uint8_t *addr = (uint8_t*)key;
75 nic_addr_entry_t *entry = member_to_inst(item, nic_addr_entry_t, link);
76
77 return 0 == bcmp(entry->addr, addr, NIC_ADDR_MAX_LENGTH);
78}
79
80static size_t nic_addr_key_hash(unsigned long *key)
81{
82 uint8_t *addr = (uint8_t*)key;
83 size_t hash = 0;
84
85 for (int i = NIC_ADDR_MAX_LENGTH - 1; i >= 0; --i) {
86 hash = (hash << 8) ^ (hash >> 24) ^ addr[i];
87 }
88
89 return hash;
90}
91
92static size_t nic_addr_hash(const link_t *item)
93{
94 nic_addr_entry_t *entry = member_to_inst(item, nic_addr_entry_t, link);
95
96 /* Ugly type-punning hack. */
97 unsigned long *key = (unsigned long*)entry->addr;
98 return nic_addr_key_hash(key);
99}
100
101static void nic_addr_removed(link_t *item)
102{
103 nic_addr_entry_t *entry = member_to_inst(item, nic_addr_entry_t, link);
104
105 free(entry);
106}
107
108static hash_table_ops_t set_ops = {
109 .hash = nic_addr_hash,
110 .key_hash = nic_addr_key_hash,
111 .match = nic_addr_match,
112 .equal = 0,
113 .remove_callback = nic_addr_removed
114};
115
116/**
117 * Initialize the database
118 *
119 * @param[in,out] db Uninitialized storage
120 * @param[in] addr_len Size of addresses in the db
121 *
122 * @return EOK If successfully initialized
123 * @return EINVAL If the address length is too big
124 * @return ENOMEM If there was not enough memory to initialize the storage
125 */
126int nic_addr_db_init(nic_addr_db_t *db, size_t addr_len)
127{
128 assert(db);
129 if (addr_len > NIC_ADDR_MAX_LENGTH) {
130 return EINVAL;
131 }
132
133 if (!hash_table_create(&db->set, 0, KEY_CNT, &set_ops))
134 return ENOMEM;
135
136 db->addr_len = addr_len;
137 return EOK;
138}
139
140/**
141 * Remove all records from the DB
142 *
143 * @param db
144 */
145void nic_addr_db_clear(nic_addr_db_t *db)
146{
147 assert(db);
148 hash_table_clear(&db->set);
149}
150
151/**
152 * Free the memory used by db, including all records...
153 *
154 * @param db
155 */
156void nic_addr_db_destroy(nic_addr_db_t *db)
157{
158 assert(db);
159 nic_addr_db_clear(db);
160 hash_table_destroy(&db->set);
161}
162
163
164/**
165 * Insert an address to the db
166 *
167 * @param db
168 * @param addr Inserted address. Length is implicitly concluded from the
169 * db's address length.
170 *
171 * @return EOK If the address was inserted
172 * @return ENOMEM If there was not enough memory
173 * @return EEXIST If this adress already is in the db
174 */
175int nic_addr_db_insert(nic_addr_db_t *db, const uint8_t *addr)
176{
177 assert(db && addr);
178 /* Ugly type-punning hack. */
179 unsigned long *key = (unsigned long*)addr;
180
181 if (hash_table_find(&db->set, key))
182 return EEXIST;
183
184 nic_addr_entry_t *entry = malloc(sizeof(nic_addr_entry_t));
185 if (entry == NULL)
186 return ENOMEM;
187
188 link_initialize(&entry->link);
189
190 bzero(entry->addr, NIC_ADDR_MAX_LENGTH);
191 memcpy(entry->addr, addr, db->addr_len);
192
193 hash_table_insert(&db->set, &entry->link);
194 return EOK;
195}
196
197/**
198 * Remove the address from the db
199 *
200 * @param db
201 * @param addr Removed address.
202 *
203 * @return EOK If the address was removed
204 * @return ENOENT If there is no address
205 */
206int nic_addr_db_remove(nic_addr_db_t *db, const uint8_t *addr)
207{
208 assert(db && addr);
209 unsigned long *key = (unsigned long*)addr;
210
211 link_t *item = hash_table_find(&db->set, key);
212
213 if (item) {
214 hash_table_remove_item(&db->set, item);
215 return EOK;
216 } else {
217 return ENOENT;
218 }
219}
220
221/**
222 * Test if the address is contained in the db
223 *
224 * @param db
225 * @param addr Tested addresss
226 *
227 * @return true if the address is in the db, false otherwise
228 */
229int nic_addr_db_contains(const nic_addr_db_t *db, const uint8_t *addr)
230{
231 assert(db && addr);
232 unsigned long *key = (unsigned long*)addr;
233
234 return 0 != hash_table_find(&db->set, key);
235}
236
237/**
238 * Helper structure for nic_addr_db_foreach
239 */
240typedef struct {
241 void (*func)(const uint8_t *, void *);
242 void *arg;
243} nic_addr_db_fe_arg_t;
244
245/**
246 * Helper function for nic_addr_db_foreach
247 */
248static bool nic_addr_db_fe_helper(link_t *item, void *arg)
249{
250 nic_addr_db_fe_arg_t *hs = (nic_addr_db_fe_arg_t *) arg;
251 nic_addr_entry_t *entry = member_to_inst(item, nic_addr_entry_t, link);
252 hs->func(entry->addr, hs->arg);
253 return true;
254}
255
256/**
257 * Executes a user-defined function on all addresses in the DB. The function
258 * must not change the addresses.
259 *
260 * @param db
261 * @param func User-defined function
262 * @param arg Custom argument passed to the function
263 */
264void nic_addr_db_foreach(const nic_addr_db_t *db,
265 void (*func)(const uint8_t *, void *), void *arg)
266{
267 nic_addr_db_fe_arg_t hs = { .func = func, .arg = arg };
268 hash_table_apply((hash_table_t*)&db->set, nic_addr_db_fe_helper, &hs);
269}
270
271/** @}
272 */
Note: See TracBrowser for help on using the repository browser.