1use 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#[derive(Clone)]
56pub struct Message {
57 pub family: u16,
59 pub command: u8,
61 pub version: u8,
63 pub flags: MessageFlags,
65 pub attributes: Vec<Attribute>,
67}
68
69impl Message {
70 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 pub fn unpack(data: &[u8]) -> Result<(usize, Message)> {
87 let command = data[0];
88 let version = data[1];
89 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 pub fn family(&self) -> u16 {
105 self.family.clone().into()
106 }
107
108 pub fn set_flags(&mut self, flags: MessageFlags) {
110 self.flags = flags;
111 }
112
113 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#[derive(Clone)]
153pub struct MulticastGroup {
154 pub id: u32,
156 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#[derive(Clone)]
196pub struct Family {
197 pub id: u16,
199 pub name: String,
201 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 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 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 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}