1use crate::{
8 GPAddr, MonotonicInstant, NullableHandle, Signals, Status, VcpuContents, guest, ok, sys,
9};
10use bitflags::bitflags;
11use std::mem;
12
13#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
18#[repr(transparent)]
19pub struct Port(NullableHandle);
20impl_handle_based!(Port);
21
22bitflags! {
23 pub struct PortOptions: u32 {
25 const BIND_TO_INTERRUPT = sys::ZX_PORT_BIND_TO_INTERRUPT;
26 }
27}
28
29#[derive(Debug, Copy, Clone, Eq, PartialEq)]
31pub enum PacketContents {
32 User(UserPacket),
34 SignalOne(SignalPacket),
36 GuestBell(GuestBellPacket),
38 GuestMem(GuestMemPacket),
40 GuestIo(GuestIoPacket),
42 GuestVcpu(GuestVcpuPacket),
44 Pager(PagerPacket),
46 Interrupt(InterruptPacket),
48 PowerTransition(PowerTransitionPacket),
51
52 #[doc(hidden)]
53 __Nonexhaustive,
54}
55
56#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
59pub struct UserPacket(sys::zx_packet_user_t);
60
61#[derive(Copy, Clone, Debug, Eq, PartialEq)]
64pub struct SignalPacket(sys::zx_packet_signal_t);
65
66#[derive(Copy, Clone, Debug, Eq, PartialEq)]
69pub struct GuestBellPacket(sys::zx_packet_guest_bell_t);
70
71#[derive(Copy, Clone, Debug, Eq, PartialEq)]
74pub struct GuestMemPacket(sys::zx_packet_guest_mem_t);
75
76#[derive(Copy, Clone, Debug, Eq, PartialEq)]
79pub struct GuestIoPacket(sys::zx_packet_guest_io_t);
80
81#[derive(Copy, Clone, Debug, Eq, PartialEq)]
84pub struct GuestVcpuPacket(sys::zx_packet_guest_vcpu_t);
85
86#[derive(Copy, Clone, Debug, Eq, PartialEq)]
89pub struct PagerPacket(sys::zx_packet_page_request_t);
90
91#[derive(Copy, Clone, Debug, Eq, PartialEq)]
94pub struct InterruptPacket(sys::zx_packet_interrupt_t);
95
96#[derive(Copy, Clone, Debug, Eq, PartialEq)]
99pub struct PowerTransitionPacket(sys::zx_packet_processor_power_level_transition_request_t);
100
101#[derive(PartialEq, Eq, Debug)]
104pub struct Packet(pub(crate) sys::zx_port_packet_t);
105
106impl Packet {
107 pub fn from_user_packet(key: u64, status: i32, user: UserPacket) -> Packet {
109 Packet(sys::zx_port_packet_t {
110 key: key,
111 packet_type: sys::zx_packet_type_t::ZX_PKT_TYPE_USER,
112 status: status,
113 union: user.0,
114 })
115 }
116
117 pub fn from_guest_mem_packet(key: u64, status: i32, mem: GuestMemPacket) -> Packet {
119 let mut raw = sys::zx_port_packet_t {
120 key,
121 packet_type: sys::zx_packet_type_t::ZX_PKT_TYPE_GUEST_MEM,
122 status,
123 union: Default::default(),
124 };
125 let bytes: &[u8; std::mem::size_of::<sys::zx_packet_guest_mem_t>()] =
133 unsafe { mem::transmute(&mem.0) };
134 raw.union[0..std::mem::size_of::<sys::zx_packet_guest_mem_t>()].copy_from_slice(bytes);
135 Packet(raw)
136 }
137
138 pub fn from_guest_io_packet(key: u64, status: i32, io: GuestIoPacket) -> Packet {
140 let mut raw = sys::zx_port_packet_t {
141 key,
142 packet_type: sys::zx_packet_type_t::ZX_PKT_TYPE_GUEST_IO,
143 status,
144 union: Default::default(),
145 };
146 let bytes: &[u8; std::mem::size_of::<sys::zx_packet_guest_io_t>()] =
149 unsafe { mem::transmute(&io.0) };
150 raw.union[0..std::mem::size_of::<sys::zx_packet_guest_io_t>()].copy_from_slice(bytes);
151 Packet(raw)
152 }
153
154 pub fn from_guest_vcpu_packet(key: u64, status: i32, vcpu: GuestVcpuPacket) -> Packet {
156 Packet(sys::zx_port_packet_t {
157 key,
158 packet_type: sys::zx_packet_type_t::ZX_PKT_TYPE_GUEST_VCPU,
159 status,
160 union: unsafe { mem::transmute_copy(&vcpu.0) },
161 })
162 }
163
164 pub fn from_power_transition_packet(
166 key: u64,
167 status: i32,
168 power_transition_packet: PowerTransitionPacket,
169 ) -> Packet {
170 Packet(sys::zx_port_packet_t {
171 key: key,
172 packet_type:
173 sys::zx_packet_type_t::ZX_PKT_TYPE_PROCESSOR_POWER_LEVEL_TRANSITION_REQUEST,
174 status: status,
175 union: unsafe { mem::transmute_copy(&power_transition_packet.0) },
176 })
177 }
178
179 pub fn key(&self) -> u64 {
181 self.0.key
182 }
183
184 pub fn status(&self) -> i32 {
187 self.0.status
188 }
189
190 pub fn contents(&self) -> PacketContents {
192 match self.0.packet_type {
193 sys::zx_packet_type_t::ZX_PKT_TYPE_USER => {
194 PacketContents::User(UserPacket(self.0.union))
195 }
196
197 sys::zx_packet_type_t::ZX_PKT_TYPE_SIGNAL_ONE => {
198 PacketContents::SignalOne(SignalPacket(unsafe {
199 mem::transmute_copy(&self.0.union)
200 }))
201 }
202
203 sys::zx_packet_type_t::ZX_PKT_TYPE_GUEST_BELL => {
204 PacketContents::GuestBell(GuestBellPacket(unsafe {
205 mem::transmute_copy(&self.0.union)
206 }))
207 }
208
209 sys::zx_packet_type_t::ZX_PKT_TYPE_GUEST_MEM => {
210 PacketContents::GuestMem(GuestMemPacket(unsafe {
211 mem::transmute_copy(&self.0.union)
212 }))
213 }
214
215 sys::zx_packet_type_t::ZX_PKT_TYPE_GUEST_IO => {
216 PacketContents::GuestIo(GuestIoPacket(unsafe {
217 mem::transmute_copy(&self.0.union)
218 }))
219 }
220
221 sys::zx_packet_type_t::ZX_PKT_TYPE_GUEST_VCPU => {
222 PacketContents::GuestVcpu(GuestVcpuPacket(unsafe {
223 mem::transmute_copy(&self.0.union)
224 }))
225 }
226
227 sys::zx_packet_type_t::ZX_PKT_TYPE_PAGE_REQUEST => {
228 PacketContents::Pager(PagerPacket(unsafe { mem::transmute_copy(&self.0.union) }))
229 }
230
231 sys::zx_packet_type_t::ZX_PKT_TYPE_INTERRUPT => {
232 PacketContents::Interrupt(InterruptPacket(unsafe {
233 mem::transmute_copy(&self.0.union)
234 }))
235 }
236
237 sys::zx_packet_type_t::ZX_PKT_TYPE_PROCESSOR_POWER_LEVEL_TRANSITION_REQUEST => {
238 PacketContents::PowerTransition(PowerTransitionPacket(unsafe {
239 mem::transmute_copy(&self.0.union)
240 }))
241 }
242
243 _ => panic!("unexpected packet type"),
244 }
245 }
246}
247
248impl UserPacket {
249 pub fn from_u8_array(val: [u8; 32]) -> UserPacket {
250 UserPacket(val)
251 }
252
253 pub fn as_u8_array(&self) -> &[u8; 32] {
254 &self.0
255 }
256
257 pub fn as_mut_u8_array(&mut self) -> &mut [u8; 32] {
258 &mut self.0
259 }
260}
261
262impl SignalPacket {
263 pub fn trigger(&self) -> Signals {
265 Signals::from_bits_truncate(self.0.trigger)
266 }
267
268 pub fn observed(&self) -> Signals {
270 Signals::from_bits_truncate(self.0.observed)
271 }
272
273 pub fn count(&self) -> u64 {
275 self.0.count
276 }
277
278 pub fn timestamp(&self) -> sys::zx_time_t {
280 self.0.timestamp
281 }
282
283 pub fn raw_packet(&self) -> &sys::zx_packet_signal_t {
285 &self.0
286 }
287}
288
289impl GuestBellPacket {
290 pub fn addr(&self) -> GPAddr {
292 GPAddr(self.0.addr)
293 }
294}
295
296impl GuestMemPacket {
297 pub fn from_raw(mem: sys::zx_packet_guest_mem_t) -> GuestMemPacket {
298 GuestMemPacket(mem)
299 }
300
301 pub fn addr(&self) -> GPAddr {
303 GPAddr(self.0.addr)
304 }
305}
306
307#[cfg(target_arch = "aarch64")]
308impl GuestMemPacket {
309 pub fn access_size(&self) -> Option<guest::MemAccessSize> {
313 match self.0.access_size {
314 1 => Some(guest::MemAccessSize::Bits8),
315 2 => Some(guest::MemAccessSize::Bits16),
316 4 => Some(guest::MemAccessSize::Bits32),
317 8 => Some(guest::MemAccessSize::Bits64),
318 _ => None,
319 }
320 }
321
322 pub fn sign_extend(&self) -> bool {
324 self.0.sign_extend
325 }
326
327 pub fn reg(&self) -> u8 {
329 self.0.xt
330 }
331
332 pub fn data(&self) -> Option<guest::MemData> {
334 if let guest::AccessType::Write = self.access_type() {
335 self.access_size().map(|size| match size {
336 guest::MemAccessSize::Bits8 => guest::MemData::Data8(self.0.data as u8),
337 guest::MemAccessSize::Bits16 => guest::MemData::Data16(self.0.data as u16),
338 guest::MemAccessSize::Bits32 => guest::MemData::Data32(self.0.data as u32),
339 guest::MemAccessSize::Bits64 => guest::MemData::Data64(self.0.data),
340 })
341 } else {
342 None
343 }
344 }
345
346 pub fn access_type(&self) -> guest::AccessType {
348 match self.0.read {
349 true => guest::AccessType::Read,
350 false => guest::AccessType::Write,
351 }
352 }
353}
354
355#[cfg(target_arch = "x86_64")]
356impl GuestMemPacket {
357 pub fn default_operand_size(&self) -> Option<guest::CSDefaultOperandSize> {
361 match self.0.default_operand_size {
363 2 => Some(guest::CSDefaultOperandSize::Bits16),
364 4 => Some(guest::CSDefaultOperandSize::Bits32),
365 _ => None,
366 }
367 }
368}
369
370impl GuestIoPacket {
371 pub fn from_raw(io: sys::zx_packet_guest_io_t) -> GuestIoPacket {
372 GuestIoPacket(io)
373 }
374
375 pub fn port(&self) -> u16 {
377 self.0.port
378 }
379
380 pub fn access_size(&self) -> Option<guest::PortAccessSize> {
384 match self.0.access_size {
385 1 => Some(guest::PortAccessSize::Bits8),
386 2 => Some(guest::PortAccessSize::Bits16),
387 4 => Some(guest::PortAccessSize::Bits32),
388 _ => None,
389 }
390 }
391
392 pub fn access_type(&self) -> guest::AccessType {
394 match self.0.input {
395 true => guest::AccessType::Read,
396 false => guest::AccessType::Write,
397 }
398 }
399
400 pub fn data(&self) -> Option<guest::PortData> {
402 if let guest::AccessType::Write = self.access_type() {
403 self.access_size().map(|size| match size {
404 guest::PortAccessSize::Bits8 => guest::PortData::Data8(self.0.data[0]),
405 guest::PortAccessSize::Bits16 => {
406 guest::PortData::Data16(u16::from_ne_bytes([self.0.data[0], self.0.data[1]]))
407 }
408 guest::PortAccessSize::Bits32 => {
409 guest::PortData::Data32(u32::from_ne_bytes(self.0.data))
410 }
411 })
412 } else {
413 None
414 }
415 }
416}
417
418impl GuestVcpuPacket {
419 pub fn from_raw(vcpu: sys::zx_packet_guest_vcpu_t) -> GuestVcpuPacket {
420 GuestVcpuPacket(vcpu)
421 }
422
423 pub fn contents(&self) -> VcpuContents {
424 match self.0.r#type {
425 sys::zx_packet_guest_vcpu_type_t::ZX_PKT_GUEST_VCPU_INTERRUPT => unsafe {
426 VcpuContents::Interrupt {
427 mask: self.0.union.interrupt.mask,
428 vector: self.0.union.interrupt.vector,
429 }
430 },
431 sys::zx_packet_guest_vcpu_type_t::ZX_PKT_GUEST_VCPU_STARTUP => unsafe {
432 VcpuContents::Startup {
433 target: self.0.union.startup.target,
434 entry: self.0.union.startup.entry,
435 context: self.0.union.startup.context,
436 }
437 },
438 _ => panic!("unexpected VCPU packet type"),
439 }
440 }
441}
442
443impl PagerPacket {
444 pub fn command(&self) -> sys::zx_page_request_command_t {
446 self.0.command
447 }
448
449 pub fn range(&self) -> std::ops::Range<u64> {
451 self.0.offset..self.0.offset + self.0.length
452 }
453}
454
455impl InterruptPacket {
456 pub fn timestamp(&self) -> sys::zx_time_t {
457 self.0.timestamp
458 }
459}
460
461impl PowerTransitionPacket {
462 pub fn from_raw(
463 packet: sys::zx_packet_processor_power_level_transition_request_t,
464 ) -> PowerTransitionPacket {
465 PowerTransitionPacket(packet)
466 }
467
468 pub fn domain_id(&self) -> u32 {
469 self.0.domain_id
470 }
471
472 pub fn options(&self) -> u32 {
473 self.0.options
474 }
475
476 pub fn control_interface(&self) -> u64 {
477 self.0.control_interface
478 }
479
480 pub fn control_argument(&self) -> u64 {
481 self.0.control_argument
482 }
483}
484
485impl Port {
486 pub fn create() -> Self {
497 Self::create_with_opts(PortOptions::from_bits_truncate(0))
498 }
499
500 pub fn create_with_opts(opts: PortOptions) -> Self {
501 unsafe {
502 let mut handle = 0;
503 let status = sys::zx_port_create(opts.bits(), &mut handle);
504 ok(status).expect(
505 "port creation always succeeds except with OOM or when job policy denies it",
506 );
507 NullableHandle::from_raw(handle).into()
508 }
509 }
510
511 pub fn queue(&self, packet: &Packet) -> Result<(), Status> {
517 let status =
518 unsafe { sys::zx_port_queue(self.raw_handle(), std::ptr::from_ref(&packet.0)) };
519 ok(status)
520 }
521
522 pub fn wait(&self, deadline: MonotonicInstant) -> Result<Packet, Status> {
528 let mut packet = Default::default();
529 ok(unsafe { sys::zx_port_wait(self.raw_handle(), deadline.into_nanos(), &mut packet) })?;
530 Ok(Packet(packet))
531 }
532
533 pub fn cancel(&self, key: u64) -> Result<(), Status> {
539 let options = 0;
540 let status = unsafe { sys::zx_port_cancel_key(self.raw_handle(), options, key) };
541 ok(status)
542 }
543}
544
545bitflags! {
546 #[repr(transparent)]
548 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
549 pub struct WaitAsyncOpts: u32 {
550 const TIMESTAMP = sys::ZX_WAIT_ASYNC_TIMESTAMP;
552
553 const BOOT_TIMESTAMP = sys::ZX_WAIT_ASYNC_BOOT_TIMESTAMP;
555
556 const EDGE_TRIGGERED = sys::ZX_WAIT_ASYNC_EDGE;
559 }
560}
561
562#[cfg(test)]
563mod tests {
564 use super::*;
565 use crate::{Duration, Event};
566 use assert_matches::assert_matches;
567
568 #[test]
569 fn port_basic() {
570 let ten_ms = Duration::from_millis(10);
571
572 let port = Port::create();
573
574 assert_eq!(port.wait(MonotonicInstant::after(ten_ms)), Err(Status::TIMED_OUT));
576
577 let packet = Packet::from_user_packet(42, 123, UserPacket::from_u8_array([13; 32]));
579 assert!(port.queue(&packet).is_ok());
580
581 let read_packet = port.wait(MonotonicInstant::after(ten_ms)).unwrap();
583 assert_eq!(read_packet, packet);
584 }
585
586 #[test]
587 fn create_with_opts() {
588 let _port = Port::create_with_opts(PortOptions::BIND_TO_INTERRUPT);
589 }
590
591 #[test]
592 fn wait_async_once() {
593 let ten_ms = Duration::from_millis(10);
594 let key = 42;
595
596 let port = Port::create();
597 let event = Event::create();
598 let no_opts = WaitAsyncOpts::empty();
599
600 assert!(event.wait_async(&port, key, Signals::USER_0 | Signals::USER_1, no_opts).is_ok());
601
602 assert_eq!(port.wait(MonotonicInstant::after(ten_ms)), Err(Status::TIMED_OUT));
604
605 assert!(event.signal(Signals::NONE, Signals::USER_0).is_ok());
607 let read_packet = port.wait(MonotonicInstant::after(ten_ms)).unwrap();
608 assert_eq!(read_packet.key(), key);
609 assert_eq!(read_packet.status(), 0);
610 match read_packet.contents() {
611 PacketContents::SignalOne(sig) => {
612 assert_eq!(sig.trigger(), Signals::USER_0 | Signals::USER_1);
613 assert_eq!(sig.observed(), Signals::USER_0);
614 assert_eq!(sig.count(), 1);
615 }
616 _ => panic!("wrong packet type"),
617 }
618
619 assert_eq!(port.wait(MonotonicInstant::after(ten_ms)), Err(Status::TIMED_OUT));
621
622 assert!(event.wait_async(&port, key, Signals::USER_0, no_opts).is_ok());
624 let read_packet = port.wait(MonotonicInstant::after(ten_ms)).unwrap();
625 assert_eq!(read_packet.key(), key);
626 assert_eq!(read_packet.status(), 0);
627 match read_packet.contents() {
628 PacketContents::SignalOne(sig) => {
629 assert_eq!(sig.trigger(), Signals::USER_0);
630 assert_eq!(sig.observed(), Signals::USER_0);
631 assert_eq!(sig.count(), 1);
632 }
633 _ => panic!("wrong packet type"),
634 }
635
636 assert!(event.wait_async(&port, key, Signals::USER_0, no_opts).is_ok());
639 assert!(port.cancel(key).is_ok());
640 assert_eq!(port.wait(MonotonicInstant::after(ten_ms)), Err(Status::TIMED_OUT));
641
642 assert!(event.signal(Signals::USER_0, Signals::NONE).is_ok()); assert!(event.wait_async(&port, key, Signals::USER_0, no_opts).is_ok());
645 assert!(port.cancel(key).is_ok());
646 assert!(event.signal(Signals::NONE, Signals::USER_0).is_ok());
647 assert_eq!(port.wait(MonotonicInstant::after(ten_ms)), Err(Status::TIMED_OUT));
648 }
649
650 #[test]
651 fn guest_mem_packet() {
652 #[cfg(target_arch = "x86_64")]
653 let guest_mem_packet = sys::zx_packet_guest_mem_t {
654 addr: 0xaaaabbbbccccdddd,
655 cr3: 0x0123456789abcdef,
656 rip: 0xffffffff00000000,
657 instruction_size: 8,
658 default_operand_size: 2,
659 };
660 #[cfg(target_arch = "aarch64")]
661 let guest_mem_packet = sys::zx_packet_guest_mem_t {
662 addr: 0x8877665544332211,
663 access_size: 8,
664 sign_extend: true,
665 xt: 0xf3,
666 read: false,
667 data: 0x1122334455667788,
668 };
669 #[cfg(target_arch = "riscv64")]
670 let guest_mem_packet = {
671 let mut ret = sys::zx_packet_guest_mem_t::default();
672 ret.addr = 0x8877665544332211;
673 ret
674 };
675 const KEY: u64 = 0x5555555555555555;
676 const STATUS: i32 = sys::ZX_ERR_INTERNAL;
677
678 let packet =
679 Packet::from_guest_mem_packet(KEY, STATUS, GuestMemPacket::from_raw(guest_mem_packet));
680
681 assert_matches!(packet.contents(), PacketContents::GuestMem(GuestMemPacket(packet)) if packet == guest_mem_packet);
682 assert_eq!(packet.key(), KEY);
683 assert_eq!(packet.status(), STATUS);
684 }
685
686 #[test]
687 fn guest_io_packet() {
688 const GUEST_IO_PACKET: sys::zx_packet_guest_io_t = sys::zx_packet_guest_io_t {
689 port: 0xabcd,
690 access_size: 4,
691 input: true,
692 data: [0xaa, 0xbb, 0xcc, 0xdd],
693 };
694 const KEY: u64 = 0x0123456789abcdef;
695 const STATUS: i32 = sys::ZX_ERR_NO_RESOURCES;
696
697 let packet =
698 Packet::from_guest_io_packet(KEY, STATUS, GuestIoPacket::from_raw(GUEST_IO_PACKET));
699
700 assert_matches!(packet.contents(), PacketContents::GuestIo(GuestIoPacket(packet)) if packet == GUEST_IO_PACKET);
701 assert_eq!(packet.key(), KEY);
702 assert_eq!(packet.status(), STATUS);
703 }
704
705 #[test]
706 fn guest_vcpu_interrupt_packet() {
707 let mut guest_vcpu_packet = sys::zx_packet_guest_vcpu_t::default();
709 guest_vcpu_packet.r#type = sys::zx_packet_guest_vcpu_type_t::ZX_PKT_GUEST_VCPU_INTERRUPT;
710 guest_vcpu_packet.union = sys::zx_packet_guest_vcpu_union_t {
711 interrupt: {
712 let mut interrupt = sys::zx_packet_guest_vcpu_interrupt_t::default();
713 interrupt.mask = 0xaaaaaaaaaaaaaaaa;
714 interrupt.vector = 0x12;
715 interrupt
716 },
717 };
718 const KEY: u64 = 0x0123456789abcdef;
719 const STATUS: i32 = sys::ZX_ERR_NO_RESOURCES;
720
721 let packet = Packet::from_guest_vcpu_packet(
722 KEY,
723 STATUS,
724 GuestVcpuPacket::from_raw(guest_vcpu_packet),
725 );
726
727 assert_matches!(packet.contents(), PacketContents::GuestVcpu(GuestVcpuPacket(packet)) if packet == guest_vcpu_packet);
728 assert_eq!(packet.key(), KEY);
729 assert_eq!(packet.status(), STATUS);
730 }
731
732 #[test]
733 fn guest_vcpu_startup_packet() {
734 let mut guest_vcpu_packet = sys::zx_packet_guest_vcpu_t::default();
735 guest_vcpu_packet.r#type = sys::zx_packet_guest_vcpu_type_t::ZX_PKT_GUEST_VCPU_STARTUP;
736 guest_vcpu_packet.union = sys::zx_packet_guest_vcpu_union_t {
737 startup: sys::zx_packet_guest_vcpu_startup_t {
738 target: 16,
739 entry: 0xffffffff11111111,
740 context: 0xfeedfacedeadbeef,
741 },
742 };
743 const KEY: u64 = 0x0123456789abcdef;
744 const STATUS: i32 = sys::ZX_ERR_NO_RESOURCES;
745
746 let packet = Packet::from_guest_vcpu_packet(
747 KEY,
748 STATUS,
749 GuestVcpuPacket::from_raw(guest_vcpu_packet),
750 );
751
752 assert_matches!(packet.contents(), PacketContents::GuestVcpu(GuestVcpuPacket(packet)) if packet == guest_vcpu_packet);
753 assert_eq!(packet.key(), KEY);
754 assert_eq!(packet.status(), STATUS);
755 }
756
757 #[test]
758 fn power_transition_packet() {
759 let power_transition_packet =
760 sys::zx_packet_processor_power_level_transition_request_t::default();
761 const KEY: u64 = 0x0123456789abcdef;
762 const STATUS: i32 = sys::ZX_ERR_NO_RESOURCES;
763
764 let packet = Packet::from_power_transition_packet(
765 KEY,
766 STATUS,
767 PowerTransitionPacket::from_raw(power_transition_packet),
768 );
769
770 assert_matches!(
771 packet.contents(),
772 PacketContents::PowerTransition(PowerTransitionPacket(packet)) if packet == power_transition_packet
773 );
774 assert_eq!(packet.key(), KEY);
775 assert_eq!(packet.status(), STATUS);
776 }
777}