1use super::*;
6use crate::ot::{InfraInterface, Ip4Address, Ip6Address, Ip6Prefix};
7use crate::Platform;
8use anyhow::{Error, Result};
9use fuchsia_sync::Mutex;
10use futures::future::BoxFuture;
11use openthread_sys::*;
12use std::task::{Context, Poll};
13
14pub(crate) struct Nat64Instance {
15 nat64_prefix_req_sender: Mutex<
16 fmpsc::UnboundedSender<Mutex<Option<BoxFuture<'static, (ot::NetifIndex, Ip6Prefix)>>>>,
17 >,
18}
19
20const K_VALID_NAT64_PREFIX_LENGTHS: [u8; 6] = [96, 64, 56, 48, 40, 32];
21const K_WELL_KNOWN_IPV4_ONLY_ADDRESS1: Ip4Address = Ip4Address::new(192, 0, 0, 170);
22const K_WELL_KNOWN_IPV4_ONLY_ADDRESS2: Ip4Address = Ip4Address::new(192, 0, 0, 171);
23
24pub(crate) struct Nat64PlatformInstance {
25 nat64_prefix_req_receiver:
26 fmpsc::UnboundedReceiver<Mutex<Option<BoxFuture<'static, (ot::NetifIndex, Ip6Prefix)>>>>,
27 nat64_pending_fut: Mutex<Option<BoxFuture<'static, (ot::NetifIndex, Ip6Prefix)>>>,
28}
29
30impl Nat64Instance {
31 pub fn new(
32 nat64_prefix_req_sender: fmpsc::UnboundedSender<
33 Mutex<Option<BoxFuture<'static, (ot::NetifIndex, Ip6Prefix)>>>,
34 >,
35 ) -> Nat64Instance {
36 Nat64Instance { nat64_prefix_req_sender: Mutex::new(nat64_prefix_req_sender) }
37 }
38}
39
40impl Nat64PlatformInstance {
41 pub fn new(
42 nat64_prefix_req_receiver: fmpsc::UnboundedReceiver<
43 Mutex<Option<BoxFuture<'static, (ot::NetifIndex, Ip6Prefix)>>>,
44 >,
45 ) -> Nat64PlatformInstance {
46 Nat64PlatformInstance { nat64_prefix_req_receiver, nat64_pending_fut: Mutex::new(None) }
47 }
48}
49
50fn extract_ipv4_addr_from_ipv6(
70 ip6_addr: std::net::Ipv6Addr,
71 prefix_length: u8,
72) -> std::net::Ipv4Addr {
73 if !K_VALID_NAT64_PREFIX_LENGTHS.contains(&prefix_length) {
75 return std::net::Ipv4Addr::new(0, 0, 0, 0);
76 }
77
78 let ip6_vec = ip6_addr.octets();
79
80 let mut ip6_idx = (prefix_length / 8) as usize;
82 let mut ip4_idx: usize = 0;
83
84 let mut res: [u8; 4] = [0; 4];
85
86 while ip4_idx < 4 {
87 if ip6_idx == 8 {
88 ip6_idx += 1;
89 continue;
90 }
91 res[ip4_idx] = ip6_vec[ip6_idx];
92 ip4_idx += 1;
93 ip6_idx += 1;
94 }
95
96 std::net::Ipv4Addr::from(res)
97}
98
99fn get_ipv6_prefix(
101 ip_addr: std::net::Ipv6Addr,
102 prefix_length: usize,
103) -> Option<std::net::Ipv6Addr> {
104 if prefix_length > 128 {
105 return None;
106 }
107
108 let mut res = [0u16; 8];
109 let ip_seg = ip_addr.segments();
110 let (byte_count, reminder) = (prefix_length / 16, prefix_length % 16);
111 let mut res_idx = 0;
112 while res_idx < byte_count {
113 res[res_idx] = ip_seg[res_idx];
114 res_idx += 1;
115 }
116 if reminder > 0 && reminder < 16 {
117 let mask = ((1 << reminder) - 1) << (16 - reminder);
118 res[res_idx] = ip_seg[res_idx] & mask;
119 }
120 Some(std::net::Ipv6Addr::from(res))
121}
122
123fn process_ail_dns_lookup_result(
126 ip_vec: Vec<fidl_fuchsia_net::IpAddress>,
127) -> Result<Ip6Prefix, Error> {
128 let mut prefix: Option<Ip6Prefix> = None;
129 for ip in ip_vec {
130 if let fidl_fuchsia_net::IpAddress::Ipv6(ip_addr) = ip {
131 let ip6_address: Ip6Address = ip_addr.addr.into();
132 for length in K_VALID_NAT64_PREFIX_LENGTHS {
133 let ip4_address = extract_ipv4_addr_from_ipv6(ip6_address, length);
134 if ip4_address.eq(&K_WELL_KNOWN_IPV4_ONLY_ADDRESS1)
135 || ip4_address.eq(&K_WELL_KNOWN_IPV4_ONLY_ADDRESS2)
136 {
137 let mut found_duplicate = false;
138 for dup_length in K_VALID_NAT64_PREFIX_LENGTHS {
139 if dup_length == length {
140 continue;
141 }
142 let ip4_address_dup = extract_ipv4_addr_from_ipv6(ip6_address, dup_length);
143
144 if ip4_address_dup.eq(&ip4_address) {
145 found_duplicate = true;
146 break;
147 }
148 }
149 if !found_duplicate {
150 if let Some(ip6_prefix_addr) = get_ipv6_prefix(ip6_address, length.into()) {
151 prefix = Some(Ip6Prefix::new(ip6_prefix_addr, length));
152 break;
153 }
154 }
155 }
156 if prefix.is_some() {
157 break;
158 }
159 }
160 }
161 }
162 match prefix {
163 Some(p) => Ok(p),
164 None => Err(Error::msg("NAT64 AIL result lookup is empty")),
165 }
166}
167
168impl PlatformBacking {
169 fn on_nat64_prefix_request(&self, infra_if_idx: ot::NetifIndex) {
170 #[no_mangle]
171 unsafe extern "C" fn otPlatInfraIfDiscoverNat64Prefix(infra_if_idx: u32) -> otError {
172 PlatformBacking::on_nat64_prefix_request(
173 PlatformBacking::as_ref(),
175 infra_if_idx,
176 );
177 ot::Error::None.into()
178 }
179
180 let fut = async move {
181 let name_lookup_proxy_res = fuchsia_component::client::connect_to_protocol::<
183 fidl_fuchsia_net_name::LookupMarker,
184 >();
185
186 if let Err(e) = name_lookup_proxy_res {
187 warn!("failed to connect to fidl_fuchsia_net_name::LookupMarker: {:?}", e);
188 return (infra_if_idx, Ip6Prefix::new(Ip6Address::new(0, 0, 0, 0, 0, 0, 0, 0), 0));
189 }
190
191 let lookup_result;
192 match name_lookup_proxy_res
193 .unwrap()
194 .lookup_ip(
195 "ipv4only.arpa",
196 &fidl_fuchsia_net_name::LookupIpOptions {
197 ipv6_lookup: Some(true),
198 ..Default::default()
199 },
200 )
201 .await
202 {
203 Ok(res) => {
204 lookup_result = res;
205 }
206 Err(e) => {
207 warn!("failed to do dns lookup_ip: {:?}", e);
208 return (
209 infra_if_idx,
210 Ip6Prefix::new(Ip6Address::new(0, 0, 0, 0, 0, 0, 0, 0), 0),
211 );
212 }
213 };
214
215 let prefix;
216 match lookup_result {
217 Ok(fidl_fuchsia_net_name::LookupResult { addresses: Some(ip_vec), .. }) => {
218 info!("processed dns response, result: {:?}", &ip_vec);
219 match process_ail_dns_lookup_result(ip_vec) {
220 Ok(prefix_output) => {
221 prefix = prefix_output;
222 }
223 Err(_) => {
224 warn!("malformed DNS response, dropping the prefix");
225 prefix = Ip6Prefix::new(Ip6Address::new(0, 0, 0, 0, 0, 0, 0, 0), 0);
226 }
227 }
228 }
229 Ok(fidl_fuchsia_net_name::LookupResult { addresses: None, .. }) => {
230 info!("failed to process dns lookup result: empty result");
231 prefix = Ip6Prefix::new(Ip6Address::new(0, 0, 0, 0, 0, 0, 0, 0), 0);
232 }
233 Err(e) => {
234 warn!("failed to process dns lookup result: {:?}", e);
235 prefix = Ip6Prefix::new(Ip6Address::new(0, 0, 0, 0, 0, 0, 0, 0), 0);
236 }
237 }
238
239 (infra_if_idx, prefix)
240 };
241
242 self.nat64
243 .nat64_prefix_req_sender
244 .lock()
245 .unbounded_send(Mutex::new(Some(fut.boxed())))
246 .expect("on_net64_prefix_request");
247 }
248}
249
250impl Platform {
251 pub fn process_poll_nat64(&mut self, instance: &ot::Instance, cx: &mut Context<'_>) {
252 while let Poll::Ready(Some(mtx)) =
253 self.nat64_platform_instance.nat64_prefix_req_receiver.poll_next_unpin(cx)
254 {
255 self.nat64_platform_instance.nat64_pending_fut = mtx;
256 }
257
258 let mut borrowed = self.nat64_platform_instance.nat64_pending_fut.lock();
259 if let Some(future) = borrowed.as_mut() {
260 match future.poll_unpin(cx) {
261 Poll::Ready((infra_if_idx, ip6_prefix)) => {
262 instance.plat_infra_if_discover_nat64_prefix_done(infra_if_idx, ip6_prefix);
263 *borrowed = None;
264 }
265 Poll::Pending => {}
266 }
267 }
268 }
269}
270
271#[cfg(test)]
272mod test {
273 use super::*;
274
275 #[test]
276 fn ail_dns_lookup_process_test() {
277 assert!(process_ail_dns_lookup_result(vec![]).is_err());
279 assert!(process_ail_dns_lookup_result(vec![fidl_fuchsia_net::IpAddress::Ipv4(
281 fidl_fuchsia_net::Ipv4Address { addr: [192, 0, 0, 170] }
282 )])
283 .is_err());
284 assert!(process_ail_dns_lookup_result(vec![fidl_fuchsia_net::IpAddress::Ipv6(
286 fidl_fuchsia_net::Ipv6Address {
287 addr: [
288 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
289 0x00, 0x00, 0x00
290 ]
291 }
292 )])
293 .is_err());
294 assert_eq!(
296 process_ail_dns_lookup_result(vec![
297 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
298 addr: [
299 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
300 0x00, 0x00, 0x00, 0x00
301 ]
302 }),
303 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
304 addr: [
305 0xfc, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0xaa, 0x00, 0x01, 0x00, 0x02,
306 0x00, 0x03, 0x00, 0x04
307 ]
308 })
309 ])
310 .unwrap(),
311 Ip6Prefix::new(Ip6Address::new(0xfc00, 0x0001, 0, 0, 0, 0, 0, 0), 32)
312 );
313 assert_eq!(
315 process_ail_dns_lookup_result(vec![
316 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
317 addr: [
318 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
319 0x00, 0x00, 0x00, 0x00
320 ]
321 }),
322 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
323 addr: [
324 0xfc, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0xab, 0x00, 0x01, 0x00, 0x02,
325 0x00, 0x03, 0x00, 0x04
326 ]
327 })
328 ])
329 .unwrap(),
330 Ip6Prefix::new(Ip6Address::new(0xfc00, 0x0001, 0, 0, 0, 0, 0, 0), 32)
331 );
332 assert_eq!(
334 process_ail_dns_lookup_result(vec![
335 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
336 addr: [
337 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
338 0x00, 0x00, 0x00, 0x00
339 ]
340 }),
341 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
342 addr: [
343 0xfc, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x02,
344 0x00, 0x03, 0x00, 0x04
345 ]
346 })
347 ])
348 .unwrap(),
349 Ip6Prefix::new(Ip6Address::new(0xfc00, 0x0000, 0x0100, 0, 0, 0, 0, 0), 40)
350 );
351 assert_eq!(
353 process_ail_dns_lookup_result(vec![
354 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
355 addr: [
356 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
357 0x00, 0x00, 0x00, 0x00
358 ]
359 }),
360 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
361 addr: [
362 0xfc, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0xaa, 0x02,
363 0x00, 0x03, 0x00, 0x04
364 ]
365 })
366 ])
367 .unwrap(),
368 Ip6Prefix::new(Ip6Address::new(0xfc00, 0x0000, 0x0001, 0, 0, 0, 0, 0), 48)
369 );
370 assert_eq!(
372 process_ail_dns_lookup_result(vec![
373 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
374 addr: [
375 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
376 0x00, 0x00, 0x00, 0x00
377 ]
378 }),
379 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
380 addr: [
381 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0xaa,
382 0x00, 0x03, 0x00, 0x04
383 ]
384 })
385 ])
386 .unwrap(),
387 Ip6Prefix::new(Ip6Address::new(0xfc00, 0x0000, 0x0000, 0x0100, 0, 0, 0, 0), 56)
388 );
389 assert_eq!(
391 process_ail_dns_lookup_result(vec![
392 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
393 addr: [
394 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
395 0x00, 0x00, 0x00, 0x00
396 ]
397 }),
398 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
399 addr: [
400 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xc0, 0x00, 0x00,
401 0xaa, 0x03, 0x00, 0x04
402 ]
403 })
404 ])
405 .unwrap(),
406 Ip6Prefix::new(Ip6Address::new(0xfc00, 0x0000, 0x0000, 0x0001, 0, 0, 0, 0), 64)
407 );
408 assert_eq!(
410 process_ail_dns_lookup_result(vec![
411 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
412 addr: [
413 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
414 0x00, 0x00, 0x00, 0x00
415 ]
416 }),
417 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
418 addr: [
419 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
420 0xc0, 0x00, 0x00, 0xaa
421 ]
422 })
423 ])
424 .unwrap(),
425 Ip6Prefix::new(
426 Ip6Address::new(0xfc00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0, 0),
427 96
428 )
429 );
430 assert!(process_ail_dns_lookup_result(vec![
432 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
433 addr: [
434 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
435 0x00, 0x00, 0x00
436 ]
437 }),
438 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
439 addr: [
440 0xfc, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0xaa, 0x00, 0xc0, 0x00, 0x00, 0xaa,
441 0x03, 0x00, 0x04
442 ]
443 })
444 ])
445 .is_err());
446 assert!(process_ail_dns_lookup_result(vec![
448 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
449 addr: [
450 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
451 0x00, 0x00, 0x00
452 ]
453 }),
454 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
455 addr: [
456 0xfc, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x00, 0xc0,
457 0x00, 0x00, 0xaa
458 ]
459 })
460 ])
461 .is_err());
462 assert!(process_ail_dns_lookup_result(vec![
464 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
465 addr: [
466 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
467 0x00, 0x00, 0x00
468 ]
469 }),
470 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
471 addr: [
472 0xfc, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0xc0,
473 0x00, 0x00, 0xaa
474 ]
475 })
476 ])
477 .is_err());
478 assert!(process_ail_dns_lookup_result(vec![
480 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
481 addr: [
482 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
483 0x00, 0x00, 0x00
484 ]
485 }),
486 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
487 addr: [
488 0xfc, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0xaa, 0x00, 0xc0,
489 0x00, 0x00, 0xaa
490 ]
491 })
492 ])
493 .is_err());
494 }
495
496 #[test]
497 fn test_ipv4_nat64_ops() {
498 assert_eq!(
499 extract_ipv4_addr_from_ipv6(
500 Ip6Address::new(0xffff, 0xffff, 0xf1f2, 0xf3f4, 0xffff, 0xffff, 0xffff, 0xffff),
501 32
502 ),
503 Ip4Address::new(0xf1, 0xf2, 0xf3, 0xf4)
504 );
505 assert_eq!(
506 extract_ipv4_addr_from_ipv6(
507 Ip6Address::new(0xffff, 0xffff, 0xfff1, 0xf2f3, 0xfff4, 0xffff, 0xffff, 0xffff),
508 40
509 ),
510 Ip4Address::new(0xf1, 0xf2, 0xf3, 0xf4)
511 );
512 assert_eq!(
513 extract_ipv4_addr_from_ipv6(
514 Ip6Address::new(0xffff, 0xffff, 0xffff, 0xf1f2, 0xfff3, 0xf4ff, 0xffff, 0xffff),
515 48
516 ),
517 Ip4Address::new(0xf1, 0xf2, 0xf3, 0xf4)
518 );
519 assert_eq!(
520 extract_ipv4_addr_from_ipv6(
521 Ip6Address::new(0xffff, 0xffff, 0xffff, 0xfff1, 0xfff2, 0xf3f4, 0xffff, 0xffff),
522 56
523 ),
524 Ip4Address::new(0xf1, 0xf2, 0xf3, 0xf4)
525 );
526 assert_eq!(
527 extract_ipv4_addr_from_ipv6(
528 Ip6Address::new(0xffff, 0xffff, 0xffff, 0xffff, 0xfff1, 0xf2f3, 0xf4ff, 0xffff),
529 64
530 ),
531 Ip4Address::new(0xf1, 0xf2, 0xf3, 0xf4)
532 );
533 assert_eq!(
534 extract_ipv4_addr_from_ipv6(
535 Ip6Address::new(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xf1f2, 0xf3f4),
536 96
537 ),
538 Ip4Address::new(0xf1, 0xf2, 0xf3, 0xf4)
539 );
540
541 assert_eq!(
543 extract_ipv4_addr_from_ipv6(
544 Ip6Address::new(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xf1f2, 0xf3f4),
545 44
546 ),
547 Ip4Address::new(0, 0, 0, 0)
548 );
549 }
550
551 #[test]
552 fn test_ipv6_nat64_ops() {
553 assert_eq!(
554 get_ipv6_prefix(
555 Ip6Address::new(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff),
556 0
557 ),
558 Some(Ip6Address::new(0, 0, 0, 0, 0, 0, 0, 0))
559 );
560 assert_eq!(
561 get_ipv6_prefix(
562 Ip6Address::new(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff),
563 16
564 ),
565 Some(Ip6Address::new(0xffff, 0, 0, 0, 0, 0, 0, 0))
566 );
567 assert_eq!(
568 get_ipv6_prefix(
569 Ip6Address::new(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff),
570 32
571 ),
572 Some(Ip6Address::new(0xffff, 0xffff, 0, 0, 0, 0, 0, 0))
573 );
574 assert_eq!(
575 get_ipv6_prefix(
576 Ip6Address::new(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff),
577 63
578 ),
579 Some(Ip6Address::new(0xffff, 0xffff, 0xffff, 0xfffe, 0, 0, 0, 0))
580 );
581 assert_eq!(
582 get_ipv6_prefix(
583 Ip6Address::new(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff),
584 64
585 ),
586 Some(Ip6Address::new(0xffff, 0xffff, 0xffff, 0xffff, 0, 0, 0, 0))
587 );
588 assert_eq!(
589 get_ipv6_prefix(
590 Ip6Address::new(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff),
591 65
592 ),
593 Some(Ip6Address::new(0xffff, 0xffff, 0xffff, 0xffff, 0x8000, 0, 0, 0))
594 );
595 assert_eq!(
596 get_ipv6_prefix(
597 Ip6Address::new(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff),
598 128
599 ),
600 Some(Ip6Address::new(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff))
601 );
602 assert_eq!(
603 get_ipv6_prefix(
604 Ip6Address::new(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff),
605 129
606 ),
607 None
608 );
609 }
610}