blob: 57e39c16a8c309030b3f4333909fe3a0040b2e1e [file] [log] [blame]
Per Lidenb97bf3f2006-01-02 19:04:38 +01001/*
2 * net/tipc/name_table.c: TIPC name table code
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003 *
Richard Alpe15931232014-11-20 10:29:20 +01004 * Copyright (c) 2000-2006, 2014, Ericsson AB
Ying Xue993bfe52014-12-02 15:00:24 +08005 * Copyright (c) 2004-2008, 2010-2014, Wind River Systems
Per Lidenb97bf3f2006-01-02 19:04:38 +01006 * All rights reserved.
7 *
Per Liden9ea1fd32006-01-11 13:30:43 +01008 * Redistribution and use in source and binary forms, with or without
Per Lidenb97bf3f2006-01-02 19:04:38 +01009 * modification, are permitted provided that the following conditions are met:
10 *
Per Liden9ea1fd32006-01-11 13:30:43 +010011 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the names of the copyright holders nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
Per Lidenb97bf3f2006-01-02 19:04:38 +010019 *
Per Liden9ea1fd32006-01-11 13:30:43 +010020 * Alternatively, this software may be distributed under the terms of the
21 * GNU General Public License ("GPL") version 2 as published by the Free
22 * Software Foundation.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
Per Lidenb97bf3f2006-01-02 19:04:38 +010034 * POSSIBILITY OF SUCH DAMAGE.
35 */
36
Ying Xue4ac1c8d2015-01-09 15:27:09 +080037#include <net/sock.h>
Per Lidenb97bf3f2006-01-02 19:04:38 +010038#include "core.h"
39#include "config.h"
Per Lidenb97bf3f2006-01-02 19:04:38 +010040#include "name_table.h"
41#include "name_distr.h"
Per Lidenb97bf3f2006-01-02 19:04:38 +010042#include "subscr.h"
Ying Xue1da46562015-01-09 15:27:07 +080043#include "bcast.h"
Per Lidenb97bf3f2006-01-02 19:04:38 +010044
Ying Xuef046e7d2012-08-16 12:09:11 +000045#define TIPC_NAMETBL_SIZE 1024 /* must be a power of 2 */
Per Lidenb97bf3f2006-01-02 19:04:38 +010046
Richard Alpe15931232014-11-20 10:29:20 +010047static const struct nla_policy
48tipc_nl_name_table_policy[TIPC_NLA_NAME_TABLE_MAX + 1] = {
49 [TIPC_NLA_NAME_TABLE_UNSPEC] = { .type = NLA_UNSPEC },
50 [TIPC_NLA_NAME_TABLE_PUBL] = { .type = NLA_NESTED }
51};
52
Per Lidenb97bf3f2006-01-02 19:04:38 +010053/**
Allan Stephensb52124a2011-05-30 09:44:38 -040054 * struct name_info - name sequence publication info
Allan Stephens968edbe2008-07-14 22:45:33 -070055 * @node_list: circular list of publications made by own node
56 * @cluster_list: circular list of publications made by own cluster
57 * @zone_list: circular list of publications made by own zone
58 * @node_list_size: number of entries in "node_list"
59 * @cluster_list_size: number of entries in "cluster_list"
60 * @zone_list_size: number of entries in "zone_list"
61 *
62 * Note: The zone list always contains at least one entry, since all
63 * publications of the associated name sequence belong to it.
64 * (The cluster and node lists may be empty.)
Per Lidenb97bf3f2006-01-02 19:04:38 +010065 */
Allan Stephensb52124a2011-05-30 09:44:38 -040066struct name_info {
Allan Stephensf6f0a4d2011-05-30 10:48:48 -040067 struct list_head node_list;
68 struct list_head cluster_list;
69 struct list_head zone_list;
Allan Stephens968edbe2008-07-14 22:45:33 -070070 u32 node_list_size;
71 u32 cluster_list_size;
72 u32 zone_list_size;
Per Lidenb97bf3f2006-01-02 19:04:38 +010073};
74
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +090075/**
Allan Stephensb52124a2011-05-30 09:44:38 -040076 * struct sub_seq - container for all published instances of a name sequence
77 * @lower: name sequence lower bound
78 * @upper: name sequence upper bound
79 * @info: pointer to name sequence publication info
80 */
Allan Stephensb52124a2011-05-30 09:44:38 -040081struct sub_seq {
82 u32 lower;
83 u32 upper;
84 struct name_info *info;
85};
86
87/**
Per Lidenb97bf3f2006-01-02 19:04:38 +010088 * struct name_seq - container for all published instances of a name type
89 * @type: 32 bit 'type' value for name sequence
90 * @sseq: pointer to dynamically-sized array of sub-sequences of this 'type';
91 * sub-sequences are sorted in ascending order
92 * @alloc: number of sub-sequences currently in array
Allan Stephensf1310722006-06-25 23:51:37 -070093 * @first_free: array index of first unused sub-sequence entry
Per Lidenb97bf3f2006-01-02 19:04:38 +010094 * @ns_list: links to adjacent name sequences in hash chain
95 * @subscriptions: list of subscriptions for this 'type'
Allan Stephens307fdf52008-06-04 17:38:22 -070096 * @lock: spinlock controlling access to publication lists of all sub-sequences
Ying Xue97ede292014-12-02 15:00:30 +080097 * @rcu: RCU callback head used for deferred freeing
Per Lidenb97bf3f2006-01-02 19:04:38 +010098 */
Per Lidenb97bf3f2006-01-02 19:04:38 +010099struct name_seq {
100 u32 type;
101 struct sub_seq *sseqs;
102 u32 alloc;
103 u32 first_free;
104 struct hlist_node ns_list;
105 struct list_head subscriptions;
106 spinlock_t lock;
Ying Xue97ede292014-12-02 15:00:30 +0800107 struct rcu_head rcu;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100108};
109
Sam Ravnborg05790c62006-03-20 22:37:04 -0800110static int hash(int x)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100111{
Ying Xuef046e7d2012-08-16 12:09:11 +0000112 return x & (TIPC_NAMETBL_SIZE - 1);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100113}
114
115/**
116 * publ_create - create a publication structure
117 */
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900118static struct publication *publ_create(u32 type, u32 lower, u32 upper,
119 u32 scope, u32 node, u32 port_ref,
Per Lidenb97bf3f2006-01-02 19:04:38 +0100120 u32 key)
121{
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700122 struct publication *publ = kzalloc(sizeof(*publ), GFP_ATOMIC);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100123 if (publ == NULL) {
Erik Hugne2cf8aa12012-06-29 00:16:37 -0400124 pr_warn("Publication creation failure, no memory\n");
Sam Ravnborg1fc54d82006-03-20 22:36:47 -0800125 return NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100126 }
127
Per Lidenb97bf3f2006-01-02 19:04:38 +0100128 publ->type = type;
129 publ->lower = lower;
130 publ->upper = upper;
131 publ->scope = scope;
132 publ->node = node;
133 publ->ref = port_ref;
134 publ->key = key;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100135 INIT_LIST_HEAD(&publ->pport_list);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100136 return publ;
137}
138
139/**
Per Liden4323add2006-01-18 00:38:21 +0100140 * tipc_subseq_alloc - allocate a specified number of sub-sequence structures
Per Lidenb97bf3f2006-01-02 19:04:38 +0100141 */
Adrian Bunk988f0882006-03-20 22:37:52 -0800142static struct sub_seq *tipc_subseq_alloc(u32 cnt)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100143{
wangweidong0cee6bb2013-12-12 09:36:39 +0800144 return kcalloc(cnt, sizeof(struct sub_seq), GFP_ATOMIC);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100145}
146
147/**
Per Liden4323add2006-01-18 00:38:21 +0100148 * tipc_nameseq_create - create a name sequence structure for the specified 'type'
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900149 *
Per Lidenb97bf3f2006-01-02 19:04:38 +0100150 * Allocates a single sub-sequence structure and sets it to all 0's.
151 */
Adrian Bunk988f0882006-03-20 22:37:52 -0800152static struct name_seq *tipc_nameseq_create(u32 type, struct hlist_head *seq_head)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100153{
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700154 struct name_seq *nseq = kzalloc(sizeof(*nseq), GFP_ATOMIC);
Per Liden4323add2006-01-18 00:38:21 +0100155 struct sub_seq *sseq = tipc_subseq_alloc(1);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100156
157 if (!nseq || !sseq) {
Erik Hugne2cf8aa12012-06-29 00:16:37 -0400158 pr_warn("Name sequence creation failed, no memory\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +0100159 kfree(nseq);
160 kfree(sseq);
Sam Ravnborg1fc54d82006-03-20 22:36:47 -0800161 return NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100162 }
163
Ingo Molnar34af9462006-06-27 02:53:55 -0700164 spin_lock_init(&nseq->lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100165 nseq->type = type;
166 nseq->sseqs = sseq;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100167 nseq->alloc = 1;
168 INIT_HLIST_NODE(&nseq->ns_list);
169 INIT_LIST_HEAD(&nseq->subscriptions);
Ying Xue97ede292014-12-02 15:00:30 +0800170 hlist_add_head_rcu(&nseq->ns_list, seq_head);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100171 return nseq;
172}
173
Ben Hutchings2c530402012-07-10 10:55:09 +0000174/**
Per Lidenb97bf3f2006-01-02 19:04:38 +0100175 * nameseq_find_subseq - find sub-sequence (if any) matching a name instance
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900176 *
Per Lidenb97bf3f2006-01-02 19:04:38 +0100177 * Very time-critical, so binary searches through sub-sequence array.
178 */
Sam Ravnborg05790c62006-03-20 22:37:04 -0800179static struct sub_seq *nameseq_find_subseq(struct name_seq *nseq,
180 u32 instance)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100181{
182 struct sub_seq *sseqs = nseq->sseqs;
183 int low = 0;
184 int high = nseq->first_free - 1;
185 int mid;
186
187 while (low <= high) {
188 mid = (low + high) / 2;
189 if (instance < sseqs[mid].lower)
190 high = mid - 1;
191 else if (instance > sseqs[mid].upper)
192 low = mid + 1;
193 else
194 return &sseqs[mid];
195 }
Sam Ravnborg1fc54d82006-03-20 22:36:47 -0800196 return NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100197}
198
199/**
200 * nameseq_locate_subseq - determine position of name instance in sub-sequence
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900201 *
Per Lidenb97bf3f2006-01-02 19:04:38 +0100202 * Returns index in sub-sequence array of the entry that contains the specified
203 * instance value; if no entry contains that value, returns the position
204 * where a new entry for it would be inserted in the array.
205 *
206 * Note: Similar to binary search code for locating a sub-sequence.
207 */
Per Lidenb97bf3f2006-01-02 19:04:38 +0100208static u32 nameseq_locate_subseq(struct name_seq *nseq, u32 instance)
209{
210 struct sub_seq *sseqs = nseq->sseqs;
211 int low = 0;
212 int high = nseq->first_free - 1;
213 int mid;
214
215 while (low <= high) {
216 mid = (low + high) / 2;
217 if (instance < sseqs[mid].lower)
218 high = mid - 1;
219 else if (instance > sseqs[mid].upper)
220 low = mid + 1;
221 else
222 return mid;
223 }
224 return low;
225}
226
227/**
Paul Gortmaker617d3c72012-04-30 15:29:02 -0400228 * tipc_nameseq_insert_publ
Per Lidenb97bf3f2006-01-02 19:04:38 +0100229 */
Adrian Bunk988f0882006-03-20 22:37:52 -0800230static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq,
231 u32 type, u32 lower, u32 upper,
232 u32 scope, u32 node, u32 port, u32 key)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100233{
Paul Gortmakerfead3902011-12-29 20:43:44 -0500234 struct tipc_subscription *s;
235 struct tipc_subscription *st;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100236 struct publication *publ;
237 struct sub_seq *sseq;
Allan Stephensb52124a2011-05-30 09:44:38 -0400238 struct name_info *info;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100239 int created_subseq = 0;
240
Per Lidenb97bf3f2006-01-02 19:04:38 +0100241 sseq = nameseq_find_subseq(nseq, lower);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100242 if (sseq) {
243
244 /* Lower end overlaps existing entry => need an exact match */
Per Lidenb97bf3f2006-01-02 19:04:38 +0100245 if ((sseq->lower != lower) || (sseq->upper != upper)) {
Sam Ravnborg1fc54d82006-03-20 22:36:47 -0800246 return NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100247 }
Allan Stephensb52124a2011-05-30 09:44:38 -0400248
249 info = sseq->info;
Allan Stephensf80c24d2011-11-03 11:12:01 -0400250
251 /* Check if an identical publication already exists */
252 list_for_each_entry(publ, &info->zone_list, zone_list) {
253 if ((publ->ref == port) && (publ->key == key) &&
254 (!publ->node || (publ->node == node)))
255 return NULL;
256 }
Per Lidenb97bf3f2006-01-02 19:04:38 +0100257 } else {
258 u32 inspos;
259 struct sub_seq *freesseq;
260
261 /* Find where lower end should be inserted */
Per Lidenb97bf3f2006-01-02 19:04:38 +0100262 inspos = nameseq_locate_subseq(nseq, lower);
263
264 /* Fail if upper end overlaps into an existing entry */
Per Lidenb97bf3f2006-01-02 19:04:38 +0100265 if ((inspos < nseq->first_free) &&
266 (upper >= nseq->sseqs[inspos].lower)) {
Sam Ravnborg1fc54d82006-03-20 22:36:47 -0800267 return NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100268 }
269
270 /* Ensure there is space for new sub-sequence */
Per Lidenb97bf3f2006-01-02 19:04:38 +0100271 if (nseq->first_free == nseq->alloc) {
Allan Stephens9ab230f2006-06-25 23:37:24 -0700272 struct sub_seq *sseqs = tipc_subseq_alloc(nseq->alloc * 2);
273
274 if (!sseqs) {
Erik Hugne2cf8aa12012-06-29 00:16:37 -0400275 pr_warn("Cannot publish {%u,%u,%u}, no memory\n",
276 type, lower, upper);
Sam Ravnborg1fc54d82006-03-20 22:36:47 -0800277 return NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100278 }
Allan Stephens9ab230f2006-06-25 23:37:24 -0700279 memcpy(sseqs, nseq->sseqs,
280 nseq->alloc * sizeof(struct sub_seq));
281 kfree(nseq->sseqs);
282 nseq->sseqs = sseqs;
283 nseq->alloc *= 2;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100284 }
Per Lidenb97bf3f2006-01-02 19:04:38 +0100285
Allan Stephensb52124a2011-05-30 09:44:38 -0400286 info = kzalloc(sizeof(*info), GFP_ATOMIC);
287 if (!info) {
Erik Hugne2cf8aa12012-06-29 00:16:37 -0400288 pr_warn("Cannot publish {%u,%u,%u}, no memory\n",
289 type, lower, upper);
Allan Stephensb52124a2011-05-30 09:44:38 -0400290 return NULL;
291 }
292
Allan Stephensf6f0a4d2011-05-30 10:48:48 -0400293 INIT_LIST_HEAD(&info->node_list);
294 INIT_LIST_HEAD(&info->cluster_list);
295 INIT_LIST_HEAD(&info->zone_list);
296
Per Lidenb97bf3f2006-01-02 19:04:38 +0100297 /* Insert new sub-sequence */
Per Lidenb97bf3f2006-01-02 19:04:38 +0100298 sseq = &nseq->sseqs[inspos];
299 freesseq = &nseq->sseqs[nseq->first_free];
Allan Stephens0e659672010-12-31 18:59:32 +0000300 memmove(sseq + 1, sseq, (freesseq - sseq) * sizeof(*sseq));
301 memset(sseq, 0, sizeof(*sseq));
Per Lidenb97bf3f2006-01-02 19:04:38 +0100302 nseq->first_free++;
303 sseq->lower = lower;
304 sseq->upper = upper;
Allan Stephensb52124a2011-05-30 09:44:38 -0400305 sseq->info = info;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100306 created_subseq = 1;
307 }
Per Lidenb97bf3f2006-01-02 19:04:38 +0100308
Paul Gortmaker617d3c72012-04-30 15:29:02 -0400309 /* Insert a publication */
Per Lidenb97bf3f2006-01-02 19:04:38 +0100310 publ = publ_create(type, lower, upper, scope, node, port, key);
311 if (!publ)
Sam Ravnborg1fc54d82006-03-20 22:36:47 -0800312 return NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100313
Allan Stephensf6f0a4d2011-05-30 10:48:48 -0400314 list_add(&publ->zone_list, &info->zone_list);
Allan Stephensb52124a2011-05-30 09:44:38 -0400315 info->zone_list_size++;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100316
Allan Stephensd4f5c122012-04-17 18:16:34 -0400317 if (in_own_cluster(node)) {
Allan Stephensf6f0a4d2011-05-30 10:48:48 -0400318 list_add(&publ->cluster_list, &info->cluster_list);
Allan Stephensb52124a2011-05-30 09:44:38 -0400319 info->cluster_list_size++;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100320 }
321
Allan Stephensd4f5c122012-04-17 18:16:34 -0400322 if (in_own_node(node)) {
Allan Stephensf6f0a4d2011-05-30 10:48:48 -0400323 list_add(&publ->node_list, &info->node_list);
Allan Stephensb52124a2011-05-30 09:44:38 -0400324 info->node_list_size++;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100325 }
326
Paul Gortmaker617d3c72012-04-30 15:29:02 -0400327 /* Any subscriptions waiting for notification? */
Per Lidenb97bf3f2006-01-02 19:04:38 +0100328 list_for_each_entry_safe(s, st, &nseq->subscriptions, nameseq_list) {
Per Liden4323add2006-01-18 00:38:21 +0100329 tipc_subscr_report_overlap(s,
330 publ->lower,
331 publ->upper,
332 TIPC_PUBLISHED,
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900333 publ->ref,
Per Liden4323add2006-01-18 00:38:21 +0100334 publ->node,
335 created_subseq);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100336 }
337 return publ;
338}
339
340/**
Paul Gortmaker617d3c72012-04-30 15:29:02 -0400341 * tipc_nameseq_remove_publ
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900342 *
Allan Stephensf1310722006-06-25 23:51:37 -0700343 * NOTE: There may be cases where TIPC is asked to remove a publication
344 * that is not in the name table. For example, if another node issues a
345 * publication for a name sequence that overlaps an existing name sequence
346 * the publication will not be recorded, which means the publication won't
347 * be found when the name sequence is later withdrawn by that node.
348 * A failed withdraw request simply returns a failure indication and lets the
349 * caller issue any error or warning messages associated with such a problem.
Per Lidenb97bf3f2006-01-02 19:04:38 +0100350 */
Adrian Bunk988f0882006-03-20 22:37:52 -0800351static struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 inst,
352 u32 node, u32 ref, u32 key)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100353{
354 struct publication *publ;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100355 struct sub_seq *sseq = nameseq_find_subseq(nseq, inst);
Allan Stephensb52124a2011-05-30 09:44:38 -0400356 struct name_info *info;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100357 struct sub_seq *free;
Paul Gortmakerfead3902011-12-29 20:43:44 -0500358 struct tipc_subscription *s, *st;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100359 int removed_subseq = 0;
360
Allan Stephensf1310722006-06-25 23:51:37 -0700361 if (!sseq)
Sam Ravnborg1fc54d82006-03-20 22:36:47 -0800362 return NULL;
Allan Stephensf1310722006-06-25 23:51:37 -0700363
Allan Stephensb52124a2011-05-30 09:44:38 -0400364 info = sseq->info;
365
Allan Stephensf6f0a4d2011-05-30 10:48:48 -0400366 /* Locate publication, if it exists */
Allan Stephensf6f0a4d2011-05-30 10:48:48 -0400367 list_for_each_entry(publ, &info->zone_list, zone_list) {
368 if ((publ->key == key) && (publ->ref == ref) &&
369 (!publ->node || (publ->node == node)))
370 goto found;
371 }
372 return NULL;
373
374found:
Allan Stephensf1310722006-06-25 23:51:37 -0700375 /* Remove publication from zone scope list */
Allan Stephensf6f0a4d2011-05-30 10:48:48 -0400376 list_del(&publ->zone_list);
Allan Stephensb52124a2011-05-30 09:44:38 -0400377 info->zone_list_size--;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100378
Allan Stephensf1310722006-06-25 23:51:37 -0700379 /* Remove publication from cluster scope list, if present */
Allan Stephensd4f5c122012-04-17 18:16:34 -0400380 if (in_own_cluster(node)) {
Allan Stephensf6f0a4d2011-05-30 10:48:48 -0400381 list_del(&publ->cluster_list);
Allan Stephensb52124a2011-05-30 09:44:38 -0400382 info->cluster_list_size--;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100383 }
Allan Stephensf1310722006-06-25 23:51:37 -0700384
385 /* Remove publication from node scope list, if present */
Allan Stephensd4f5c122012-04-17 18:16:34 -0400386 if (in_own_node(node)) {
Allan Stephensf6f0a4d2011-05-30 10:48:48 -0400387 list_del(&publ->node_list);
Allan Stephensb52124a2011-05-30 09:44:38 -0400388 info->node_list_size--;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100389 }
Per Lidenb97bf3f2006-01-02 19:04:38 +0100390
Allan Stephensf1310722006-06-25 23:51:37 -0700391 /* Contract subseq list if no more publications for that subseq */
Allan Stephensf6f0a4d2011-05-30 10:48:48 -0400392 if (list_empty(&info->zone_list)) {
Allan Stephensb52124a2011-05-30 09:44:38 -0400393 kfree(info);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100394 free = &nseq->sseqs[nseq->first_free--];
Allan Stephens0e659672010-12-31 18:59:32 +0000395 memmove(sseq, sseq + 1, (free - (sseq + 1)) * sizeof(*sseq));
Per Lidenb97bf3f2006-01-02 19:04:38 +0100396 removed_subseq = 1;
397 }
398
Allan Stephensf1310722006-06-25 23:51:37 -0700399 /* Notify any waiting subscriptions */
Per Lidenb97bf3f2006-01-02 19:04:38 +0100400 list_for_each_entry_safe(s, st, &nseq->subscriptions, nameseq_list) {
Per Liden4323add2006-01-18 00:38:21 +0100401 tipc_subscr_report_overlap(s,
402 publ->lower,
403 publ->upper,
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900404 TIPC_WITHDRAWN,
405 publ->ref,
Per Liden4323add2006-01-18 00:38:21 +0100406 publ->node,
407 removed_subseq);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100408 }
Allan Stephensf1310722006-06-25 23:51:37 -0700409
Per Lidenb97bf3f2006-01-02 19:04:38 +0100410 return publ;
411}
412
413/**
Ben Hutchings2c530402012-07-10 10:55:09 +0000414 * tipc_nameseq_subscribe - attach a subscription, and issue
Per Lidenb97bf3f2006-01-02 19:04:38 +0100415 * the prescribed number of events if there is any sub-
416 * sequence overlapping with the requested sequence
417 */
Paul Gortmakerfead3902011-12-29 20:43:44 -0500418static void tipc_nameseq_subscribe(struct name_seq *nseq,
Paul Gortmakerae8509c2013-06-17 10:54:47 -0400419 struct tipc_subscription *s)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100420{
421 struct sub_seq *sseq = nseq->sseqs;
422
423 list_add(&s->nameseq_list, &nseq->subscriptions);
424
425 if (!sseq)
426 return;
427
428 while (sseq != &nseq->sseqs[nseq->first_free]) {
Allan Stephensf6f0a4d2011-05-30 10:48:48 -0400429 if (tipc_subscr_overlap(s, sseq->lower, sseq->upper)) {
430 struct publication *crs;
431 struct name_info *info = sseq->info;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100432 int must_report = 1;
433
Allan Stephensf6f0a4d2011-05-30 10:48:48 -0400434 list_for_each_entry(crs, &info->zone_list, zone_list) {
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900435 tipc_subscr_report_overlap(s,
436 sseq->lower,
Per Liden4323add2006-01-18 00:38:21 +0100437 sseq->upper,
438 TIPC_PUBLISHED,
439 crs->ref,
440 crs->node,
441 must_report);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100442 must_report = 0;
Allan Stephensf6f0a4d2011-05-30 10:48:48 -0400443 }
Per Lidenb97bf3f2006-01-02 19:04:38 +0100444 }
445 sseq++;
446 }
447}
448
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800449static struct name_seq *nametbl_find_seq(struct net *net, u32 type)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100450{
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800451 struct tipc_net *tn = net_generic(net, tipc_net_id);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100452 struct hlist_head *seq_head;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100453 struct name_seq *ns;
454
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800455 seq_head = &tn->nametbl->seq_hlist[hash(type)];
Ying Xue97ede292014-12-02 15:00:30 +0800456 hlist_for_each_entry_rcu(ns, seq_head, ns_list) {
Allan Stephensb29f1422010-12-31 18:59:25 +0000457 if (ns->type == type)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100458 return ns;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100459 }
460
Sam Ravnborg1fc54d82006-03-20 22:36:47 -0800461 return NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100462};
463
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800464struct publication *tipc_nametbl_insert_publ(struct net *net, u32 type,
465 u32 lower, u32 upper, u32 scope,
466 u32 node, u32 port, u32 key)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100467{
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800468 struct tipc_net *tn = net_generic(net, tipc_net_id);
Ying Xuefb9962f2014-12-02 15:00:26 +0800469 struct publication *publ;
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800470 struct name_seq *seq = nametbl_find_seq(net, type);
Ying Xue993bfe52014-12-02 15:00:24 +0800471 int index = hash(type);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100472
Allan Stephens8f177892012-04-26 17:57:17 -0400473 if ((scope < TIPC_ZONE_SCOPE) || (scope > TIPC_NODE_SCOPE) ||
474 (lower > upper)) {
Erik Hugne2cf8aa12012-06-29 00:16:37 -0400475 pr_debug("Failed to publish illegal {%u,%u,%u} with scope %u\n",
476 type, lower, upper, scope);
Sam Ravnborg1fc54d82006-03-20 22:36:47 -0800477 return NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100478 }
479
Allan Stephensb29f1422010-12-31 18:59:25 +0000480 if (!seq)
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800481 seq = tipc_nameseq_create(type, &tn->nametbl->seq_hlist[index]);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100482 if (!seq)
Sam Ravnborg1fc54d82006-03-20 22:36:47 -0800483 return NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100484
Ying Xuefb9962f2014-12-02 15:00:26 +0800485 spin_lock_bh(&seq->lock);
486 publ = tipc_nameseq_insert_publ(seq, type, lower, upper,
Per Liden4323add2006-01-18 00:38:21 +0100487 scope, node, port, key);
Ying Xuefb9962f2014-12-02 15:00:26 +0800488 spin_unlock_bh(&seq->lock);
489 return publ;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100490}
491
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800492struct publication *tipc_nametbl_remove_publ(struct net *net, u32 type,
493 u32 lower, u32 node, u32 ref,
494 u32 key)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100495{
496 struct publication *publ;
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800497 struct name_seq *seq = nametbl_find_seq(net, type);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100498
499 if (!seq)
Sam Ravnborg1fc54d82006-03-20 22:36:47 -0800500 return NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100501
Ying Xuefb9962f2014-12-02 15:00:26 +0800502 spin_lock_bh(&seq->lock);
Per Liden4323add2006-01-18 00:38:21 +0100503 publ = tipc_nameseq_remove_publ(seq, lower, node, ref, key);
Ying Xuefb9962f2014-12-02 15:00:26 +0800504 if (!seq->first_free && list_empty(&seq->subscriptions)) {
Ying Xue97ede292014-12-02 15:00:30 +0800505 hlist_del_init_rcu(&seq->ns_list);
Ying Xuefb9962f2014-12-02 15:00:26 +0800506 kfree(seq->sseqs);
Ying Xue97ede292014-12-02 15:00:30 +0800507 spin_unlock_bh(&seq->lock);
508 kfree_rcu(seq, rcu);
Ying Xuefb9962f2014-12-02 15:00:26 +0800509 return publ;
510 }
511 spin_unlock_bh(&seq->lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100512 return publ;
513}
514
Ben Hutchings2c530402012-07-10 10:55:09 +0000515/**
Allan Stephensbc9f8142011-11-07 17:00:54 -0500516 * tipc_nametbl_translate - perform name translation
Per Lidenb97bf3f2006-01-02 19:04:38 +0100517 *
Allan Stephensbc9f8142011-11-07 17:00:54 -0500518 * On entry, 'destnode' is the search domain used during translation.
519 *
520 * On exit:
521 * - if name translation is deferred to another node/cluster/zone,
522 * leaves 'destnode' unchanged (will be non-zero) and returns 0
523 * - if name translation is attempted and succeeds, sets 'destnode'
524 * to publishing node and returns port reference (will be non-zero)
525 * - if name translation is attempted and fails, sets 'destnode' to 0
526 * and returns 0
Per Lidenb97bf3f2006-01-02 19:04:38 +0100527 */
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800528u32 tipc_nametbl_translate(struct net *net, u32 type, u32 instance,
529 u32 *destnode)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100530{
531 struct sub_seq *sseq;
Allan Stephensb52124a2011-05-30 09:44:38 -0400532 struct name_info *info;
Allan Stephensf6f0a4d2011-05-30 10:48:48 -0400533 struct publication *publ;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100534 struct name_seq *seq;
Allan Stephensf6f0a4d2011-05-30 10:48:48 -0400535 u32 ref = 0;
Allan Stephensbc9f8142011-11-07 17:00:54 -0500536 u32 node = 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100537
Allan Stephensc68ca7b2010-05-11 14:30:12 +0000538 if (!tipc_in_scope(*destnode, tipc_own_addr))
Per Lidenb97bf3f2006-01-02 19:04:38 +0100539 return 0;
540
Ying Xue97ede292014-12-02 15:00:30 +0800541 rcu_read_lock();
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800542 seq = nametbl_find_seq(net, type);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100543 if (unlikely(!seq))
544 goto not_found;
Ying Xuefb9962f2014-12-02 15:00:26 +0800545 spin_lock_bh(&seq->lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100546 sseq = nameseq_find_subseq(seq, instance);
547 if (unlikely(!sseq))
Ying Xuefb9962f2014-12-02 15:00:26 +0800548 goto no_match;
Allan Stephensb52124a2011-05-30 09:44:38 -0400549 info = sseq->info;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100550
Paul Gortmaker617d3c72012-04-30 15:29:02 -0400551 /* Closest-First Algorithm */
Per Lidenb97bf3f2006-01-02 19:04:38 +0100552 if (likely(!*destnode)) {
Allan Stephensf6f0a4d2011-05-30 10:48:48 -0400553 if (!list_empty(&info->node_list)) {
554 publ = list_first_entry(&info->node_list,
555 struct publication,
556 node_list);
557 list_move_tail(&publ->node_list,
558 &info->node_list);
559 } else if (!list_empty(&info->cluster_list)) {
560 publ = list_first_entry(&info->cluster_list,
561 struct publication,
562 cluster_list);
563 list_move_tail(&publ->cluster_list,
564 &info->cluster_list);
Allan Stephens8af46382011-05-30 11:27:50 -0400565 } else {
Allan Stephensf6f0a4d2011-05-30 10:48:48 -0400566 publ = list_first_entry(&info->zone_list,
567 struct publication,
568 zone_list);
569 list_move_tail(&publ->zone_list,
570 &info->zone_list);
Allan Stephens8af46382011-05-30 11:27:50 -0400571 }
Per Lidenb97bf3f2006-01-02 19:04:38 +0100572 }
573
Paul Gortmaker617d3c72012-04-30 15:29:02 -0400574 /* Round-Robin Algorithm */
Per Lidenb97bf3f2006-01-02 19:04:38 +0100575 else if (*destnode == tipc_own_addr) {
Allan Stephensf6f0a4d2011-05-30 10:48:48 -0400576 if (list_empty(&info->node_list))
577 goto no_match;
578 publ = list_first_entry(&info->node_list, struct publication,
579 node_list);
580 list_move_tail(&publ->node_list, &info->node_list);
Allan Stephens336ebf52012-04-17 18:02:01 -0400581 } else if (in_own_cluster_exact(*destnode)) {
Allan Stephensf6f0a4d2011-05-30 10:48:48 -0400582 if (list_empty(&info->cluster_list))
583 goto no_match;
584 publ = list_first_entry(&info->cluster_list, struct publication,
585 cluster_list);
586 list_move_tail(&publ->cluster_list, &info->cluster_list);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100587 } else {
Allan Stephensf6f0a4d2011-05-30 10:48:48 -0400588 publ = list_first_entry(&info->zone_list, struct publication,
589 zone_list);
590 list_move_tail(&publ->zone_list, &info->zone_list);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100591 }
Allan Stephensf6f0a4d2011-05-30 10:48:48 -0400592
593 ref = publ->ref;
Allan Stephensbc9f8142011-11-07 17:00:54 -0500594 node = publ->node;
Allan Stephensf6f0a4d2011-05-30 10:48:48 -0400595no_match:
Per Lidenb97bf3f2006-01-02 19:04:38 +0100596 spin_unlock_bh(&seq->lock);
597not_found:
Ying Xue97ede292014-12-02 15:00:30 +0800598 rcu_read_unlock();
Allan Stephensbc9f8142011-11-07 17:00:54 -0500599 *destnode = node;
Allan Stephensf6f0a4d2011-05-30 10:48:48 -0400600 return ref;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100601}
602
603/**
Per Liden4323add2006-01-18 00:38:21 +0100604 * tipc_nametbl_mc_translate - find multicast destinations
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900605 *
Per Lidenb97bf3f2006-01-02 19:04:38 +0100606 * Creates list of all local ports that overlap the given multicast address;
607 * also determines if any off-node ports overlap.
608 *
609 * Note: Publications with a scope narrower than 'limit' are ignored.
610 * (i.e. local node-scope publications mustn't receive messages arriving
611 * from another node, even if the multcast link brought it here)
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900612 *
Per Lidenb97bf3f2006-01-02 19:04:38 +0100613 * Returns non-zero if any off-node ports overlap
614 */
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800615int tipc_nametbl_mc_translate(struct net *net, u32 type, u32 lower, u32 upper,
616 u32 limit, struct tipc_port_list *dports)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100617{
618 struct name_seq *seq;
619 struct sub_seq *sseq;
620 struct sub_seq *sseq_stop;
Allan Stephensb52124a2011-05-30 09:44:38 -0400621 struct name_info *info;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100622 int res = 0;
623
Ying Xue97ede292014-12-02 15:00:30 +0800624 rcu_read_lock();
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800625 seq = nametbl_find_seq(net, type);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100626 if (!seq)
627 goto exit;
628
629 spin_lock_bh(&seq->lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100630 sseq = seq->sseqs + nameseq_locate_subseq(seq, lower);
631 sseq_stop = seq->sseqs + seq->first_free;
632 for (; sseq != sseq_stop; sseq++) {
633 struct publication *publ;
634
635 if (sseq->lower > upper)
636 break;
Allan Stephens968edbe2008-07-14 22:45:33 -0700637
Allan Stephensb52124a2011-05-30 09:44:38 -0400638 info = sseq->info;
Allan Stephensf6f0a4d2011-05-30 10:48:48 -0400639 list_for_each_entry(publ, &info->node_list, node_list) {
640 if (publ->scope <= limit)
641 tipc_port_list_add(dports, publ->ref);
Allan Stephens968edbe2008-07-14 22:45:33 -0700642 }
643
Allan Stephensb52124a2011-05-30 09:44:38 -0400644 if (info->cluster_list_size != info->node_list_size)
Allan Stephens968edbe2008-07-14 22:45:33 -0700645 res = 1;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100646 }
Per Lidenb97bf3f2006-01-02 19:04:38 +0100647 spin_unlock_bh(&seq->lock);
648exit:
Ying Xue97ede292014-12-02 15:00:30 +0800649 rcu_read_unlock();
Per Lidenb97bf3f2006-01-02 19:04:38 +0100650 return res;
651}
652
Allan Stephensc422f1b2011-11-02 15:49:40 -0400653/*
Per Liden4323add2006-01-18 00:38:21 +0100654 * tipc_nametbl_publish - add name publication to network name tables
Per Lidenb97bf3f2006-01-02 19:04:38 +0100655 */
Ying Xuef2f98002015-01-09 15:27:05 +0800656struct publication *tipc_nametbl_publish(struct net *net, u32 type, u32 lower,
657 u32 upper, u32 scope, u32 port_ref,
658 u32 key)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100659{
660 struct publication *publ;
Ying Xueeab8c0452014-04-28 18:00:10 +0800661 struct sk_buff *buf = NULL;
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800662 struct tipc_net *tn = net_generic(net, tipc_net_id);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100663
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800664 spin_lock_bh(&tn->nametbl_lock);
665 if (tn->nametbl->local_publ_count >= TIPC_MAX_PUBLICATIONS) {
Erik Hugne2cf8aa12012-06-29 00:16:37 -0400666 pr_warn("Publication failed, local publication limit reached (%u)\n",
Ying Xuee6a04b12012-08-16 12:09:14 +0000667 TIPC_MAX_PUBLICATIONS);
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800668 spin_unlock_bh(&tn->nametbl_lock);
Sam Ravnborg1fc54d82006-03-20 22:36:47 -0800669 return NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100670 }
Per Lidenb97bf3f2006-01-02 19:04:38 +0100671
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800672 publ = tipc_nametbl_insert_publ(net, type, lower, upper, scope,
673 tipc_own_addr, port_ref, key);
Allan Stephensfd6eced2011-11-09 14:22:52 -0500674 if (likely(publ)) {
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800675 tn->nametbl->local_publ_count++;
676 buf = tipc_named_publish(net, publ);
Erik Hugnea5325ae2014-08-28 09:08:47 +0200677 /* Any pending external events? */
Ying Xuef2f98002015-01-09 15:27:05 +0800678 tipc_named_process_backlog(net);
Allan Stephensfd6eced2011-11-09 14:22:52 -0500679 }
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800680 spin_unlock_bh(&tn->nametbl_lock);
Ying Xueeab8c0452014-04-28 18:00:10 +0800681
682 if (buf)
Ying Xuef2f98002015-01-09 15:27:05 +0800683 named_cluster_distribute(net, buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100684 return publ;
685}
686
687/**
Per Liden4323add2006-01-18 00:38:21 +0100688 * tipc_nametbl_withdraw - withdraw name publication from network name tables
Per Lidenb97bf3f2006-01-02 19:04:38 +0100689 */
Ying Xuef2f98002015-01-09 15:27:05 +0800690int tipc_nametbl_withdraw(struct net *net, u32 type, u32 lower, u32 ref,
691 u32 key)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100692{
693 struct publication *publ;
Ying Xue54923902014-12-02 15:00:28 +0800694 struct sk_buff *skb = NULL;
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800695 struct tipc_net *tn = net_generic(net, tipc_net_id);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100696
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800697 spin_lock_bh(&tn->nametbl_lock);
698 publ = tipc_nametbl_remove_publ(net, type, lower, tipc_own_addr,
699 ref, key);
Allan Stephensf1310722006-06-25 23:51:37 -0700700 if (likely(publ)) {
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800701 tn->nametbl->local_publ_count--;
Ying Xue54923902014-12-02 15:00:28 +0800702 skb = tipc_named_withdraw(publ);
Erik Hugnea5325ae2014-08-28 09:08:47 +0200703 /* Any pending external events? */
Ying Xuef2f98002015-01-09 15:27:05 +0800704 tipc_named_process_backlog(net);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100705 list_del_init(&publ->pport_list);
Ying Xue97ede292014-12-02 15:00:30 +0800706 kfree_rcu(publ, rcu);
Ying Xue54923902014-12-02 15:00:28 +0800707 } else {
708 pr_err("Unable to remove local publication\n"
709 "(type=%u, lower=%u, ref=%u, key=%u)\n",
710 type, lower, ref, key);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100711 }
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800712 spin_unlock_bh(&tn->nametbl_lock);
Ying Xue54923902014-12-02 15:00:28 +0800713
714 if (skb) {
Ying Xuef2f98002015-01-09 15:27:05 +0800715 named_cluster_distribute(net, skb);
Ying Xue54923902014-12-02 15:00:28 +0800716 return 1;
717 }
Per Lidenb97bf3f2006-01-02 19:04:38 +0100718 return 0;
719}
720
721/**
Per Liden4323add2006-01-18 00:38:21 +0100722 * tipc_nametbl_subscribe - add a subscription object to the name table
Per Lidenb97bf3f2006-01-02 19:04:38 +0100723 */
Paul Gortmakerfead3902011-12-29 20:43:44 -0500724void tipc_nametbl_subscribe(struct tipc_subscription *s)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100725{
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800726 struct tipc_net *tn = net_generic(s->net, tipc_net_id);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100727 u32 type = s->seq.type;
Ying Xue993bfe52014-12-02 15:00:24 +0800728 int index = hash(type);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100729 struct name_seq *seq;
730
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800731 spin_lock_bh(&tn->nametbl_lock);
732 seq = nametbl_find_seq(s->net, type);
Allan Stephensa0168922010-12-31 18:59:35 +0000733 if (!seq)
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800734 seq = tipc_nameseq_create(type, &tn->nametbl->seq_hlist[index]);
Allan Stephens0e659672010-12-31 18:59:32 +0000735 if (seq) {
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900736 spin_lock_bh(&seq->lock);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900737 tipc_nameseq_subscribe(seq, s);
738 spin_unlock_bh(&seq->lock);
739 } else {
Erik Hugne2cf8aa12012-06-29 00:16:37 -0400740 pr_warn("Failed to create subscription for {%u,%u,%u}\n",
741 s->seq.type, s->seq.lower, s->seq.upper);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900742 }
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800743 spin_unlock_bh(&tn->nametbl_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100744}
745
746/**
Per Liden4323add2006-01-18 00:38:21 +0100747 * tipc_nametbl_unsubscribe - remove a subscription object from name table
Per Lidenb97bf3f2006-01-02 19:04:38 +0100748 */
Paul Gortmakerfead3902011-12-29 20:43:44 -0500749void tipc_nametbl_unsubscribe(struct tipc_subscription *s)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100750{
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800751 struct tipc_net *tn = net_generic(s->net, tipc_net_id);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100752 struct name_seq *seq;
753
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800754 spin_lock_bh(&tn->nametbl_lock);
755 seq = nametbl_find_seq(s->net, s->seq.type);
Allan Stephens0e659672010-12-31 18:59:32 +0000756 if (seq != NULL) {
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900757 spin_lock_bh(&seq->lock);
758 list_del_init(&s->nameseq_list);
Ying Xuefb9962f2014-12-02 15:00:26 +0800759 if (!seq->first_free && list_empty(&seq->subscriptions)) {
Ying Xue97ede292014-12-02 15:00:30 +0800760 hlist_del_init_rcu(&seq->ns_list);
Ying Xuefb9962f2014-12-02 15:00:26 +0800761 kfree(seq->sseqs);
Ying Xue97ede292014-12-02 15:00:30 +0800762 spin_unlock_bh(&seq->lock);
763 kfree_rcu(seq, rcu);
Ying Xuefb9962f2014-12-02 15:00:26 +0800764 } else {
765 spin_unlock_bh(&seq->lock);
766 }
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900767 }
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800768 spin_unlock_bh(&tn->nametbl_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100769}
770
Per Lidenb97bf3f2006-01-02 19:04:38 +0100771/**
Ben Hutchings2c530402012-07-10 10:55:09 +0000772 * subseq_list - print specified sub-sequence contents into the given buffer
Per Lidenb97bf3f2006-01-02 19:04:38 +0100773 */
Erik Hugnedc1aed32012-06-29 00:50:23 -0400774static int subseq_list(struct sub_seq *sseq, char *buf, int len, u32 depth,
Paul Gortmakerae8509c2013-06-17 10:54:47 -0400775 u32 index)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100776{
777 char portIdStr[27];
Allan Stephensc2de5812010-08-17 11:00:14 +0000778 const char *scope_str[] = {"", " zone", " cluster", " node"};
Allan Stephensf6f0a4d2011-05-30 10:48:48 -0400779 struct publication *publ;
780 struct name_info *info;
Erik Hugnedc1aed32012-06-29 00:50:23 -0400781 int ret;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100782
Erik Hugnedc1aed32012-06-29 00:50:23 -0400783 ret = tipc_snprintf(buf, len, "%-10u %-10u ", sseq->lower, sseq->upper);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100784
Allan Stephensf6f0a4d2011-05-30 10:48:48 -0400785 if (depth == 2) {
Erik Hugnedc1aed32012-06-29 00:50:23 -0400786 ret += tipc_snprintf(buf - ret, len + ret, "\n");
787 return ret;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100788 }
789
Allan Stephensf6f0a4d2011-05-30 10:48:48 -0400790 info = sseq->info;
791
792 list_for_each_entry(publ, &info->zone_list, zone_list) {
Allan Stephens0e659672010-12-31 18:59:32 +0000793 sprintf(portIdStr, "<%u.%u.%u:%u>",
Per Lidenb97bf3f2006-01-02 19:04:38 +0100794 tipc_zone(publ->node), tipc_cluster(publ->node),
795 tipc_node(publ->node), publ->ref);
Erik Hugnedc1aed32012-06-29 00:50:23 -0400796 ret += tipc_snprintf(buf + ret, len - ret, "%-26s ", portIdStr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100797 if (depth > 3) {
Erik Hugnedc1aed32012-06-29 00:50:23 -0400798 ret += tipc_snprintf(buf + ret, len - ret, "%-10u %s",
799 publ->key, scope_str[publ->scope]);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100800 }
Allan Stephensf6f0a4d2011-05-30 10:48:48 -0400801 if (!list_is_last(&publ->zone_list, &info->zone_list))
Erik Hugnedc1aed32012-06-29 00:50:23 -0400802 ret += tipc_snprintf(buf + ret, len - ret,
803 "\n%33s", " ");
Peter Senna Tschudinadccff32012-09-18 07:10:45 +0000804 }
Per Lidenb97bf3f2006-01-02 19:04:38 +0100805
Erik Hugnedc1aed32012-06-29 00:50:23 -0400806 ret += tipc_snprintf(buf + ret, len - ret, "\n");
807 return ret;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100808}
809
810/**
Ben Hutchings2c530402012-07-10 10:55:09 +0000811 * nameseq_list - print specified name sequence contents into the given buffer
Per Lidenb97bf3f2006-01-02 19:04:38 +0100812 */
Erik Hugnedc1aed32012-06-29 00:50:23 -0400813static int nameseq_list(struct name_seq *seq, char *buf, int len, u32 depth,
Paul Gortmakerae8509c2013-06-17 10:54:47 -0400814 u32 type, u32 lowbound, u32 upbound, u32 index)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100815{
816 struct sub_seq *sseq;
817 char typearea[11];
Erik Hugnedc1aed32012-06-29 00:50:23 -0400818 int ret = 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100819
Allan Stephens0f15d362008-06-04 17:37:59 -0700820 if (seq->first_free == 0)
Erik Hugnedc1aed32012-06-29 00:50:23 -0400821 return 0;
Allan Stephens0f15d362008-06-04 17:37:59 -0700822
Per Lidenb97bf3f2006-01-02 19:04:38 +0100823 sprintf(typearea, "%-10u", seq->type);
824
825 if (depth == 1) {
Erik Hugnedc1aed32012-06-29 00:50:23 -0400826 ret += tipc_snprintf(buf, len, "%s\n", typearea);
827 return ret;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100828 }
829
830 for (sseq = seq->sseqs; sseq != &seq->sseqs[seq->first_free]; sseq++) {
831 if ((lowbound <= sseq->upper) && (upbound >= sseq->lower)) {
Erik Hugnedc1aed32012-06-29 00:50:23 -0400832 ret += tipc_snprintf(buf + ret, len - ret, "%s ",
833 typearea);
Allan Stephens307fdf52008-06-04 17:38:22 -0700834 spin_lock_bh(&seq->lock);
Erik Hugnedc1aed32012-06-29 00:50:23 -0400835 ret += subseq_list(sseq, buf + ret, len - ret,
836 depth, index);
Allan Stephens307fdf52008-06-04 17:38:22 -0700837 spin_unlock_bh(&seq->lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100838 sprintf(typearea, "%10s", " ");
839 }
840 }
Erik Hugnedc1aed32012-06-29 00:50:23 -0400841 return ret;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100842}
843
844/**
845 * nametbl_header - print name table header into the given buffer
846 */
Erik Hugnedc1aed32012-06-29 00:50:23 -0400847static int nametbl_header(char *buf, int len, u32 depth)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100848{
Allan Stephensc2de5812010-08-17 11:00:14 +0000849 const char *header[] = {
850 "Type ",
851 "Lower Upper ",
852 "Port Identity ",
853 "Publication Scope"
854 };
Per Lidenb97bf3f2006-01-02 19:04:38 +0100855
Allan Stephensc2de5812010-08-17 11:00:14 +0000856 int i;
Erik Hugnedc1aed32012-06-29 00:50:23 -0400857 int ret = 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100858
Allan Stephensc2de5812010-08-17 11:00:14 +0000859 if (depth > 4)
860 depth = 4;
861 for (i = 0; i < depth; i++)
Erik Hugnedc1aed32012-06-29 00:50:23 -0400862 ret += tipc_snprintf(buf + ret, len - ret, header[i]);
863 ret += tipc_snprintf(buf + ret, len - ret, "\n");
864 return ret;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100865}
866
867/**
868 * nametbl_list - print specified name table contents into the given buffer
869 */
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800870static int nametbl_list(struct net *net, char *buf, int len, u32 depth_info,
Paul Gortmakerae8509c2013-06-17 10:54:47 -0400871 u32 type, u32 lowbound, u32 upbound)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100872{
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800873 struct tipc_net *tn = net_generic(net, tipc_net_id);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100874 struct hlist_head *seq_head;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100875 struct name_seq *seq;
876 int all_types;
Erik Hugnedc1aed32012-06-29 00:50:23 -0400877 int ret = 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100878 u32 depth;
879 u32 i;
880
881 all_types = (depth_info & TIPC_NTQ_ALLTYPES);
882 depth = (depth_info & ~TIPC_NTQ_ALLTYPES);
883
884 if (depth == 0)
Erik Hugnedc1aed32012-06-29 00:50:23 -0400885 return 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100886
887 if (all_types) {
888 /* display all entries in name table to specified depth */
Erik Hugnedc1aed32012-06-29 00:50:23 -0400889 ret += nametbl_header(buf, len, depth);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100890 lowbound = 0;
891 upbound = ~0;
Ying Xuef046e7d2012-08-16 12:09:11 +0000892 for (i = 0; i < TIPC_NAMETBL_SIZE; i++) {
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800893 seq_head = &tn->nametbl->seq_hlist[i];
Ying Xue97ede292014-12-02 15:00:30 +0800894 hlist_for_each_entry_rcu(seq, seq_head, ns_list) {
Erik Hugnedc1aed32012-06-29 00:50:23 -0400895 ret += nameseq_list(seq, buf + ret, len - ret,
896 depth, seq->type,
897 lowbound, upbound, i);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100898 }
899 }
900 } else {
901 /* display only the sequence that matches the specified type */
902 if (upbound < lowbound) {
Erik Hugnedc1aed32012-06-29 00:50:23 -0400903 ret += tipc_snprintf(buf + ret, len - ret,
904 "invalid name sequence specified\n");
905 return ret;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100906 }
Erik Hugnedc1aed32012-06-29 00:50:23 -0400907 ret += nametbl_header(buf + ret, len - ret, depth);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100908 i = hash(type);
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800909 seq_head = &tn->nametbl->seq_hlist[i];
Ying Xue97ede292014-12-02 15:00:30 +0800910 hlist_for_each_entry_rcu(seq, seq_head, ns_list) {
Per Lidenb97bf3f2006-01-02 19:04:38 +0100911 if (seq->type == type) {
Erik Hugnedc1aed32012-06-29 00:50:23 -0400912 ret += nameseq_list(seq, buf + ret, len - ret,
913 depth, type,
914 lowbound, upbound, i);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100915 break;
916 }
917 }
918 }
Erik Hugnedc1aed32012-06-29 00:50:23 -0400919 return ret;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100920}
921
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800922struct sk_buff *tipc_nametbl_get(struct net *net, const void *req_tlv_area,
923 int req_tlv_space)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100924{
925 struct sk_buff *buf;
926 struct tipc_name_table_query *argv;
927 struct tlv_desc *rep_tlv;
Erik Hugnedc1aed32012-06-29 00:50:23 -0400928 char *pb;
929 int pb_len;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100930 int str_len;
931
932 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NAME_TBL_QUERY))
Per Liden4323add2006-01-18 00:38:21 +0100933 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100934
Erik Hugnedc1aed32012-06-29 00:50:23 -0400935 buf = tipc_cfg_reply_alloc(TLV_SPACE(ULTRA_STRING_MAX_LEN));
Per Lidenb97bf3f2006-01-02 19:04:38 +0100936 if (!buf)
937 return NULL;
938
939 rep_tlv = (struct tlv_desc *)buf->data;
Erik Hugnedc1aed32012-06-29 00:50:23 -0400940 pb = TLV_DATA(rep_tlv);
941 pb_len = ULTRA_STRING_MAX_LEN;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100942 argv = (struct tipc_name_table_query *)TLV_DATA(req_tlv_area);
Ying Xue97ede292014-12-02 15:00:30 +0800943 rcu_read_lock();
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800944 str_len = nametbl_list(net, pb, pb_len, ntohl(argv->depth),
Erik Hugnedc1aed32012-06-29 00:50:23 -0400945 ntohl(argv->type),
946 ntohl(argv->lowbound), ntohl(argv->upbound));
Ying Xue97ede292014-12-02 15:00:30 +0800947 rcu_read_unlock();
Erik Hugnedc1aed32012-06-29 00:50:23 -0400948 str_len += 1; /* for "\0" */
Per Lidenb97bf3f2006-01-02 19:04:38 +0100949 skb_put(buf, TLV_SPACE(str_len));
950 TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
951
952 return buf;
953}
954
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800955int tipc_nametbl_init(struct net *net)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100956{
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800957 struct tipc_net *tn = net_generic(net, tipc_net_id);
958 struct name_table *tipc_nametbl;
Ying Xue993bfe52014-12-02 15:00:24 +0800959 int i;
960
961 tipc_nametbl = kzalloc(sizeof(*tipc_nametbl), GFP_ATOMIC);
962 if (!tipc_nametbl)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100963 return -ENOMEM;
964
Ying Xue993bfe52014-12-02 15:00:24 +0800965 for (i = 0; i < TIPC_NAMETBL_SIZE; i++)
966 INIT_HLIST_HEAD(&tipc_nametbl->seq_hlist[i]);
967
968 INIT_LIST_HEAD(&tipc_nametbl->publ_list[TIPC_ZONE_SCOPE]);
969 INIT_LIST_HEAD(&tipc_nametbl->publ_list[TIPC_CLUSTER_SCOPE]);
970 INIT_LIST_HEAD(&tipc_nametbl->publ_list[TIPC_NODE_SCOPE]);
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800971 tn->nametbl = tipc_nametbl;
972 spin_lock_init(&tn->nametbl_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100973 return 0;
974}
975
Erik Hugne1bb8dce2014-03-06 14:40:20 +0100976/**
977 * tipc_purge_publications - remove all publications for a given type
978 *
979 * tipc_nametbl_lock must be held when calling this function
980 */
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800981static void tipc_purge_publications(struct net *net, struct name_seq *seq)
Erik Hugne1bb8dce2014-03-06 14:40:20 +0100982{
983 struct publication *publ, *safe;
984 struct sub_seq *sseq;
985 struct name_info *info;
986
Ying Xuefb9962f2014-12-02 15:00:26 +0800987 spin_lock_bh(&seq->lock);
Erik Hugne1bb8dce2014-03-06 14:40:20 +0100988 sseq = seq->sseqs;
989 info = sseq->info;
990 list_for_each_entry_safe(publ, safe, &info->zone_list, zone_list) {
Ying Xue4ac1c8d2015-01-09 15:27:09 +0800991 tipc_nametbl_remove_publ(net, publ->type, publ->lower,
992 publ->node, publ->ref, publ->key);
Ying Xue97ede292014-12-02 15:00:30 +0800993 kfree_rcu(publ, rcu);
Erik Hugne1bb8dce2014-03-06 14:40:20 +0100994 }
Ying Xue97ede292014-12-02 15:00:30 +0800995 hlist_del_init_rcu(&seq->ns_list);
996 kfree(seq->sseqs);
Ying Xue023160b2014-12-09 15:17:56 +0800997 spin_unlock_bh(&seq->lock);
Ying Xuefb9962f2014-12-02 15:00:26 +0800998
Ying Xue97ede292014-12-02 15:00:30 +0800999 kfree_rcu(seq, rcu);
Erik Hugne1bb8dce2014-03-06 14:40:20 +01001000}
1001
Ying Xue4ac1c8d2015-01-09 15:27:09 +08001002void tipc_nametbl_stop(struct net *net)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001003{
Per Lidenb97bf3f2006-01-02 19:04:38 +01001004 u32 i;
Erik Hugne1bb8dce2014-03-06 14:40:20 +01001005 struct name_seq *seq;
1006 struct hlist_head *seq_head;
Ying Xue4ac1c8d2015-01-09 15:27:09 +08001007 struct tipc_net *tn = net_generic(net, tipc_net_id);
1008 struct name_table *tipc_nametbl = tn->nametbl;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001009
Erik Hugne1bb8dce2014-03-06 14:40:20 +01001010 /* Verify name table is empty and purge any lingering
1011 * publications, then release the name table
1012 */
Ying Xue4ac1c8d2015-01-09 15:27:09 +08001013 spin_lock_bh(&tn->nametbl_lock);
Ying Xuef046e7d2012-08-16 12:09:11 +00001014 for (i = 0; i < TIPC_NAMETBL_SIZE; i++) {
Ying Xue993bfe52014-12-02 15:00:24 +08001015 if (hlist_empty(&tipc_nametbl->seq_hlist[i]))
Paul Gortmakerf705ab92012-07-11 17:35:01 -04001016 continue;
Ying Xue993bfe52014-12-02 15:00:24 +08001017 seq_head = &tipc_nametbl->seq_hlist[i];
Ying Xue97ede292014-12-02 15:00:30 +08001018 hlist_for_each_entry_rcu(seq, seq_head, ns_list) {
Ying Xue4ac1c8d2015-01-09 15:27:09 +08001019 tipc_purge_publications(net, seq);
Erik Hugne1bb8dce2014-03-06 14:40:20 +01001020 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01001021 }
Ying Xue4ac1c8d2015-01-09 15:27:09 +08001022 spin_unlock_bh(&tn->nametbl_lock);
Ying Xue993bfe52014-12-02 15:00:24 +08001023
Ying Xue97ede292014-12-02 15:00:30 +08001024 synchronize_net();
Ying Xue993bfe52014-12-02 15:00:24 +08001025 kfree(tipc_nametbl);
1026
Per Lidenb97bf3f2006-01-02 19:04:38 +01001027}
Richard Alpe15931232014-11-20 10:29:20 +01001028
Richard Alped8182802014-11-24 11:10:29 +01001029static int __tipc_nl_add_nametable_publ(struct tipc_nl_msg *msg,
1030 struct name_seq *seq,
1031 struct sub_seq *sseq, u32 *last_publ)
Richard Alpe15931232014-11-20 10:29:20 +01001032{
1033 void *hdr;
1034 struct nlattr *attrs;
1035 struct nlattr *publ;
1036 struct publication *p;
1037
1038 if (*last_publ) {
1039 list_for_each_entry(p, &sseq->info->zone_list, zone_list)
1040 if (p->key == *last_publ)
1041 break;
1042 if (p->key != *last_publ)
1043 return -EPIPE;
1044 } else {
1045 p = list_first_entry(&sseq->info->zone_list, struct publication,
1046 zone_list);
1047 }
1048
1049 list_for_each_entry_from(p, &sseq->info->zone_list, zone_list) {
1050 *last_publ = p->key;
1051
1052 hdr = genlmsg_put(msg->skb, msg->portid, msg->seq,
1053 &tipc_genl_v2_family, NLM_F_MULTI,
1054 TIPC_NL_NAME_TABLE_GET);
1055 if (!hdr)
1056 return -EMSGSIZE;
1057
1058 attrs = nla_nest_start(msg->skb, TIPC_NLA_NAME_TABLE);
1059 if (!attrs)
1060 goto msg_full;
1061
1062 publ = nla_nest_start(msg->skb, TIPC_NLA_NAME_TABLE_PUBL);
1063 if (!publ)
1064 goto attr_msg_full;
1065
1066 if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_TYPE, seq->type))
1067 goto publ_msg_full;
1068 if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_LOWER, sseq->lower))
1069 goto publ_msg_full;
1070 if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_UPPER, sseq->upper))
1071 goto publ_msg_full;
1072 if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_SCOPE, p->scope))
1073 goto publ_msg_full;
1074 if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_NODE, p->node))
1075 goto publ_msg_full;
1076 if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_REF, p->ref))
1077 goto publ_msg_full;
1078 if (nla_put_u32(msg->skb, TIPC_NLA_PUBL_KEY, p->key))
1079 goto publ_msg_full;
1080
1081 nla_nest_end(msg->skb, publ);
1082 nla_nest_end(msg->skb, attrs);
1083 genlmsg_end(msg->skb, hdr);
1084 }
1085 *last_publ = 0;
1086
1087 return 0;
1088
1089publ_msg_full:
1090 nla_nest_cancel(msg->skb, publ);
1091attr_msg_full:
1092 nla_nest_cancel(msg->skb, attrs);
1093msg_full:
1094 genlmsg_cancel(msg->skb, hdr);
1095
1096 return -EMSGSIZE;
1097}
1098
Richard Alped8182802014-11-24 11:10:29 +01001099static int __tipc_nl_subseq_list(struct tipc_nl_msg *msg, struct name_seq *seq,
1100 u32 *last_lower, u32 *last_publ)
Richard Alpe15931232014-11-20 10:29:20 +01001101{
1102 struct sub_seq *sseq;
1103 struct sub_seq *sseq_start;
1104 int err;
1105
1106 if (*last_lower) {
1107 sseq_start = nameseq_find_subseq(seq, *last_lower);
1108 if (!sseq_start)
1109 return -EPIPE;
1110 } else {
1111 sseq_start = seq->sseqs;
1112 }
1113
1114 for (sseq = sseq_start; sseq != &seq->sseqs[seq->first_free]; sseq++) {
1115 err = __tipc_nl_add_nametable_publ(msg, seq, sseq, last_publ);
1116 if (err) {
1117 *last_lower = sseq->lower;
1118 return err;
1119 }
1120 }
1121 *last_lower = 0;
1122
1123 return 0;
1124}
1125
Ying Xue4ac1c8d2015-01-09 15:27:09 +08001126static int tipc_nl_seq_list(struct net *net, struct tipc_nl_msg *msg,
1127 u32 *last_type, u32 *last_lower, u32 *last_publ)
Richard Alpe15931232014-11-20 10:29:20 +01001128{
Ying Xue4ac1c8d2015-01-09 15:27:09 +08001129 struct tipc_net *tn = net_generic(net, tipc_net_id);
Richard Alpe15931232014-11-20 10:29:20 +01001130 struct hlist_head *seq_head;
Ying Xue97ede292014-12-02 15:00:30 +08001131 struct name_seq *seq = NULL;
Richard Alpe15931232014-11-20 10:29:20 +01001132 int err;
1133 int i;
1134
1135 if (*last_type)
1136 i = hash(*last_type);
1137 else
1138 i = 0;
1139
1140 for (; i < TIPC_NAMETBL_SIZE; i++) {
Ying Xue4ac1c8d2015-01-09 15:27:09 +08001141 seq_head = &tn->nametbl->seq_hlist[i];
Richard Alpe15931232014-11-20 10:29:20 +01001142
1143 if (*last_type) {
Ying Xue4ac1c8d2015-01-09 15:27:09 +08001144 seq = nametbl_find_seq(net, *last_type);
Richard Alpe15931232014-11-20 10:29:20 +01001145 if (!seq)
1146 return -EPIPE;
1147 } else {
Ying Xue97ede292014-12-02 15:00:30 +08001148 hlist_for_each_entry_rcu(seq, seq_head, ns_list)
1149 break;
Richard Alpe15931232014-11-20 10:29:20 +01001150 if (!seq)
1151 continue;
1152 }
1153
Ying Xue97ede292014-12-02 15:00:30 +08001154 hlist_for_each_entry_from_rcu(seq, ns_list) {
Richard Alpe15931232014-11-20 10:29:20 +01001155 spin_lock_bh(&seq->lock);
Richard Alpe15931232014-11-20 10:29:20 +01001156 err = __tipc_nl_subseq_list(msg, seq, last_lower,
1157 last_publ);
1158
1159 if (err) {
1160 *last_type = seq->type;
1161 spin_unlock_bh(&seq->lock);
1162 return err;
1163 }
1164 spin_unlock_bh(&seq->lock);
1165 }
1166 *last_type = 0;
1167 }
1168 return 0;
1169}
1170
1171int tipc_nl_name_table_dump(struct sk_buff *skb, struct netlink_callback *cb)
1172{
1173 int err;
1174 int done = cb->args[3];
1175 u32 last_type = cb->args[0];
1176 u32 last_lower = cb->args[1];
1177 u32 last_publ = cb->args[2];
Ying Xue4ac1c8d2015-01-09 15:27:09 +08001178 struct net *net = sock_net(skb->sk);
Richard Alpe15931232014-11-20 10:29:20 +01001179 struct tipc_nl_msg msg;
1180
1181 if (done)
1182 return 0;
1183
1184 msg.skb = skb;
1185 msg.portid = NETLINK_CB(cb->skb).portid;
1186 msg.seq = cb->nlh->nlmsg_seq;
1187
Ying Xue97ede292014-12-02 15:00:30 +08001188 rcu_read_lock();
Ying Xue4ac1c8d2015-01-09 15:27:09 +08001189 err = tipc_nl_seq_list(net, &msg, &last_type, &last_lower, &last_publ);
Richard Alpe15931232014-11-20 10:29:20 +01001190 if (!err) {
1191 done = 1;
1192 } else if (err != -EMSGSIZE) {
1193 /* We never set seq or call nl_dump_check_consistent() this
1194 * means that setting prev_seq here will cause the consistence
1195 * check to fail in the netlink callback handler. Resulting in
1196 * the NLMSG_DONE message having the NLM_F_DUMP_INTR flag set if
1197 * we got an error.
1198 */
1199 cb->prev_seq = 1;
1200 }
Ying Xue97ede292014-12-02 15:00:30 +08001201 rcu_read_unlock();
Richard Alpe15931232014-11-20 10:29:20 +01001202
1203 cb->args[0] = last_type;
1204 cb->args[1] = last_lower;
1205 cb->args[2] = last_publ;
1206 cb->args[3] = done;
1207
1208 return skb->len;
1209}