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
00085
00086
00087
00088
00089
00090
00091
00092 #include <pthread.h>
00093
00094 #include <netlink-local.h>
00095 #include <netlink/netlink.h>
00096 #include <netlink/utils.h>
00097 #include <netlink/handlers.h>
00098 #include <netlink/msg.h>
00099 #include <netlink/attr.h>
00100
00101 static int default_cb = NL_CB_DEFAULT;
00102
00103 static void __init init_default_cb(void)
00104 {
00105 char *nlcb;
00106
00107 if ((nlcb = getenv("NLCB"))) {
00108 if (!strcasecmp(nlcb, "default"))
00109 default_cb = NL_CB_DEFAULT;
00110 else if (!strcasecmp(nlcb, "verbose"))
00111 default_cb = NL_CB_VERBOSE;
00112 else if (!strcasecmp(nlcb, "debug"))
00113 default_cb = NL_CB_DEBUG;
00114 else {
00115 fprintf(stderr, "Unknown value for NLCB, valid values: "
00116 "{default | verbose | debug}\n");
00117 }
00118 }
00119 }
00120
00121 static uint32_t used_ports_map[32];
00122 static pthread_mutex_t port_map_mutex = PTHREAD_MUTEX_INITIALIZER;
00123
00124 static uint32_t generate_local_port(void)
00125 {
00126 int i, n;
00127 uint32_t pid = getpid() & 0x3FFFFF;
00128
00129 pthread_mutex_lock(&port_map_mutex);
00130
00131 for (i = 0; i < 32; i++) {
00132 if (used_ports_map[i] == 0xFFFFFFFF)
00133 continue;
00134
00135 for (n = 0; n < 32; n++) {
00136 if (1UL & (used_ports_map[i] >> n))
00137 continue;
00138
00139 used_ports_map[i] |= (1UL << n);
00140 n += (i * 32);
00141
00142
00143
00144
00145 pthread_mutex_unlock(&port_map_mutex);
00146
00147 return pid + (n << 22);
00148 }
00149 }
00150
00151 pthread_mutex_unlock(&port_map_mutex);
00152
00153
00154 return UINT_MAX;
00155 }
00156
00157 static void release_local_port(uint32_t port)
00158 {
00159 int nr;
00160
00161 if (port == UINT_MAX)
00162 return;
00163
00164 nr = port >> 22;
00165
00166 pthread_mutex_lock(&port_map_mutex);
00167 used_ports_map[nr / 32] &= ~(1 << (nr % 32));
00168 pthread_mutex_unlock(&port_map_mutex);
00169 }
00170
00171
00172
00173
00174
00175
00176 static struct nl_handle *__alloc_handle(struct nl_cb *cb)
00177 {
00178 struct nl_handle *handle;
00179
00180 handle = calloc(1, sizeof(*handle));
00181 if (!handle) {
00182 nl_errno(ENOMEM);
00183 return NULL;
00184 }
00185
00186 handle->h_fd = -1;
00187 handle->h_cb = cb;
00188 handle->h_local.nl_family = AF_NETLINK;
00189 handle->h_peer.nl_family = AF_NETLINK;
00190 handle->h_seq_expect = handle->h_seq_next = time(0);
00191 handle->h_local.nl_pid = generate_local_port();
00192 if (handle->h_local.nl_pid == UINT_MAX) {
00193 nl_handle_destroy(handle);
00194 nl_error(ENOBUFS, "Out of local ports");
00195 return NULL;
00196 }
00197
00198 return handle;
00199 }
00200
00201
00202
00203
00204
00205
00206 struct nl_handle *nl_handle_alloc(void)
00207 {
00208 struct nl_cb *cb;
00209
00210 cb = nl_cb_alloc(default_cb);
00211 if (!cb) {
00212 nl_errno(ENOMEM);
00213 return NULL;
00214 }
00215
00216 return __alloc_handle(cb);
00217 }
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228 struct nl_handle *nl_handle_alloc_cb(struct nl_cb *cb)
00229 {
00230 if (cb == NULL)
00231 BUG();
00232
00233 return __alloc_handle(nl_cb_get(cb));
00234 }
00235
00236
00237
00238
00239
00240 void nl_handle_destroy(struct nl_handle *handle)
00241 {
00242 if (!handle)
00243 return;
00244
00245 if (handle->h_fd >= 0)
00246 close(handle->h_fd);
00247
00248 if (!(handle->h_flags & NL_OWN_PORT))
00249 release_local_port(handle->h_local.nl_pid);
00250
00251 nl_cb_put(handle->h_cb);
00252 free(handle);
00253 }
00254
00255
00256
00257
00258
00259
00260
00261
00262 static int noop_seq_check(struct nl_msg *msg, void *arg)
00263 {
00264 return NL_OK;
00265 }
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279 void nl_disable_sequence_check(struct nl_handle *handle)
00280 {
00281 nl_cb_set(handle->h_cb, NL_CB_SEQ_CHECK,
00282 NL_CB_CUSTOM, noop_seq_check, NULL);
00283 }
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294 unsigned int nl_socket_use_seq(struct nl_handle *handle)
00295 {
00296 return handle->h_seq_next++;
00297 }
00298
00299
00300
00301
00302
00303
00304
00305
00306 uint32_t nl_socket_get_local_port(struct nl_handle *handle)
00307 {
00308 return handle->h_local.nl_pid;
00309 }
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319 void nl_socket_set_local_port(struct nl_handle *handle, uint32_t port)
00320 {
00321 if (port == 0) {
00322 port = generate_local_port();
00323 handle->h_flags &= ~NL_OWN_PORT;
00324 } else {
00325 if (!(handle->h_flags & NL_OWN_PORT))
00326 release_local_port(handle->h_local.nl_pid);
00327 handle->h_flags |= NL_OWN_PORT;
00328 }
00329
00330 handle->h_local.nl_pid = port;
00331 }
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355 int nl_socket_add_membership(struct nl_handle *handle, int group)
00356 {
00357 int err;
00358
00359 if (handle->h_fd == -1)
00360 return nl_error(EBADFD, "Socket not connected");
00361
00362 err = setsockopt(handle->h_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
00363 &group, sizeof(group));
00364 if (err < 0)
00365 return nl_error(errno, "setsockopt(NETLINK_ADD_MEMBERSHIP) "
00366 "failed");
00367
00368 return 0;
00369 }
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382 int nl_socket_drop_membership(struct nl_handle *handle, int group)
00383 {
00384 int err;
00385
00386 if (handle->h_fd == -1)
00387 return nl_error(EBADFD, "Socket not connected");
00388
00389 err = setsockopt(handle->h_fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP,
00390 &group, sizeof(group));
00391 if (err < 0)
00392 return nl_error(errno, "setsockopt(NETLINK_DROP_MEMBERSHIP) "
00393 "failed");
00394
00395 return 0;
00396 }
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407 void nl_join_groups(struct nl_handle *handle, int groups)
00408 {
00409 handle->h_local.nl_groups |= groups;
00410 }
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420 uint32_t nl_socket_get_peer_port(struct nl_handle *handle)
00421 {
00422 return handle->h_peer.nl_pid;
00423 }
00424
00425 void nl_socket_set_peer_port(struct nl_handle *handle, uint32_t port)
00426 {
00427 handle->h_peer.nl_pid = port;
00428 }
00429
00430
00431
00432
00433
00434
00435
00436
00437 int nl_socket_get_fd(struct nl_handle *handle)
00438 {
00439 return handle->h_fd;
00440 }
00441
00442
00443
00444
00445
00446
00447
00448 int nl_socket_set_nonblocking(struct nl_handle *handle)
00449 {
00450 if (handle->h_fd == -1)
00451 return nl_error(EBADFD, "Socket not connected");
00452
00453 if (fcntl(handle->h_fd, F_SETFL, O_NONBLOCK) < 0)
00454 return nl_error(errno, "fcntl(F_SETFL, O_NONBLOCK) failed");
00455
00456 return 0;
00457 }
00458
00459
00460
00461
00462
00463 void nl_socket_enable_msg_peek(struct nl_handle *handle)
00464 {
00465 handle->h_flags |= NL_MSG_PEEK;
00466 }
00467
00468
00469
00470
00471
00472 void nl_socket_disable_msg_peek(struct nl_handle *handle)
00473 {
00474 handle->h_flags &= ~NL_MSG_PEEK;
00475 }
00476
00477
00478
00479
00480
00481
00482
00483
00484 struct nl_cb *nl_socket_get_cb(struct nl_handle *handle)
00485 {
00486 return nl_cb_get(handle->h_cb);
00487 }
00488
00489 void nl_socket_set_cb(struct nl_handle *handle, struct nl_cb *cb)
00490 {
00491 nl_cb_put(handle->h_cb);
00492 handle->h_cb = nl_cb_get(cb);
00493 }
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505 int nl_socket_modify_cb(struct nl_handle *handle, enum nl_cb_type type,
00506 enum nl_cb_kind kind, nl_recvmsg_msg_cb_t func,
00507 void *arg)
00508 {
00509 return nl_cb_set(handle->h_cb, type, kind, func, arg);
00510 }
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532 int nl_set_buffer_size(struct nl_handle *handle, int rxbuf, int txbuf)
00533 {
00534 int err;
00535
00536 if (rxbuf <= 0)
00537 rxbuf = 32768;
00538
00539 if (txbuf <= 0)
00540 txbuf = 32768;
00541
00542 if (handle->h_fd == -1)
00543 return nl_error(EBADFD, "Socket not connected");
00544
00545 err = setsockopt(handle->h_fd, SOL_SOCKET, SO_SNDBUF,
00546 &txbuf, sizeof(txbuf));
00547 if (err < 0)
00548 return nl_error(errno, "setsockopt(SO_SNDBUF) failed");
00549
00550 err = setsockopt(handle->h_fd, SOL_SOCKET, SO_RCVBUF,
00551 &rxbuf, sizeof(rxbuf));
00552 if (err < 0)
00553 return nl_error(errno, "setsockopt(SO_RCVBUF) failed");
00554
00555 handle->h_flags |= NL_SOCK_BUFSIZE_SET;
00556
00557 return 0;
00558 }
00559
00560
00561
00562
00563
00564
00565
00566
00567 int nl_set_passcred(struct nl_handle *handle, int state)
00568 {
00569 int err;
00570
00571 if (handle->h_fd == -1)
00572 return nl_error(EBADFD, "Socket not connected");
00573
00574 err = setsockopt(handle->h_fd, SOL_SOCKET, SO_PASSCRED,
00575 &state, sizeof(state));
00576 if (err < 0)
00577 return nl_error(errno, "setsockopt(SO_PASSCRED) failed");
00578
00579 if (state)
00580 handle->h_flags |= NL_SOCK_PASSCRED;
00581 else
00582 handle->h_flags &= ~NL_SOCK_PASSCRED;
00583
00584 return 0;
00585 }
00586
00587
00588
00589
00590
00591
00592
00593
00594 int nl_socket_recv_pktinfo(struct nl_handle *handle, int state)
00595 {
00596 int err;
00597
00598 if (handle->h_fd == -1)
00599 return nl_error(EBADFD, "Socket not connected");
00600
00601 err = setsockopt(handle->h_fd, SOL_NETLINK, NETLINK_PKTINFO,
00602 &state, sizeof(state));
00603 if (err < 0)
00604 return nl_error(errno, "setsockopt(NETLINK_PKTINFO) failed");
00605
00606 return 0;
00607 }
00608
00609
00610
00611