]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /********************************************************************* |
2 | * | |
3 | * Filename: irias_object.c | |
4 | * Version: 0.3 | |
5 | * Description: IAS object database and functions | |
6 | * Status: Experimental. | |
7 | * Author: Dag Brattli <[email protected]> | |
8 | * Created at: Thu Oct 1 22:50:04 1998 | |
9 | * Modified at: Wed Dec 15 11:23:16 1999 | |
10 | * Modified by: Dag Brattli <[email protected]> | |
11 | * | |
12 | * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved. | |
13 | * | |
14 | * This program is free software; you can redistribute it and/or | |
15 | * modify it under the terms of the GNU General Public License as | |
16 | * published by the Free Software Foundation; either version 2 of | |
17 | * the License, or (at your option) any later version. | |
18 | * | |
96de0e25 | 19 | * Neither Dag Brattli nor University of Tromsø admit liability nor |
1da177e4 LT |
20 | * provide warranty for any of this software. This material is |
21 | * provided "AS-IS" and at no charge. | |
22 | * | |
23 | ********************************************************************/ | |
24 | ||
5a0e3ad6 | 25 | #include <linux/slab.h> |
1da177e4 LT |
26 | #include <linux/string.h> |
27 | #include <linux/socket.h> | |
28 | #include <linux/module.h> | |
29 | ||
30 | #include <net/irda/irda.h> | |
31 | #include <net/irda/irias_object.h> | |
32 | ||
33 | hashbin_t *irias_objects; | |
34 | ||
35 | /* | |
36 | * Used when a missing value needs to be returned | |
37 | */ | |
38 | struct ias_value irias_missing = { IAS_MISSING, 0, 0, 0, {0}}; | |
39 | ||
1da177e4 LT |
40 | |
41 | /* | |
42 | * Function ias_new_object (name, id) | |
43 | * | |
44 | * Create a new IAS object | |
45 | * | |
46 | */ | |
47 | struct ias_object *irias_new_object( char *name, int id) | |
48 | { | |
6819bc2e | 49 | struct ias_object *obj; |
1da177e4 | 50 | |
0da974f4 | 51 | obj = kzalloc(sizeof(struct ias_object), GFP_ATOMIC); |
1da177e4 | 52 | if (obj == NULL) { |
6c91023d JP |
53 | net_warn_ratelimited("%s(), Unable to allocate object!\n", |
54 | __func__); | |
1da177e4 LT |
55 | return NULL; |
56 | } | |
1da177e4 LT |
57 | |
58 | obj->magic = IAS_OBJECT_MAGIC; | |
1e66df3e | 59 | obj->name = kstrndup(name, IAS_MAX_CLASSNAME, GFP_ATOMIC); |
bb5aa427 | 60 | if (!obj->name) { |
6c91023d JP |
61 | net_warn_ratelimited("%s(), Unable to allocate name!\n", |
62 | __func__); | |
bb5aa427 AM |
63 | kfree(obj); |
64 | return NULL; | |
65 | } | |
1da177e4 LT |
66 | obj->id = id; |
67 | ||
68 | /* Locking notes : the attrib spinlock has lower precendence | |
69 | * than the objects spinlock. Never grap the objects spinlock | |
70 | * while holding any attrib spinlock (risk of deadlock). Jean II */ | |
71 | obj->attribs = hashbin_new(HB_LOCK); | |
72 | ||
73 | if (obj->attribs == NULL) { | |
6c91023d JP |
74 | net_warn_ratelimited("%s(), Unable to allocate attribs!\n", |
75 | __func__); | |
bb5aa427 | 76 | kfree(obj->name); |
1da177e4 LT |
77 | kfree(obj); |
78 | return NULL; | |
79 | } | |
80 | ||
81 | return obj; | |
82 | } | |
83 | EXPORT_SYMBOL(irias_new_object); | |
84 | ||
85 | /* | |
86 | * Function irias_delete_attrib (attrib) | |
87 | * | |
88 | * Delete given attribute and deallocate all its memory | |
89 | * | |
90 | */ | |
91 | static void __irias_delete_attrib(struct ias_attrib *attrib) | |
92 | { | |
93 | IRDA_ASSERT(attrib != NULL, return;); | |
94 | IRDA_ASSERT(attrib->magic == IAS_ATTRIB_MAGIC, return;); | |
95 | ||
a51482bd | 96 | kfree(attrib->name); |
1da177e4 LT |
97 | |
98 | irias_delete_value(attrib->value); | |
99 | attrib->magic = ~IAS_ATTRIB_MAGIC; | |
100 | ||
101 | kfree(attrib); | |
102 | } | |
103 | ||
104 | void __irias_delete_object(struct ias_object *obj) | |
105 | { | |
106 | IRDA_ASSERT(obj != NULL, return;); | |
107 | IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;); | |
108 | ||
a51482bd | 109 | kfree(obj->name); |
1da177e4 LT |
110 | |
111 | hashbin_delete(obj->attribs, (FREE_FUNC) __irias_delete_attrib); | |
112 | ||
113 | obj->magic = ~IAS_OBJECT_MAGIC; | |
114 | ||
115 | kfree(obj); | |
116 | } | |
117 | ||
118 | /* | |
119 | * Function irias_delete_object (obj) | |
120 | * | |
121 | * Remove object from hashbin and deallocate all attributes associated with | |
122 | * with this object and the object itself | |
123 | * | |
124 | */ | |
125 | int irias_delete_object(struct ias_object *obj) | |
126 | { | |
127 | struct ias_object *node; | |
128 | ||
129 | IRDA_ASSERT(obj != NULL, return -1;); | |
130 | IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return -1;); | |
131 | ||
132 | /* Remove from list */ | |
133 | node = hashbin_remove_this(irias_objects, (irda_queue_t *) obj); | |
134 | if (!node) | |
955a9d20 JP |
135 | pr_debug("%s(), object already removed!\n", |
136 | __func__); | |
1da177e4 LT |
137 | |
138 | /* Destroy */ | |
139 | __irias_delete_object(obj); | |
140 | ||
141 | return 0; | |
142 | } | |
143 | EXPORT_SYMBOL(irias_delete_object); | |
144 | ||
145 | /* | |
146 | * Function irias_delete_attrib (obj) | |
147 | * | |
148 | * Remove attribute from hashbin and, if it was the last attribute of | |
149 | * the object, remove the object as well. | |
150 | * | |
151 | */ | |
152 | int irias_delete_attrib(struct ias_object *obj, struct ias_attrib *attrib, | |
153 | int cleanobject) | |
154 | { | |
155 | struct ias_attrib *node; | |
156 | ||
157 | IRDA_ASSERT(obj != NULL, return -1;); | |
158 | IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return -1;); | |
159 | IRDA_ASSERT(attrib != NULL, return -1;); | |
160 | ||
161 | /* Remove attribute from object */ | |
162 | node = hashbin_remove_this(obj->attribs, (irda_queue_t *) attrib); | |
163 | if (!node) | |
164 | return 0; /* Already removed or non-existent */ | |
165 | ||
166 | /* Deallocate attribute */ | |
167 | __irias_delete_attrib(node); | |
168 | ||
169 | /* Check if object has still some attributes, destroy it if none. | |
170 | * At first glance, this look dangerous, as the kernel reference | |
171 | * various IAS objects. However, we only use this function on | |
172 | * user attributes, not kernel attributes, so there is no risk | |
173 | * of deleting a kernel object this way. Jean II */ | |
174 | node = (struct ias_attrib *) hashbin_get_first(obj->attribs); | |
175 | if (cleanobject && !node) | |
176 | irias_delete_object(obj); | |
177 | ||
178 | return 0; | |
179 | } | |
180 | ||
181 | /* | |
182 | * Function irias_insert_object (obj) | |
183 | * | |
184 | * Insert an object into the LM-IAS database | |
185 | * | |
186 | */ | |
187 | void irias_insert_object(struct ias_object *obj) | |
188 | { | |
189 | IRDA_ASSERT(obj != NULL, return;); | |
190 | IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;); | |
191 | ||
192 | hashbin_insert(irias_objects, (irda_queue_t *) obj, 0, obj->name); | |
193 | } | |
194 | EXPORT_SYMBOL(irias_insert_object); | |
195 | ||
196 | /* | |
197 | * Function irias_find_object (name) | |
198 | * | |
199 | * Find object with given name | |
200 | * | |
201 | */ | |
202 | struct ias_object *irias_find_object(char *name) | |
203 | { | |
204 | IRDA_ASSERT(name != NULL, return NULL;); | |
205 | ||
206 | /* Unsafe (locking), object might change */ | |
207 | return hashbin_lock_find(irias_objects, 0, name); | |
208 | } | |
209 | EXPORT_SYMBOL(irias_find_object); | |
210 | ||
211 | /* | |
212 | * Function irias_find_attrib (obj, name) | |
213 | * | |
214 | * Find named attribute in object | |
215 | * | |
216 | */ | |
217 | struct ias_attrib *irias_find_attrib(struct ias_object *obj, char *name) | |
218 | { | |
219 | struct ias_attrib *attrib; | |
220 | ||
221 | IRDA_ASSERT(obj != NULL, return NULL;); | |
222 | IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return NULL;); | |
223 | IRDA_ASSERT(name != NULL, return NULL;); | |
224 | ||
225 | attrib = hashbin_lock_find(obj->attribs, 0, name); | |
226 | if (attrib == NULL) | |
227 | return NULL; | |
228 | ||
229 | /* Unsafe (locking), attrib might change */ | |
230 | return attrib; | |
231 | } | |
1da177e4 LT |
232 | |
233 | /* | |
234 | * Function irias_add_attribute (obj, attrib) | |
235 | * | |
236 | * Add attribute to object | |
237 | * | |
238 | */ | |
239 | static void irias_add_attrib(struct ias_object *obj, struct ias_attrib *attrib, | |
240 | int owner) | |
241 | { | |
242 | IRDA_ASSERT(obj != NULL, return;); | |
243 | IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;); | |
244 | ||
245 | IRDA_ASSERT(attrib != NULL, return;); | |
246 | IRDA_ASSERT(attrib->magic == IAS_ATTRIB_MAGIC, return;); | |
247 | ||
248 | /* Set if attrib is owned by kernel or user space */ | |
249 | attrib->value->owner = owner; | |
250 | ||
251 | hashbin_insert(obj->attribs, (irda_queue_t *) attrib, 0, attrib->name); | |
252 | } | |
253 | ||
254 | /* | |
255 | * Function irias_object_change_attribute (obj_name, attrib_name, new_value) | |
256 | * | |
257 | * Change the value of an objects attribute. | |
258 | * | |
259 | */ | |
260 | int irias_object_change_attribute(char *obj_name, char *attrib_name, | |
261 | struct ias_value *new_value) | |
262 | { | |
263 | struct ias_object *obj; | |
264 | struct ias_attrib *attrib; | |
265 | unsigned long flags; | |
266 | ||
267 | /* Find object */ | |
268 | obj = hashbin_lock_find(irias_objects, 0, obj_name); | |
269 | if (obj == NULL) { | |
6c91023d JP |
270 | net_warn_ratelimited("%s: Unable to find object: %s\n", |
271 | __func__, obj_name); | |
1da177e4 LT |
272 | return -1; |
273 | } | |
274 | ||
275 | /* Slightly unsafe (obj might get removed under us) */ | |
276 | spin_lock_irqsave(&obj->attribs->hb_spinlock, flags); | |
277 | ||
278 | /* Find attribute */ | |
279 | attrib = hashbin_find(obj->attribs, 0, attrib_name); | |
280 | if (attrib == NULL) { | |
6c91023d JP |
281 | net_warn_ratelimited("%s: Unable to find attribute: %s\n", |
282 | __func__, attrib_name); | |
1da177e4 LT |
283 | spin_unlock_irqrestore(&obj->attribs->hb_spinlock, flags); |
284 | return -1; | |
285 | } | |
286 | ||
287 | if ( attrib->value->type != new_value->type) { | |
955a9d20 JP |
288 | pr_debug("%s(), changing value type not allowed!\n", |
289 | __func__); | |
1da177e4 LT |
290 | spin_unlock_irqrestore(&obj->attribs->hb_spinlock, flags); |
291 | return -1; | |
292 | } | |
293 | ||
294 | /* Delete old value */ | |
295 | irias_delete_value(attrib->value); | |
296 | ||
297 | /* Insert new value */ | |
298 | attrib->value = new_value; | |
299 | ||
300 | /* Success */ | |
301 | spin_unlock_irqrestore(&obj->attribs->hb_spinlock, flags); | |
302 | return 0; | |
303 | } | |
304 | EXPORT_SYMBOL(irias_object_change_attribute); | |
305 | ||
306 | /* | |
307 | * Function irias_object_add_integer_attrib (obj, name, value) | |
308 | * | |
309 | * Add an integer attribute to an LM-IAS object | |
310 | * | |
311 | */ | |
312 | void irias_add_integer_attrib(struct ias_object *obj, char *name, int value, | |
313 | int owner) | |
314 | { | |
315 | struct ias_attrib *attrib; | |
316 | ||
317 | IRDA_ASSERT(obj != NULL, return;); | |
318 | IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;); | |
319 | IRDA_ASSERT(name != NULL, return;); | |
320 | ||
0da974f4 | 321 | attrib = kzalloc(sizeof(struct ias_attrib), GFP_ATOMIC); |
1da177e4 | 322 | if (attrib == NULL) { |
6c91023d JP |
323 | net_warn_ratelimited("%s: Unable to allocate attribute!\n", |
324 | __func__); | |
1da177e4 LT |
325 | return; |
326 | } | |
1da177e4 LT |
327 | |
328 | attrib->magic = IAS_ATTRIB_MAGIC; | |
1e66df3e | 329 | attrib->name = kstrndup(name, IAS_MAX_ATTRIBNAME, GFP_ATOMIC); |
1da177e4 LT |
330 | |
331 | /* Insert value */ | |
332 | attrib->value = irias_new_integer_value(value); | |
bb5aa427 | 333 | if (!attrib->name || !attrib->value) { |
6c91023d JP |
334 | net_warn_ratelimited("%s: Unable to allocate attribute!\n", |
335 | __func__); | |
bb5aa427 AM |
336 | if (attrib->value) |
337 | irias_delete_value(attrib->value); | |
338 | kfree(attrib->name); | |
339 | kfree(attrib); | |
340 | return; | |
341 | } | |
1da177e4 LT |
342 | |
343 | irias_add_attrib(obj, attrib, owner); | |
344 | } | |
345 | EXPORT_SYMBOL(irias_add_integer_attrib); | |
346 | ||
347 | /* | |
348 | * Function irias_add_octseq_attrib (obj, name, octet_seq, len) | |
349 | * | |
350 | * Add a octet sequence attribute to an LM-IAS object | |
351 | * | |
352 | */ | |
353 | ||
354 | void irias_add_octseq_attrib(struct ias_object *obj, char *name, __u8 *octets, | |
355 | int len, int owner) | |
356 | { | |
357 | struct ias_attrib *attrib; | |
358 | ||
359 | IRDA_ASSERT(obj != NULL, return;); | |
360 | IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;); | |
361 | ||
362 | IRDA_ASSERT(name != NULL, return;); | |
363 | IRDA_ASSERT(octets != NULL, return;); | |
364 | ||
0da974f4 | 365 | attrib = kzalloc(sizeof(struct ias_attrib), GFP_ATOMIC); |
1da177e4 | 366 | if (attrib == NULL) { |
6c91023d JP |
367 | net_warn_ratelimited("%s: Unable to allocate attribute!\n", |
368 | __func__); | |
1da177e4 LT |
369 | return; |
370 | } | |
1da177e4 LT |
371 | |
372 | attrib->magic = IAS_ATTRIB_MAGIC; | |
1e66df3e | 373 | attrib->name = kstrndup(name, IAS_MAX_ATTRIBNAME, GFP_ATOMIC); |
1da177e4 LT |
374 | |
375 | attrib->value = irias_new_octseq_value( octets, len); | |
bb5aa427 | 376 | if (!attrib->name || !attrib->value) { |
6c91023d JP |
377 | net_warn_ratelimited("%s: Unable to allocate attribute!\n", |
378 | __func__); | |
bb5aa427 AM |
379 | if (attrib->value) |
380 | irias_delete_value(attrib->value); | |
381 | kfree(attrib->name); | |
382 | kfree(attrib); | |
383 | return; | |
384 | } | |
1da177e4 LT |
385 | |
386 | irias_add_attrib(obj, attrib, owner); | |
387 | } | |
388 | EXPORT_SYMBOL(irias_add_octseq_attrib); | |
389 | ||
390 | /* | |
391 | * Function irias_object_add_string_attrib (obj, string) | |
392 | * | |
393 | * Add a string attribute to an LM-IAS object | |
394 | * | |
395 | */ | |
396 | void irias_add_string_attrib(struct ias_object *obj, char *name, char *value, | |
397 | int owner) | |
398 | { | |
399 | struct ias_attrib *attrib; | |
400 | ||
401 | IRDA_ASSERT(obj != NULL, return;); | |
402 | IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;); | |
403 | ||
404 | IRDA_ASSERT(name != NULL, return;); | |
405 | IRDA_ASSERT(value != NULL, return;); | |
406 | ||
0da974f4 | 407 | attrib = kzalloc(sizeof( struct ias_attrib), GFP_ATOMIC); |
1da177e4 | 408 | if (attrib == NULL) { |
6c91023d JP |
409 | net_warn_ratelimited("%s: Unable to allocate attribute!\n", |
410 | __func__); | |
1da177e4 LT |
411 | return; |
412 | } | |
1da177e4 LT |
413 | |
414 | attrib->magic = IAS_ATTRIB_MAGIC; | |
1e66df3e | 415 | attrib->name = kstrndup(name, IAS_MAX_ATTRIBNAME, GFP_ATOMIC); |
1da177e4 LT |
416 | |
417 | attrib->value = irias_new_string_value(value); | |
bb5aa427 | 418 | if (!attrib->name || !attrib->value) { |
6c91023d JP |
419 | net_warn_ratelimited("%s: Unable to allocate attribute!\n", |
420 | __func__); | |
bb5aa427 AM |
421 | if (attrib->value) |
422 | irias_delete_value(attrib->value); | |
423 | kfree(attrib->name); | |
424 | kfree(attrib); | |
425 | return; | |
426 | } | |
1da177e4 LT |
427 | |
428 | irias_add_attrib(obj, attrib, owner); | |
429 | } | |
430 | EXPORT_SYMBOL(irias_add_string_attrib); | |
431 | ||
432 | /* | |
433 | * Function irias_new_integer_value (integer) | |
434 | * | |
435 | * Create new IAS integer value | |
436 | * | |
437 | */ | |
438 | struct ias_value *irias_new_integer_value(int integer) | |
439 | { | |
440 | struct ias_value *value; | |
441 | ||
0da974f4 | 442 | value = kzalloc(sizeof(struct ias_value), GFP_ATOMIC); |
6c91023d | 443 | if (value == NULL) |
1da177e4 | 444 | return NULL; |
1da177e4 LT |
445 | |
446 | value->type = IAS_INTEGER; | |
447 | value->len = 4; | |
448 | value->t.integer = integer; | |
449 | ||
450 | return value; | |
451 | } | |
452 | EXPORT_SYMBOL(irias_new_integer_value); | |
453 | ||
454 | /* | |
455 | * Function irias_new_string_value (string) | |
456 | * | |
457 | * Create new IAS string value | |
458 | * | |
459 | * Per IrLMP 1.1, 4.3.3.2, strings are up to 256 chars - Jean II | |
460 | */ | |
461 | struct ias_value *irias_new_string_value(char *string) | |
462 | { | |
463 | struct ias_value *value; | |
464 | ||
0da974f4 | 465 | value = kzalloc(sizeof(struct ias_value), GFP_ATOMIC); |
6c91023d | 466 | if (value == NULL) |
1da177e4 | 467 | return NULL; |
1da177e4 LT |
468 | |
469 | value->type = IAS_STRING; | |
470 | value->charset = CS_ASCII; | |
1e66df3e | 471 | value->t.string = kstrndup(string, IAS_MAX_STRING, GFP_ATOMIC); |
bb5aa427 | 472 | if (!value->t.string) { |
6c91023d | 473 | net_warn_ratelimited("%s: Unable to kmalloc!\n", __func__); |
bb5aa427 AM |
474 | kfree(value); |
475 | return NULL; | |
476 | } | |
477 | ||
1da177e4 LT |
478 | value->len = strlen(value->t.string); |
479 | ||
480 | return value; | |
481 | } | |
1da177e4 LT |
482 | |
483 | /* | |
484 | * Function irias_new_octseq_value (octets, len) | |
485 | * | |
486 | * Create new IAS octet-sequence value | |
487 | * | |
488 | * Per IrLMP 1.1, 4.3.3.2, octet-sequence are up to 1024 bytes - Jean II | |
489 | */ | |
490 | struct ias_value *irias_new_octseq_value(__u8 *octseq , int len) | |
491 | { | |
492 | struct ias_value *value; | |
493 | ||
0da974f4 | 494 | value = kzalloc(sizeof(struct ias_value), GFP_ATOMIC); |
6c91023d | 495 | if (value == NULL) |
1da177e4 | 496 | return NULL; |
1da177e4 LT |
497 | |
498 | value->type = IAS_OCT_SEQ; | |
499 | /* Check length */ | |
500 | if(len > IAS_MAX_OCTET_STRING) | |
501 | len = IAS_MAX_OCTET_STRING; | |
502 | value->len = len; | |
503 | ||
b3ab09f9 | 504 | value->t.oct_seq = kmemdup(octseq, len, GFP_ATOMIC); |
1da177e4 | 505 | if (value->t.oct_seq == NULL){ |
6c91023d | 506 | net_warn_ratelimited("%s: Unable to kmalloc!\n", __func__); |
1da177e4 LT |
507 | kfree(value); |
508 | return NULL; | |
509 | } | |
1da177e4 LT |
510 | return value; |
511 | } | |
1da177e4 LT |
512 | |
513 | struct ias_value *irias_new_missing_value(void) | |
514 | { | |
515 | struct ias_value *value; | |
516 | ||
0da974f4 | 517 | value = kzalloc(sizeof(struct ias_value), GFP_ATOMIC); |
6c91023d | 518 | if (value == NULL) |
1da177e4 | 519 | return NULL; |
1da177e4 LT |
520 | |
521 | value->type = IAS_MISSING; | |
1da177e4 LT |
522 | |
523 | return value; | |
524 | } | |
525 | ||
526 | /* | |
527 | * Function irias_delete_value (value) | |
528 | * | |
529 | * Delete IAS value | |
530 | * | |
531 | */ | |
532 | void irias_delete_value(struct ias_value *value) | |
533 | { | |
1da177e4 LT |
534 | IRDA_ASSERT(value != NULL, return;); |
535 | ||
536 | switch (value->type) { | |
537 | case IAS_INTEGER: /* Fallthrough */ | |
538 | case IAS_MISSING: | |
539 | /* No need to deallocate */ | |
540 | break; | |
541 | case IAS_STRING: | |
a51482bd JJ |
542 | /* Deallocate string */ |
543 | kfree(value->t.string); | |
1da177e4 LT |
544 | break; |
545 | case IAS_OCT_SEQ: | |
a51482bd JJ |
546 | /* Deallocate byte stream */ |
547 | kfree(value->t.oct_seq); | |
1da177e4 LT |
548 | break; |
549 | default: | |
955a9d20 | 550 | pr_debug("%s(), Unknown value type!\n", __func__); |
1da177e4 LT |
551 | break; |
552 | } | |
553 | kfree(value); | |
554 | } | |
555 | EXPORT_SYMBOL(irias_delete_value); |