00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043 #include <netlink-local.h>
00044 #include <netlink/netlink.h>
00045 #include <netlink/cache.h>
00046 #include <netlink/object.h>
00047 #include <netlink/utils.h>
00048
00049 static inline char *nl_cache_name(struct nl_cache *cache)
00050 {
00051 return cache->c_ops ? cache->c_ops->co_name : "unknown";
00052 }
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063 int nl_cache_nitems(struct nl_cache *cache)
00064 {
00065 return cache->c_nitems;
00066 }
00067
00068
00069
00070
00071
00072
00073 int nl_cache_nitems_filter(struct nl_cache *cache, struct nl_object *filter)
00074 {
00075 struct nl_cache_ops *ops = cache->c_ops;
00076 struct nl_object *obj;
00077 int nitems = 0;
00078
00079 nl_list_for_each_entry(obj, &cache->c_items, ce_list) {
00080 if (filter && ops->co_filter && !ops->co_filter(obj, filter))
00081 continue;
00082
00083 nitems++;
00084 }
00085
00086 return nitems;
00087 }
00088
00089
00090
00091
00092
00093
00094 int nl_cache_is_empty(struct nl_cache *cache)
00095 {
00096 return nl_list_empty(&cache->c_items);
00097 }
00098
00099
00100
00101
00102
00103 struct nl_cache_ops *nl_cache_get_ops(struct nl_cache *cache)
00104 {
00105 return cache->c_ops;
00106 }
00107
00108
00109
00110
00111
00112 struct nl_object *nl_cache_get_first(struct nl_cache *cache)
00113 {
00114 if (nl_list_empty(&cache->c_items))
00115 return NULL;
00116
00117 return nl_list_entry(cache->c_items.next,
00118 struct nl_object, ce_list);
00119 }
00120
00121
00122
00123
00124
00125 struct nl_object *nl_cache_get_last(struct nl_cache *cache)
00126 {
00127 if (nl_list_empty(&cache->c_items))
00128 return NULL;
00129
00130 return nl_list_entry(cache->c_items.prev,
00131 struct nl_object, ce_list);
00132 }
00133
00134
00135
00136
00137
00138 struct nl_object *nl_cache_get_next(struct nl_object *obj)
00139 {
00140 if (nl_list_at_tail(obj, &obj->ce_cache->c_items, ce_list))
00141 return NULL;
00142 else
00143 return nl_list_entry(obj->ce_list.next,
00144 struct nl_object, ce_list);
00145 }
00146
00147
00148
00149
00150
00151 struct nl_object *nl_cache_get_prev(struct nl_object *obj)
00152 {
00153 if (nl_list_at_head(obj, &obj->ce_cache->c_items, ce_list))
00154 return NULL;
00155 else
00156 return nl_list_entry(obj->ce_list.prev,
00157 struct nl_object, ce_list);
00158 }
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172 struct nl_cache *nl_cache_alloc(void)
00173 {
00174 struct nl_cache *cache;
00175
00176 cache = calloc(1, sizeof(*cache));
00177 if (!cache) {
00178 nl_errno(ENOMEM);
00179 return NULL;
00180 }
00181
00182 nl_init_list_head(&cache->c_items);
00183 NL_DBG(2, "Allocated cache %p <%s>.\n", cache, nl_cache_name(cache));
00184
00185 return cache;
00186 }
00187
00188
00189
00190
00191
00192
00193 struct nl_cache *nl_cache_alloc_from_ops(struct nl_cache_ops *ops)
00194 {
00195 struct nl_cache *new;
00196
00197 new = nl_cache_alloc();
00198 if (!new)
00199 return NULL;
00200
00201 new->c_ops = ops;
00202
00203 return new;
00204 }
00205
00206
00207
00208
00209
00210
00211 struct nl_cache *nl_cache_alloc_name(const char *kind)
00212 {
00213 struct nl_cache_ops *ops;
00214
00215 ops = nl_cache_mngt_lookup(kind);
00216 if (!ops) {
00217 nl_error(ENOENT, "Unable to lookup cache \"%s\"", kind);
00218 return NULL;
00219 }
00220
00221 return nl_cache_alloc_from_ops(ops);
00222 }
00223
00224
00225
00226
00227
00228
00229
00230 void nl_cache_clear(struct nl_cache *cache)
00231 {
00232 struct nl_object *obj, *tmp;
00233
00234 NL_DBG(1, "Clearing cache %p <%s>...\n", cache, nl_cache_name(cache));
00235
00236 nl_list_for_each_entry_safe(obj, tmp, &cache->c_items, ce_list)
00237 nl_cache_delete(cache, obj);
00238 }
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248 void nl_cache_free(struct nl_cache *cache)
00249 {
00250 nl_cache_clear(cache);
00251 NL_DBG(1, "Freeing cache %p <%s>...\n", cache, nl_cache_name(cache));
00252 free(cache);
00253 }
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272 int nl_cache_add(struct nl_cache *cache, struct nl_object *obj)
00273 {
00274 struct nl_object *new;
00275
00276 if (nl_object_shared(obj)) {
00277 new = nl_object_clone(obj);
00278 if (!new)
00279 return nl_errno(ENOMEM);
00280
00281 nl_object_put(obj);
00282 } else
00283 new = obj;
00284
00285 new->ce_cache = cache;
00286
00287 nl_list_add_tail(&new->ce_list, &cache->c_items);
00288 cache->c_nitems++;
00289
00290 NL_DBG(1, "Added %p to cache %p <%s>.\n",
00291 new, cache, nl_cache_name(cache));
00292
00293 return 0;
00294 }
00295
00296 static int subsys_parse_cb(struct nl_object *c, struct nl_parser_param *p)
00297 {
00298 return nl_cache_add((struct nl_cache *) p->pp_arg, c);
00299 }
00300
00301
00302 int nl_cache_parse(struct nl_cache_ops *ops, struct sockaddr_nl *who,
00303 struct nlmsghdr *nlh, struct nl_parser_param *params)
00304 {
00305 int i, len, err, hdrsize;
00306
00307 hdrsize = ops->co_hdrsize;
00308 len = nlh->nlmsg_len - nlmsg_msg_size(hdrsize);
00309 if (len < 0) {
00310 err = nl_error(EINVAL, "netlink message too short to "
00311 "of kind %s", ops->co_name);
00312 goto errout;
00313 }
00314
00315 for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++)
00316 if (ops->co_msgtypes[i].mt_id == nlh->nlmsg_type)
00317 return ops->co_msg_parser(who, nlh, params);
00318
00319 err = nl_error(EINVAL, "Unsupported netlink message type %d",
00320 nlh->nlmsg_type);
00321 errout:
00322 return err;
00323 }
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336 int nl_cache_parse_and_add(struct nl_cache *cache, struct nl_msg *msg)
00337 {
00338 struct nl_parser_param p = {
00339 .pp_cb = subsys_parse_cb,
00340 .pp_arg = cache,
00341 };
00342
00343 return nl_cache_parse(cache->c_ops, NULL, nlmsg_hdr(msg), &p);
00344 }
00345
00346
00347
00348
00349
00350
00351
00352
00353 void nl_cache_delete(struct nl_cache *cache, struct nl_object *obj)
00354 {
00355 if (obj->ce_cache != cache)
00356 BUG();
00357
00358 nl_list_del(&obj->ce_list);
00359 obj->ce_cache = NULL;
00360 nl_object_put(obj);
00361 cache->c_nitems--;
00362
00363 NL_DBG(1, "Deleted %p from cache %p <%s>.\n",
00364 obj, cache, nl_cache_name(cache));
00365 }
00366
00367
00368 struct update_xdata {
00369 struct nl_cache_ops *ops;
00370 struct nl_parser_param *params;
00371 };
00372
00373
00374 static int update_msg_parser(struct nl_msg *msg, void *arg)
00375 {
00376 struct update_xdata *x = arg;
00377
00378 return nl_cache_parse(x->ops, &msg->nm_src, msg->nm_nlh, x->params);
00379 }
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391 int nl_cache_pickup(struct nl_handle *handle, struct nl_cache *cache)
00392 {
00393 int err;
00394 struct nl_cache_ops *ops = cache->c_ops;
00395 struct nl_cb *cb;
00396 struct nl_parser_param p = {
00397 .pp_cb = subsys_parse_cb,
00398 .pp_arg = cache,
00399 };
00400 struct update_xdata x = {
00401 .ops = ops,
00402 .params = &p,
00403 };
00404
00405 NL_DBG(1, "Filling cache %p <%s>...\n", cache, nl_cache_name(cache));
00406
00407 cb = nl_cb_clone(nl_handle_get_cb(handle));
00408 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, update_msg_parser, &x);
00409
00410 err = nl_recvmsgs(handle, cb);
00411 if (err < 0)
00412 NL_DBG(2, "While picking up for %p <%s>, recvmsgs() returned " \
00413 "%d: %s", cache, nl_cache_name(cache),
00414 err, nl_geterror());
00415
00416 nl_cb_destroy(cb);
00417
00418 return err;
00419 }
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432 int nl_cache_update(struct nl_handle *handle, struct nl_cache *cache)
00433 {
00434 int err;
00435 struct nl_cache_ops *ops = cache->c_ops;
00436
00437 err = ops->co_request_update(cache, handle);
00438 if (err < 0)
00439 return err;
00440
00441 NL_DBG(2, "Upading cache %p <%s>, request sent, waiting for dump...\n",
00442 cache, nl_cache_name(cache));
00443 nl_cache_clear(cache);
00444
00445 return nl_cache_pickup(handle, cache);
00446 }
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462 void nl_cache_dump(struct nl_cache *cache, struct nl_dump_params *params)
00463 {
00464 NL_DBG(1, "Dumping cache %p <%s>\n", cache, nl_cache_name(cache));
00465 nl_cache_dump_filter(cache, params, NULL);
00466 }
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477 void nl_cache_dump_filter(struct nl_cache *cache,
00478 struct nl_dump_params *params,
00479 struct nl_object *filter)
00480 {
00481 int type = params ? params->dp_type : NL_DUMP_FULL;
00482 struct nl_cache_ops *ops = cache->c_ops;
00483 struct nl_object *obj;
00484
00485 if (type > NL_DUMP_MAX || type < 0)
00486 BUG();
00487
00488 if (!ops->co_dump[type])
00489 return;
00490
00491 nl_list_for_each_entry(obj, &cache->c_items, ce_list) {
00492 if (filter && obj->ce_ops != filter->ce_ops)
00493 continue;
00494
00495 if (filter && ops->co_filter && !ops->co_filter(obj, filter))
00496 continue;
00497
00498 dump_from_ops(obj, params);
00499 }
00500 }
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518 void nl_cache_foreach(struct nl_cache *cache,
00519 void (*cb)(struct nl_object *, void *), void *arg)
00520 {
00521 nl_cache_foreach_filter(cache, NULL, cb, arg);
00522 }
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535 void nl_cache_foreach_filter(struct nl_cache *cache, struct nl_object *filter,
00536 void (*cb)(struct nl_object *, void *), void *arg)
00537 {
00538 struct nl_object *obj, *tmp;
00539 struct nl_cache_ops *ops = cache->c_ops;
00540
00541 nl_list_for_each_entry_safe(obj, tmp, &cache->c_items, ce_list) {
00542 if (filter && ops->co_filter && !ops->co_filter(obj, filter))
00543 continue;
00544
00545 cb(obj, arg);
00546 }
00547 }
00548
00549
00550
00551