1use crate::ip::IpNextProtocol;
2use crate::packet::{MutablePacket, Packet};
3use bytes::{BufMut, Bytes, BytesMut};
4use std::net::Ipv6Addr;
5
6#[cfg(feature = "serde")]
7use serde::{Deserialize, Serialize};
8
9pub const IPV6_HEADER_LEN: usize = 40;
10
11#[derive(Debug, Clone, PartialEq, Eq)]
12#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
13pub struct Ipv6Header {
14 pub version: u8, pub traffic_class: u8, pub flow_label: u32, pub payload_length: u16,
18 pub next_header: IpNextProtocol,
19 pub hop_limit: u8,
20 pub source: Ipv6Addr,
21 pub destination: Ipv6Addr,
22}
23
24#[derive(Debug, Clone, PartialEq, Eq)]
25pub struct Ipv6Packet {
26 pub header: Ipv6Header,
27 pub extensions: Vec<Ipv6ExtensionHeader>,
28 pub payload: Bytes,
29}
30
31impl Packet for Ipv6Packet {
32 type Header = Ipv6Header;
33
34 fn from_buf(bytes: &[u8]) -> Option<Self> {
35 if bytes.len() < IPV6_HEADER_LEN {
36 return None;
37 }
38
39 let version_traffic_flow = &bytes[..4];
41 let version = version_traffic_flow[0] >> 4;
42 let traffic_class =
43 ((version_traffic_flow[0] & 0x0F) << 4) | (version_traffic_flow[1] >> 4);
44 let flow_label = u32::from(version_traffic_flow[1] & 0x0F) << 16
45 | u32::from(version_traffic_flow[2]) << 8
46 | u32::from(version_traffic_flow[3]);
47
48 let payload_length = u16::from_be_bytes([bytes[4], bytes[5]]);
49 let mut next_header = IpNextProtocol::new(bytes[6]);
50 let hop_limit = bytes[7];
51
52 let source = Ipv6Addr::from(<[u8; 16]>::try_from(&bytes[8..24]).ok()?);
53 let destination = Ipv6Addr::from(<[u8; 16]>::try_from(&bytes[24..40]).ok()?);
54
55 let header = Ipv6Header {
56 version,
57 traffic_class,
58 flow_label,
59 payload_length,
60 next_header,
61 hop_limit,
62 source,
63 destination,
64 };
65
66 let mut offset = IPV6_HEADER_LEN;
68 let mut extensions = Vec::new();
69
70 loop {
71 match next_header {
72 IpNextProtocol::Hopopt
73 | IpNextProtocol::Ipv6Route
74 | IpNextProtocol::Ipv6Frag
75 | IpNextProtocol::Ipv6Opts => {
76 if offset + 2 > bytes.len() {
77 return None;
78 }
79
80 let nh = IpNextProtocol::new(bytes[offset]);
81 let ext_len = bytes[offset + 1] as usize;
82
83 match next_header {
84 IpNextProtocol::Hopopt | IpNextProtocol::Ipv6Opts => {
85 let total_len = 8 + ext_len * 8;
86 if offset + total_len > bytes.len() {
87 return None;
88 }
89
90 let data =
91 Bytes::copy_from_slice(&bytes[offset + 2..offset + total_len]);
92 let ext = match next_header {
93 IpNextProtocol::Hopopt => {
94 Ipv6ExtensionHeader::HopByHop { next: nh, data }
95 }
96 IpNextProtocol::Ipv6Opts => {
97 Ipv6ExtensionHeader::Destination { next: nh, data }
98 }
99 _ => Ipv6ExtensionHeader::Raw {
100 next: nh,
101 raw: Bytes::copy_from_slice(&bytes[offset..offset + total_len]),
102 },
103 };
104
105 extensions.push(ext);
106 next_header = nh;
107 offset += total_len;
108 }
109
110 IpNextProtocol::Ipv6Route => {
111 if offset + 4 > bytes.len() {
112 return None;
113 }
114
115 let routing_type = bytes[offset + 2];
116 let segments_left = bytes[offset + 3];
117 let total_len = 8 + ext_len * 8;
118 if offset + total_len > bytes.len() {
119 return None;
120 }
121
122 let data =
123 Bytes::copy_from_slice(&bytes[offset + 4..offset + total_len]);
124 extensions.push(Ipv6ExtensionHeader::Routing {
125 next: nh,
126 routing_type,
127 segments_left,
128 data,
129 });
130
131 next_header = nh;
132 offset += total_len;
133 }
134
135 IpNextProtocol::Ipv6Frag => {
136 if offset + 8 > bytes.len() {
137 return None;
138 }
139
140 let frag_off_flags =
142 u16::from_be_bytes([bytes[offset + 2], bytes[offset + 3]]);
143 let offset_val = frag_off_flags >> 3;
144 let more = (frag_off_flags & 0x1) != 0;
145 let id = u32::from_be_bytes([
146 bytes[offset + 4],
147 bytes[offset + 5],
148 bytes[offset + 6],
149 bytes[offset + 7],
150 ]);
151
152 extensions.push(Ipv6ExtensionHeader::Fragment {
153 next: nh,
154 offset: offset_val,
155 more,
156 id,
157 });
158
159 next_header = nh;
160 offset += 8;
161 }
162
163 _ => break,
164 }
165 }
166
167 _ => break,
168 }
169 }
170
171 let payload = Bytes::copy_from_slice(&bytes[offset..]);
172 Some(Ipv6Packet {
173 header,
174 extensions,
175 payload,
176 })
177 }
178 fn from_bytes(bytes: Bytes) -> Option<Self> {
179 Self::from_buf(&bytes)
180 }
181
182 fn to_bytes(&self) -> Bytes {
183 let mut buf = BytesMut::with_capacity(self.total_len());
184
185 let vtf_1 = (self.header.version << 4) | (self.header.traffic_class >> 4);
187 let vtf_2 =
188 ((self.header.traffic_class & 0x0F) << 4) | ((self.header.flow_label >> 16) as u8);
189 let vtf_3 = (self.header.flow_label >> 8) as u8;
190 let vtf_4 = self.header.flow_label as u8;
191
192 buf.put_u8(vtf_1);
193 buf.put_u8(vtf_2);
194 buf.put_u8(vtf_3);
195 buf.put_u8(vtf_4);
196 buf.put_u16(self.header.payload_length);
197 let first_next_header = self
199 .extensions
200 .first()
201 .map(|ext| ext.next_protocol())
202 .unwrap_or(self.header.next_header);
203 buf.put_u8(first_next_header.value());
204 buf.put_u8(self.header.hop_limit);
205 buf.extend_from_slice(&self.header.source.octets());
206 buf.extend_from_slice(&self.header.destination.octets());
207
208 for ext in &self.extensions {
210 match ext {
211 Ipv6ExtensionHeader::HopByHop { next, data }
212 | Ipv6ExtensionHeader::Destination { next, data } => {
213 let hdr_ext_len = ((data.len() + 6) / 8) as u8 - 1;
214 buf.put_u8(next.value());
215 buf.put_u8(hdr_ext_len);
216 buf.extend_from_slice(data);
217 while (2 + data.len()) % 8 != 0 {
219 buf.put_u8(0);
220 }
221 }
222
223 Ipv6ExtensionHeader::Routing {
224 next,
225 routing_type,
226 segments_left,
227 data,
228 } => {
229 let hdr_ext_len = ((data.len() + 4 + 6) / 8) as u8 - 1;
230 buf.put_u8(next.value());
231 buf.put_u8(hdr_ext_len);
232 buf.put_u8(*routing_type);
233 buf.put_u8(*segments_left);
234 buf.extend_from_slice(data);
235 while (4 + data.len()) % 8 != 0 {
236 buf.put_u8(0);
237 }
238 }
239
240 Ipv6ExtensionHeader::Fragment {
241 next,
242 offset,
243 more,
244 id,
245 } => {
246 buf.put_u8(next.value());
247 buf.put_u8(0); let offset_flags = (offset << 3) | if *more { 1 } else { 0 };
249 buf.put_u16(offset_flags);
250 buf.put_u32(*id);
251 }
252
253 Ipv6ExtensionHeader::Raw { next: _, raw } => {
254 buf.extend_from_slice(&raw[..]);
256 }
257 }
258 }
259
260 buf.extend_from_slice(&self.payload);
262
263 buf.freeze()
264 }
265
266 fn header(&self) -> Bytes {
267 self.to_bytes().slice(..IPV6_HEADER_LEN)
268 }
269
270 fn payload(&self) -> Bytes {
271 self.payload.clone()
272 }
273
274 fn header_len(&self) -> usize {
275 IPV6_HEADER_LEN
276 }
277
278 fn payload_len(&self) -> usize {
279 self.payload.len()
280 }
281
282 fn total_len(&self) -> usize {
283 self.header_len() + self.payload_len()
284 }
285
286 fn into_parts(self) -> (Self::Header, Bytes) {
287 (self.header, self.payload)
288 }
289}
290
291impl Ipv6Packet {
292 pub fn total_len(&self) -> usize {
293 IPV6_HEADER_LEN
294 + self.extensions.iter().map(|ext| ext.len()).sum::<usize>()
295 + self.payload.len()
296 }
297 pub fn get_extension(&self, kind: ExtensionHeaderType) -> Option<&Ipv6ExtensionHeader> {
298 self.extensions.iter().find(|ext| ext.kind() == kind)
299 }
300}
301
302pub struct MutableIpv6Packet<'a> {
304 buffer: &'a mut [u8],
305}
306
307impl<'a> MutablePacket<'a> for MutableIpv6Packet<'a> {
308 type Packet = Ipv6Packet;
309
310 fn new(buffer: &'a mut [u8]) -> Option<Self> {
311 if buffer.len() < IPV6_HEADER_LEN {
312 None
313 } else {
314 Some(Self { buffer })
315 }
316 }
317
318 fn packet(&self) -> &[u8] {
319 &*self.buffer
320 }
321
322 fn packet_mut(&mut self) -> &mut [u8] {
323 &mut *self.buffer
324 }
325
326 fn header(&self) -> &[u8] {
327 &self.packet()[..IPV6_HEADER_LEN]
328 }
329
330 fn header_mut(&mut self) -> &mut [u8] {
331 let (header, _) = (&mut *self.buffer).split_at_mut(IPV6_HEADER_LEN);
332 header
333 }
334
335 fn payload(&self) -> &[u8] {
336 &self.packet()[IPV6_HEADER_LEN..]
337 }
338
339 fn payload_mut(&mut self) -> &mut [u8] {
340 let (_, payload) = (&mut *self.buffer).split_at_mut(IPV6_HEADER_LEN);
341 payload
342 }
343}
344
345impl<'a> MutableIpv6Packet<'a> {
346 pub fn new_unchecked(buffer: &'a mut [u8]) -> Self {
348 Self { buffer }
349 }
350
351 fn raw(&self) -> &[u8] {
352 &*self.buffer
353 }
354
355 fn raw_mut(&mut self) -> &mut [u8] {
356 &mut *self.buffer
357 }
358
359 pub fn payload_len(&self) -> usize {
360 self.raw().len().saturating_sub(IPV6_HEADER_LEN)
361 }
362
363 pub fn get_version(&self) -> u8 {
364 self.raw()[0] >> 4
365 }
366
367 pub fn set_version(&mut self, version: u8) {
368 let buf = self.raw_mut();
369 buf[0] = (buf[0] & 0x0F) | ((version & 0x0F) << 4);
370 }
371
372 pub fn get_traffic_class(&self) -> u8 {
373 ((self.raw()[0] & 0x0F) << 4) | (self.raw()[1] >> 4)
374 }
375
376 pub fn set_traffic_class(&mut self, class: u8) {
377 let buf = self.raw_mut();
378 buf[0] = (buf[0] & 0xF0) | ((class >> 4) & 0x0F);
379 buf[1] = (buf[1] & 0x0F) | ((class & 0x0F) << 4);
380 }
381
382 pub fn get_flow_label(&self) -> u32 {
383 let buf = self.raw();
384 let high = (buf[1] as u32 & 0x0F) << 16;
385 let mid = (buf[2] as u32) << 8;
386 let low = buf[3] as u32;
387 high | mid | low
388 }
389
390 pub fn set_flow_label(&mut self, label: u32) {
391 let buf = self.raw_mut();
392 buf[1] = (buf[1] & 0xF0) | (((label >> 16) as u8) & 0x0F);
393 buf[2] = (label >> 8) as u8;
394 buf[3] = label as u8;
395 }
396
397 pub fn get_payload_length(&self) -> u16 {
398 u16::from_be_bytes([self.raw()[4], self.raw()[5]])
399 }
400
401 pub fn set_payload_length(&mut self, length: u16) {
402 self.raw_mut()[4..6].copy_from_slice(&length.to_be_bytes());
403 }
404
405 pub fn get_next_header(&self) -> IpNextProtocol {
406 IpNextProtocol::new(self.raw()[6])
407 }
408
409 pub fn set_next_header(&mut self, proto: IpNextProtocol) {
410 self.raw_mut()[6] = proto.value();
411 }
412
413 pub fn get_hop_limit(&self) -> u8 {
414 self.raw()[7]
415 }
416
417 pub fn set_hop_limit(&mut self, value: u8) {
418 self.raw_mut()[7] = value;
419 }
420
421 pub fn get_source(&self) -> Ipv6Addr {
422 Ipv6Addr::from(<[u8; 16]>::try_from(&self.raw()[8..24]).unwrap())
423 }
424
425 pub fn set_source(&mut self, addr: Ipv6Addr) {
426 self.raw_mut()[8..24].copy_from_slice(&addr.octets());
427 }
428
429 pub fn get_destination(&self) -> Ipv6Addr {
430 Ipv6Addr::from(<[u8; 16]>::try_from(&self.raw()[24..40]).unwrap())
431 }
432
433 pub fn set_destination(&mut self, addr: Ipv6Addr) {
434 self.raw_mut()[24..40].copy_from_slice(&addr.octets());
435 }
436}
437
438#[derive(Debug, Clone, PartialEq, Eq)]
439pub enum ExtensionHeaderType {
440 HopByHop,
441 Destination,
442 Routing,
443 Fragment,
444 Unknown(u8),
445}
446
447#[derive(Debug, Clone, PartialEq, Eq)]
448pub enum Ipv6ExtensionHeader {
449 HopByHop {
450 next: IpNextProtocol,
451 data: Bytes,
452 },
453 Destination {
454 next: IpNextProtocol,
455 data: Bytes,
456 },
457 Routing {
458 next: IpNextProtocol,
459 routing_type: u8,
460 segments_left: u8,
461 data: Bytes,
462 },
463 Fragment {
464 next: IpNextProtocol,
465 offset: u16,
466 more: bool,
467 id: u32,
468 },
469 Raw {
470 next: IpNextProtocol,
471 raw: Bytes,
472 },
473}
474
475impl Ipv6ExtensionHeader {
476 pub fn next_protocol(&self) -> IpNextProtocol {
477 match self {
478 Ipv6ExtensionHeader::HopByHop { next, .. } => *next,
479 Ipv6ExtensionHeader::Destination { next, .. } => *next,
480 Ipv6ExtensionHeader::Routing { next, .. } => *next,
481 Ipv6ExtensionHeader::Fragment { next, .. } => *next,
482 Ipv6ExtensionHeader::Raw { next, .. } => *next,
483 }
484 }
485 pub fn len(&self) -> usize {
486 match self {
487 Ipv6ExtensionHeader::HopByHop { data, .. }
488 | Ipv6ExtensionHeader::Destination { data, .. } => {
489 let base = 2 + data.len();
490 (base + 7) / 8 * 8 }
492 Ipv6ExtensionHeader::Routing { data, .. } => {
493 let base = 4 + data.len();
494 (base + 7) / 8 * 8
495 }
496 Ipv6ExtensionHeader::Fragment { .. } => 8,
497 Ipv6ExtensionHeader::Raw { raw, .. } => raw.len(),
498 }
499 }
500 pub fn kind(&self) -> ExtensionHeaderType {
501 match self {
502 Ipv6ExtensionHeader::HopByHop { .. } => ExtensionHeaderType::HopByHop,
503 Ipv6ExtensionHeader::Destination { .. } => ExtensionHeaderType::Destination,
504 Ipv6ExtensionHeader::Routing { .. } => ExtensionHeaderType::Routing,
505 Ipv6ExtensionHeader::Fragment { .. } => ExtensionHeaderType::Fragment,
506 Ipv6ExtensionHeader::Raw { raw, .. } => {
507 let kind = raw.get(0).copied().unwrap_or(0xff);
509 match kind {
510 0 => ExtensionHeaderType::HopByHop,
511 43 => ExtensionHeaderType::Routing,
512 44 => ExtensionHeaderType::Fragment,
513 60 => ExtensionHeaderType::Destination,
514 other => ExtensionHeaderType::Unknown(other),
515 }
516 }
517 }
518 }
519}
520
521#[cfg(test)]
522mod tests {
523 use super::*;
524 use crate::ip::IpNextProtocol;
525 use std::net::Ipv6Addr;
526
527 #[test]
528 fn test_ipv6_basic_header_fields() {
529 let header = Ipv6Header {
530 version: 6,
531 traffic_class: 0xaa,
532 flow_label: 0x12345,
533 payload_length: 0,
534 next_header: IpNextProtocol::Udp,
535 hop_limit: 64,
536 source: Ipv6Addr::LOCALHOST,
537 destination: Ipv6Addr::UNSPECIFIED,
538 };
539
540 let packet = Ipv6Packet {
541 header: header.clone(),
542 extensions: vec![],
543 payload: Bytes::new(),
544 };
545
546 assert_eq!(packet.header.version, 6);
547 assert_eq!(packet.header.traffic_class, 0xaa);
548 assert_eq!(packet.header.flow_label, 0x12345);
549 assert_eq!(packet.header.payload_length, 0);
550 assert_eq!(packet.header.next_header, IpNextProtocol::Udp);
551 assert_eq!(packet.header.hop_limit, 64);
552 assert_eq!(packet.header.source, Ipv6Addr::LOCALHOST);
553 assert_eq!(packet.header.destination, Ipv6Addr::UNSPECIFIED);
554
555 let raw = packet.to_bytes();
556 assert_eq!(raw.len(), IPV6_HEADER_LEN);
557 let reparsed = Ipv6Packet::from_bytes(raw.clone()).unwrap();
558 assert_eq!(reparsed.header, packet.header);
559 }
560
561 #[test]
562 fn test_ipv6_from_bytes_parsing() {
563 use bytes::Bytes;
564
565 let raw_bytes = Bytes::from_static(&[
566 0x60, 0xA1, 0x23, 0x45, 0x00, 0x08, 0x06, 0x40, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1a, 0x2b, 0xff, 0xfe, 0x1a,
572 0x2b, 0x3c, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
574 0x00, 0x02, b'H', b'e', b'l', b'l', b'o', b'!', b'!', b'\n',
576 ]);
577
578 let parsed = Ipv6Packet::from_bytes(raw_bytes.clone()).expect("should parse successfully");
579
580 assert_eq!(parsed.header.version, 6);
581 assert_eq!(parsed.header.traffic_class, 0xa);
582 assert_eq!(parsed.header.flow_label, 0x12345);
583 assert_eq!(parsed.header.payload_length, 8);
584 assert_eq!(parsed.header.next_header, IpNextProtocol::Tcp);
585 assert_eq!(parsed.header.hop_limit, 0x40);
586 assert_eq!(
587 parsed.header.source,
588 "fe80::21a:2bff:fe1a:2b3c".parse::<Ipv6Addr>().unwrap()
589 );
590 assert_eq!(
591 parsed.header.destination,
592 "ff02::2".parse::<Ipv6Addr>().unwrap()
593 );
594 assert_eq!(&parsed.payload[..], b"Hello!!\n");
595 assert_eq!(parsed.extensions.len(), 0);
596 assert_eq!(parsed.to_bytes(), raw_bytes);
597 }
598
599 #[test]
600 fn test_ipv6_payload_roundtrip() {
601 use bytes::Bytes;
602
603 let payload = Bytes::from_static(b"HELLO_WORLDS");
604 let packet = Ipv6Packet {
605 header: super::Ipv6Header {
606 version: 6,
607 traffic_class: 0,
608 flow_label: 0,
609 payload_length: payload.len() as u16,
610 next_header: IpNextProtocol::Tcp,
611 hop_limit: 32,
612 source: Ipv6Addr::LOCALHOST,
613 destination: Ipv6Addr::LOCALHOST,
614 },
615 extensions: vec![],
616 payload: payload.clone(),
617 };
618
619 let raw = packet.to_bytes();
620 let parsed = Ipv6Packet::from_bytes(raw.clone()).unwrap();
621
622 assert_eq!(parsed.header, packet.header);
623 assert_eq!(parsed.payload, payload);
624 assert_eq!(raw.len(), packet.total_len());
625 }
626
627 #[test]
628 fn test_ipv6_truncated_packet_rejected() {
629 use bytes::Bytes;
630
631 let short = Bytes::from_static(&[0u8; 20]); assert!(Ipv6Packet::from_bytes(short).is_none());
633 }
634
635 #[test]
636 fn test_ipv6_total_len_computation() {
637 use bytes::Bytes;
638
639 let ext = Ipv6ExtensionHeader::Fragment {
640 next: IpNextProtocol::Tcp,
641 offset: 1,
642 more: true,
643 id: 42,
644 };
645
646 let packet = Ipv6Packet {
647 header: Ipv6Header {
648 version: 6,
649 traffic_class: 0,
650 flow_label: 0,
651 payload_length: 8,
652 next_header: IpNextProtocol::Tcp,
653 hop_limit: 1,
654 source: Ipv6Addr::LOCALHOST,
655 destination: Ipv6Addr::LOCALHOST,
656 },
657 extensions: vec![ext],
658 payload: Bytes::from_static(b"ABCDEFGH"),
659 };
660
661 let expected_len = IPV6_HEADER_LEN + 8 + 8; assert_eq!(packet.total_len(), expected_len);
663 assert_eq!(packet.to_bytes().len(), expected_len);
664 }
665
666 #[test]
667 fn test_extension_kind_known_variants() {
668 let hop = Ipv6ExtensionHeader::HopByHop {
669 next: IpNextProtocol::Tcp,
670 data: Bytes::from_static(&[1, 2, 3, 4]),
671 };
672 assert_eq!(hop.kind(), ExtensionHeaderType::HopByHop);
673
674 let dst = Ipv6ExtensionHeader::Destination {
675 next: IpNextProtocol::Udp,
676 data: Bytes::from_static(&[9, 8, 7]),
677 };
678 assert_eq!(dst.kind(), ExtensionHeaderType::Destination);
679
680 let route = Ipv6ExtensionHeader::Routing {
681 next: IpNextProtocol::Tcp,
682 routing_type: 0,
683 segments_left: 0,
684 data: Bytes::from_static(&[1, 2, 3]),
685 };
686 assert_eq!(route.kind(), ExtensionHeaderType::Routing);
687
688 let frag = Ipv6ExtensionHeader::Fragment {
689 next: IpNextProtocol::Udp,
690 offset: 0,
691 more: false,
692 id: 12345,
693 };
694 assert_eq!(frag.kind(), ExtensionHeaderType::Fragment);
695 }
696
697 #[test]
698 fn test_extension_kind_raw_known() {
699 let raw_routing = Ipv6ExtensionHeader::Raw {
700 next: IpNextProtocol::new(43),
701 raw: Bytes::from_static(&[43, 1, 2, 3]),
702 };
703 assert_eq!(raw_routing.kind(), ExtensionHeaderType::Routing);
704
705 let raw_frag = Ipv6ExtensionHeader::Raw {
706 next: IpNextProtocol::new(44),
707 raw: Bytes::from_static(&[44, 0, 0, 0]),
708 };
709 assert_eq!(raw_frag.kind(), ExtensionHeaderType::Fragment);
710 }
711
712 #[test]
713 fn test_extension_kind_raw_unknown() {
714 let raw_unknown = Ipv6ExtensionHeader::Raw {
715 next: IpNextProtocol::new(250),
716 raw: Bytes::from_static(&[250, 0, 1, 2]),
717 };
718 assert_eq!(raw_unknown.kind(), ExtensionHeaderType::Unknown(250));
719 }
720
721 #[test]
722 fn test_mutable_ipv6_packet_mutations() {
723 let mut raw = [
724 0x60, 0x00, 0x00, 0x00, 0x00, 0x04, 0x11, 0x40, 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0xde, 0xad, 0xbe, 0xef,
732 ];
733
734 let mut packet = MutableIpv6Packet::new(&mut raw).expect("mutable ipv6");
735 assert_eq!(packet.get_version(), 6);
736 packet.set_hop_limit(0x7f);
737 packet.set_next_header(IpNextProtocol::Tcp);
738 packet.set_flow_label(0x12345);
739 packet.set_source(Ipv6Addr::LOCALHOST);
740 packet.payload_mut()[0] = 0xaa;
741
742 let frozen = packet.freeze().expect("freeze");
743 assert_eq!(frozen.header.hop_limit, 0x7f);
744 assert_eq!(frozen.header.next_header, IpNextProtocol::Tcp);
745 assert_eq!(frozen.header.flow_label, 0x12345);
746 assert_eq!(frozen.header.source, Ipv6Addr::LOCALHOST);
747 assert_eq!(frozen.payload[0], 0xaa);
748 }
749}