]> git.karo-electronics.de Git - mv-sheeva.git/blob - net/tipc/user_reg.c
[TIPC] Moved configuration interface into tipc_config.h
[mv-sheeva.git] / net / tipc / user_reg.c
1 /*
2  * net/tipc/user_reg.c: TIPC user registry code
3  * 
4  * Copyright (c) 2003-2005, Ericsson Research Canada
5  * Copyright (c) 2004-2005, Wind River Systems
6  * Copyright (c) 2005-2006, Ericsson AB
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions are met:
11  * 
12  * Redistributions of source code must retain the above copyright notice, this
13  * list of conditions and the following disclaimer.
14  * Redistributions in binary form must reproduce the above copyright notice,
15  * this list of conditions and the following disclaimer in the documentation
16  * and/or other materials provided with the distribution.
17  * Neither the names of the copyright holders nor the names of its 
18  * contributors may be used to endorse or promote products derived from this
19  * software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include "core.h"
35 #include "user_reg.h"
36
37 /*
38  * TIPC user registry keeps track of users of the tipc_port interface.
39  *
40  * The registry utilizes an array of "TIPC user" entries; 
41  * a user's ID is the index of their associated array entry.
42  * Array entry 0 is not used, so userid 0 is not valid;
43  * TIPC sometimes uses this value to denote an anonymous user.
44  * The list of free entries is initially chained from last entry to entry 1.
45  */
46
47 /**
48  * struct tipc_user - registered TIPC user info
49  * @next: index of next free registry entry (or -1 for an allocated entry)
50  * @callback: ptr to routine to call when TIPC mode changes (NULL if none)
51  * @usr_handle: user-defined value passed to callback routine 
52  * @ports: list of user ports owned by the user
53  */
54
55 struct tipc_user {
56         int next;
57         tipc_mode_event callback;
58         void *usr_handle;
59         struct list_head ports;
60 };
61
62 #define MAX_USERID 64
63 #define USER_LIST_SIZE ((MAX_USERID + 1) * sizeof(struct tipc_user))
64
65 static struct tipc_user *users = 0;
66 static u32 next_free_user = MAX_USERID + 1;
67 static spinlock_t reg_lock = SPIN_LOCK_UNLOCKED;
68
69 /**
70  * reg_init - create TIPC user registry (but don't activate it)
71  * 
72  * If registry has been pre-initialized it is left "as is".
73  * NOTE: This routine may be called when TIPC is inactive.
74  */
75
76 static int reg_init(void)
77 {
78         u32 i;
79         
80         spin_lock_bh(&reg_lock);
81         if (!users) {
82                 users = (struct tipc_user *)kmalloc(USER_LIST_SIZE, GFP_ATOMIC);
83                 if (users) {
84                         memset(users, 0, USER_LIST_SIZE);
85                         for (i = 1; i <= MAX_USERID; i++) {
86                                 users[i].next = i - 1;
87                         }
88                         next_free_user = MAX_USERID;
89                 }
90         }
91         spin_unlock_bh(&reg_lock);
92         return users ? TIPC_OK : -ENOMEM;
93 }
94
95 /**
96  * reg_callback - inform TIPC user about current operating mode
97  */
98
99 static void reg_callback(struct tipc_user *user_ptr)
100 {
101         tipc_mode_event cb;
102         void *arg;
103
104         spin_lock_bh(&reg_lock);
105         cb = user_ptr->callback;
106         arg = user_ptr->usr_handle;
107         spin_unlock_bh(&reg_lock);
108
109         if (cb)
110                 cb(arg, tipc_mode, tipc_own_addr);
111 }
112
113 /**
114  * reg_start - activate TIPC user registry
115  */
116
117 int reg_start(void)
118 {
119         u32 u;
120         int res;
121
122         if ((res = reg_init()))
123                 return res;
124
125         for (u = 1; u <= MAX_USERID; u++) {
126                 if (users[u].callback)
127                         k_signal((Handler)reg_callback,
128                                  (unsigned long)&users[u]);
129         }
130         return TIPC_OK;
131 }
132
133 /**
134  * reg_stop - shut down & delete TIPC user registry
135  */
136
137 void reg_stop(void)
138 {               
139         int id;
140
141         if (!users)
142                 return;
143
144         for (id = 1; id <= MAX_USERID; id++) {
145                 if (users[id].callback)
146                         reg_callback(&users[id]);
147         }
148         kfree(users);
149         users = 0;
150 }
151
152 /**
153  * tipc_attach - register a TIPC user
154  *
155  * NOTE: This routine may be called when TIPC is inactive.
156  */
157
158 int tipc_attach(u32 *userid, tipc_mode_event cb, void *usr_handle)
159 {
160         struct tipc_user *user_ptr;
161
162         if ((tipc_mode == TIPC_NOT_RUNNING) && !cb)
163                 return -ENOPROTOOPT;
164         if (!users)
165                 reg_init();
166
167         spin_lock_bh(&reg_lock);
168         if (!next_free_user) {
169                 spin_unlock_bh(&reg_lock);
170                 return -EBUSY;
171         }
172         user_ptr = &users[next_free_user];
173         *userid = next_free_user;
174         next_free_user = user_ptr->next;
175         user_ptr->next = -1; 
176         spin_unlock_bh(&reg_lock);
177
178         user_ptr->callback = cb;
179         user_ptr->usr_handle = usr_handle;
180         INIT_LIST_HEAD(&user_ptr->ports);
181         atomic_inc(&tipc_user_count);
182         
183         if (cb && (tipc_mode != TIPC_NOT_RUNNING))
184                 k_signal((Handler)reg_callback, (unsigned long)user_ptr);
185         return TIPC_OK;
186 }
187
188 /**
189  * tipc_detach - deregister a TIPC user
190  */
191
192 void tipc_detach(u32 userid)
193 {
194         struct tipc_user *user_ptr;
195         struct list_head ports_temp;
196         struct user_port *up_ptr, *temp_up_ptr;
197
198         if ((userid == 0) || (userid > MAX_USERID))
199                 return;
200
201         spin_lock_bh(&reg_lock);
202         if ((!users) || (users[userid].next >= 0)) {
203                 spin_unlock_bh(&reg_lock);
204                 return;
205         }
206
207         user_ptr = &users[userid];
208         user_ptr->callback = NULL;              
209         INIT_LIST_HEAD(&ports_temp);
210         list_splice(&user_ptr->ports, &ports_temp);
211         user_ptr->next = next_free_user;
212         next_free_user = userid;
213         spin_unlock_bh(&reg_lock);
214
215         atomic_dec(&tipc_user_count);
216
217         list_for_each_entry_safe(up_ptr, temp_up_ptr, &ports_temp, uport_list) {
218                 tipc_deleteport(up_ptr->ref);
219         }
220 }
221
222 /**
223  * reg_add_port - register a user's driver port
224  */
225
226 int reg_add_port(struct user_port *up_ptr)
227 {
228         struct tipc_user *user_ptr;
229
230         if (up_ptr->user_ref == 0)
231                 return TIPC_OK;
232         if (up_ptr->user_ref > MAX_USERID)
233                 return -EINVAL;
234         if ((tipc_mode == TIPC_NOT_RUNNING) || !users )
235                 return -ENOPROTOOPT;
236
237         spin_lock_bh(&reg_lock);
238         user_ptr = &users[up_ptr->user_ref];
239         list_add(&up_ptr->uport_list, &user_ptr->ports);
240         spin_unlock_bh(&reg_lock);
241         return TIPC_OK;
242 }
243
244 /**
245  * reg_remove_port - deregister a user's driver port
246  */
247
248 int reg_remove_port(struct user_port *up_ptr)
249 {
250         if (up_ptr->user_ref == 0)
251                 return TIPC_OK;
252         if (up_ptr->user_ref > MAX_USERID)
253                 return -EINVAL;
254         if (!users )
255                 return -ENOPROTOOPT;
256
257         spin_lock_bh(&reg_lock);
258         list_del_init(&up_ptr->uport_list);
259         spin_unlock_bh(&reg_lock);
260         return TIPC_OK;
261 }
262