1ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes/*
2ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes * Copyright (C) 2015 The Android Open Source Project
3ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes * All rights reserved.
4ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes *
5ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes * Redistribution and use in source and binary forms, with or without
6ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes * modification, are permitted provided that the following conditions
7ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes * are met:
8ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes *  * Redistributions of source code must retain the above copyright
9ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes *    notice, this list of conditions and the following disclaimer.
10ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes *  * Redistributions in binary form must reproduce the above copyright
11ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes *    notice, this list of conditions and the following disclaimer in
12ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes *    the documentation and/or other materials provided with the
13ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes *    distribution.
14ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes *
15ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes * SUCH DAMAGE.
27ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes */
28ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes
29ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes#include "bionic_netlink.h"
30ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes
31ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes#include <errno.h>
32ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes#include <linux/netlink.h>
33ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes#include <linux/rtnetlink.h>
34ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes#include <string.h>
35ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes#include <stdlib.h>
36ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes#include <sys/socket.h>
37ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes#include <unistd.h>
38ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes
39ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes#include "private/ErrnoRestorer.h"
40ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes
41ed57b98758176f0cccdec16cbed524e444039fe7Elliott HughesNetlinkConnection::NetlinkConnection() {
42ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes  fd_ = -1;
43ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes
44ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes  // The kernel keeps packets under 8KiB (NLMSG_GOODSIZE),
45ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes  // but that's a bit too large to go on the stack.
46ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes  size_ = 8192;
47ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes  data_ = new char[size_];
48ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes}
49ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes
50ed57b98758176f0cccdec16cbed524e444039fe7Elliott HughesNetlinkConnection::~NetlinkConnection() {
51ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes  ErrnoRestorer errno_restorer;
52ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes  if (fd_ != -1) close(fd_);
53ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes  delete[] data_;
54ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes}
55ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes
56ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughesbool NetlinkConnection::SendRequest(int type) {
57ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes  // Rather than force all callers to check for the unlikely event of being
58ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes  // unable to allocate 8KiB, check here.
59ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes  if (data_ == nullptr) return false;
60ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes
61ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes  // Did we open a netlink socket yet?
62ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes  if (fd_ == -1) {
63ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes    fd_ = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
64ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes  }
65ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes
66ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes  // Construct and send the message.
67ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes  struct NetlinkMessage {
68ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes    nlmsghdr hdr;
69ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes    rtgenmsg msg;
70ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes  } request;
71ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes  memset(&request, 0, sizeof(request));
72ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes  request.hdr.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
73ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes  request.hdr.nlmsg_type = type;
74ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes  request.hdr.nlmsg_len = sizeof(request);
75ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes  request.msg.rtgen_family = AF_UNSPEC; // All families.
76ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes  return (TEMP_FAILURE_RETRY(send(fd_, &request, sizeof(request), 0)) == sizeof(request));
77ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes}
78ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes
79ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughesbool NetlinkConnection::ReadResponses(void callback(void*, nlmsghdr*), void* context) {
80ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes  // Read through all the responses, handing interesting ones to the callback.
81ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes  ssize_t bytes_read;
82ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes  while ((bytes_read = TEMP_FAILURE_RETRY(recv(fd_, data_, size_, 0))) > 0) {
83ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes    nlmsghdr* hdr = reinterpret_cast<nlmsghdr*>(data_);
84ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes    for (; NLMSG_OK(hdr, static_cast<size_t>(bytes_read)); hdr = NLMSG_NEXT(hdr, bytes_read)) {
85ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes      if (hdr->nlmsg_type == NLMSG_DONE) return true;
86ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes      if (hdr->nlmsg_type == NLMSG_ERROR) return false;
87ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes      callback(context, hdr);
88ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes    }
89ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes  }
90ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes
91ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes  // We only get here if recv fails before we see a NLMSG_DONE.
92ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes  return false;
93ed57b98758176f0cccdec16cbed524e444039fe7Elliott Hughes}
94