1use super::*;
6use crate::Platform;
7use crate::ot::{InfraInterface, Ip4Address, Ip6Address, Ip6Prefix};
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 #[unsafe(no_mangle)]
171 unsafe extern "C" fn otPlatInfraIfDiscoverNat64Prefix(infra_if_idx: u32) -> otError {
172 PlatformBacking::on_nat64_prefix_request(
173 unsafe { 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!(
281 process_ail_dns_lookup_result(vec![fidl_fuchsia_net::IpAddress::Ipv4(
282 fidl_fuchsia_net::Ipv4Address { addr: [192, 0, 0, 170] }
283 )])
284 .is_err()
285 );
286 assert!(
288 process_ail_dns_lookup_result(vec![fidl_fuchsia_net::IpAddress::Ipv6(
289 fidl_fuchsia_net::Ipv6Address {
290 addr: [
291 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
292 0x00, 0x00, 0x00, 0x00
293 ]
294 }
295 )])
296 .is_err()
297 );
298 assert_eq!(
300 process_ail_dns_lookup_result(vec![
301 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
302 addr: [
303 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
304 0x00, 0x00, 0x00, 0x00
305 ]
306 }),
307 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
308 addr: [
309 0xfc, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0xaa, 0x00, 0x01, 0x00, 0x02,
310 0x00, 0x03, 0x00, 0x04
311 ]
312 })
313 ])
314 .unwrap(),
315 Ip6Prefix::new(Ip6Address::new(0xfc00, 0x0001, 0, 0, 0, 0, 0, 0), 32)
316 );
317 assert_eq!(
319 process_ail_dns_lookup_result(vec![
320 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
321 addr: [
322 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
323 0x00, 0x00, 0x00, 0x00
324 ]
325 }),
326 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
327 addr: [
328 0xfc, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0xab, 0x00, 0x01, 0x00, 0x02,
329 0x00, 0x03, 0x00, 0x04
330 ]
331 })
332 ])
333 .unwrap(),
334 Ip6Prefix::new(Ip6Address::new(0xfc00, 0x0001, 0, 0, 0, 0, 0, 0), 32)
335 );
336 assert_eq!(
338 process_ail_dns_lookup_result(vec![
339 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
340 addr: [
341 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
342 0x00, 0x00, 0x00, 0x00
343 ]
344 }),
345 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
346 addr: [
347 0xfc, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x02,
348 0x00, 0x03, 0x00, 0x04
349 ]
350 })
351 ])
352 .unwrap(),
353 Ip6Prefix::new(Ip6Address::new(0xfc00, 0x0000, 0x0100, 0, 0, 0, 0, 0), 40)
354 );
355 assert_eq!(
357 process_ail_dns_lookup_result(vec![
358 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
359 addr: [
360 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
361 0x00, 0x00, 0x00, 0x00
362 ]
363 }),
364 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
365 addr: [
366 0xfc, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0xaa, 0x02,
367 0x00, 0x03, 0x00, 0x04
368 ]
369 })
370 ])
371 .unwrap(),
372 Ip6Prefix::new(Ip6Address::new(0xfc00, 0x0000, 0x0001, 0, 0, 0, 0, 0), 48)
373 );
374 assert_eq!(
376 process_ail_dns_lookup_result(vec![
377 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
378 addr: [
379 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
380 0x00, 0x00, 0x00, 0x00
381 ]
382 }),
383 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
384 addr: [
385 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0xaa,
386 0x00, 0x03, 0x00, 0x04
387 ]
388 })
389 ])
390 .unwrap(),
391 Ip6Prefix::new(Ip6Address::new(0xfc00, 0x0000, 0x0000, 0x0100, 0, 0, 0, 0), 56)
392 );
393 assert_eq!(
395 process_ail_dns_lookup_result(vec![
396 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
397 addr: [
398 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
399 0x00, 0x00, 0x00, 0x00
400 ]
401 }),
402 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
403 addr: [
404 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xc0, 0x00, 0x00,
405 0xaa, 0x03, 0x00, 0x04
406 ]
407 })
408 ])
409 .unwrap(),
410 Ip6Prefix::new(Ip6Address::new(0xfc00, 0x0000, 0x0000, 0x0001, 0, 0, 0, 0), 64)
411 );
412 assert_eq!(
414 process_ail_dns_lookup_result(vec![
415 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
416 addr: [
417 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
418 0x00, 0x00, 0x00, 0x00
419 ]
420 }),
421 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
422 addr: [
423 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
424 0xc0, 0x00, 0x00, 0xaa
425 ]
426 })
427 ])
428 .unwrap(),
429 Ip6Prefix::new(
430 Ip6Address::new(0xfc00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0, 0),
431 96
432 )
433 );
434 assert!(
436 process_ail_dns_lookup_result(vec![
437 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
438 addr: [
439 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
440 0x00, 0x00, 0x00, 0x00
441 ]
442 }),
443 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
444 addr: [
445 0xfc, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0xaa, 0x00, 0xc0, 0x00, 0x00,
446 0xaa, 0x03, 0x00, 0x04
447 ]
448 })
449 ])
450 .is_err()
451 );
452 assert!(
454 process_ail_dns_lookup_result(vec![
455 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
456 addr: [
457 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
458 0x00, 0x00, 0x00, 0x00
459 ]
460 }),
461 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
462 addr: [
463 0xfc, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x00,
464 0xc0, 0x00, 0x00, 0xaa
465 ]
466 })
467 ])
468 .is_err()
469 );
470 assert!(
472 process_ail_dns_lookup_result(vec![
473 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
474 addr: [
475 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
476 0x00, 0x00, 0x00, 0x00
477 ]
478 }),
479 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
480 addr: [
481 0xfc, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00,
482 0xc0, 0x00, 0x00, 0xaa
483 ]
484 })
485 ])
486 .is_err()
487 );
488 assert!(
490 process_ail_dns_lookup_result(vec![
491 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
492 addr: [
493 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
494 0x00, 0x00, 0x00, 0x00
495 ]
496 }),
497 fidl_fuchsia_net::IpAddress::Ipv6(fidl_fuchsia_net::Ipv6Address {
498 addr: [
499 0xfc, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0xaa, 0x00,
500 0xc0, 0x00, 0x00, 0xaa
501 ]
502 })
503 ])
504 .is_err()
505 );
506 }
507
508 #[test]
509 fn test_ipv4_nat64_ops() {
510 assert_eq!(
511 extract_ipv4_addr_from_ipv6(
512 Ip6Address::new(0xffff, 0xffff, 0xf1f2, 0xf3f4, 0xffff, 0xffff, 0xffff, 0xffff),
513 32
514 ),
515 Ip4Address::new(0xf1, 0xf2, 0xf3, 0xf4)
516 );
517 assert_eq!(
518 extract_ipv4_addr_from_ipv6(
519 Ip6Address::new(0xffff, 0xffff, 0xfff1, 0xf2f3, 0xfff4, 0xffff, 0xffff, 0xffff),
520 40
521 ),
522 Ip4Address::new(0xf1, 0xf2, 0xf3, 0xf4)
523 );
524 assert_eq!(
525 extract_ipv4_addr_from_ipv6(
526 Ip6Address::new(0xffff, 0xffff, 0xffff, 0xf1f2, 0xfff3, 0xf4ff, 0xffff, 0xffff),
527 48
528 ),
529 Ip4Address::new(0xf1, 0xf2, 0xf3, 0xf4)
530 );
531 assert_eq!(
532 extract_ipv4_addr_from_ipv6(
533 Ip6Address::new(0xffff, 0xffff, 0xffff, 0xfff1, 0xfff2, 0xf3f4, 0xffff, 0xffff),
534 56
535 ),
536 Ip4Address::new(0xf1, 0xf2, 0xf3, 0xf4)
537 );
538 assert_eq!(
539 extract_ipv4_addr_from_ipv6(
540 Ip6Address::new(0xffff, 0xffff, 0xffff, 0xffff, 0xfff1, 0xf2f3, 0xf4ff, 0xffff),
541 64
542 ),
543 Ip4Address::new(0xf1, 0xf2, 0xf3, 0xf4)
544 );
545 assert_eq!(
546 extract_ipv4_addr_from_ipv6(
547 Ip6Address::new(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xf1f2, 0xf3f4),
548 96
549 ),
550 Ip4Address::new(0xf1, 0xf2, 0xf3, 0xf4)
551 );
552
553 assert_eq!(
555 extract_ipv4_addr_from_ipv6(
556 Ip6Address::new(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xf1f2, 0xf3f4),
557 44
558 ),
559 Ip4Address::new(0, 0, 0, 0)
560 );
561 }
562
563 #[test]
564 fn test_ipv6_nat64_ops() {
565 assert_eq!(
566 get_ipv6_prefix(
567 Ip6Address::new(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff),
568 0
569 ),
570 Some(Ip6Address::new(0, 0, 0, 0, 0, 0, 0, 0))
571 );
572 assert_eq!(
573 get_ipv6_prefix(
574 Ip6Address::new(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff),
575 16
576 ),
577 Some(Ip6Address::new(0xffff, 0, 0, 0, 0, 0, 0, 0))
578 );
579 assert_eq!(
580 get_ipv6_prefix(
581 Ip6Address::new(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff),
582 32
583 ),
584 Some(Ip6Address::new(0xffff, 0xffff, 0, 0, 0, 0, 0, 0))
585 );
586 assert_eq!(
587 get_ipv6_prefix(
588 Ip6Address::new(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff),
589 63
590 ),
591 Some(Ip6Address::new(0xffff, 0xffff, 0xffff, 0xfffe, 0, 0, 0, 0))
592 );
593 assert_eq!(
594 get_ipv6_prefix(
595 Ip6Address::new(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff),
596 64
597 ),
598 Some(Ip6Address::new(0xffff, 0xffff, 0xffff, 0xffff, 0, 0, 0, 0))
599 );
600 assert_eq!(
601 get_ipv6_prefix(
602 Ip6Address::new(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff),
603 65
604 ),
605 Some(Ip6Address::new(0xffff, 0xffff, 0xffff, 0xffff, 0x8000, 0, 0, 0))
606 );
607 assert_eq!(
608 get_ipv6_prefix(
609 Ip6Address::new(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff),
610 128
611 ),
612 Some(Ip6Address::new(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff))
613 );
614 assert_eq!(
615 get_ipv6_prefix(
616 Ip6Address::new(0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff),
617 129
618 ),
619 None
620 );
621 }
622}