blob: 3e28d78485cc4be3a0488ef8d053b872e3e737f2 [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
Tomasz Wasilczyk55f21932019-12-20 09:20:24 -080024namespace android::netdevice {
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070025
26typedef unsigned short rtattrtype_t; // as in rtnetlink.h
27typedef __u16 nlmsgtype_t; // as in netlink.h
28
chrisweircf36cea2019-11-08 16:41:02 -080029/** Implementation details, do not use outside NetlinkRequest template. */
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070030namespace impl {
31
32struct rtattr* addattr_l(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type, const void* data,
33 size_t dataLen);
34struct rtattr* addattr_nest(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type);
35void addattr_nest_end(struct nlmsghdr* n, struct rtattr* nest);
36
37} // namespace impl
38
39/**
40 * Wrapper around NETLINK_ROUTE messages, to build them in C++ style.
41 *
42 * \param T specific message header (such as struct ifinfomsg)
43 * \param BUFSIZE how much space to reserve for payload (not counting the header size)
44 */
45template <class T, unsigned int BUFSIZE = 128>
46struct NetlinkRequest {
47 /**
48 * Create empty message.
49 *
50 * \param type Message type (such as RTM_NEWLINK)
51 * \param flags Message flags (such as NLM_F_REQUEST)
52 */
53 NetlinkRequest(nlmsgtype_t type, uint16_t flags) {
54 mRequest.nlmsg.nlmsg_len = NLMSG_LENGTH(sizeof(mRequest.data));
55 mRequest.nlmsg.nlmsg_type = type;
56 mRequest.nlmsg.nlmsg_flags = flags;
57 }
58
chrisweircf36cea2019-11-08 16:41:02 -080059 /** \return pointer to raw netlink message header. */
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070060 struct nlmsghdr* header() {
61 return &mRequest.nlmsg;
62 }
63 /** Reference to message-specific header. */
64 T& data() { return mRequest.data; }
65
66 /**
67 * Adds an attribute of a simple type.
68 *
69 * If this method fails (i.e. due to insufficient space), the message will be marked
70 * as bad (\see isGood).
71 *
72 * \param type attribute type (such as IFLA_IFNAME)
73 * \param attr attribute data
74 */
75 template <class A>
76 void addattr(rtattrtype_t type, const A& attr) {
77 if (!mIsGood) return;
78 auto ap = impl::addattr_l(&mRequest.nlmsg, sizeof(mRequest), type, &attr, sizeof(attr));
79 if (ap == nullptr) mIsGood = false;
80 }
81
82 template <>
83 void addattr(rtattrtype_t type, const std::string& s) {
84 if (!mIsGood) return;
85 auto ap = impl::addattr_l(&mRequest.nlmsg, sizeof(mRequest), type, s.c_str(), s.size() + 1);
86 if (ap == nullptr) mIsGood = false;
87 }
88
chrisweircf36cea2019-11-08 16:41:02 -080089 /** Guard class to frame nested attributes. See nest(int). */
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070090 struct Nest {
91 Nest(NetlinkRequest& req, rtattrtype_t type) : mReq(req), mAttr(req.nestStart(type)) {}
92 ~Nest() { mReq.nestEnd(mAttr); }
93
94 private:
95 NetlinkRequest& mReq;
96 struct rtattr* mAttr;
97
98 DISALLOW_COPY_AND_ASSIGN(Nest);
99 };
100
101 /**
102 * Add nested attribute.
103 *
104 * The returned object is a guard for auto-nesting children inside the argument attribute.
105 * When the Nest object goes out of scope, the nesting attribute is closed.
106 *
107 * Example usage nesting IFLA_CAN_BITTIMING inside IFLA_INFO_DATA, which is nested
108 * inside IFLA_LINKINFO:
109 * NetlinkRequest<struct ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST);
110 * {
111 * auto linkinfo = req.nest(IFLA_LINKINFO);
112 * req.addattr(IFLA_INFO_KIND, "can");
113 * {
114 * auto infodata = req.nest(IFLA_INFO_DATA);
115 * req.addattr(IFLA_CAN_BITTIMING, bitTimingStruct);
116 * }
117 * }
118 * // use req
119 *
120 * \param type attribute type (such as IFLA_LINKINFO)
121 */
122 Nest nest(int type) { return Nest(*this, type); }
123
124 /**
125 * Indicates, whether the message is in a good state.
126 *
127 * The bad state is usually a result of payload buffer being too small.
128 * You can modify BUFSIZE template parameter to fix this.
129 */
130 bool isGood() const { return mIsGood; }
131
132 private:
133 bool mIsGood = true;
134
135 struct {
136 struct nlmsghdr nlmsg;
137 T data;
138 char buf[BUFSIZE];
139 } mRequest = {};
140
141 struct rtattr* nestStart(rtattrtype_t type) {
142 if (!mIsGood) return nullptr;
143 auto attr = impl::addattr_nest(&mRequest.nlmsg, sizeof(mRequest), type);
144 if (attr == nullptr) mIsGood = false;
145 return attr;
146 }
147
148 void nestEnd(struct rtattr* nest) {
149 if (mIsGood && nest != nullptr) impl::addattr_nest_end(&mRequest.nlmsg, nest);
150 }
151};
152
Tomasz Wasilczyk55f21932019-12-20 09:20:24 -0800153} // namespace android::netdevice