packet_formats/icmp/
macros.rs

1// Copyright 2018 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Macros for parsing and serialization of ICMP packets.
6
7/// Implement `IcmpMessage` for a type.
8///
9/// The arguments are:
10/// - `$ip` - `Ipv4` or `Ipv6`
11/// - `$type` - the type to implement for
12/// - `$msg_variant` - the variant of `Icmpv4MessageType` or `icmpv6::MessageType`
13///   associated with this message type
14/// - `$code` - the type to use for `IcmpMessage::Code`; if `()` is used, 0 will
15///   be the only valid code
16/// - `$has_body` - `true` or `false` depending on whether this message type
17///   supports a body
18macro_rules! impl_icmp_message {
19    ($ip:ident, $type:ident, $msg_variant:ident, $code:tt, $body_type:ty, $expects_body:ident) => {
20        impl crate::icmp::IcmpMessage<$ip> for $type {
21            const EXPECTS_BODY: bool = $expects_body;
22
23            type Code = $code;
24
25            type Body<B: SplitByteSlice> = $body_type;
26
27            const TYPE: <$ip as IcmpIpExt>::IcmpMessageType =
28                impl_icmp_message_inner_message_type!($ip, $msg_variant);
29
30            fn code_from_u8(u: u8) -> Option<Self::Code> {
31                impl_icmp_message_inner_code_from_u8!($code, u)
32            }
33        }
34    };
35
36    ($ip:ident, $type:ident, $msg_variant:ident, $code:tt, $body_type:ty) => {
37        impl_icmp_message!($ip, $type, $msg_variant, $code, $body_type, true);
38    };
39
40    ($ip:ident, $type:ident, $msg_variant:ident, $code:tt) => {
41        impl_icmp_message!($ip, $type, $msg_variant, $code, crate::icmp::EmptyMessage<B>, false);
42    };
43}
44
45macro_rules! impl_common_icmp_message {
46    ($type:ident, $icmp_type:ident, $code:tt, $body_type:ty, $expects_body:ident) => {
47        impl<I: crate::icmp::IcmpIpExt> crate::icmp::IcmpMessage<I> for $type {
48            const EXPECTS_BODY: bool = $expects_body;
49
50            type Code = $code;
51
52            type Body<B: zerocopy::SplitByteSlice> = $body_type;
53
54            const TYPE: I::IcmpMessageType = I::$icmp_type;
55
56            fn code_from_u8(u: u8) -> Option<Self::Code> {
57                impl_icmp_message_inner_code_from_u8!($code, u)
58            }
59        }
60    };
61
62    ($type:ident, $icmp_type:ident, $code:tt, $body_type:ty) => {
63        impl_common_icmp_message!($type, $icmp_type, $code, $body_type, true);
64    };
65
66    ($type:ident, $icmp_type:ident, $code:tt) => {
67        impl_common_icmp_message!($type, $icmp_type, $code, crate::icmp::EmptyMessage<B>, false);
68    };
69}
70
71macro_rules! impl_icmp_message_inner_message_type {
72    (Ipv4, $msg_variant:ident) => {
73        crate::icmp::icmpv4::Icmpv4MessageType::$msg_variant
74    };
75    (Ipv6, $msg_variant:ident) => {
76        crate::icmp::icmpv6::Icmpv6MessageType::$msg_variant
77    };
78}
79
80macro_rules! impl_icmp_message_inner_code_from_u8 {
81    ($code:tt, $var:ident) => {
82        $code::try_from($var).ok()
83    };
84}