1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2021 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker
5*bb4ee6a4SAndroid Build Coastguard Worker use std::alloc::Layout;
6*bb4ee6a4SAndroid Build Coastguard Worker use std::mem::MaybeUninit;
7*bb4ee6a4SAndroid Build Coastguard Worker use std::os::unix::io::AsRawFd;
8*bb4ee6a4SAndroid Build Coastguard Worker use std::str;
9*bb4ee6a4SAndroid Build Coastguard Worker
10*bb4ee6a4SAndroid Build Coastguard Worker use libc::EINVAL;
11*bb4ee6a4SAndroid Build Coastguard Worker use log::error;
12*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::AsBytes;
13*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::FromBytes;
14*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::FromZeroes;
15*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::Ref;
16*bb4ee6a4SAndroid Build Coastguard Worker
17*bb4ee6a4SAndroid Build Coastguard Worker use super::errno_result;
18*bb4ee6a4SAndroid Build Coastguard Worker use super::getpid;
19*bb4ee6a4SAndroid Build Coastguard Worker use super::Error;
20*bb4ee6a4SAndroid Build Coastguard Worker use super::RawDescriptor;
21*bb4ee6a4SAndroid Build Coastguard Worker use super::Result;
22*bb4ee6a4SAndroid Build Coastguard Worker use crate::alloc::LayoutAllocation;
23*bb4ee6a4SAndroid Build Coastguard Worker use crate::descriptor::AsRawDescriptor;
24*bb4ee6a4SAndroid Build Coastguard Worker use crate::descriptor::FromRawDescriptor;
25*bb4ee6a4SAndroid Build Coastguard Worker use crate::descriptor::SafeDescriptor;
26*bb4ee6a4SAndroid Build Coastguard Worker
27*bb4ee6a4SAndroid Build Coastguard Worker macro_rules! debug_pr {
28*bb4ee6a4SAndroid Build Coastguard Worker // By default debugs are suppressed, to enabled them replace macro body with:
29*bb4ee6a4SAndroid Build Coastguard Worker // $($args:tt)+) => (println!($($args)*))
30*bb4ee6a4SAndroid Build Coastguard Worker ($($args:tt)+) => {};
31*bb4ee6a4SAndroid Build Coastguard Worker }
32*bb4ee6a4SAndroid Build Coastguard Worker
33*bb4ee6a4SAndroid Build Coastguard Worker const NLMSGHDR_SIZE: usize = std::mem::size_of::<NlMsgHdr>();
34*bb4ee6a4SAndroid Build Coastguard Worker const GENL_HDRLEN: usize = std::mem::size_of::<GenlMsgHdr>();
35*bb4ee6a4SAndroid Build Coastguard Worker const NLA_HDRLEN: usize = std::mem::size_of::<NlAttr>();
36*bb4ee6a4SAndroid Build Coastguard Worker const NLATTR_ALIGN_TO: usize = 4;
37*bb4ee6a4SAndroid Build Coastguard Worker
38*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)]
39*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Copy, Clone, FromZeroes, FromBytes, AsBytes)]
40*bb4ee6a4SAndroid Build Coastguard Worker struct NlMsgHdr {
41*bb4ee6a4SAndroid Build Coastguard Worker pub nlmsg_len: u32,
42*bb4ee6a4SAndroid Build Coastguard Worker pub nlmsg_type: u16,
43*bb4ee6a4SAndroid Build Coastguard Worker pub nlmsg_flags: u16,
44*bb4ee6a4SAndroid Build Coastguard Worker pub nlmsg_seq: u32,
45*bb4ee6a4SAndroid Build Coastguard Worker pub nlmsg_pid: u32,
46*bb4ee6a4SAndroid Build Coastguard Worker }
47*bb4ee6a4SAndroid Build Coastguard Worker
48*bb4ee6a4SAndroid Build Coastguard Worker /// Netlink attribute struct, can be used by netlink consumer
49*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)]
50*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Copy, Clone, FromZeroes, FromBytes, AsBytes)]
51*bb4ee6a4SAndroid Build Coastguard Worker pub struct NlAttr {
52*bb4ee6a4SAndroid Build Coastguard Worker pub len: u16,
53*bb4ee6a4SAndroid Build Coastguard Worker pub _type: u16,
54*bb4ee6a4SAndroid Build Coastguard Worker }
55*bb4ee6a4SAndroid Build Coastguard Worker
56*bb4ee6a4SAndroid Build Coastguard Worker /// Generic netlink header struct, can be used by netlink consumer
57*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)]
58*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Copy, Clone, FromZeroes, FromBytes, AsBytes)]
59*bb4ee6a4SAndroid Build Coastguard Worker pub struct GenlMsgHdr {
60*bb4ee6a4SAndroid Build Coastguard Worker pub cmd: u8,
61*bb4ee6a4SAndroid Build Coastguard Worker pub version: u8,
62*bb4ee6a4SAndroid Build Coastguard Worker pub reserved: u16,
63*bb4ee6a4SAndroid Build Coastguard Worker }
64*bb4ee6a4SAndroid Build Coastguard Worker /// A single netlink message, including its header and data.
65*bb4ee6a4SAndroid Build Coastguard Worker pub struct NetlinkMessage<'a> {
66*bb4ee6a4SAndroid Build Coastguard Worker pub _type: u16,
67*bb4ee6a4SAndroid Build Coastguard Worker pub flags: u16,
68*bb4ee6a4SAndroid Build Coastguard Worker pub seq: u32,
69*bb4ee6a4SAndroid Build Coastguard Worker pub pid: u32,
70*bb4ee6a4SAndroid Build Coastguard Worker pub data: &'a [u8],
71*bb4ee6a4SAndroid Build Coastguard Worker }
72*bb4ee6a4SAndroid Build Coastguard Worker
73*bb4ee6a4SAndroid Build Coastguard Worker pub struct NlAttrWithData<'a> {
74*bb4ee6a4SAndroid Build Coastguard Worker pub len: u16,
75*bb4ee6a4SAndroid Build Coastguard Worker pub _type: u16,
76*bb4ee6a4SAndroid Build Coastguard Worker pub data: &'a [u8],
77*bb4ee6a4SAndroid Build Coastguard Worker }
78*bb4ee6a4SAndroid Build Coastguard Worker
nlattr_align(offset: usize) -> usize79*bb4ee6a4SAndroid Build Coastguard Worker fn nlattr_align(offset: usize) -> usize {
80*bb4ee6a4SAndroid Build Coastguard Worker (offset + NLATTR_ALIGN_TO - 1) & !(NLATTR_ALIGN_TO - 1)
81*bb4ee6a4SAndroid Build Coastguard Worker }
82*bb4ee6a4SAndroid Build Coastguard Worker
83*bb4ee6a4SAndroid Build Coastguard Worker /// Iterator over `struct NlAttr` as received from a netlink socket.
84*bb4ee6a4SAndroid Build Coastguard Worker pub struct NetlinkGenericDataIter<'a> {
85*bb4ee6a4SAndroid Build Coastguard Worker // `data` must be properly aligned for NlAttr.
86*bb4ee6a4SAndroid Build Coastguard Worker data: &'a [u8],
87*bb4ee6a4SAndroid Build Coastguard Worker }
88*bb4ee6a4SAndroid Build Coastguard Worker
89*bb4ee6a4SAndroid Build Coastguard Worker impl<'a> Iterator for NetlinkGenericDataIter<'a> {
90*bb4ee6a4SAndroid Build Coastguard Worker type Item = NlAttrWithData<'a>;
91*bb4ee6a4SAndroid Build Coastguard Worker
next(&mut self) -> Option<Self::Item>92*bb4ee6a4SAndroid Build Coastguard Worker fn next(&mut self) -> Option<Self::Item> {
93*bb4ee6a4SAndroid Build Coastguard Worker if self.data.len() < NLA_HDRLEN {
94*bb4ee6a4SAndroid Build Coastguard Worker return None;
95*bb4ee6a4SAndroid Build Coastguard Worker }
96*bb4ee6a4SAndroid Build Coastguard Worker let nl_hdr = NlAttr::read_from(&self.data[..NLA_HDRLEN])?;
97*bb4ee6a4SAndroid Build Coastguard Worker
98*bb4ee6a4SAndroid Build Coastguard Worker // Make sure NlAtrr fits
99*bb4ee6a4SAndroid Build Coastguard Worker let nl_data_len = nl_hdr.len as usize;
100*bb4ee6a4SAndroid Build Coastguard Worker if nl_data_len < NLA_HDRLEN || nl_data_len > self.data.len() {
101*bb4ee6a4SAndroid Build Coastguard Worker return None;
102*bb4ee6a4SAndroid Build Coastguard Worker }
103*bb4ee6a4SAndroid Build Coastguard Worker
104*bb4ee6a4SAndroid Build Coastguard Worker // Get data related to processed NlAttr
105*bb4ee6a4SAndroid Build Coastguard Worker let data_start = NLA_HDRLEN;
106*bb4ee6a4SAndroid Build Coastguard Worker let data = &self.data[data_start..nl_data_len];
107*bb4ee6a4SAndroid Build Coastguard Worker
108*bb4ee6a4SAndroid Build Coastguard Worker // Get next NlAttr
109*bb4ee6a4SAndroid Build Coastguard Worker let next_hdr = nlattr_align(nl_data_len);
110*bb4ee6a4SAndroid Build Coastguard Worker if next_hdr >= self.data.len() {
111*bb4ee6a4SAndroid Build Coastguard Worker self.data = &[];
112*bb4ee6a4SAndroid Build Coastguard Worker } else {
113*bb4ee6a4SAndroid Build Coastguard Worker self.data = &self.data[next_hdr..];
114*bb4ee6a4SAndroid Build Coastguard Worker }
115*bb4ee6a4SAndroid Build Coastguard Worker
116*bb4ee6a4SAndroid Build Coastguard Worker Some(NlAttrWithData {
117*bb4ee6a4SAndroid Build Coastguard Worker _type: nl_hdr._type,
118*bb4ee6a4SAndroid Build Coastguard Worker len: nl_hdr.len,
119*bb4ee6a4SAndroid Build Coastguard Worker data,
120*bb4ee6a4SAndroid Build Coastguard Worker })
121*bb4ee6a4SAndroid Build Coastguard Worker }
122*bb4ee6a4SAndroid Build Coastguard Worker }
123*bb4ee6a4SAndroid Build Coastguard Worker
124*bb4ee6a4SAndroid Build Coastguard Worker /// Iterator over `struct nlmsghdr` as received from a netlink socket.
125*bb4ee6a4SAndroid Build Coastguard Worker pub struct NetlinkMessageIter<'a> {
126*bb4ee6a4SAndroid Build Coastguard Worker // `data` must be properly aligned for nlmsghdr.
127*bb4ee6a4SAndroid Build Coastguard Worker data: &'a [u8],
128*bb4ee6a4SAndroid Build Coastguard Worker }
129*bb4ee6a4SAndroid Build Coastguard Worker
130*bb4ee6a4SAndroid Build Coastguard Worker impl<'a> Iterator for NetlinkMessageIter<'a> {
131*bb4ee6a4SAndroid Build Coastguard Worker type Item = NetlinkMessage<'a>;
132*bb4ee6a4SAndroid Build Coastguard Worker
next(&mut self) -> Option<Self::Item>133*bb4ee6a4SAndroid Build Coastguard Worker fn next(&mut self) -> Option<Self::Item> {
134*bb4ee6a4SAndroid Build Coastguard Worker if self.data.len() < NLMSGHDR_SIZE {
135*bb4ee6a4SAndroid Build Coastguard Worker return None;
136*bb4ee6a4SAndroid Build Coastguard Worker }
137*bb4ee6a4SAndroid Build Coastguard Worker let hdr = NlMsgHdr::read_from(&self.data[..NLMSGHDR_SIZE])?;
138*bb4ee6a4SAndroid Build Coastguard Worker
139*bb4ee6a4SAndroid Build Coastguard Worker // NLMSG_OK
140*bb4ee6a4SAndroid Build Coastguard Worker let msg_len = hdr.nlmsg_len as usize;
141*bb4ee6a4SAndroid Build Coastguard Worker if msg_len < NLMSGHDR_SIZE || msg_len > self.data.len() {
142*bb4ee6a4SAndroid Build Coastguard Worker return None;
143*bb4ee6a4SAndroid Build Coastguard Worker }
144*bb4ee6a4SAndroid Build Coastguard Worker
145*bb4ee6a4SAndroid Build Coastguard Worker // NLMSG_DATA
146*bb4ee6a4SAndroid Build Coastguard Worker let data_start = NLMSGHDR_SIZE;
147*bb4ee6a4SAndroid Build Coastguard Worker let data = &self.data[data_start..msg_len];
148*bb4ee6a4SAndroid Build Coastguard Worker
149*bb4ee6a4SAndroid Build Coastguard Worker // NLMSG_NEXT
150*bb4ee6a4SAndroid Build Coastguard Worker let align_to = std::mem::align_of::<NlMsgHdr>();
151*bb4ee6a4SAndroid Build Coastguard Worker let next_hdr = (msg_len + align_to - 1) & !(align_to - 1);
152*bb4ee6a4SAndroid Build Coastguard Worker if next_hdr >= self.data.len() {
153*bb4ee6a4SAndroid Build Coastguard Worker self.data = &[];
154*bb4ee6a4SAndroid Build Coastguard Worker } else {
155*bb4ee6a4SAndroid Build Coastguard Worker self.data = &self.data[next_hdr..];
156*bb4ee6a4SAndroid Build Coastguard Worker }
157*bb4ee6a4SAndroid Build Coastguard Worker
158*bb4ee6a4SAndroid Build Coastguard Worker Some(NetlinkMessage {
159*bb4ee6a4SAndroid Build Coastguard Worker _type: hdr.nlmsg_type,
160*bb4ee6a4SAndroid Build Coastguard Worker flags: hdr.nlmsg_flags,
161*bb4ee6a4SAndroid Build Coastguard Worker seq: hdr.nlmsg_seq,
162*bb4ee6a4SAndroid Build Coastguard Worker pid: hdr.nlmsg_pid,
163*bb4ee6a4SAndroid Build Coastguard Worker data,
164*bb4ee6a4SAndroid Build Coastguard Worker })
165*bb4ee6a4SAndroid Build Coastguard Worker }
166*bb4ee6a4SAndroid Build Coastguard Worker }
167*bb4ee6a4SAndroid Build Coastguard Worker
168*bb4ee6a4SAndroid Build Coastguard Worker /// Safe wrapper for `NETLINK_GENERIC` netlink sockets.
169*bb4ee6a4SAndroid Build Coastguard Worker pub struct NetlinkGenericSocket {
170*bb4ee6a4SAndroid Build Coastguard Worker sock: SafeDescriptor,
171*bb4ee6a4SAndroid Build Coastguard Worker }
172*bb4ee6a4SAndroid Build Coastguard Worker
173*bb4ee6a4SAndroid Build Coastguard Worker impl AsRawDescriptor for NetlinkGenericSocket {
as_raw_descriptor(&self) -> RawDescriptor174*bb4ee6a4SAndroid Build Coastguard Worker fn as_raw_descriptor(&self) -> RawDescriptor {
175*bb4ee6a4SAndroid Build Coastguard Worker self.sock.as_raw_descriptor()
176*bb4ee6a4SAndroid Build Coastguard Worker }
177*bb4ee6a4SAndroid Build Coastguard Worker }
178*bb4ee6a4SAndroid Build Coastguard Worker
179*bb4ee6a4SAndroid Build Coastguard Worker impl NetlinkGenericSocket {
180*bb4ee6a4SAndroid Build Coastguard Worker /// Create and bind a new `NETLINK_GENERIC` socket.
new(nl_groups: u32) -> Result<Self>181*bb4ee6a4SAndroid Build Coastguard Worker pub fn new(nl_groups: u32) -> Result<Self> {
182*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
183*bb4ee6a4SAndroid Build Coastguard Worker // Safe because we check the return value and convert the raw fd into a SafeDescriptor.
184*bb4ee6a4SAndroid Build Coastguard Worker let sock = unsafe {
185*bb4ee6a4SAndroid Build Coastguard Worker let fd = libc::socket(
186*bb4ee6a4SAndroid Build Coastguard Worker libc::AF_NETLINK,
187*bb4ee6a4SAndroid Build Coastguard Worker libc::SOCK_RAW | libc::SOCK_CLOEXEC,
188*bb4ee6a4SAndroid Build Coastguard Worker libc::NETLINK_GENERIC,
189*bb4ee6a4SAndroid Build Coastguard Worker );
190*bb4ee6a4SAndroid Build Coastguard Worker if fd < 0 {
191*bb4ee6a4SAndroid Build Coastguard Worker return errno_result();
192*bb4ee6a4SAndroid Build Coastguard Worker }
193*bb4ee6a4SAndroid Build Coastguard Worker
194*bb4ee6a4SAndroid Build Coastguard Worker SafeDescriptor::from_raw_descriptor(fd)
195*bb4ee6a4SAndroid Build Coastguard Worker };
196*bb4ee6a4SAndroid Build Coastguard Worker
197*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
198*bb4ee6a4SAndroid Build Coastguard Worker // This MaybeUninit dance is needed because sockaddr_nl has a private padding field and
199*bb4ee6a4SAndroid Build Coastguard Worker // doesn't implement Default. Safe because all 0s is valid data for sockaddr_nl.
200*bb4ee6a4SAndroid Build Coastguard Worker let mut sa = unsafe { MaybeUninit::<libc::sockaddr_nl>::zeroed().assume_init() };
201*bb4ee6a4SAndroid Build Coastguard Worker sa.nl_family = libc::AF_NETLINK as libc::sa_family_t;
202*bb4ee6a4SAndroid Build Coastguard Worker sa.nl_groups = nl_groups;
203*bb4ee6a4SAndroid Build Coastguard Worker
204*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
205*bb4ee6a4SAndroid Build Coastguard Worker // Safe because we pass a descriptor that we own and valid pointer/size for sockaddr.
206*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
207*bb4ee6a4SAndroid Build Coastguard Worker let res = libc::bind(
208*bb4ee6a4SAndroid Build Coastguard Worker sock.as_raw_fd(),
209*bb4ee6a4SAndroid Build Coastguard Worker &sa as *const libc::sockaddr_nl as *const libc::sockaddr,
210*bb4ee6a4SAndroid Build Coastguard Worker std::mem::size_of_val(&sa) as libc::socklen_t,
211*bb4ee6a4SAndroid Build Coastguard Worker );
212*bb4ee6a4SAndroid Build Coastguard Worker if res < 0 {
213*bb4ee6a4SAndroid Build Coastguard Worker return errno_result();
214*bb4ee6a4SAndroid Build Coastguard Worker }
215*bb4ee6a4SAndroid Build Coastguard Worker }
216*bb4ee6a4SAndroid Build Coastguard Worker
217*bb4ee6a4SAndroid Build Coastguard Worker Ok(NetlinkGenericSocket { sock })
218*bb4ee6a4SAndroid Build Coastguard Worker }
219*bb4ee6a4SAndroid Build Coastguard Worker
220*bb4ee6a4SAndroid Build Coastguard Worker /// Receive messages from the netlink socket.
recv(&self) -> Result<NetlinkGenericRead>221*bb4ee6a4SAndroid Build Coastguard Worker pub fn recv(&self) -> Result<NetlinkGenericRead> {
222*bb4ee6a4SAndroid Build Coastguard Worker let buf_size = 8192; // TODO(dverkamp): make this configurable?
223*bb4ee6a4SAndroid Build Coastguard Worker
224*bb4ee6a4SAndroid Build Coastguard Worker // Create a buffer with sufficient alignment for nlmsghdr.
225*bb4ee6a4SAndroid Build Coastguard Worker let layout = Layout::from_size_align(buf_size, std::mem::align_of::<NlMsgHdr>())
226*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|_| Error::new(EINVAL))?;
227*bb4ee6a4SAndroid Build Coastguard Worker let allocation = LayoutAllocation::uninitialized(layout);
228*bb4ee6a4SAndroid Build Coastguard Worker
229*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
230*bb4ee6a4SAndroid Build Coastguard Worker // Safe because we pass a valid, owned socket fd and a valid pointer/size for the buffer.
231*bb4ee6a4SAndroid Build Coastguard Worker let bytes_read = unsafe {
232*bb4ee6a4SAndroid Build Coastguard Worker let res = libc::recv(self.sock.as_raw_fd(), allocation.as_ptr(), buf_size, 0);
233*bb4ee6a4SAndroid Build Coastguard Worker if res < 0 {
234*bb4ee6a4SAndroid Build Coastguard Worker return errno_result();
235*bb4ee6a4SAndroid Build Coastguard Worker }
236*bb4ee6a4SAndroid Build Coastguard Worker res as usize
237*bb4ee6a4SAndroid Build Coastguard Worker };
238*bb4ee6a4SAndroid Build Coastguard Worker
239*bb4ee6a4SAndroid Build Coastguard Worker Ok(NetlinkGenericRead {
240*bb4ee6a4SAndroid Build Coastguard Worker allocation,
241*bb4ee6a4SAndroid Build Coastguard Worker len: bytes_read,
242*bb4ee6a4SAndroid Build Coastguard Worker })
243*bb4ee6a4SAndroid Build Coastguard Worker }
244*bb4ee6a4SAndroid Build Coastguard Worker
family_name_query(&self, family_name: String) -> Result<NetlinkGenericRead>245*bb4ee6a4SAndroid Build Coastguard Worker pub fn family_name_query(&self, family_name: String) -> Result<NetlinkGenericRead> {
246*bb4ee6a4SAndroid Build Coastguard Worker let buf_size = 1024;
247*bb4ee6a4SAndroid Build Coastguard Worker debug_pr!(
248*bb4ee6a4SAndroid Build Coastguard Worker "preparing query for family name {}, len {}",
249*bb4ee6a4SAndroid Build Coastguard Worker family_name,
250*bb4ee6a4SAndroid Build Coastguard Worker family_name.len()
251*bb4ee6a4SAndroid Build Coastguard Worker );
252*bb4ee6a4SAndroid Build Coastguard Worker
253*bb4ee6a4SAndroid Build Coastguard Worker // Create a buffer with sufficient alignment for nlmsghdr.
254*bb4ee6a4SAndroid Build Coastguard Worker let layout = Layout::from_size_align(buf_size, std::mem::align_of::<NlMsgHdr>())
255*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|_| Error::new(EINVAL))
256*bb4ee6a4SAndroid Build Coastguard Worker .unwrap();
257*bb4ee6a4SAndroid Build Coastguard Worker let mut allocation = LayoutAllocation::zeroed(layout);
258*bb4ee6a4SAndroid Build Coastguard Worker
259*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
260*bb4ee6a4SAndroid Build Coastguard Worker // Safe because the data in allocation was initialized up to `buf_size` and is
261*bb4ee6a4SAndroid Build Coastguard Worker // sufficiently aligned.
262*bb4ee6a4SAndroid Build Coastguard Worker let data = unsafe { allocation.as_mut_slice(buf_size) };
263*bb4ee6a4SAndroid Build Coastguard Worker
264*bb4ee6a4SAndroid Build Coastguard Worker // Prepare the netlink message header
265*bb4ee6a4SAndroid Build Coastguard Worker let hdr = Ref::<_, NlMsgHdr>::new(&mut data[..NLMSGHDR_SIZE])
266*bb4ee6a4SAndroid Build Coastguard Worker .expect("failed to unwrap")
267*bb4ee6a4SAndroid Build Coastguard Worker .into_mut();
268*bb4ee6a4SAndroid Build Coastguard Worker hdr.nlmsg_len = NLMSGHDR_SIZE as u32 + GENL_HDRLEN as u32;
269*bb4ee6a4SAndroid Build Coastguard Worker hdr.nlmsg_len += NLA_HDRLEN as u32 + family_name.len() as u32 + 1;
270*bb4ee6a4SAndroid Build Coastguard Worker hdr.nlmsg_flags = libc::NLM_F_REQUEST as u16;
271*bb4ee6a4SAndroid Build Coastguard Worker hdr.nlmsg_type = libc::GENL_ID_CTRL as u16;
272*bb4ee6a4SAndroid Build Coastguard Worker hdr.nlmsg_pid = getpid() as u32;
273*bb4ee6a4SAndroid Build Coastguard Worker
274*bb4ee6a4SAndroid Build Coastguard Worker // Prepare generic netlink message header
275*bb4ee6a4SAndroid Build Coastguard Worker let genl_hdr_end = NLMSGHDR_SIZE + GENL_HDRLEN;
276*bb4ee6a4SAndroid Build Coastguard Worker let genl_hdr = Ref::<_, GenlMsgHdr>::new(&mut data[NLMSGHDR_SIZE..genl_hdr_end])
277*bb4ee6a4SAndroid Build Coastguard Worker .expect("unable to get GenlMsgHdr from slice")
278*bb4ee6a4SAndroid Build Coastguard Worker .into_mut();
279*bb4ee6a4SAndroid Build Coastguard Worker genl_hdr.cmd = libc::CTRL_CMD_GETFAMILY as u8;
280*bb4ee6a4SAndroid Build Coastguard Worker genl_hdr.version = 0x1;
281*bb4ee6a4SAndroid Build Coastguard Worker
282*bb4ee6a4SAndroid Build Coastguard Worker // Netlink attributes
283*bb4ee6a4SAndroid Build Coastguard Worker let nlattr_start = genl_hdr_end;
284*bb4ee6a4SAndroid Build Coastguard Worker let nlattr_end = nlattr_start + NLA_HDRLEN;
285*bb4ee6a4SAndroid Build Coastguard Worker let nl_attr = Ref::<_, NlAttr>::new(&mut data[nlattr_start..nlattr_end])
286*bb4ee6a4SAndroid Build Coastguard Worker .expect("unable to get NlAttr from slice")
287*bb4ee6a4SAndroid Build Coastguard Worker .into_mut();
288*bb4ee6a4SAndroid Build Coastguard Worker nl_attr._type = libc::CTRL_ATTR_FAMILY_NAME as u16;
289*bb4ee6a4SAndroid Build Coastguard Worker nl_attr.len = family_name.len() as u16 + 1 + NLA_HDRLEN as u16;
290*bb4ee6a4SAndroid Build Coastguard Worker
291*bb4ee6a4SAndroid Build Coastguard Worker // Fill the message payload with the family name
292*bb4ee6a4SAndroid Build Coastguard Worker let payload_start = nlattr_end;
293*bb4ee6a4SAndroid Build Coastguard Worker let payload_end = payload_start + family_name.len();
294*bb4ee6a4SAndroid Build Coastguard Worker data[payload_start..payload_end].copy_from_slice(family_name.as_bytes());
295*bb4ee6a4SAndroid Build Coastguard Worker
296*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
297*bb4ee6a4SAndroid Build Coastguard Worker // Safe because we pass a valid, owned socket fd and a valid pointer/size for the buffer.
298*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
299*bb4ee6a4SAndroid Build Coastguard Worker let res = libc::send(
300*bb4ee6a4SAndroid Build Coastguard Worker self.sock.as_raw_fd(),
301*bb4ee6a4SAndroid Build Coastguard Worker allocation.as_ptr(),
302*bb4ee6a4SAndroid Build Coastguard Worker payload_end + 1,
303*bb4ee6a4SAndroid Build Coastguard Worker 0,
304*bb4ee6a4SAndroid Build Coastguard Worker );
305*bb4ee6a4SAndroid Build Coastguard Worker if res < 0 {
306*bb4ee6a4SAndroid Build Coastguard Worker error!("failed to send get_family_cmd");
307*bb4ee6a4SAndroid Build Coastguard Worker return errno_result();
308*bb4ee6a4SAndroid Build Coastguard Worker }
309*bb4ee6a4SAndroid Build Coastguard Worker };
310*bb4ee6a4SAndroid Build Coastguard Worker
311*bb4ee6a4SAndroid Build Coastguard Worker // Return the answer
312*bb4ee6a4SAndroid Build Coastguard Worker match self.recv() {
313*bb4ee6a4SAndroid Build Coastguard Worker Ok(msg) => Ok(msg),
314*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => {
315*bb4ee6a4SAndroid Build Coastguard Worker error!("recv get_family returned with error {}", e);
316*bb4ee6a4SAndroid Build Coastguard Worker Err(e)
317*bb4ee6a4SAndroid Build Coastguard Worker }
318*bb4ee6a4SAndroid Build Coastguard Worker }
319*bb4ee6a4SAndroid Build Coastguard Worker }
320*bb4ee6a4SAndroid Build Coastguard Worker }
321*bb4ee6a4SAndroid Build Coastguard Worker
parse_ctrl_group_name_and_id( nested_nl_attr_data: NetlinkGenericDataIter, group_name: &str, ) -> Option<u32>322*bb4ee6a4SAndroid Build Coastguard Worker fn parse_ctrl_group_name_and_id(
323*bb4ee6a4SAndroid Build Coastguard Worker nested_nl_attr_data: NetlinkGenericDataIter,
324*bb4ee6a4SAndroid Build Coastguard Worker group_name: &str,
325*bb4ee6a4SAndroid Build Coastguard Worker ) -> Option<u32> {
326*bb4ee6a4SAndroid Build Coastguard Worker let mut mcast_group_id: Option<u32> = None;
327*bb4ee6a4SAndroid Build Coastguard Worker
328*bb4ee6a4SAndroid Build Coastguard Worker for nested_nl_attr in nested_nl_attr_data {
329*bb4ee6a4SAndroid Build Coastguard Worker debug_pr!(
330*bb4ee6a4SAndroid Build Coastguard Worker "\t\tmcast_grp: nlattr type {}, len {}",
331*bb4ee6a4SAndroid Build Coastguard Worker nested_nl_attr._type,
332*bb4ee6a4SAndroid Build Coastguard Worker nested_nl_attr.len
333*bb4ee6a4SAndroid Build Coastguard Worker );
334*bb4ee6a4SAndroid Build Coastguard Worker
335*bb4ee6a4SAndroid Build Coastguard Worker if nested_nl_attr._type == libc::CTRL_ATTR_MCAST_GRP_ID as u16 {
336*bb4ee6a4SAndroid Build Coastguard Worker mcast_group_id = Some(u32::from_ne_bytes(nested_nl_attr.data.try_into().unwrap()));
337*bb4ee6a4SAndroid Build Coastguard Worker debug_pr!("\t\t mcast group_id {}", mcast_group_id?);
338*bb4ee6a4SAndroid Build Coastguard Worker }
339*bb4ee6a4SAndroid Build Coastguard Worker
340*bb4ee6a4SAndroid Build Coastguard Worker if nested_nl_attr._type == libc::CTRL_ATTR_MCAST_GRP_NAME as u16 {
341*bb4ee6a4SAndroid Build Coastguard Worker debug_pr!(
342*bb4ee6a4SAndroid Build Coastguard Worker "\t\t mcast group name {}",
343*bb4ee6a4SAndroid Build Coastguard Worker strip_padding(&nested_nl_attr.data)
344*bb4ee6a4SAndroid Build Coastguard Worker );
345*bb4ee6a4SAndroid Build Coastguard Worker
346*bb4ee6a4SAndroid Build Coastguard Worker // If the group name match and the group_id was set in previous iteration, return,
347*bb4ee6a4SAndroid Build Coastguard Worker // valid for group_name, group_id
348*bb4ee6a4SAndroid Build Coastguard Worker if group_name.eq(strip_padding(nested_nl_attr.data)) && mcast_group_id.is_some() {
349*bb4ee6a4SAndroid Build Coastguard Worker debug_pr!(
350*bb4ee6a4SAndroid Build Coastguard Worker "\t\t Got what we were looking for group_id = {} for {}",
351*bb4ee6a4SAndroid Build Coastguard Worker mcast_group_id?,
352*bb4ee6a4SAndroid Build Coastguard Worker group_name
353*bb4ee6a4SAndroid Build Coastguard Worker );
354*bb4ee6a4SAndroid Build Coastguard Worker
355*bb4ee6a4SAndroid Build Coastguard Worker return mcast_group_id;
356*bb4ee6a4SAndroid Build Coastguard Worker }
357*bb4ee6a4SAndroid Build Coastguard Worker }
358*bb4ee6a4SAndroid Build Coastguard Worker }
359*bb4ee6a4SAndroid Build Coastguard Worker
360*bb4ee6a4SAndroid Build Coastguard Worker None
361*bb4ee6a4SAndroid Build Coastguard Worker }
362*bb4ee6a4SAndroid Build Coastguard Worker
363*bb4ee6a4SAndroid Build Coastguard Worker /// Parse CTRL_ATTR_MCAST_GROUPS data in order to get multicast group id
364*bb4ee6a4SAndroid Build Coastguard Worker ///
365*bb4ee6a4SAndroid Build Coastguard Worker /// On success, returns group_id for a given `group_name`
366*bb4ee6a4SAndroid Build Coastguard Worker ///
367*bb4ee6a4SAndroid Build Coastguard Worker /// # Arguments
368*bb4ee6a4SAndroid Build Coastguard Worker ///
369*bb4ee6a4SAndroid Build Coastguard Worker /// * `nl_attr_area`
370*bb4ee6a4SAndroid Build Coastguard Worker ///
371*bb4ee6a4SAndroid Build Coastguard Worker /// Nested attributes area (CTRL_ATTR_MCAST_GROUPS data), where nl_attr's corresponding to
372*bb4ee6a4SAndroid Build Coastguard Worker /// specific groups are embed
373*bb4ee6a4SAndroid Build Coastguard Worker ///
374*bb4ee6a4SAndroid Build Coastguard Worker /// * `group_name`
375*bb4ee6a4SAndroid Build Coastguard Worker ///
376*bb4ee6a4SAndroid Build Coastguard Worker /// String with group_name for which we are looking group_id
377*bb4ee6a4SAndroid Build Coastguard Worker ///
378*bb4ee6a4SAndroid Build Coastguard Worker /// the CTRL_ATTR_MCAST_GROUPS data has nested attributes. Each of nested attribute is per
379*bb4ee6a4SAndroid Build Coastguard Worker /// multicast group attributes, which have another nested attributes: CTRL_ATTR_MCAST_GRP_NAME and
380*bb4ee6a4SAndroid Build Coastguard Worker /// CTRL_ATTR_MCAST_GRP_ID. Need to parse all of them to get mcast group id for a given group_name..
381*bb4ee6a4SAndroid Build Coastguard Worker ///
382*bb4ee6a4SAndroid Build Coastguard Worker /// Illustrated layout:
383*bb4ee6a4SAndroid Build Coastguard Worker /// CTRL_ATTR_MCAST_GROUPS:
384*bb4ee6a4SAndroid Build Coastguard Worker /// GR1 (nl_attr._type = 1):
385*bb4ee6a4SAndroid Build Coastguard Worker /// CTRL_ATTR_MCAST_GRP_ID,
386*bb4ee6a4SAndroid Build Coastguard Worker /// CTRL_ATTR_MCAST_GRP_NAME,
387*bb4ee6a4SAndroid Build Coastguard Worker /// GR2 (nl_attr._type = 2):
388*bb4ee6a4SAndroid Build Coastguard Worker /// CTRL_ATTR_MCAST_GRP_ID,
389*bb4ee6a4SAndroid Build Coastguard Worker /// CTRL_ATTR_MCAST_GRP_NAME,
390*bb4ee6a4SAndroid Build Coastguard Worker /// ..
391*bb4ee6a4SAndroid Build Coastguard Worker ///
392*bb4ee6a4SAndroid Build Coastguard Worker /// Unfortunately kernel implementation uses `nla_nest_start_noflag` for that
393*bb4ee6a4SAndroid Build Coastguard Worker /// purpose, which means that it never marked their nest attributes with NLA_F_NESTED flag.
394*bb4ee6a4SAndroid Build Coastguard Worker /// Therefore all this nesting stages need to be deduced based on specific nl_attr type.
parse_ctrl_mcast_group_id( nl_attr_area: NetlinkGenericDataIter, group_name: &str, ) -> Option<u32>395*bb4ee6a4SAndroid Build Coastguard Worker fn parse_ctrl_mcast_group_id(
396*bb4ee6a4SAndroid Build Coastguard Worker nl_attr_area: NetlinkGenericDataIter,
397*bb4ee6a4SAndroid Build Coastguard Worker group_name: &str,
398*bb4ee6a4SAndroid Build Coastguard Worker ) -> Option<u32> {
399*bb4ee6a4SAndroid Build Coastguard Worker // There may be multiple nested multicast groups, go through all of them.
400*bb4ee6a4SAndroid Build Coastguard Worker // Each of nested group, has other nested nlattr:
401*bb4ee6a4SAndroid Build Coastguard Worker // CTRL_ATTR_MCAST_GRP_ID
402*bb4ee6a4SAndroid Build Coastguard Worker // CTRL_ATTR_MCAST_GRP_NAME
403*bb4ee6a4SAndroid Build Coastguard Worker //
404*bb4ee6a4SAndroid Build Coastguard Worker // which are further proceed by parse_ctrl_group_name_and_id
405*bb4ee6a4SAndroid Build Coastguard Worker for nested_gr_nl_attr in nl_attr_area {
406*bb4ee6a4SAndroid Build Coastguard Worker debug_pr!(
407*bb4ee6a4SAndroid Build Coastguard Worker "\tmcast_groups: nlattr type(gr_nr) {}, len {}",
408*bb4ee6a4SAndroid Build Coastguard Worker nested_gr_nl_attr._type,
409*bb4ee6a4SAndroid Build Coastguard Worker nested_gr_nl_attr.len
410*bb4ee6a4SAndroid Build Coastguard Worker );
411*bb4ee6a4SAndroid Build Coastguard Worker
412*bb4ee6a4SAndroid Build Coastguard Worker let netlink_nested_attr = NetlinkGenericDataIter {
413*bb4ee6a4SAndroid Build Coastguard Worker data: nested_gr_nl_attr.data,
414*bb4ee6a4SAndroid Build Coastguard Worker };
415*bb4ee6a4SAndroid Build Coastguard Worker
416*bb4ee6a4SAndroid Build Coastguard Worker if let Some(mcast_group_id) = parse_ctrl_group_name_and_id(netlink_nested_attr, group_name)
417*bb4ee6a4SAndroid Build Coastguard Worker {
418*bb4ee6a4SAndroid Build Coastguard Worker return Some(mcast_group_id);
419*bb4ee6a4SAndroid Build Coastguard Worker }
420*bb4ee6a4SAndroid Build Coastguard Worker }
421*bb4ee6a4SAndroid Build Coastguard Worker
422*bb4ee6a4SAndroid Build Coastguard Worker None
423*bb4ee6a4SAndroid Build Coastguard Worker }
424*bb4ee6a4SAndroid Build Coastguard Worker
425*bb4ee6a4SAndroid Build Coastguard Worker // Like `CStr::from_bytes_with_nul` but strips any bytes starting from first '\0'-byte and
426*bb4ee6a4SAndroid Build Coastguard Worker // returns &str. Panics if `b` doesn't contain any '\0' bytes.
strip_padding(b: &[u8]) -> &str427*bb4ee6a4SAndroid Build Coastguard Worker fn strip_padding(b: &[u8]) -> &str {
428*bb4ee6a4SAndroid Build Coastguard Worker // It would be nice if we could use memchr here but that's locked behind an unstable gate.
429*bb4ee6a4SAndroid Build Coastguard Worker let pos = b
430*bb4ee6a4SAndroid Build Coastguard Worker .iter()
431*bb4ee6a4SAndroid Build Coastguard Worker .position(|&c| c == 0)
432*bb4ee6a4SAndroid Build Coastguard Worker .expect("`b` doesn't contain any nul bytes");
433*bb4ee6a4SAndroid Build Coastguard Worker
434*bb4ee6a4SAndroid Build Coastguard Worker str::from_utf8(&b[..pos]).unwrap()
435*bb4ee6a4SAndroid Build Coastguard Worker }
436*bb4ee6a4SAndroid Build Coastguard Worker
437*bb4ee6a4SAndroid Build Coastguard Worker pub struct NetlinkGenericRead {
438*bb4ee6a4SAndroid Build Coastguard Worker allocation: LayoutAllocation,
439*bb4ee6a4SAndroid Build Coastguard Worker len: usize,
440*bb4ee6a4SAndroid Build Coastguard Worker }
441*bb4ee6a4SAndroid Build Coastguard Worker
442*bb4ee6a4SAndroid Build Coastguard Worker impl NetlinkGenericRead {
iter(&self) -> NetlinkMessageIter443*bb4ee6a4SAndroid Build Coastguard Worker pub fn iter(&self) -> NetlinkMessageIter {
444*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
445*bb4ee6a4SAndroid Build Coastguard Worker // Safe because the data in allocation was initialized up to `self.len` by `recv()` and is
446*bb4ee6a4SAndroid Build Coastguard Worker // sufficiently aligned.
447*bb4ee6a4SAndroid Build Coastguard Worker let data = unsafe { &self.allocation.as_slice(self.len) };
448*bb4ee6a4SAndroid Build Coastguard Worker NetlinkMessageIter { data }
449*bb4ee6a4SAndroid Build Coastguard Worker }
450*bb4ee6a4SAndroid Build Coastguard Worker
451*bb4ee6a4SAndroid Build Coastguard Worker /// Parse NetlinkGeneric response in order to get multicast group id
452*bb4ee6a4SAndroid Build Coastguard Worker ///
453*bb4ee6a4SAndroid Build Coastguard Worker /// On success, returns group_id for a given `group_name`
454*bb4ee6a4SAndroid Build Coastguard Worker ///
455*bb4ee6a4SAndroid Build Coastguard Worker /// # Arguments
456*bb4ee6a4SAndroid Build Coastguard Worker ///
457*bb4ee6a4SAndroid Build Coastguard Worker /// * `group_name` - String with group_name for which we are looking group_id
458*bb4ee6a4SAndroid Build Coastguard Worker ///
459*bb4ee6a4SAndroid Build Coastguard Worker /// Response from family_name_query (CTRL_CMD_GETFAMILY) is a netlink message with multiple
460*bb4ee6a4SAndroid Build Coastguard Worker /// attributes encapsulated (some of them are nested). An example response layout is
461*bb4ee6a4SAndroid Build Coastguard Worker /// illustrated below:
462*bb4ee6a4SAndroid Build Coastguard Worker ///
463*bb4ee6a4SAndroid Build Coastguard Worker /// {
464*bb4ee6a4SAndroid Build Coastguard Worker /// CTRL_ATTR_FAMILY_NAME
465*bb4ee6a4SAndroid Build Coastguard Worker /// CTRL_ATTR_FAMILY_ID
466*bb4ee6a4SAndroid Build Coastguard Worker /// CTRL_ATTR_VERSION
467*bb4ee6a4SAndroid Build Coastguard Worker /// ...
468*bb4ee6a4SAndroid Build Coastguard Worker /// CTRL_ATTR_MCAST_GROUPS {
469*bb4ee6a4SAndroid Build Coastguard Worker /// GR1 (nl_attr._type = 1) {
470*bb4ee6a4SAndroid Build Coastguard Worker /// CTRL_ATTR_MCAST_GRP_ID *we need parse this attr to obtain group id used for
471*bb4ee6a4SAndroid Build Coastguard Worker /// the group mask
472*bb4ee6a4SAndroid Build Coastguard Worker /// CTRL_ATTR_MCAST_GRP_NAME *group_name that we need to match with
473*bb4ee6a4SAndroid Build Coastguard Worker /// }
474*bb4ee6a4SAndroid Build Coastguard Worker /// GR2 (nl_attr._type = 2) {
475*bb4ee6a4SAndroid Build Coastguard Worker /// CTRL_ATTR_MCAST_GRP_ID
476*bb4ee6a4SAndroid Build Coastguard Worker /// CTRL_ATTR_MCAST_GRP_NAME
477*bb4ee6a4SAndroid Build Coastguard Worker /// }
478*bb4ee6a4SAndroid Build Coastguard Worker /// ...
479*bb4ee6a4SAndroid Build Coastguard Worker /// }
480*bb4ee6a4SAndroid Build Coastguard Worker /// }
get_multicast_group_id(&self, group_name: String) -> Option<u32>481*bb4ee6a4SAndroid Build Coastguard Worker pub fn get_multicast_group_id(&self, group_name: String) -> Option<u32> {
482*bb4ee6a4SAndroid Build Coastguard Worker for netlink_msg in self.iter() {
483*bb4ee6a4SAndroid Build Coastguard Worker debug_pr!(
484*bb4ee6a4SAndroid Build Coastguard Worker "received type: {}, flags {}, pid {}, data {:?}",
485*bb4ee6a4SAndroid Build Coastguard Worker netlink_msg._type,
486*bb4ee6a4SAndroid Build Coastguard Worker netlink_msg.flags,
487*bb4ee6a4SAndroid Build Coastguard Worker netlink_msg.pid,
488*bb4ee6a4SAndroid Build Coastguard Worker netlink_msg.data
489*bb4ee6a4SAndroid Build Coastguard Worker );
490*bb4ee6a4SAndroid Build Coastguard Worker
491*bb4ee6a4SAndroid Build Coastguard Worker if netlink_msg._type != libc::GENL_ID_CTRL as u16 {
492*bb4ee6a4SAndroid Build Coastguard Worker error!("Received not a generic netlink controller msg");
493*bb4ee6a4SAndroid Build Coastguard Worker return None;
494*bb4ee6a4SAndroid Build Coastguard Worker }
495*bb4ee6a4SAndroid Build Coastguard Worker
496*bb4ee6a4SAndroid Build Coastguard Worker let netlink_data = NetlinkGenericDataIter {
497*bb4ee6a4SAndroid Build Coastguard Worker data: &netlink_msg.data[GENL_HDRLEN..],
498*bb4ee6a4SAndroid Build Coastguard Worker };
499*bb4ee6a4SAndroid Build Coastguard Worker for nl_attr in netlink_data {
500*bb4ee6a4SAndroid Build Coastguard Worker debug_pr!("nl_attr type {}, len {}", nl_attr._type, nl_attr.len);
501*bb4ee6a4SAndroid Build Coastguard Worker
502*bb4ee6a4SAndroid Build Coastguard Worker if nl_attr._type == libc::CTRL_ATTR_MCAST_GROUPS as u16 {
503*bb4ee6a4SAndroid Build Coastguard Worker let netlink_nested_attr = NetlinkGenericDataIter { data: nl_attr.data };
504*bb4ee6a4SAndroid Build Coastguard Worker
505*bb4ee6a4SAndroid Build Coastguard Worker if let Some(mcast_group_id) =
506*bb4ee6a4SAndroid Build Coastguard Worker parse_ctrl_mcast_group_id(netlink_nested_attr, &group_name)
507*bb4ee6a4SAndroid Build Coastguard Worker {
508*bb4ee6a4SAndroid Build Coastguard Worker return Some(mcast_group_id);
509*bb4ee6a4SAndroid Build Coastguard Worker }
510*bb4ee6a4SAndroid Build Coastguard Worker }
511*bb4ee6a4SAndroid Build Coastguard Worker }
512*bb4ee6a4SAndroid Build Coastguard Worker }
513*bb4ee6a4SAndroid Build Coastguard Worker None
514*bb4ee6a4SAndroid Build Coastguard Worker }
515*bb4ee6a4SAndroid Build Coastguard Worker }
516