netlink_rust/
generic.rs

1//! Netlink generic message
2
3use std::fmt;
4
5use std::convert::{From, Into};
6
7use crate::errors::{NetlinkError, NetlinkErrorKind, Result};
8
9use crate::core;
10use crate::core::{Attribute, ConvertFrom, MessageFlags, MessageMode, NativePack, SendMessage};
11
12extended_enum!(FamilyId, u16,
13    Control => 16,
14    VirtualFileSystemDiskQuota => 17,
15    Raid => 18,
16);
17
18extended_enum_default!(Command, u8,
19    Unspecified => 0,
20    NewFamily => 1,
21    DelFamily => 2,
22    GetFamily => 3,
23    NewOps => 4,
24    DelOps => 5,
25    GetOps => 6,
26    NewMulticastGroup => 7,
27    DelMulticastGroup => 8,
28    GetMulticastGroup => 9,
29);
30
31extended_enum_default!(AttributeId, u16,
32    Unspecified => 0,
33    FamilyId => 1,
34    FamilyName => 2,
35    Version => 3,
36    HeaderSize => 4,
37    MaximumAttributes => 5,
38    Operations => 6,
39    MulticastGroups => 7,
40);
41
42extended_enum_default!(OperationAttributeId, u16,
43    Unspecified => 0,
44    Id => 1,
45    Flags => 2,
46);
47
48extended_enum_default!(MulticastAttributeId, u16,
49    Unspecified => 0,
50    Name => 1,
51    Id => 2,
52);
53
54/// Netlink generic message
55#[derive(Clone)]
56pub struct Message {
57    /// Family identifier, Message to or from this subsystem
58    pub family: u16,
59    /// Command to send or receive
60    pub command: u8,
61    /// Message version
62    pub version: u8,
63    /// Message flags
64    pub flags: MessageFlags,
65    /// Message attributes
66    pub attributes: Vec<Attribute>,
67}
68
69impl Message {
70    /// Create a new message
71    pub fn new<F: Into<u16>, C: Into<u8>, M: Into<MessageFlags>>(
72        family: F,
73        command: C,
74        mode: M,
75    ) -> Message {
76        return Message {
77            family: family.into(),
78            command: command.into(),
79            version: 1u8,
80            flags: mode.into(),
81            attributes: vec![],
82        };
83    }
84
85    /// unpack message from slice
86    pub fn unpack(data: &[u8]) -> Result<(usize, Message)> {
87        let command = data[0];
88        let version = data[1];
89        // skip reserved u16
90        let (consumed, attributes) = core::Attribute::unpack_all(&data[4..]);
91        Ok((
92            consumed + 4usize,
93            Message {
94                family: 0xffff,
95                command: command,
96                version: version,
97                flags: MessageFlags::from_bits_truncate(0),
98                attributes: attributes,
99            },
100        ))
101    }
102
103    /// Get the message family as u16
104    pub fn family(&self) -> u16 {
105        self.family.clone().into()
106    }
107
108    /// Set message flags
109    pub fn set_flags(&mut self, flags: MessageFlags) {
110        self.flags = flags;
111    }
112
113    /// Append a attribute to the message
114    pub fn append_attribute(&mut self, attr: Attribute) {
115        self.attributes.push(attr);
116    }
117}
118
119impl SendMessage for Message {
120    fn pack(&self, data: &mut [u8]) -> Result<usize> {
121        let slice = self.command.pack(data)?;
122        let slice = self.version.pack(slice)?;
123        let slice = 0u16.pack(slice)?;
124        let size = core::pack_vec(slice, &self.attributes)?;
125        Ok(size + 4)
126    }
127    fn message_type(&self) -> u16 {
128        self.family
129    }
130    fn query_flags(&self) -> MessageFlags {
131        self.flags
132    }
133}
134
135impl fmt::Display for Message {
136    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
137        write!(
138            f,
139            "Family: {} Command: {} Version: {} Flags: {:x} Attribute Count: {}",
140            self.family,
141            self.command,
142            self.version,
143            self.flags.bits(),
144            self.attributes.len()
145        )
146    }
147}
148
149/// Netlink generic Multi-cast group
150///
151/// Maps a identifier with a name.
152#[derive(Clone)]
153pub struct MulticastGroup {
154    /// Multi-cast group identifier
155    pub id: u32,
156    /// Multi-cast group name
157    pub name: String,
158}
159
160impl MulticastGroup {
161    fn from_bytes(bytes: &[u8]) -> Result<MulticastGroup> {
162        let (_, attributes) = core::Attribute::unpack_all(bytes);
163        let mut group_name = String::new();
164        let mut group_id = None;
165        for attribute in attributes {
166            match MulticastAttributeId::from(attribute.identifier) {
167                MulticastAttributeId::Unspecified => {}
168                MulticastAttributeId::Id => {
169                    group_id = attribute.as_u32().ok();
170                }
171                MulticastAttributeId::Name => {
172                    group_name = attribute.as_string()?;
173                }
174            }
175        }
176        if let Some(id) = group_id {
177            return Ok(MulticastGroup {
178                id: id,
179                name: group_name,
180            });
181        }
182        Err(NetlinkError::new(NetlinkErrorKind::InvalidValue).into())
183    }
184}
185
186impl fmt::Display for MulticastGroup {
187    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
188        write!(f, "Multicast Group: {} Name: {}", self.id, self.name)
189    }
190}
191
192/// Netlink generic family
193///
194/// Contains identifier, name and multi-cast groups for a Netlink family.
195#[derive(Clone)]
196pub struct Family {
197    /// Family identifier
198    pub id: u16,
199    /// Family name
200    pub name: String,
201    /// Family multi-cast groups
202    pub multicast_groups: Vec<MulticastGroup>,
203}
204
205impl Family {
206    fn from_message(message: Message) -> Result<Family> {
207        let mut family_name = String::new();
208        let mut family_id = 0u16;
209        let mut groups = vec![];
210        for attr in message.attributes {
211            match AttributeId::from(attr.identifier) {
212                AttributeId::Unspecified => {}
213                AttributeId::FamilyName => {
214                    family_name = attr.as_string()?;
215                }
216                AttributeId::FamilyId => {
217                    family_id = attr.as_u16()?;
218                }
219                AttributeId::MulticastGroups => {
220                    let (_, mcs_attributes) = core::Attribute::unpack_all(&attr.as_bytes());
221                    for mcs_attr in mcs_attributes {
222                        groups.push(MulticastGroup::from_bytes(&mcs_attr.as_bytes())?);
223                    }
224                }
225                _ => {}
226            }
227        }
228        if family_id > 0 {
229            return Ok(Family {
230                id: family_id,
231                name: family_name,
232                multicast_groups: groups,
233            });
234        }
235        Err(NetlinkError::new(NetlinkErrorKind::NotFound).into())
236    }
237
238    /// Request family with the provided name
239    pub fn from_name(socket: &mut core::Socket, name: &str) -> Result<Family> {
240        {
241            let mut tx_msg = Message::new(
242                FamilyId::Control,
243                Command::GetFamily,
244                MessageMode::Acknowledge,
245            );
246            tx_msg.attributes.push(Attribute::new_string_with_nul(
247                AttributeId::FamilyName,
248                name,
249            ));
250            socket.send_message(&tx_msg)?;
251        }
252        loop {
253            let messages = socket.receive_messages()?;
254            if messages.is_empty() {
255                break;
256            }
257            for m in messages {
258                if FamilyId::convert_from(m.header.identifier) == Some(FamilyId::Control) {
259                    let (_, msg) = Message::unpack(&m.data)?;
260                    let family = Family::from_message(msg)?;
261                    if family.name == name {
262                        return Ok(family);
263                    }
264                }
265            }
266        }
267        Err(NetlinkError::new(NetlinkErrorKind::NotFound).into())
268    }
269
270    /// Request family with the provided identifier
271    pub fn from_id<ID: Into<u16>>(socket: &mut core::Socket, id: ID) -> Result<Family> {
272        let id = id.into().clone();
273        {
274            let mut tx_msg = Message::new(
275                FamilyId::Control,
276                Command::GetFamily,
277                MessageMode::Acknowledge,
278            );
279            tx_msg
280                .attributes
281                .push(Attribute::new(AttributeId::FamilyId, id));
282            socket.send_message(&tx_msg)?;
283        }
284        loop {
285            let messages = socket.receive_messages()?;
286            if messages.is_empty() {
287                break;
288            }
289            for m in messages {
290                if FamilyId::convert_from(m.header.identifier) == Some(FamilyId::Control) {
291                    let (_, msg) = Message::unpack(&m.data)?;
292                    let family = Family::from_message(msg)?;
293                    if family.id == id {
294                        return Ok(family);
295                    }
296                }
297            }
298        }
299        Err(NetlinkError::new(NetlinkErrorKind::NotFound).into())
300    }
301
302    /// Request all famelies
303    pub fn all(socket: &mut core::Socket) -> Result<Vec<Family>> {
304        {
305            let tx_msg = Message::new(FamilyId::Control, Command::GetFamily, MessageMode::Dump);
306            socket.send_message(&tx_msg)?;
307        }
308        let messages = socket.receive_messages()?;
309        let mut families = vec![];
310        for m in messages {
311            if FamilyId::from(m.header.identifier) == FamilyId::Control {
312                let (_, msg) = Message::unpack(&m.data)?;
313                families.push(Family::from_message(msg)?);
314            }
315        }
316        return Ok(families);
317    }
318}
319
320impl fmt::Display for Family {
321    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
322        write!(f, "Generic Family: {} Name: {}", self.id, self.name)
323    }
324}
325
326#[cfg(test)]
327mod tests {
328    use super::*;
329    use libc;
330
331    #[test]
332    fn check_family_ids() {
333        assert_eq!(u16::from(FamilyId::Control), libc::GENL_ID_CTRL as u16);
334        assert_eq!(
335            u16::from(FamilyId::VirtualFileSystemDiskQuota),
336            libc::GENL_ID_VFS_DQUOT as u16
337        );
338        assert_eq!(u16::from(FamilyId::Raid), libc::GENL_ID_PMCRAID as u16);
339    }
340
341    #[test]
342    fn check_commands() {
343        assert_eq!(u8::from(Command::Unspecified), libc::CTRL_CMD_UNSPEC as u8);
344        assert_eq!(u8::from(Command::NewFamily), libc::CTRL_CMD_NEWFAMILY as u8);
345        assert_eq!(u8::from(Command::DelFamily), libc::CTRL_CMD_DELFAMILY as u8);
346        assert_eq!(u8::from(Command::GetFamily), libc::CTRL_CMD_GETFAMILY as u8);
347        assert_eq!(u8::from(Command::NewOps), libc::CTRL_CMD_NEWOPS as u8);
348        assert_eq!(u8::from(Command::DelOps), libc::CTRL_CMD_DELOPS as u8);
349        assert_eq!(u8::from(Command::GetOps), libc::CTRL_CMD_GETOPS as u8);
350        assert_eq!(
351            u8::from(Command::NewMulticastGroup),
352            libc::CTRL_CMD_NEWMCAST_GRP as u8
353        );
354        assert_eq!(
355            u8::from(Command::DelMulticastGroup),
356            libc::CTRL_CMD_DELMCAST_GRP as u8
357        );
358        assert_eq!(
359            u8::from(Command::GetMulticastGroup),
360            libc::CTRL_CMD_GETMCAST_GRP as u8
361        );
362    }
363
364    #[test]
365    fn check_attributes() {
366        assert_eq!(
367            u16::from(AttributeId::Unspecified),
368            libc::CTRL_ATTR_UNSPEC as u16
369        );
370        assert_eq!(
371            u16::from(AttributeId::FamilyId),
372            libc::CTRL_ATTR_FAMILY_ID as u16
373        );
374        assert_eq!(
375            u16::from(AttributeId::FamilyName),
376            libc::CTRL_ATTR_FAMILY_NAME as u16
377        );
378        assert_eq!(
379            u16::from(AttributeId::Version),
380            libc::CTRL_ATTR_VERSION as u16
381        );
382        assert_eq!(
383            u16::from(AttributeId::HeaderSize),
384            libc::CTRL_ATTR_HDRSIZE as u16
385        );
386        assert_eq!(
387            u16::from(AttributeId::MaximumAttributes),
388            libc::CTRL_ATTR_MAXATTR as u16
389        );
390        assert_eq!(
391            u16::from(AttributeId::Operations),
392            libc::CTRL_ATTR_OPS as u16
393        );
394        assert_eq!(
395            u16::from(AttributeId::MulticastGroups),
396            libc::CTRL_ATTR_MCAST_GROUPS as u16
397        );
398    }
399
400    #[test]
401    fn check_operation_attributes() {
402        assert_eq!(
403            u16::from(OperationAttributeId::Unspecified),
404            libc::CTRL_ATTR_OP_UNSPEC as u16
405        );
406        assert_eq!(
407            u16::from(OperationAttributeId::Id),
408            libc::CTRL_ATTR_OP_ID as u16
409        );
410        assert_eq!(
411            u16::from(OperationAttributeId::Flags),
412            libc::CTRL_ATTR_OP_FLAGS as u16
413        );
414    }
415
416    #[test]
417    fn check_multicast_attributes() {
418        assert_eq!(
419            u16::from(MulticastAttributeId::Unspecified),
420            libc::CTRL_ATTR_MCAST_GRP_UNSPEC as u16
421        );
422        assert_eq!(
423            u16::from(MulticastAttributeId::Name),
424            libc::CTRL_ATTR_MCAST_GRP_NAME as u16
425        );
426        assert_eq!(
427            u16::from(MulticastAttributeId::Id),
428            libc::CTRL_ATTR_MCAST_GRP_ID as u16
429        );
430    }
431}