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 {
116            self.resolved_family_id
117        } else {
118            static_id
119        }
120    }
121}
122
123impl<F> Emitable for GenlMessage<F>
124where
125    F: GenlFamily + Emitable + Debug,
126{
127    fn buffer_len(&self) -> usize {
128        self.header.buffer_len() + self.payload.buffer_len()
129    }
130
131    fn emit(&self, buffer: &mut [u8]) {
132        self.header.emit(buffer);
133
134        let buffer = &mut buffer[self.header.buffer_len()..];
135        self.payload.emit(buffer);
136    }
137}
138
139impl<F> NetlinkSerializable for GenlMessage<F>
140where
141    F: GenlFamily + Emitable + Debug,
142{
143    fn message_type(&self) -> u16 {
144        self.family_id()
145    }
146
147    fn buffer_len(&self) -> usize {
148        <Self as Emitable>::buffer_len(self)
149    }
150
151    fn serialize(&self, buffer: &mut [u8]) {
152        self.emit(buffer)
153    }
154}
155
156impl<F> NetlinkDeserializable for GenlMessage<F>
157where
158    F: ParseableParametrized<[u8], GenlHeader> + Debug,
159    F::Error: Into<DecodeError>,
160{
161    type Error = DecodeError;
162    fn deserialize(header: &NetlinkHeader, payload: &[u8]) -> Result<Self, Self::Error> {
163        let buffer = GenlBuffer::new_checked(payload)?;
164        GenlMessage::parse_with_param(&buffer, header.message_type)
165    }
166}
167
168impl<F> From<GenlMessage<F>> for NetlinkPayload<GenlMessage<F>>
169where
170    F: Debug,
171{
172    fn from(message: GenlMessage<F>) -> Self {
173        NetlinkPayload::InnerMessage(message)
174    }
175}