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