blob: 9b35ff37297e03d18f3ab485835b3da60aaf3faa [file] [log] [blame]
Wade Guthrie0d438532012-05-18 14:18:50 -07001// 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.
4
5#include "shill/kernel_bound_nlmessage.h"
6
7#include <net/if.h>
8#include <netlink/genl/genl.h>
9#include <netlink/msg.h>
10#include <netlink/netlink.h>
11
12#include <base/logging.h>
13
14#include "shill/logging.h"
15#include "shill/netlink_socket.h"
16#include "shill/scope_logger.h"
17
18namespace shill {
19
20const uint32_t KernelBoundNlMessage::kIllegalMessage = 0xFFFFFFFF;
21
22KernelBoundNlMessage::~KernelBoundNlMessage() {
23 if (message_) {
24 nlmsg_free(message_);
25 message_ = NULL;
26 }
27}
28
29bool KernelBoundNlMessage::Init() {
30 message_ = nlmsg_alloc();
31
32 if (!message_) {
33 LOG(ERROR) << "Couldn't allocate |message_|";
34 return false;
35 }
36
37 return true;
38}
39
40uint32_t KernelBoundNlMessage::GetId() const {
41 if (!message_) {
42 LOG(ERROR) << "NULL |message_|";
43 return kIllegalMessage;
44 }
45 struct nlmsghdr *header = nlmsg_hdr(message_);
46 if (!header) {
47 LOG(ERROR) << "Couldn't make header";
48 return kIllegalMessage;
49 }
50 return header->nlmsg_seq;
51}
52
53bool KernelBoundNlMessage::AddNetlinkHeader(uint32_t port, uint32_t seq,
54 int family_id, int hdrlen,
55 int flags, uint8_t cmd,
56 uint8_t version) {
57 if (!message_) {
58 LOG(ERROR) << "NULL |message_|";
59 return false;
60 }
61
62 // Parameters to genlmsg_put:
63 // @message: struct nl_msg *message_.
64 // @pid: netlink pid the message is addressed to.
65 // @seq: sequence number (usually the one of the sender).
66 // @family: generic netlink family.
67 // @flags netlink message flags.
68 // @cmd: netlink command.
69 // @version: version of communication protocol.
70 // genlmsg_put returns a void * pointing to the header but we don't want to
71 // encourage its use outside of this object.
72
73 if (genlmsg_put(message_, port, seq, family_id, hdrlen, flags, cmd, version)
74 == NULL) {
75 LOG(ERROR) << "genlmsg_put returned a NULL pointer.";
76 return false;
77 }
78
79 return true;
80}
81
82int KernelBoundNlMessage::AddAttribute(int attrtype, int attrlen,
83 const void *data) {
84 if (!data) {
85 LOG(ERROR) << "NULL |data| parameter";
86 return -1;
87 }
88 if (!message_) {
89 LOG(ERROR) << "NULL |message_|.";
90 return -1;
91 }
92 return nla_put(message_, attrtype, attrlen, data);
93}
94
95bool KernelBoundNlMessage::Send(NetlinkSocket *socket) {
96 if (!socket) {
97 LOG(ERROR) << "NULL |socket| parameter";
98 return false;
99 }
100 if (!message_) {
101 LOG(ERROR) << "NULL |message_|.";
102 return -1;
103 }
104
105 // Manually set the sequence number -- seems to work.
106 struct nlmsghdr *header = nlmsg_hdr(message_);
107 if (header != 0) {
108 header->nlmsg_seq = socket->GetSequenceNumber();
109 }
110
111 // Complete AND SEND a message.
112 int result = nl_send_auto_complete(
113 const_cast<struct nl_sock *>(socket->GetConstNlSock()), message_);
114
115 SLOG(WiFi, 6) << "NL Message " << GetId() << " ===>";
116
117 if (result < 0) {
118 LOG(ERROR) << "Failed call to 'nl_send_auto_complete': " << result;
119 return false;
120 }
121 return true;
122}
123
124} // namespace shill.