/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* NOTICE: This is a clean room re-implementation of libnl */ #include <errno.h> #include <unistd.h> #include <malloc.h> #include <sys/time.h> #include <sys/socket.h> #include "netlink-types.h" /* Join group */ int nl_socket_add_membership(struct nl_sock *sk, int group) { return setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group, sizeof(group)); } /* Allocate new netlink socket. */ static struct nl_sock *_nl_socket_alloc(void) { struct nl_sock *sk; struct timeval tv; struct nl_cb *cb; sk = (struct nl_sock *) malloc(sizeof(struct nl_sock)); if (!sk) return NULL; memset(sk, 0, sizeof(*sk)); /* Get current time */ if (gettimeofday(&tv, NULL)) goto fail; else sk->s_seq_next = (int) tv.tv_sec; /* Create local socket */ sk->s_local.nl_family = AF_NETLINK; sk->s_local.nl_pid = 0; /* Kernel fills in pid */ sk->s_local.nl_groups = 0; /* No groups */ /* Create peer socket */ sk->s_peer.nl_family = AF_NETLINK; sk->s_peer.nl_pid = 0; /* Kernel */ sk->s_peer.nl_groups = 0; /* No groups */ return sk; fail: free(sk); return NULL; } /* Allocate new netlink socket. */ struct nl_sock *nl_socket_alloc(void) { struct nl_sock *sk = _nl_socket_alloc(); struct nl_cb *cb; if (!sk) return NULL; cb = nl_cb_alloc(NL_CB_DEFAULT); if (!cb) goto cb_fail; sk->s_cb = cb; return sk; cb_fail: free(sk); return NULL; } /* Allocate new socket with custom callbacks. */ struct nl_sock *nl_socket_alloc_cb(struct nl_cb *cb) { struct nl_sock *sk = _nl_socket_alloc(); if (!sk) return NULL; sk->s_cb = cb; nl_cb_get(cb); return sk; } /* Free a netlink socket. */ void nl_socket_free(struct nl_sock *sk) { nl_cb_put(sk->s_cb); close(sk->s_fd); free(sk); } /* Sets socket buffer size of netlink socket */ int nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf) { if (setsockopt(sk->s_fd, SOL_SOCKET, SO_SNDBUF, \ &rxbuf, (socklen_t) sizeof(rxbuf))) goto error; if (setsockopt(sk->s_fd, SOL_SOCKET, SO_RCVBUF, \ &txbuf, (socklen_t) sizeof(txbuf))) goto error; return 0; error: return -errno; } int nl_socket_get_fd(struct nl_sock *sk) { return sk->s_fd; }