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
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084 #include <netlink-local.h>
00085 #include <netlink/netlink.h>
00086 #include <netlink/cache.h>
00087 #include <netlink/utils.h>
00088
00089 static int include_cb(struct nl_object *obj, struct nl_parser_param *p)
00090 {
00091 struct nl_cache_assoc *ca = p->pp_arg;
00092
00093 NL_DBG(2, "Including object %p into cache %p\n", obj, ca->ca_cache);
00094 #ifdef NL_DEBUG
00095 if (nl_debug >= 4)
00096 nl_object_dump(obj, &nl_debug_dp);
00097 #endif
00098 return nl_cache_include(ca->ca_cache, obj, ca->ca_change);
00099 }
00100
00101 static int event_input(struct nl_msg *msg, void *arg)
00102 {
00103 struct nl_cache_mngr *mngr = arg;
00104 int protocol = nlmsg_get_proto(msg);
00105 int type = nlmsg_hdr(msg)->nlmsg_type;
00106 struct nl_cache_ops *ops;
00107 int i, n;
00108 struct nl_parser_param p = {
00109 .pp_cb = include_cb,
00110 };
00111
00112 NL_DBG(2, "Cache manager %p, handling new message %p as event\n",
00113 mngr, msg);
00114 #ifdef NL_DEBUG
00115 if (nl_debug >= 4)
00116 nl_msg_dump(msg, stderr);
00117 #endif
00118
00119 if (mngr->cm_protocol != protocol)
00120 BUG();
00121
00122 for (i = 0; i < mngr->cm_nassocs; i++) {
00123 if (mngr->cm_assocs[i].ca_cache) {
00124 ops = mngr->cm_assocs[i].ca_cache->c_ops;
00125 for (n = 0; ops->co_msgtypes[n].mt_id >= 0; n++)
00126 if (ops->co_msgtypes[n].mt_id == type)
00127 goto found;
00128 }
00129 }
00130
00131 return NL_SKIP;
00132
00133 found:
00134 NL_DBG(2, "Associated message %p to cache %p\n",
00135 msg, mngr->cm_assocs[i].ca_cache);
00136 p.pp_arg = &mngr->cm_assocs[i];
00137
00138 return nl_cache_parse(ops, NULL, nlmsg_hdr(msg), &p);
00139 }
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149 struct nl_cache_mngr *nl_cache_mngr_alloc(struct nl_handle *handle,
00150 int protocol, int flags)
00151 {
00152 struct nl_cache_mngr *mngr;
00153
00154 if (handle == NULL)
00155 BUG();
00156
00157 mngr = calloc(1, sizeof(*mngr));
00158 if (!mngr)
00159 goto enomem;
00160
00161 mngr->cm_handle = handle;
00162 mngr->cm_nassocs = 32;
00163 mngr->cm_protocol = protocol;
00164 mngr->cm_flags = flags;
00165 mngr->cm_assocs = calloc(mngr->cm_nassocs,
00166 sizeof(struct nl_cache_assoc));
00167 if (!mngr->cm_assocs)
00168 goto enomem;
00169
00170
00171 nl_socket_modify_cb(mngr->cm_handle, NL_CB_VALID, NL_CB_CUSTOM,
00172 event_input, mngr);
00173
00174
00175 nl_disable_sequence_check(mngr->cm_handle);
00176
00177 if (nl_connect(mngr->cm_handle, protocol) < 0)
00178 goto errout;
00179
00180 if (nl_socket_set_nonblocking(mngr->cm_handle) < 0)
00181 goto errout;
00182
00183 NL_DBG(1, "Allocated cache manager %p, protocol %d, %d caches\n",
00184 mngr, protocol, mngr->cm_nassocs);
00185
00186 return mngr;
00187
00188 enomem:
00189 nl_errno(ENOMEM);
00190 errout:
00191 nl_cache_mngr_free(mngr);
00192 return NULL;
00193 }
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209 struct nl_cache *nl_cache_mngr_add(struct nl_cache_mngr *mngr, const char *name,
00210 change_func_t cb)
00211 {
00212 struct nl_cache_ops *ops;
00213 struct nl_cache *cache;
00214 struct nl_af_group *grp;
00215 int err, i;
00216
00217 ops = nl_cache_ops_lookup(name);
00218 if (!ops) {
00219 nl_error(ENOENT, "Unknown cache type");
00220 return NULL;
00221 }
00222
00223 if (ops->co_protocol != mngr->cm_protocol) {
00224 nl_error(EINVAL, "Netlink protocol mismatch");
00225 return NULL;
00226 }
00227
00228 if (ops->co_groups == NULL) {
00229 nl_error(EOPNOTSUPP, NULL);
00230 return NULL;
00231 }
00232
00233 for (i = 0; i < mngr->cm_nassocs; i++) {
00234 if (mngr->cm_assocs[i].ca_cache &&
00235 mngr->cm_assocs[i].ca_cache->c_ops == ops) {
00236 nl_error(EEXIST, "Cache of this type already managed");
00237 return NULL;
00238 }
00239 }
00240
00241 retry:
00242 for (i = 0; i < mngr->cm_nassocs; i++)
00243 if (!mngr->cm_assocs[i].ca_cache)
00244 break;
00245
00246 if (i >= mngr->cm_nassocs) {
00247 mngr->cm_nassocs += 16;
00248 mngr->cm_assocs = realloc(mngr->cm_assocs,
00249 mngr->cm_nassocs *
00250 sizeof(struct nl_cache_assoc));
00251 if (mngr->cm_assocs == NULL) {
00252 nl_errno(ENOMEM);
00253 return NULL;
00254 } else {
00255 NL_DBG(1, "Increased capacity of cache manager %p " \
00256 "to %d\n", mngr, mngr->cm_nassocs);
00257 goto retry;
00258 }
00259 }
00260
00261 cache = nl_cache_alloc(ops);
00262 if (!cache) {
00263 nl_errno(ENOMEM);
00264 return NULL;
00265 }
00266
00267 for (grp = ops->co_groups; grp->ag_group; grp++) {
00268 err = nl_socket_add_membership(mngr->cm_handle, grp->ag_group);
00269 if (err < 0)
00270 goto errout_free_cache;
00271 }
00272
00273 err = nl_cache_refill(mngr->cm_handle, cache);
00274 if (err < 0)
00275 goto errout_drop_membership;
00276
00277 mngr->cm_assocs[i].ca_cache = cache;
00278 mngr->cm_assocs[i].ca_change = cb;
00279
00280 if (mngr->cm_flags & NL_AUTO_PROVIDE)
00281 nl_cache_mngt_provide(cache);
00282
00283 NL_DBG(1, "Added cache %p <%s> to cache manager %p\n",
00284 cache, nl_cache_name(cache), mngr);
00285
00286 return cache;
00287
00288 errout_drop_membership:
00289 for (grp = ops->co_groups; grp->ag_group; grp++)
00290 nl_socket_drop_membership(mngr->cm_handle, grp->ag_group);
00291 errout_free_cache:
00292 nl_cache_free(cache);
00293
00294 return NULL;
00295 }
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305 int nl_cache_mngr_get_fd(struct nl_cache_mngr *mngr)
00306 {
00307 return nl_socket_get_fd(mngr->cm_handle);
00308 }
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325 int nl_cache_mngr_poll(struct nl_cache_mngr *mngr, int timeout)
00326 {
00327 int ret;
00328 struct pollfd fds = {
00329 .fd = nl_socket_get_fd(mngr->cm_handle),
00330 .events = POLLIN,
00331 };
00332
00333 NL_DBG(3, "Cache manager %p, poll() fd %d\n", mngr, fds.fd);
00334 ret = poll(&fds, 1, timeout);
00335 NL_DBG(3, "Cache manager %p, poll() returned %d\n", mngr, ret);
00336 if (ret < 0)
00337 return nl_errno(errno);
00338
00339 if (ret == 0)
00340 return 0;
00341
00342 return nl_cache_mngr_data_ready(mngr);
00343 }
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356 int nl_cache_mngr_data_ready(struct nl_cache_mngr *mngr)
00357 {
00358 int err;
00359
00360 err = nl_recvmsgs_default(mngr->cm_handle);
00361 if (err < 0)
00362 return err;
00363
00364 return 1;
00365 }
00366
00367
00368
00369
00370
00371
00372
00373 void nl_cache_mngr_free(struct nl_cache_mngr *mngr)
00374 {
00375 if (!mngr)
00376 return;
00377
00378 if (mngr->cm_handle) {
00379 nl_close(mngr->cm_handle);
00380 nl_handle_destroy(mngr->cm_handle);
00381 }
00382
00383 free(mngr->cm_assocs);
00384 free(mngr);
00385
00386 NL_DBG(1, "Cache manager %p freed\n", mngr);
00387 }
00388
00389