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