netlink_packet_generic/
message.rs

1// SPDX-License-Identifier: MIT
2
3//! Message definition and method implementations
4
5use crate::buffer::GenlBuffer;
6use crate::header::GenlHeader;
7use crate::traits::*;
8use netlink_packet_core::{
9    NetlinkDeserializable, NetlinkHeader, NetlinkPayload, NetlinkSerializable,
10};
11use netlink_packet_utils::{DecodeError, Emitable, ParseableParametrized};
12use std::fmt::Debug;
13
14#[cfg(doc)]
15use netlink_packet_core::NetlinkMessage;
16
17/// Represent the generic netlink messages
18///
19/// This type can wrap data types `F` which represents a generic family payload.
20/// The message can be serialize/deserialize if the type `F` implements
21/// [`GenlFamily`], [`Emitable`], and [`ParseableParametrized<[u8],
22/// GenlHeader>`](ParseableParametrized).
23#[derive(Clone, Debug, PartialEq, Eq)]
24pub struct GenlMessage<F> {
25    pub header: GenlHeader,
26    pub payload: F,
27    resolved_family_id: u16,
28}
29
30impl<F> GenlMessage<F>
31where
32    F: Debug,
33{
34    /// Construct the message
35    pub fn new(header: GenlHeader, payload: F, family_id: u16) -> Self {
36        Self { header, payload, resolved_family_id: family_id }
37    }
38
39    /// Construct the message by the given header and payload
40    pub fn from_parts(header: GenlHeader, payload: F) -> Self {
41        Self { header, payload, resolved_family_id: 0 }
42    }
43
44    /// Consume this message and return its header and payload
45    pub fn into_parts(self) -> (GenlHeader, F) {
46        (self.header, self.payload)
47    }
48
49    /// Return the previously set resolved family ID in this message.
50    ///
51    /// This value would be used to serialize the message only if
52    /// the ([`GenlFamily::family_id()`]) return 0 in the underlying type.
53    pub fn resolved_family_id(&self) -> u16 {
54        self.resolved_family_id
55    }
56
57    /// Set the resolved dynamic family ID of the message, if the generic family
58    /// uses dynamic generated ID by kernel.
59    ///
60    /// This method is a interface to provide other high level library to
61    /// set the resolved family ID before the message is serialized.
62    ///
63    /// # Usage
64    /// Normally, you don't have to call this function directly if you are
65    /// using library which helps you handle the dynamic family id.
66    ///
67    /// If you are the developer of some high level generic netlink library,
68    /// you can call this method to set the family id resolved by your resolver.
69    /// Without having to modify the `message_type` field of the serialized
70    /// netlink packet header before sending it.
71    pub fn set_resolved_family_id(&mut self, family_id: u16) {
72        self.resolved_family_id = family_id;
73    }
74}
75
76impl<F> GenlMessage<F>
77where
78    F: GenlFamily + Debug,
79{
80    /// Build the message from the payload
81    ///
82    /// This function would automatically fill the header for you. You can
83    /// directly emit the message without having to call
84    /// [`finalize()`](Self::finalize).
85    pub fn from_payload(payload: F) -> Self {
86        Self {
87            header: GenlHeader { cmd: payload.command(), version: payload.version() },
88            payload,
89            resolved_family_id: 0,
90        }
91    }
92
93    /// Ensure the header ([`GenlHeader`]) is consistent with the payload (`F:
94    /// GenlFamily`):
95    ///
96    /// - Fill the command and version number into the header
97    ///
98    /// If you are not 100% sure the header is correct, this method should be
99    /// called before calling [`Emitable::emit()`], as it could get error
100    /// result if the header is inconsistent with the message.
101    pub fn finalize(&mut self) {
102        self.header.cmd = self.payload.command();
103        self.header.version = self.payload.version();
104    }
105
106    /// Return the resolved family ID which should be filled into the
107    /// `message_type` field in [`NetlinkHeader`].
108    ///
109    /// The implementation of [`NetlinkSerializable::message_type()`] would use
110    /// this function's result as its the return value. Thus, the family id can
111    /// be automatically filled into the `message_type` during the call to
112    /// [`NetlinkMessage::finalize()`].
113    pub fn family_id(&self) -> u16 {
114        let static_id = self.payload.family_id();
115        if static_id == 0 { self.resolved_family_id } else { static_id }
116    }
117}
118
119impl<F> Emitable for GenlMessage<F>
120where
121    F: GenlFamily + Emitable + Debug,
122{
123    fn buffer_len(&self) -> usize {
124        self.header.buffer_len() + self.payload.buffer_len()
125    }
126
127    fn emit(&self, buffer: &mut [u8]) {
128        self.header.emit(buffer);
129
130        let buffer = &mut buffer[self.header.buffer_len()..];
131        self.payload.emit(buffer);
132    }
133}
134
135impl<F> NetlinkSerializable for GenlMessage<F>
136where
137    F: GenlFamily + Emitable + Debug,
138{
139    fn message_type(&self) -> u16 {
140        self.family_id()
141    }
142
143    fn buffer_len(&self) -> usize {
144        <Self as Emitable>::buffer_len(self)
145    }
146
147    fn serialize(&self, buffer: &mut [u8]) {
148        self.emit(buffer)
149    }
150}
151
152impl<F> NetlinkDeserializable for GenlMessage<F>
153where
154    F: ParseableParametrized<[u8], GenlHeader> + Debug,
155    F::Error: Into<DecodeError>,
156{
157    type Error = DecodeError;
158    fn deserialize(header: &NetlinkHeader, payload: &[u8]) -> Result<Self, Self::Error> {
159        let buffer = GenlBuffer::new_checked(payload)?;
160        GenlMessage::parse_with_param(&buffer, header.message_type)
161    }
162}
163
164impl<F> From<GenlMessage<F>> for NetlinkPayload<GenlMessage<F>>
165where
166    F: Debug,
167{
168    fn from(message: GenlMessage<F>) -> Self {
169        NetlinkPayload::InnerMessage(message)
170    }
171}