1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
use super::super::iana::OptionCode;
use super::super::message_builder::OptBuilder;
use super::super::net::IpAddr;
use super::super::octets::{
Compose, FormError, OctetsBuilder, Parse, ParseError, Parser, ShortBuf
};
use super::CodeOptData;
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct ClientSubnet {
source_prefix_len: u8,
scope_prefix_len: u8,
addr: IpAddr,
}
impl ClientSubnet {
pub fn new(
source_prefix_len: u8,
scope_prefix_len: u8,
addr: IpAddr
) -> ClientSubnet {
ClientSubnet { source_prefix_len, scope_prefix_len, addr }
}
pub fn push<Target: OctetsBuilder>(
builder: &mut OptBuilder<Target>,
source_prefix_len: u8,
scope_prefix_len: u8,
addr: IpAddr
) -> Result<(), ShortBuf> {
builder.push(&Self::new(source_prefix_len, scope_prefix_len, addr))
}
pub fn source_prefix_len(&self) -> u8 { self.source_prefix_len }
pub fn scope_prefix_len(&self) -> u8 { self.scope_prefix_len }
pub fn addr(&self) -> IpAddr { self.addr }
}
impl<Ref: AsRef<[u8]>> Parse<Ref> for ClientSubnet {
fn parse(parser: &mut Parser<Ref>) -> Result<Self, ParseError> {
let family = parser.parse_u16()?;
let source_prefix_len = parser.parse_u8()?;
let scope_prefix_len = parser.parse_u8()?;
let prefix_bytes = prefix_bytes(usize::from(source_prefix_len));
let addr = match family {
1 => {
let mut buf = [0; 4];
if prefix_bytes > buf.len() {
return Err(
FormError::new(
"invalid address length in client subnet option"
).into()
);
}
parser.parse_buf(&mut buf[..prefix_bytes])?;
IpAddr::from(buf)
}
2 => {
let mut buf = [0; 16];
if prefix_bytes > buf.len() {
return Err(
FormError::new(
"invalid address length in client subnet option"
).into()
);
}
parser.parse_buf(&mut buf[..prefix_bytes])?;
IpAddr::from(buf)
}
_ => {
return Err(
FormError::new(
"invalid client subnet address family"
).into()
)
}
};
Ok(ClientSubnet::new(source_prefix_len, scope_prefix_len, addr))
}
fn skip(parser: &mut Parser<Ref>) -> Result<(), ParseError> {
parser.advance_to_end();
Ok(())
}
}
impl Compose for ClientSubnet {
fn compose<T: OctetsBuilder>(
&self,
target: &mut T
) -> Result<(), ShortBuf> {
let prefix_bytes = prefix_bytes(self.source_prefix_len as usize);
target.append_all(|target| {
match self.addr {
IpAddr::V4(addr) => {
1u16.compose(target)?;
self.source_prefix_len.compose(target)?;
self.scope_prefix_len.compose(target)?;
target.append_slice(&addr.octets()[..prefix_bytes])
}
IpAddr::V6(addr) => {
2u16.compose(target)?;
self.source_prefix_len.compose(target)?;
self.scope_prefix_len.compose(target)?;
target.append_slice(&addr.octets()[..prefix_bytes])
}
}
})
}
}
fn prefix_bytes(bits: usize) -> usize {
(bits + 7) / 8
}
impl CodeOptData for ClientSubnet {
const CODE: OptionCode = OptionCode::ClientSubnet;
}