blob: 92636e45958734ea1e006d2c192bf732556194db [file] [log] [blame]
Paul Stewartdd7df792011-07-15 11:09:50 -07001// Copyright (c) 2011 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/rtnl_message.h"
6
7#include <base/logging.h>
8
9#include <sys/socket.h>
10#include <linux/netlink.h>
11#include <linux/rtnetlink.h>
12
13namespace shill {
14
15struct RTNLHeader {
16 RTNLHeader() {
17 memset(this, 0, sizeof(*this));
18 }
19 struct nlmsghdr hdr;
20 union {
21 struct ifinfomsg ifi;
22 struct ifaddrmsg ifa;
23 struct rtmsg rtm;
24 struct rtgenmsg gen;
25 };
26};
27
28RTNLMessage::RTNLMessage()
29 : type_(kMessageTypeUnknown),
30 mode_(kMessageModeUnknown),
31 flags_(0),
32 interface_index_(0),
33 family_(IPAddress::kAddressFamilyUnknown) {}
34
35RTNLMessage::RTNLMessage(MessageType type,
36 MessageMode mode,
37 unsigned int flags,
38 uint32 seq,
39 uint32 pid,
40 int interface_index,
41 IPAddress::Family family)
42 : type_(type),
43 mode_(mode),
44 flags_(flags),
45 seq_(seq),
46 pid_(pid),
47 interface_index_(interface_index),
48 family_(family) {}
49
50bool RTNLMessage::Decode(const ByteString &msg) {
51 bool ret = DecodeInternal(msg);
52 if (!ret) {
53 mode_ = kMessageModeUnknown;
54 type_ = kMessageTypeUnknown;
55 }
56 return ret;
57}
58
59bool RTNLMessage::DecodeInternal(const ByteString &msg) {
60 const RTNLHeader *hdr =
61 reinterpret_cast<const RTNLHeader *>(msg.GetConstData());
62
63 if (msg.GetLength() < sizeof(hdr->hdr) ||
64 msg.GetLength() < hdr->hdr.nlmsg_len)
65 return false;
66
67 MessageMode mode = kMessageModeUnknown;
68 switch (hdr->hdr.nlmsg_type) {
69 case RTM_NEWLINK:
70 case RTM_NEWADDR:
71 case RTM_NEWROUTE:
72 mode = kMessageModeAdd;
73 break;
74
75 case RTM_DELLINK:
76 case RTM_DELADDR:
77 case RTM_DELROUTE:
78 mode = kMessageModeDelete;
79 break;
80
81 default:
82 return false;
83 }
84
85 rtattr *attr_data = NULL;
86 int attr_length = 0;
87
88 switch (hdr->hdr.nlmsg_type) {
89 case RTM_NEWLINK:
90 case RTM_DELLINK:
91 if (!DecodeLink(hdr, mode, &attr_data, &attr_length))
92 return false;
93 break;
94
95 case RTM_NEWADDR:
96 case RTM_DELADDR:
97 if (!DecodeAddress(hdr, mode, &attr_data, &attr_length))
98 return false;
99 break;
100
101 case RTM_NEWROUTE:
102 case RTM_DELROUTE:
103 if (!DecodeRoute(hdr, mode, &attr_data, &attr_length))
104 return false;
105 break;
106
107 default:
108 NOTREACHED();
109 }
110
111 flags_ = hdr->hdr.nlmsg_flags;
112 seq_ = hdr->hdr.nlmsg_seq;
113 pid_ = hdr->hdr.nlmsg_pid;
114
115 while (attr_data && RTA_OK(attr_data, attr_length)) {
116 SetAttribute(
117 attr_data->rta_type,
118 ByteString(reinterpret_cast<unsigned char *>(RTA_DATA(attr_data)),
119 RTA_PAYLOAD(attr_data)));
120 attr_data = RTA_NEXT(attr_data, attr_length);
121 }
122
123 if (attr_length) {
124 // We hit a parse error while going through the attributes
125 attributes_.clear();
126 return false;
127 }
128
129 return true;
130}
131
132bool RTNLMessage::DecodeLink(const RTNLHeader *hdr,
133 MessageMode mode,
134 rtattr **attr_data,
135 int *attr_length) {
136 if (hdr->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(hdr->ifi))) {
137 return false;
138 }
139
140 mode_ = mode;
141 *attr_data = IFLA_RTA(NLMSG_DATA(&hdr->hdr));
142 *attr_length = IFLA_PAYLOAD(&hdr->hdr);
143
144 type_ = kMessageTypeLink;
145 family_ = hdr->ifi.ifi_family;
146 interface_index_ = hdr->ifi.ifi_index;
147 set_link_status(LinkStatus(hdr->ifi.ifi_type,
148 hdr->ifi.ifi_flags,
149 hdr->ifi.ifi_change));
150 return true;
151}
152
153bool RTNLMessage::DecodeAddress(const RTNLHeader *hdr,
154 MessageMode mode,
155 rtattr **attr_data,
156 int *attr_length) {
157 if (hdr->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(hdr->ifa))) {
158 return false;
159 }
160 mode_ = mode;
161 *attr_data = IFA_RTA(NLMSG_DATA(&hdr->hdr));
162 *attr_length = IFA_PAYLOAD(&hdr->hdr);
163
164 type_ = kMessageTypeAddress;
165 family_ = hdr->ifa.ifa_family;
166 interface_index_ = hdr->ifa.ifa_index;
167 set_address_status(AddressStatus(hdr->ifa.ifa_prefixlen,
168 hdr->ifa.ifa_flags,
169 hdr->ifa.ifa_scope));
170 return true;
171}
172
173bool RTNLMessage::DecodeRoute(const RTNLHeader *hdr,
174 MessageMode mode,
175 rtattr **attr_data,
176 int *attr_length) {
177 if (hdr->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(hdr->rtm))) {
178 return false;
179 }
180 mode_ = mode;
181 *attr_data = RTM_RTA(NLMSG_DATA(&hdr->hdr));
182 *attr_length = RTM_PAYLOAD(&hdr->hdr);
183
184 type_ = kMessageTypeRoute;
185 family_ = hdr->rtm.rtm_family;
186 set_route_status(RouteStatus(hdr->rtm.rtm_dst_len,
187 hdr->rtm.rtm_src_len,
188 hdr->rtm.rtm_table,
189 hdr->rtm.rtm_protocol,
190 hdr->rtm.rtm_scope,
191 hdr->rtm.rtm_type,
192 hdr->rtm.rtm_flags));
193 return true;
194}
195
196ByteString RTNLMessage::Encode() {
197 if (type_ != kMessageTypeLink &&
198 type_ != kMessageTypeAddress &&
199 type_ != kMessageTypeRoute) {
200 return ByteString();
201 }
202
203 RTNLHeader hdr;
204 hdr.hdr.nlmsg_flags = flags_;
205 hdr.hdr.nlmsg_seq = seq_;
206 hdr.hdr.nlmsg_pid = pid_;
207 hdr.hdr.nlmsg_seq = 0;
208
209 if (mode_ == kMessageModeGet) {
210 if (type_ == kMessageTypeLink) {
211 hdr.hdr.nlmsg_type = RTM_GETLINK;
212 } else if (type_ == kMessageTypeAddress) {
213 hdr.hdr.nlmsg_type = RTM_GETADDR;
214 } else if (type_ == kMessageTypeRoute) {
215 hdr.hdr.nlmsg_type = RTM_GETROUTE;
216 }
217 hdr.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(hdr.gen));
218 hdr.gen.rtgen_family = family_;
219 } else {
220 switch (type_) {
221 case kMessageTypeLink:
222 EncodeLink(&hdr);
223 break;
224
225 case kMessageTypeAddress:
226 EncodeAddress(&hdr);
227 break;
228
229 case kMessageTypeRoute:
230 EncodeRoute(&hdr);
231 break;
232
233 default:
234 NOTREACHED();
235 }
236 }
237
238 size_t header_length = hdr.hdr.nlmsg_len;
239 ByteString attributes;
240
241 base::hash_map<uint16, ByteString>::iterator attr;
242 for (attr = attributes_.begin(); attr != attributes_.end(); ++attr) {
243 size_t len = RTA_LENGTH(attr->second.GetLength());
244 hdr.hdr.nlmsg_len = NLMSG_ALIGN(hdr.hdr.nlmsg_len) + RTA_ALIGN(len);
245
246 struct rtattr rt_attr = { len, attr->first };
247 ByteString attr_header(reinterpret_cast<unsigned char *>(&rt_attr),
248 sizeof(rt_attr));
249 attr_header.Resize(RTA_ALIGN(attr_header.GetLength()));
250 attributes.Append(attr_header);
251
252 ByteString attr_data(attr->second);
253 attr_data.Resize(RTA_ALIGN(attr_data.GetLength()));
254 attributes.Append(attr_data);
255 }
256
257 ByteString packet(reinterpret_cast<unsigned char *>(&hdr), header_length);
258 packet.Append(attributes);
259
260 return packet;
261}
262
263void RTNLMessage::EncodeLink(RTNLHeader *hdr) {
264 hdr->hdr.nlmsg_type = (mode_ == kMessageModeAdd) ? RTM_NEWLINK : RTM_DELLINK;
265 hdr->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(hdr->ifi));
266 hdr->ifi.ifi_family = family_;
267 hdr->ifi.ifi_type = link_status_.type;
268 hdr->ifi.ifi_flags = link_status_.flags;
269 hdr->ifi.ifi_change = link_status_.change;
270}
271
272void RTNLMessage::EncodeAddress(RTNLHeader *hdr) {
273 hdr->hdr.nlmsg_type = (mode_ == kMessageModeAdd) ? RTM_NEWADDR : RTM_DELADDR;
274 hdr->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(hdr->ifa));
275 hdr->ifa.ifa_family = family_;
276 hdr->ifa.ifa_prefixlen = address_status_.prefix_len;
277 hdr->ifa.ifa_flags = address_status_.flags;
278 hdr->ifa.ifa_scope = address_status_.scope;
279 hdr->ifa.ifa_index = interface_index_;
280}
281
282void RTNLMessage::EncodeRoute(RTNLHeader *hdr) {
283 hdr->hdr.nlmsg_type =
284 (mode_ == kMessageModeAdd) ? RTM_NEWROUTE : RTM_DELROUTE;
285 hdr->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(hdr->rtm));
286 hdr->rtm.rtm_family = family_;
287 hdr->rtm.rtm_dst_len = route_status_.dst_prefix;
288 hdr->rtm.rtm_src_len = route_status_.src_prefix;
289 hdr->rtm.rtm_table = route_status_.table;
290 hdr->rtm.rtm_protocol = route_status_.protocol;
291 hdr->rtm.rtm_scope = route_status_.scope;
292 hdr->rtm.rtm_type = route_status_.type;
293 hdr->rtm.rtm_flags = route_status_.flags;
294}
295
296} // namespace shill