source: mainline/uspace/lib/nic/src/nic_addr_db.c@ 5e801dc

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 5e801dc was 5e801dc, checked in by GitHub <noreply@…>, 6 years ago

Indicate and enforce constness of hash table key in certain functions (#158)

The assumption here is that modifying key in the hash/equal functions in something completely unexpected, and not something you would ever want to do intentionally, so it makes sense to disallow it entirely to get that extra level of checking.

  • Property mode set to 100644
File size: 6.3 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 "nic_addr_db.h"
38#include <assert.h>
39#include <stdlib.h>
40#include <stdbool.h>
41#include <errno.h>
42#include <mem.h>
43#include <adt/hash_table.h>
44#include <macros.h>
45#include <stdint.h>
46
47/**
48 * Helper structure for keeping the address in the hash set.
49 */
50typedef struct nic_addr_entry {
51 ht_link_t link;
52 uint8_t len;
53 uint8_t addr[1];
54} nic_addr_entry_t;
55
56/*
57 * Hash table helper functions
58 */
59typedef struct {
60 size_t len;
61 const uint8_t *addr;
62} addr_key_t;
63
64static bool nic_addr_key_equal(const void *key_arg, const ht_link_t *item)
65{
66 const addr_key_t *key = key_arg;
67 nic_addr_entry_t *entry = member_to_inst(item, nic_addr_entry_t, link);
68
69 return memcmp(entry->addr, key->addr, entry->len) == 0;
70}
71
72static size_t addr_hash(size_t len, const uint8_t *addr)
73{
74 size_t hash = 0;
75
76 for (size_t i = 0; i < len; ++i) {
77 hash = (hash << 5) ^ addr[i];
78 }
79
80 return hash;
81}
82
83static size_t nic_addr_key_hash(const void *k)
84{
85 const addr_key_t *key = k;
86 return addr_hash(key->len, key->addr);
87}
88
89static size_t nic_addr_hash(const ht_link_t *item)
90{
91 nic_addr_entry_t *entry = member_to_inst(item, nic_addr_entry_t, link);
92 return addr_hash(entry->len, entry->addr);
93}
94
95static void nic_addr_removed(ht_link_t *item)
96{
97 nic_addr_entry_t *entry = member_to_inst(item, nic_addr_entry_t, link);
98
99 free(entry);
100}
101
102static hash_table_ops_t set_ops = {
103 .hash = nic_addr_hash,
104 .key_hash = nic_addr_key_hash,
105 .key_equal = nic_addr_key_equal,
106 .equal = NULL,
107 .remove_callback = nic_addr_removed
108};
109
110/**
111 * Initialize the database
112 *
113 * @param[in,out] db Uninitialized storage
114 * @param[in] addr_len Size of addresses in the db
115 *
116 * @return EOK If successfully initialized
117 * @return EINVAL If the address length is too big
118 * @return ENOMEM If there was not enough memory to initialize the storage
119 */
120errno_t nic_addr_db_init(nic_addr_db_t *db, size_t addr_len)
121{
122 assert(db);
123
124 if (addr_len > UCHAR_MAX)
125 return EINVAL;
126
127 if (!hash_table_create(&db->set, 0, 0, &set_ops))
128 return ENOMEM;
129
130 db->addr_len = addr_len;
131 return EOK;
132}
133
134/**
135 * Remove all records from the DB
136 *
137 * @param db
138 */
139void nic_addr_db_clear(nic_addr_db_t *db)
140{
141 assert(db);
142 hash_table_clear(&db->set);
143}
144
145/**
146 * Free the memory used by db, including all records...
147 *
148 * @param db
149 */
150void nic_addr_db_destroy(nic_addr_db_t *db)
151{
152 assert(db);
153 hash_table_destroy(&db->set);
154}
155
156/**
157 * Insert an address to the db
158 *
159 * @param db
160 * @param addr Inserted address. Length is implicitly concluded from the
161 * db's address length.
162 *
163 * @return EOK If the address was inserted
164 * @return ENOMEM If there was not enough memory
165 * @return EEXIST If this address already is in the db
166 */
167errno_t nic_addr_db_insert(nic_addr_db_t *db, const uint8_t *addr)
168{
169 assert(db && addr);
170
171 addr_key_t key = {
172 .len = db->addr_len,
173 .addr = addr
174 };
175
176 if (hash_table_find(&db->set, &key))
177 return EEXIST;
178
179 nic_addr_entry_t *entry = malloc(sizeof(nic_addr_entry_t) + db->addr_len - 1);
180 if (entry == NULL)
181 return ENOMEM;
182
183 entry->len = (uint8_t) db->addr_len;
184 memcpy(entry->addr, addr, db->addr_len);
185
186 hash_table_insert(&db->set, &entry->link);
187 return EOK;
188}
189
190/**
191 * Remove the address from the db
192 *
193 * @param db
194 * @param addr Removed address.
195 *
196 * @return EOK If the address was removed
197 * @return ENOENT If there is no address
198 */
199errno_t nic_addr_db_remove(nic_addr_db_t *db, const uint8_t *addr)
200{
201 assert(db && addr);
202
203 addr_key_t key = {
204 .len = db->addr_len,
205 .addr = addr
206 };
207
208 if (hash_table_remove(&db->set, &key))
209 return EOK;
210 else
211 return ENOENT;
212}
213
214/**
215 * Test if the address is contained in the db
216 *
217 * @param db
218 * @param addr Tested addresss
219 *
220 * @return true if the address is in the db, false otherwise
221 */
222bool nic_addr_db_contains(const nic_addr_db_t *db, const uint8_t *addr)
223{
224 assert(db && addr);
225
226 addr_key_t key = {
227 .len = db->addr_len,
228 .addr = addr
229 };
230
231 return 0 != hash_table_find(&db->set, &key);
232}
233
234/**
235 * Helper structure for nic_addr_db_foreach
236 */
237typedef struct {
238 void (*func)(const uint8_t *, void *);
239 void *arg;
240} nic_addr_db_fe_arg_t;
241
242/**
243 * Helper function for nic_addr_db_foreach
244 */
245static bool nic_addr_db_fe_helper(ht_link_t *item, void *arg)
246{
247 nic_addr_db_fe_arg_t *hs = (nic_addr_db_fe_arg_t *) arg;
248 nic_addr_entry_t *entry = member_to_inst(item, nic_addr_entry_t, link);
249 hs->func(entry->addr, hs->arg);
250 return true;
251}
252
253/**
254 * Executes a user-defined function on all addresses in the DB. The function
255 * must not change the addresses.
256 *
257 * @param db
258 * @param func User-defined function
259 * @param arg Custom argument passed to the function
260 */
261void nic_addr_db_foreach(const nic_addr_db_t *db,
262 void (*func)(const uint8_t *, void *), void *arg)
263{
264 nic_addr_db_fe_arg_t hs = { .func = func, .arg = arg };
265 hash_table_apply((hash_table_t *)&db->set, nic_addr_db_fe_helper, &hs);
266}
267
268/** @}
269 */
Note: See TracBrowser for help on using the repository browser.