Wade Guthrie | 0d43853 | 2012-05-18 14:18:50 -0700 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium OS Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
Wade Guthrie | 0d43853 | 2012-05-18 14:18:50 -0700 | [diff] [blame] | 4 | |
| 5 | #include "shill/netlink_socket.h" |
| 6 | |
Wade Guthrie | cc53f23 | 2013-03-05 13:22:23 -0800 | [diff] [blame] | 7 | #include <linux/if_packet.h> |
Wade Guthrie | 0ae4b8e | 2013-04-10 16:49:15 -0700 | [diff] [blame] | 8 | #include <linux/netlink.h> |
Wade Guthrie | cc53f23 | 2013-03-05 13:22:23 -0800 | [diff] [blame] | 9 | #include <sys/socket.h> |
Wade Guthrie | 0d43853 | 2012-05-18 14:18:50 -0700 | [diff] [blame] | 10 | |
Christopher Wiley | 393b93f | 2012-11-08 17:30:58 -0800 | [diff] [blame] | 11 | #include "shill/logging.h" |
Wade Guthrie | 0ae4b8e | 2013-04-10 16:49:15 -0700 | [diff] [blame] | 12 | #include "shill/netlink_message.h" |
Wade Guthrie | cc53f23 | 2013-03-05 13:22:23 -0800 | [diff] [blame] | 13 | #include "shill/sockets.h" |
repo sync | dc085c8 | 2012-12-28 08:54:41 -0800 | [diff] [blame] | 14 | |
Wade Guthrie | bee87c2 | 2013-03-06 11:00:46 -0800 | [diff] [blame] | 15 | // This is from a version of linux/socket.h that we don't have. |
| 16 | #define SOL_NETLINK 270 |
| 17 | |
Wade Guthrie | 0d43853 | 2012-05-18 14:18:50 -0700 | [diff] [blame] | 18 | namespace shill { |
| 19 | |
Wade Guthrie | cc53f23 | 2013-03-05 13:22:23 -0800 | [diff] [blame] | 20 | // Keep this large enough to avoid overflows on IPv6 SNM routing update spikes |
| 21 | const int NetlinkSocket::kReceiveBufferSize = 512 * 1024; |
| 22 | |
| 23 | NetlinkSocket::NetlinkSocket() : sequence_number_(0), file_descriptor_(-1) {} |
| 24 | |
Wade Guthrie | 0d43853 | 2012-05-18 14:18:50 -0700 | [diff] [blame] | 25 | NetlinkSocket::~NetlinkSocket() { |
Wade Guthrie | cc53f23 | 2013-03-05 13:22:23 -0800 | [diff] [blame] | 26 | if (sockets_ && (file_descriptor_ >= 0)) { |
| 27 | sockets_->Close(file_descriptor_); |
Wade Guthrie | 0d43853 | 2012-05-18 14:18:50 -0700 | [diff] [blame] | 28 | } |
| 29 | } |
| 30 | |
| 31 | bool NetlinkSocket::Init() { |
Wade Guthrie | cc53f23 | 2013-03-05 13:22:23 -0800 | [diff] [blame] | 32 | // Allows for a test to set |sockets_| before calling |Init|. |
| 33 | if (sockets_) { |
| 34 | LOG(INFO) << "|sockets_| already has a value -- this must be a test."; |
| 35 | } else { |
| 36 | sockets_.reset(new Sockets); |
| 37 | } |
| 38 | |
| 39 | // The following is stolen directly from RTNLHandler. |
| 40 | // TODO(wdg): refactor this and RTNLHandler together to use common code. |
| 41 | // crosbug.com/39842 |
| 42 | |
| 43 | file_descriptor_ = sockets_->Socket(PF_NETLINK, SOCK_DGRAM, NETLINK_GENERIC); |
| 44 | if (file_descriptor_ < 0) { |
| 45 | LOG(ERROR) << "Failed to open netlink socket"; |
Wade Guthrie | 0d43853 | 2012-05-18 14:18:50 -0700 | [diff] [blame] | 46 | return false; |
| 47 | } |
| 48 | |
Wade Guthrie | cc53f23 | 2013-03-05 13:22:23 -0800 | [diff] [blame] | 49 | if (sockets_->SetReceiveBuffer(file_descriptor_, kReceiveBufferSize)) { |
| 50 | LOG(ERROR) << "Failed to increase receive buffer size"; |
| 51 | } |
| 52 | |
| 53 | struct sockaddr_nl addr; |
| 54 | memset(&addr, 0, sizeof(addr)); |
| 55 | addr.nl_family = AF_NETLINK; |
| 56 | |
| 57 | if (sockets_->Bind(file_descriptor_, |
| 58 | reinterpret_cast<struct sockaddr *>(&addr), |
| 59 | sizeof(addr)) < 0) { |
| 60 | sockets_->Close(file_descriptor_); |
| 61 | file_descriptor_ = -1; |
| 62 | LOG(ERROR) << "Netlink socket bind failed"; |
| 63 | return false; |
| 64 | } |
| 65 | SLOG(WiFi, 2) << "Netlink socket started"; |
| 66 | |
| 67 | return true; |
| 68 | } |
| 69 | |
| 70 | bool NetlinkSocket::RecvMessage(ByteString *message) { |
| 71 | if (!message) { |
| 72 | LOG(ERROR) << "Null |message|"; |
Wade Guthrie | 0d43853 | 2012-05-18 14:18:50 -0700 | [diff] [blame] | 73 | return false; |
| 74 | } |
| 75 | |
Wade Guthrie | cc53f23 | 2013-03-05 13:22:23 -0800 | [diff] [blame] | 76 | // Determine the amount of data currently waiting. |
| 77 | const size_t kDummyReadByteCount = 1; |
| 78 | ByteString dummy_read(kDummyReadByteCount); |
| 79 | ssize_t result; |
| 80 | result = sockets_->RecvFrom( |
| 81 | file_descriptor_, |
| 82 | dummy_read.GetData(), |
| 83 | dummy_read.GetLength(), |
| 84 | MSG_TRUNC | MSG_PEEK, |
| 85 | NULL, |
| 86 | NULL); |
| 87 | if (result < 0) { |
| 88 | PLOG(ERROR) << "Socket recvfrom failed."; |
| 89 | return false; |
| 90 | } |
| 91 | |
| 92 | // Read the data that was waiting when we did our previous read. |
| 93 | message->Resize(result); |
| 94 | result = sockets_->RecvFrom( |
| 95 | file_descriptor_, |
| 96 | message->GetData(), |
| 97 | message->GetLength(), |
| 98 | 0, |
| 99 | NULL, |
| 100 | NULL); |
| 101 | if (result < 0) { |
| 102 | PLOG(ERROR) << "Second socket recvfrom failed."; |
| 103 | return false; |
| 104 | } |
Wade Guthrie | 0d43853 | 2012-05-18 14:18:50 -0700 | [diff] [blame] | 105 | return true; |
| 106 | } |
| 107 | |
Wade Guthrie | bdcdaa7 | 2013-03-04 12:47:12 -0800 | [diff] [blame] | 108 | bool NetlinkSocket::SendMessage(const ByteString &out_msg) { |
Wade Guthrie | cc53f23 | 2013-03-05 13:22:23 -0800 | [diff] [blame] | 109 | ssize_t result = sockets_->Send(file_descriptor(), out_msg.GetConstData(), |
| 110 | out_msg.GetLength(), 0); |
repo sync | dc085c8 | 2012-12-28 08:54:41 -0800 | [diff] [blame] | 111 | if (!result) { |
| 112 | PLOG(ERROR) << "Send failed."; |
| 113 | return false; |
Wade Guthrie | 5d53d49 | 2012-11-07 09:53:31 -0800 | [diff] [blame] | 114 | } |
Wade Guthrie | cc53f23 | 2013-03-05 13:22:23 -0800 | [diff] [blame] | 115 | if (result != static_cast<ssize_t>(out_msg.GetLength())) { |
| 116 | LOG(ERROR) << "Only sent " << result << " bytes out of " |
| 117 | << out_msg.GetLength() << "."; |
Wade Guthrie | 0d43853 | 2012-05-18 14:18:50 -0700 | [diff] [blame] | 118 | return false; |
| 119 | } |
| 120 | |
| 121 | return true; |
| 122 | } |
| 123 | |
Wade Guthrie | bee87c2 | 2013-03-06 11:00:46 -0800 | [diff] [blame] | 124 | bool NetlinkSocket::SubscribeToEvents(uint32_t group_id) { |
| 125 | int err = setsockopt(file_descriptor_, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, |
| 126 | &group_id, sizeof(group_id)); |
| 127 | if (err < 0) { |
| 128 | PLOG(ERROR) << "setsockopt didn't work."; |
| 129 | return false; |
| 130 | } |
| 131 | return true; |
| 132 | } |
| 133 | |
Wade Guthrie | cc53f23 | 2013-03-05 13:22:23 -0800 | [diff] [blame] | 134 | uint32_t NetlinkSocket::GetSequenceNumber() { |
| 135 | if (++sequence_number_ == NetlinkMessage::kBroadcastSequenceNumber) |
| 136 | ++sequence_number_; |
| 137 | return sequence_number_; |
Wade Guthrie | 0d43853 | 2012-05-18 14:18:50 -0700 | [diff] [blame] | 138 | } |
| 139 | |
| 140 | } // namespace shill. |