blob: ba9b65bdd303229a06b29c1f543eca7374c19165 [file] [log] [blame]
Tomasz Wasilczyk87329672019-07-12 11:43:00 -07001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#pragma once
18
19#include <android-base/macros.h>
20#include <linux/rtnetlink.h>
21
22#include <string>
23
24namespace android {
25namespace netdevice {
26
27typedef unsigned short rtattrtype_t; // as in rtnetlink.h
28typedef __u16 nlmsgtype_t; // as in netlink.h
29
chrisweircf36cea2019-11-08 16:41:02 -080030/** Implementation details, do not use outside NetlinkRequest template. */
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070031namespace impl {
32
33struct rtattr* addattr_l(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type, const void* data,
34 size_t dataLen);
35struct rtattr* addattr_nest(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type);
36void addattr_nest_end(struct nlmsghdr* n, struct rtattr* nest);
37
38} // namespace impl
39
40/**
41 * Wrapper around NETLINK_ROUTE messages, to build them in C++ style.
42 *
43 * \param T specific message header (such as struct ifinfomsg)
44 * \param BUFSIZE how much space to reserve for payload (not counting the header size)
45 */
46template <class T, unsigned int BUFSIZE = 128>
47struct NetlinkRequest {
48 /**
49 * Create empty message.
50 *
51 * \param type Message type (such as RTM_NEWLINK)
52 * \param flags Message flags (such as NLM_F_REQUEST)
53 */
54 NetlinkRequest(nlmsgtype_t type, uint16_t flags) {
55 mRequest.nlmsg.nlmsg_len = NLMSG_LENGTH(sizeof(mRequest.data));
56 mRequest.nlmsg.nlmsg_type = type;
57 mRequest.nlmsg.nlmsg_flags = flags;
58 }
59
chrisweircf36cea2019-11-08 16:41:02 -080060 /** \return pointer to raw netlink message header. */
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070061 struct nlmsghdr* header() {
62 return &mRequest.nlmsg;
63 }
64 /** Reference to message-specific header. */
65 T& data() { return mRequest.data; }
66
67 /**
68 * Adds an attribute of a simple type.
69 *
70 * If this method fails (i.e. due to insufficient space), the message will be marked
71 * as bad (\see isGood).
72 *
73 * \param type attribute type (such as IFLA_IFNAME)
74 * \param attr attribute data
75 */
76 template <class A>
77 void addattr(rtattrtype_t type, const A& attr) {
78 if (!mIsGood) return;
79 auto ap = impl::addattr_l(&mRequest.nlmsg, sizeof(mRequest), type, &attr, sizeof(attr));
80 if (ap == nullptr) mIsGood = false;
81 }
82
83 template <>
84 void addattr(rtattrtype_t type, const std::string& s) {
85 if (!mIsGood) return;
86 auto ap = impl::addattr_l(&mRequest.nlmsg, sizeof(mRequest), type, s.c_str(), s.size() + 1);
87 if (ap == nullptr) mIsGood = false;
88 }
89
chrisweircf36cea2019-11-08 16:41:02 -080090 /** Guard class to frame nested attributes. See nest(int). */
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070091 struct Nest {
92 Nest(NetlinkRequest& req, rtattrtype_t type) : mReq(req), mAttr(req.nestStart(type)) {}
93 ~Nest() { mReq.nestEnd(mAttr); }
94
95 private:
96 NetlinkRequest& mReq;
97 struct rtattr* mAttr;
98
99 DISALLOW_COPY_AND_ASSIGN(Nest);
100 };
101
102 /**
103 * Add nested attribute.
104 *
105 * The returned object is a guard for auto-nesting children inside the argument attribute.
106 * When the Nest object goes out of scope, the nesting attribute is closed.
107 *
108 * Example usage nesting IFLA_CAN_BITTIMING inside IFLA_INFO_DATA, which is nested
109 * inside IFLA_LINKINFO:
110 * NetlinkRequest<struct ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST);
111 * {
112 * auto linkinfo = req.nest(IFLA_LINKINFO);
113 * req.addattr(IFLA_INFO_KIND, "can");
114 * {
115 * auto infodata = req.nest(IFLA_INFO_DATA);
116 * req.addattr(IFLA_CAN_BITTIMING, bitTimingStruct);
117 * }
118 * }
119 * // use req
120 *
121 * \param type attribute type (such as IFLA_LINKINFO)
122 */
123 Nest nest(int type) { return Nest(*this, type); }
124
125 /**
126 * Indicates, whether the message is in a good state.
127 *
128 * The bad state is usually a result of payload buffer being too small.
129 * You can modify BUFSIZE template parameter to fix this.
130 */
131 bool isGood() const { return mIsGood; }
132
133 private:
134 bool mIsGood = true;
135
136 struct {
137 struct nlmsghdr nlmsg;
138 T data;
139 char buf[BUFSIZE];
140 } mRequest = {};
141
142 struct rtattr* nestStart(rtattrtype_t type) {
143 if (!mIsGood) return nullptr;
144 auto attr = impl::addattr_nest(&mRequest.nlmsg, sizeof(mRequest), type);
145 if (attr == nullptr) mIsGood = false;
146 return attr;
147 }
148
149 void nestEnd(struct rtattr* nest) {
150 if (mIsGood && nest != nullptr) impl::addattr_nest_end(&mRequest.nlmsg, nest);
151 }
152};
153
154} // namespace netdevice
155} // namespace android