1ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker/*
2ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * Copyright (C) 2011 The Android Open Source Project
3ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker *
4ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * Licensed under the Apache License, Version 2.0 (the "License");
5ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * you may not use this file except in compliance with the License.
6ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * You may obtain a copy of the License at
7ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker *
8ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker *	http://www.apache.org/licenses/LICENSE-2.0
9ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker *
10ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * Unless required by applicable law or agreed to in writing, software
11ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * distributed under the License is distributed on an "AS IS" BASIS,
12ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * See the License for the specific language governing permissions and
14ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * limitations under the License.
15ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker */
16ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
17ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker/* NOTICE: This is a clean room re-implementation of libnl */
18ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
19ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker#include <errno.h>
20ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker#include <unistd.h>
21ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker#include <malloc.h>
22ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker#include <sys/time.h>
23ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker#include <sys/socket.h>
24ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker#include "netlink-types.h"
25ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
26ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker/* Join group */
27ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makerint nl_socket_add_membership(struct nl_sock *sk, int group)
28ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker{
29ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	return setsockopt(sk->s_fd, SOL_NETLINK,
30ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			NETLINK_ADD_MEMBERSHIP, &group, sizeof(group));
31ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker}
32ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
33ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker/* Allocate new netlink socket. */
34d99fe5ec960b5eae96585d5ceb59fe287fe0c5e7Dmitry Shmidtstatic struct nl_sock *_nl_socket_alloc(void)
35ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker{
36c28b79a6c23226c1c24a2d8b954f7199195bba6fFrank Maker	struct nl_sock *sk;
37ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	struct timeval tv;
38ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	struct nl_cb *cb;
39ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
40c28b79a6c23226c1c24a2d8b954f7199195bba6fFrank Maker	sk = (struct nl_sock *) malloc(sizeof(struct nl_sock));
41ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	if (!sk)
42d99fe5ec960b5eae96585d5ceb59fe287fe0c5e7Dmitry Shmidt		return NULL;
43c28b79a6c23226c1c24a2d8b954f7199195bba6fFrank Maker	memset(sk, 0, sizeof(*sk));
44ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
45ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/* Get current time */
46ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
47ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	if (gettimeofday(&tv, NULL))
48d99fe5ec960b5eae96585d5ceb59fe287fe0c5e7Dmitry Shmidt		goto fail;
49ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	else
50ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		sk->s_seq_next = (int) tv.tv_sec;
51ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
52ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/* Create local socket */
53ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	sk->s_local.nl_family = AF_NETLINK;
54c28b79a6c23226c1c24a2d8b954f7199195bba6fFrank Maker	sk->s_local.nl_pid = 0; /* Kernel fills in pid */
55ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	sk->s_local.nl_groups = 0; /* No groups */
56ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
57ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/* Create peer socket */
58ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	sk->s_peer.nl_family = AF_NETLINK;
59ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	sk->s_peer.nl_pid = 0; /* Kernel */
60ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	sk->s_peer.nl_groups = 0; /* No groups */
61ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
62d99fe5ec960b5eae96585d5ceb59fe287fe0c5e7Dmitry Shmidt	return sk;
63d99fe5ec960b5eae96585d5ceb59fe287fe0c5e7Dmitry Shmidtfail:
64d99fe5ec960b5eae96585d5ceb59fe287fe0c5e7Dmitry Shmidt	free(sk);
65d99fe5ec960b5eae96585d5ceb59fe287fe0c5e7Dmitry Shmidt	return NULL;
66d99fe5ec960b5eae96585d5ceb59fe287fe0c5e7Dmitry Shmidt}
67ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
68d99fe5ec960b5eae96585d5ceb59fe287fe0c5e7Dmitry Shmidt/* Allocate new netlink socket. */
69d99fe5ec960b5eae96585d5ceb59fe287fe0c5e7Dmitry Shmidtstruct nl_sock *nl_socket_alloc(void)
70d99fe5ec960b5eae96585d5ceb59fe287fe0c5e7Dmitry Shmidt{
71d99fe5ec960b5eae96585d5ceb59fe287fe0c5e7Dmitry Shmidt	struct nl_sock *sk = _nl_socket_alloc();
72d99fe5ec960b5eae96585d5ceb59fe287fe0c5e7Dmitry Shmidt	struct nl_cb *cb;
73ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
74d99fe5ec960b5eae96585d5ceb59fe287fe0c5e7Dmitry Shmidt	if (!sk)
75d99fe5ec960b5eae96585d5ceb59fe287fe0c5e7Dmitry Shmidt		return NULL;
76d99fe5ec960b5eae96585d5ceb59fe287fe0c5e7Dmitry Shmidt
77d99fe5ec960b5eae96585d5ceb59fe287fe0c5e7Dmitry Shmidt	cb = nl_cb_alloc(NL_CB_DEFAULT);
78d99fe5ec960b5eae96585d5ceb59fe287fe0c5e7Dmitry Shmidt	if (!cb)
79d99fe5ec960b5eae96585d5ceb59fe287fe0c5e7Dmitry Shmidt		goto cb_fail;
80d99fe5ec960b5eae96585d5ceb59fe287fe0c5e7Dmitry Shmidt	sk->s_cb = cb;
81ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	return sk;
82ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makercb_fail:
83ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	free(sk);
84ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	return NULL;
85ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker}
86ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
87ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker/* Allocate new socket with custom callbacks. */
88ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makerstruct nl_sock *nl_socket_alloc_cb(struct nl_cb *cb)
89ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker{
90d99fe5ec960b5eae96585d5ceb59fe287fe0c5e7Dmitry Shmidt	struct nl_sock *sk = _nl_socket_alloc();
91d99fe5ec960b5eae96585d5ceb59fe287fe0c5e7Dmitry Shmidt
92ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	if (!sk)
93c28b79a6c23226c1c24a2d8b954f7199195bba6fFrank Maker		return NULL;
94ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
95ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	sk->s_cb = cb;
96ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	nl_cb_get(cb);
97ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
98ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	return sk;
99ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker}
100ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
101ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker/* Free a netlink socket. */
102ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makervoid nl_socket_free(struct nl_sock *sk)
103ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker{
104ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	nl_cb_put(sk->s_cb);
10569bc179b203c17380ba0b4fda7cf99af65cc5324Frank Maker	close(sk->s_fd);
106ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	free(sk);
107ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker}
108ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
109ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker/* Sets socket buffer size of netlink socket */
110ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makerint nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf)
111ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker{
112ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	if (setsockopt(sk->s_fd, SOL_SOCKET, SO_SNDBUF, \
113ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			&rxbuf, (socklen_t) sizeof(rxbuf)))
114ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		goto error;
115ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
116ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	if (setsockopt(sk->s_fd, SOL_SOCKET, SO_RCVBUF, \
117ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			&txbuf, (socklen_t) sizeof(txbuf)))
118ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		goto error;
119ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
120ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	return 0;
121ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makererror:
122ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	return -errno;
123ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
124ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker}
125ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
126ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makerint nl_socket_get_fd(struct nl_sock *sk)
127ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker{
128ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	return sk->s_fd;
129ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker}
130de92239055ac87e51ef7e868ed9697d038a72368Dmitry Shmidt
131de92239055ac87e51ef7e868ed9697d038a72368Dmitry Shmidtvoid nl_socket_set_cb(struct nl_sock *sk, struct nl_cb *cb)
132de92239055ac87e51ef7e868ed9697d038a72368Dmitry Shmidt{
133de92239055ac87e51ef7e868ed9697d038a72368Dmitry Shmidt	nl_cb_put(sk->s_cb);
134de92239055ac87e51ef7e868ed9697d038a72368Dmitry Shmidt	sk->s_cb = cb;
135de92239055ac87e51ef7e868ed9697d038a72368Dmitry Shmidt	nl_cb_get(cb);
136de92239055ac87e51ef7e868ed9697d038a72368Dmitry Shmidt}
137de92239055ac87e51ef7e868ed9697d038a72368Dmitry Shmidt
138de92239055ac87e51ef7e868ed9697d038a72368Dmitry Shmidtstruct nl_cb *nl_socket_get_cb(struct nl_sock *sk)
139de92239055ac87e51ef7e868ed9697d038a72368Dmitry Shmidt{
140de92239055ac87e51ef7e868ed9697d038a72368Dmitry Shmidt	return nl_cb_get(sk->s_cb);
141de92239055ac87e51ef7e868ed9697d038a72368Dmitry Shmidt}
142