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 "defs.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 NL_RW_LOCK(port_map_lock);
00123
00124 static uint32_t generate_local_port(void)
00125 {
00126 int i, n;
00127 uint32_t pid = getpid() & 0x3FFFFF;
00128
00129 nl_write_lock(&port_map_lock);
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 nl_write_unlock(&port_map_lock);
00146
00147 return pid + (n << 22);
00148 }
00149 }
00150
00151 nl_write_unlock(&port_map_lock);
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 nl_write_lock(&port_map_lock);
00167 used_ports_map[nr / 32] &= ~(1 << (nr % 32));
00168 nl_write_unlock(&port_map_lock);
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 = nl_cb_get(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 struct nl_handle *sk;
00210
00211 cb = nl_cb_alloc(default_cb);
00212 if (!cb) {
00213 nl_errno(ENOMEM);
00214 return NULL;
00215 }
00216
00217
00218 sk = __alloc_handle(cb);
00219
00220 nl_cb_put(cb);
00221
00222 return sk;
00223 }
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234 struct nl_handle *nl_handle_alloc_cb(struct nl_cb *cb)
00235 {
00236 if (cb == NULL)
00237 BUG();
00238
00239 return __alloc_handle(cb);
00240 }
00241
00242
00243
00244
00245
00246 void nl_handle_destroy(struct nl_handle *handle)
00247 {
00248 if (!handle)
00249 return;
00250
00251 if (handle->h_fd >= 0)
00252 close(handle->h_fd);
00253
00254 if (!(handle->h_flags & NL_OWN_PORT))
00255 release_local_port(handle->h_local.nl_pid);
00256
00257 nl_cb_put(handle->h_cb);
00258 free(handle);
00259 }
00260
00261
00262
00263
00264
00265
00266
00267
00268 static int noop_seq_check(struct nl_msg *msg, void *arg)
00269 {
00270 return NL_OK;
00271 }
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285 void nl_disable_sequence_check(struct nl_handle *handle)
00286 {
00287 nl_cb_set(handle->h_cb, NL_CB_SEQ_CHECK,
00288 NL_CB_CUSTOM, noop_seq_check, NULL);
00289 }
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300 unsigned int nl_socket_use_seq(struct nl_handle *handle)
00301 {
00302 return handle->h_seq_next++;
00303 }
00304
00305
00306
00307
00308
00309
00310
00311
00312 uint32_t nl_socket_get_local_port(struct nl_handle *handle)
00313 {
00314 return handle->h_local.nl_pid;
00315 }
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325 void nl_socket_set_local_port(struct nl_handle *handle, uint32_t port)
00326 {
00327 if (port == 0) {
00328 port = generate_local_port();
00329 handle->h_flags &= ~NL_OWN_PORT;
00330 } else {
00331 if (!(handle->h_flags & NL_OWN_PORT))
00332 release_local_port(handle->h_local.nl_pid);
00333 handle->h_flags |= NL_OWN_PORT;
00334 }
00335
00336 handle->h_local.nl_pid = port;
00337 }
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361 int nl_socket_add_membership(struct nl_handle *handle, int group)
00362 {
00363 int err;
00364
00365 if (handle->h_fd == -1)
00366 return nl_error(EBADFD, "Socket not connected");
00367
00368 err = setsockopt(handle->h_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
00369 &group, sizeof(group));
00370 if (err < 0)
00371 return nl_error(errno, "setsockopt(NETLINK_ADD_MEMBERSHIP) "
00372 "failed");
00373
00374 return 0;
00375 }
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388 int nl_socket_drop_membership(struct nl_handle *handle, int group)
00389 {
00390 int err;
00391
00392 if (handle->h_fd == -1)
00393 return nl_error(EBADFD, "Socket not connected");
00394
00395 err = setsockopt(handle->h_fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP,
00396 &group, sizeof(group));
00397 if (err < 0)
00398 return nl_error(errno, "setsockopt(NETLINK_DROP_MEMBERSHIP) "
00399 "failed");
00400
00401 return 0;
00402 }
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413 void nl_join_groups(struct nl_handle *handle, int groups)
00414 {
00415 handle->h_local.nl_groups |= groups;
00416 }
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426 uint32_t nl_socket_get_peer_port(struct nl_handle *handle)
00427 {
00428 return handle->h_peer.nl_pid;
00429 }
00430
00431 void nl_socket_set_peer_port(struct nl_handle *handle, uint32_t port)
00432 {
00433 handle->h_peer.nl_pid = port;
00434 }
00435
00436
00437
00438
00439
00440
00441
00442
00443 int nl_socket_get_fd(struct nl_handle *handle)
00444 {
00445 return handle->h_fd;
00446 }
00447
00448
00449
00450
00451
00452
00453
00454 int nl_socket_set_nonblocking(struct nl_handle *handle)
00455 {
00456 if (handle->h_fd == -1)
00457 return nl_error(EBADFD, "Socket not connected");
00458
00459 if (fcntl(handle->h_fd, F_SETFL, O_NONBLOCK) < 0)
00460 return nl_error(errno, "fcntl(F_SETFL, O_NONBLOCK) failed");
00461
00462 return 0;
00463 }
00464
00465
00466
00467
00468
00469 void nl_socket_enable_msg_peek(struct nl_handle *handle)
00470 {
00471 handle->h_flags |= NL_MSG_PEEK;
00472 }
00473
00474
00475
00476
00477
00478 void nl_socket_disable_msg_peek(struct nl_handle *handle)
00479 {
00480 handle->h_flags &= ~NL_MSG_PEEK;
00481 }
00482
00483
00484
00485
00486
00487
00488
00489
00490 struct nl_cb *nl_socket_get_cb(struct nl_handle *handle)
00491 {
00492 return nl_cb_get(handle->h_cb);
00493 }
00494
00495 void nl_socket_set_cb(struct nl_handle *handle, struct nl_cb *cb)
00496 {
00497 if (cb == NULL)
00498 BUG();
00499
00500 nl_cb_put(handle->h_cb);
00501 handle->h_cb = nl_cb_get(cb);
00502 }
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514 int nl_socket_modify_cb(struct nl_handle *handle, enum nl_cb_type type,
00515 enum nl_cb_kind kind, nl_recvmsg_msg_cb_t func,
00516 void *arg)
00517 {
00518 return nl_cb_set(handle->h_cb, type, kind, func, arg);
00519 }
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541 int nl_set_buffer_size(struct nl_handle *handle, int rxbuf, int txbuf)
00542 {
00543 int err;
00544
00545 if (rxbuf <= 0)
00546 rxbuf = 32768;
00547
00548 if (txbuf <= 0)
00549 txbuf = 32768;
00550
00551 if (handle->h_fd == -1)
00552 return nl_error(EBADFD, "Socket not connected");
00553
00554 err = setsockopt(handle->h_fd, SOL_SOCKET, SO_SNDBUF,
00555 &txbuf, sizeof(txbuf));
00556 if (err < 0)
00557 return nl_error(errno, "setsockopt(SO_SNDBUF) failed");
00558
00559 err = setsockopt(handle->h_fd, SOL_SOCKET, SO_RCVBUF,
00560 &rxbuf, sizeof(rxbuf));
00561 if (err < 0)
00562 return nl_error(errno, "setsockopt(SO_RCVBUF) failed");
00563
00564 handle->h_flags |= NL_SOCK_BUFSIZE_SET;
00565
00566 return 0;
00567 }
00568
00569
00570
00571
00572
00573
00574
00575
00576 int nl_set_passcred(struct nl_handle *handle, int state)
00577 {
00578 int err;
00579
00580 if (handle->h_fd == -1)
00581 return nl_error(EBADFD, "Socket not connected");
00582
00583 err = setsockopt(handle->h_fd, SOL_SOCKET, SO_PASSCRED,
00584 &state, sizeof(state));
00585 if (err < 0)
00586 return nl_error(errno, "setsockopt(SO_PASSCRED) failed");
00587
00588 if (state)
00589 handle->h_flags |= NL_SOCK_PASSCRED;
00590 else
00591 handle->h_flags &= ~NL_SOCK_PASSCRED;
00592
00593 return 0;
00594 }
00595
00596
00597
00598
00599
00600
00601
00602
00603 int nl_socket_recv_pktinfo(struct nl_handle *handle, int state)
00604 {
00605 int err;
00606
00607 if (handle->h_fd == -1)
00608 return nl_error(EBADFD, "Socket not connected");
00609
00610 err = setsockopt(handle->h_fd, SOL_NETLINK, NETLINK_PKTINFO,
00611 &state, sizeof(state));
00612 if (err < 0)
00613 return nl_error(errno, "setsockopt(NETLINK_PKTINFO) failed");
00614
00615 return 0;
00616 }
00617
00618
00619
00620