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