1use bitflags::bitflags;
2use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
3use encoding::all::ISO_8859_1;
4use encoding::{DecoderTrap, EncoderTrap, Encoding};
5use snafu::{ensure_whatever, whatever, ResultExt, Whatever};
6use std::{
7 io::{Cursor, Read},
8 net::{Ipv4Addr, SocketAddrV4},
9};
10
11use super::addresses::IndividualAddress;
12
13pub const KNX_NET_IP_HEADER_LENGTH: u8 = 6;
15pub const KNX_NET_IP_PROTOCOL_VERSION: u8 = 0x10;
17
18pub const TUNNEL_LINKLAYER: u8 = 0x02;
22pub const TUNNEL_RAW: u8 = 0x04;
23pub const TUNNEL_BUSMONITOR: u8 = 0x80;
24pub const E_NO_ERROR: u8 = 0x00;
25pub const E_CONNECTION_TYPE: u8 = 0x22;
26pub const E_CONNECTION_OPTION: u8 = 0x23;
27pub const E_NO_MORE_CONNECTIONS: u8 = 0x24;
28pub const E_TUNNELING_LAYER: u8 = 0x29;
29
30pub const SYSTEM_MULTICAST_ADDRESS: Ipv4Addr = Ipv4Addr::new(224, 0, 23, 12);
32pub const DISCOVERY_ENDPOINT_PORT: u16 = 3671;
34
35pub struct KnxNetIpHeader {
39 pub service_type_identifier: u16,
40 pub total_length: u16,
41}
42
43impl KnxNetIpHeader {
44 pub fn packet(&self) -> Vec<u8> {
45 let mut packet = vec![KNX_NET_IP_HEADER_LENGTH, KNX_NET_IP_PROTOCOL_VERSION];
46 packet.write_u16::<BigEndian>(self.service_type_identifier).unwrap();
47 packet.write_u16::<BigEndian>(self.total_length).unwrap();
48 packet
49 }
50
51 pub fn from_packet(packet_reader: &mut Cursor<&[u8]>) -> Result<Self, Whatever> {
52 let _header_length = match packet_reader.read_u8() {
53 Ok(header_length) => {
54 ensure_whatever!(
55 header_length == KNX_NET_IP_HEADER_LENGTH,
56 "Header length should be {} instead of {}",
57 KNX_NET_IP_HEADER_LENGTH,
58 header_length
59 );
60 header_length
61 }
62 Err(e) => whatever!("Unable to read header length {:?}", e),
63 };
64
65 match packet_reader.read_u8() {
66 Ok(version) => {
67 ensure_whatever!(
68 version == KNX_NET_IP_PROTOCOL_VERSION,
69 "KNXIP protocol version should be 0x10 instead of {:2X}",
70 KNX_NET_IP_PROTOCOL_VERSION
71 );
72 }
73 Err(e) => whatever!("Unable to read KNXIP version {:?}", e),
74 };
75
76 let service_type_identifier = packet_reader
77 .read_u16::<BigEndian>()
78 .whatever_context("Unable to read service type identifier")?;
79
80 let total_length = packet_reader.read_u16::<BigEndian>().whatever_context("Unable to read total length")?;
81
82 Ok(Self {
83 service_type_identifier,
84 total_length,
85 })
86 }
87}
88
89#[derive(Debug)]
90pub struct CRI {
91 connection_type: u8,
92}
93
94impl CRI {
95 pub fn tunnel_linklayer() -> Self {
96 Self {
97 connection_type: TUNNEL_LINKLAYER,
98 }
99 }
100 pub fn tunnel_raw() -> Self {
101 Self { connection_type: TUNNEL_RAW }
102 }
103 pub fn tunnel_busmonitor() -> Self {
104 Self {
105 connection_type: TUNNEL_BUSMONITOR,
106 }
107 }
108
109 pub fn packet(&self) -> Vec<u8> {
110 vec![4, 4, self.connection_type, 0]
111 }
112}
113
114#[derive(Debug)]
117pub struct CRD {
118 knx_individual_address: IndividualAddress,
119}
120
121impl CRD {
122 pub fn from_packet(packet_reader: &mut Cursor<&[u8]>) -> Result<Self, Whatever> {
123 let _size = match packet_reader.read_u8() {
124 Ok(size) => {
125 ensure_whatever!(size == 4, "Connection Response Data Block should have length 4 instead of {}", size);
126 size
127 }
128 Err(e) => whatever!("Unable to read CRD packet size {:?}", e),
129 };
130 let _tunnel_connection = match packet_reader.read_u8() {
131 Ok(tunnel_connection) => {
132 ensure_whatever!(
133 tunnel_connection == 4,
134 "Connection Response Data Block should have connection type 4 (TUNNELING) instead of {}",
135 tunnel_connection
136 );
137 tunnel_connection
138 }
139 Err(e) => whatever!("Unable to read CRD tunnel connection {:?}", e),
140 };
141 let knx_individual_address = match packet_reader.read_u16::<BigEndian>() {
142 Ok(addr) => IndividualAddress::from_u16(addr),
143 Err(e) => whatever!("Unable to read CRD KNX individual address {:?}", e),
144 };
145 Ok(Self { knx_individual_address })
146 }
147
148 pub fn packet(&self) -> Vec<u8> {
149 let mut packet = vec![0x04, 0x04];
150 packet.write_u16::<BigEndian>(self.knx_individual_address.to_u16()).unwrap();
151 packet
152 }
153}
154
155#[derive(Debug)]
159pub struct ConnectionRequest {
160 control_endpoint: HPAI,
161 data_endpoint: HPAI,
162 cri: CRI,
163}
164
165impl ConnectionRequest {
166 pub fn tunnel() -> Self {
167 Self {
168 control_endpoint: HPAI::udp(),
169 data_endpoint: HPAI::udp(),
170 cri: CRI::tunnel_linklayer(),
171 }
172 }
173
174 pub fn busmonitor() -> Self {
175 Self {
176 control_endpoint: HPAI::udp(),
177 data_endpoint: HPAI::udp(),
178 cri: CRI::tunnel_busmonitor(),
179 }
180 }
181
182 pub fn packet(&self) -> Vec<u8> {
183 let mut packet = vec![6, 0x10, 2, 5]; let mut control_endpoint_packet = self.control_endpoint.packet();
185 let mut data_endpoint_packet = self.data_endpoint.packet();
186 let mut cri_packet = self.cri.packet();
187
188 let mut packet_size = 6;
189 packet_size += control_endpoint_packet.len();
190 packet_size += data_endpoint_packet.len();
191 packet_size += cri_packet.len();
192
193 packet.write_u16::<BigEndian>(packet_size as u16).unwrap();
194 packet.append(&mut control_endpoint_packet);
195 packet.append(&mut data_endpoint_packet);
196 packet.append(&mut cri_packet);
197
198 packet
199 }
200}
201
202#[derive(Debug)]
206pub struct ConnectionResponse {
207 communication_channel_id: u8,
208 status: u8,
209 data_endpoint: HPAI,
210 crd: CRD,
211}
212
213impl ConnectionResponse {
214 pub fn get_communication_channel_id(&self) -> u8 {
215 self.communication_channel_id
216 }
217 pub fn get_data_endpoint(&self) -> HPAI {
218 self.data_endpoint.clone()
219 }
220 pub fn get_status(&self) -> u8 {
221 self.status
222 }
223 pub fn from_packet(packet_reader: &mut Cursor<&[u8]>) -> Result<Self, Whatever> {
224 let header_size = match packet_reader.read_u8() {
225 Ok(header_size) => {
226 ensure_whatever!(header_size == 6, "Header size should be 6 instead of {}", header_size);
227 header_size
228 }
229 Err(e) => whatever!("Unable to read header size {:?}", e),
230 };
231
232 let _version = match packet_reader.read_u8() {
233 Ok(version) => {
234 ensure_whatever!(version == 0x10, "KNXIP version should be 0x10 instead of {:02X}", header_size);
235 version
236 }
237 Err(e) => whatever!("Unable to read KNXIP version {:?}", e),
238 };
239
240 let _connect_response = match packet_reader.read_u16::<BigEndian>() {
241 Ok(connect_response) => {
242 ensure_whatever!(
243 connect_response == 0x0206,
244 "Connect response should be 0x0206 instead of {:02X}",
245 connect_response
246 );
247 connect_response
248 }
249 Err(e) => whatever!("Unable to read Connect Response {:?}", e),
250 };
251
252 let _size = match packet_reader.read_u16::<BigEndian>() {
253 Ok(size) => {
254 ensure_whatever!(size >= 8, "Packet size should greather than 8, received size {}", size);
255 size
256 }
257 Err(e) => whatever!("Unable to read packet size {:?}", e),
258 };
259
260 let communication_channel_id = match packet_reader.read_u8() {
261 Ok(id) => id,
262 Err(e) => whatever!("Unable to read Communication Channel Id {:?}", e),
263 };
264
265 let status = match packet_reader.read_u8() {
266 Ok(status) => status,
267 Err(e) => whatever!("Unable to read status {:?}", e),
268 };
269
270 match status {
271 E_CONNECTION_TYPE => {
272 whatever!("Target KNX/IP device does not support requested connection type")
273 }
274 E_CONNECTION_OPTION => whatever!("Target KNX/IP device does not support one or more requested connection options"),
275 E_NO_MORE_CONNECTIONS => {
276 whatever!("No more connections available on target KNX/IP device")
277 }
278 E_TUNNELING_LAYER => {
279 whatever!("Target KNX/IP device does not support requested tunneling layer")
280 }
281 _ => (),
282 }
283
284 let data_endpoint = HPAI::from_packet(packet_reader)?;
285 let crd = CRD::from_packet(packet_reader)?;
286
287 Ok(Self {
288 communication_channel_id,
289 status,
290 data_endpoint,
291 crd,
292 })
293 }
294
295 pub fn packet(&self) -> Vec<u8> {
296 let mut packet = vec![0x06, 0x10, 0x02, 0x06, 0x08, self.communication_channel_id, self.status];
297 packet.extend_from_slice(&self.data_endpoint.packet());
298 packet.extend_from_slice(&self.crd.packet());
299 packet
300 }
301}
302
303#[derive(Debug)]
307pub struct ConnectionstateRequest {
308 pub communication_channel_id: u8,
309 pub control_endpoint: HPAI,
310}
311
312impl ConnectionstateRequest {
313 pub fn new(communication_channel_id: u8, control_endpoint: HPAI) -> Self {
314 Self {
315 communication_channel_id,
316 control_endpoint,
317 }
318 }
319
320 pub fn from_connection_response(resp: &ConnectionResponse) -> Self {
321 Self {
322 communication_channel_id: resp.communication_channel_id,
323 control_endpoint: resp.data_endpoint.clone(),
324 }
325 }
326
327 pub fn from_packet(packet_reader: &mut Cursor<&[u8]>) -> Result<Self, Whatever> {
328 let header_size = match packet_reader.read_u8() {
329 Ok(header_size) => {
330 ensure_whatever!(header_size == 6, "Header size should be 6 instead of {}", header_size);
331 header_size
332 }
333 Err(e) => whatever!("Unable to read header size {:?}", e),
334 };
335
336 match packet_reader.read_u8() {
337 Ok(version) => {
338 ensure_whatever!(version == 0x10, "KNXIP version should be 0x10 instead of {:2X}", header_size);
339 }
340 Err(e) => whatever!("Unable to read KNXIP version {:?}", e),
341 };
342
343 match packet_reader.read_u16::<BigEndian>() {
344 Ok(code) => {
345 ensure_whatever!(code == 0x0207, "Connect request should be 0x0207 instead of {:2X}", code);
346 }
347 Err(e) => whatever!("Unable to read Connectstate request code {:?}", e),
348 };
349
350 let _size = match packet_reader.read_u16::<BigEndian>() {
351 Ok(size) => size,
352 Err(e) => whatever!("Unable to read packet size {:?}", e),
353 };
354
355 let communication_channel_id = match packet_reader.read_u8() {
356 Ok(id) => id,
357 Err(e) => whatever!("Unable to read communication channel id {:?}", e),
358 };
359
360 let _padding = match packet_reader.read_u8() {
361 Ok(pad) => pad,
362 Err(e) => whatever!("Unable to read padding data {:?}", e),
363 };
364
365 let control_endpoint = HPAI::from_packet(packet_reader)?;
366
367 Ok(Self {
368 communication_channel_id,
369 control_endpoint,
370 })
371 }
372
373 pub fn packet(&self) -> Vec<u8> {
374 let mut packet = vec![0x06, 0x10, 0x02, 0x07];
375 let mut control_endpoint_packet = self.control_endpoint.packet();
376 let size = packet.len() + 4 + control_endpoint_packet.len();
377 packet.write_u16::<BigEndian>(size as u16).unwrap();
378 packet.write_u8(self.communication_channel_id).unwrap();
379 packet.write_u8(0).unwrap();
380
381 packet.append(&mut control_endpoint_packet);
382
383 packet
384 }
385}
386
387pub const E_CONNECTION_ID: u8 = 0x21;
391pub const E_DATA_CONNECTION: u8 = 0x26;
392pub const E_KNX_CONNECTION: u8 = 0x27;
393#[derive(Debug)]
394pub struct ConnectionstateResponse {
395 pub communication_channel_id: u8,
396 pub status: u8,
397}
398
399impl ConnectionstateResponse {
400 pub fn from_packet(packet_reader: &mut Cursor<&[u8]>) -> Result<Self, Whatever> {
401 let header_size = match packet_reader.read_u8() {
402 Ok(header_size) => {
403 ensure_whatever!(header_size == 6, "Header size should be 6 instead of {}", header_size);
404 header_size
405 }
406 Err(e) => whatever!("Unable to read header size {:?}", e),
407 };
408
409 let _version = match packet_reader.read_u8() {
410 Ok(version) => {
411 ensure_whatever!(version == 0x10, "KNXIP version should be 0x10 instead of {:2X}", header_size);
412 version
413 }
414 Err(e) => whatever!("Unable to read KNXIP version {:?}", e),
415 };
416
417 let _connectionstate_response = match packet_reader.read_u16::<BigEndian>() {
418 Ok(code) => {
419 ensure_whatever!(code == 0x0208, "Connect response should be 0x0208 instead of {:2X}", code);
420 code
421 }
422 Err(e) => whatever!("Unable to read Connectstate Response {:?}", e),
423 };
424
425 let _size = match packet_reader.read_u16::<BigEndian>() {
426 Ok(size) => {
427 ensure_whatever!(size == 8, "Packet size should be 8, received size {}", size);
428 size
429 }
430 Err(e) => whatever!("Unable to read packet size {:?}", e),
431 };
432
433 let communication_channel_id = match packet_reader.read_u8() {
434 Ok(id) => id,
435 Err(e) => whatever!("Unable to read Communication Channel Id {:?}", e),
436 };
437
438 let status = match packet_reader.read_u8() {
439 Ok(status) => status,
440 Err(e) => whatever!("Unable to read status {:?}", e),
441 };
442
443 Ok(Self {
444 communication_channel_id,
445 status,
446 })
447 }
448
449 pub fn packet(&self) -> Vec<u8> {
450 let packet = vec![0x06, 0x10, 0x02, 0x08, 0x00, 0x08, self.communication_channel_id, self.status];
451 packet
452 }
453}
454
455#[derive(Debug)]
459pub struct DisconnectRequest {
460 communication_channel_id: u8,
461 control_endpoint: HPAI,
462}
463
464impl DisconnectRequest {
465 pub fn new(communication_channel_id: u8, control_endpoint: HPAI) -> Self {
466 Self {
467 communication_channel_id,
468 control_endpoint,
469 }
470 }
471 pub fn from_connection_response(resp: &ConnectionResponse) -> Self {
472 Self {
473 communication_channel_id: resp.communication_channel_id,
474 control_endpoint: resp.data_endpoint.clone(),
475 }
476 }
477
478 pub fn from_packet(packet_reader: &mut Cursor<&[u8]>) -> Result<Self, Whatever> {
479 let header_size = match packet_reader.read_u8() {
480 Ok(header_size) => {
481 ensure_whatever!(header_size >= 8, "Header size should be at least 8 instead of {}", header_size);
482 header_size
483 }
484 Err(e) => whatever!("Unable to read header size {:?}", e),
485 };
486
487 let communication_channel_id = match packet_reader.read_u8() {
488 Ok(communication_channel_id) => communication_channel_id,
489 Err(e) => whatever!("Unable to read communication channel id {:?}", e),
490 };
491
492 let _reserved = match packet_reader.read_u8() {
493 Ok(reserved) => reserved,
494 Err(e) => whatever!("Unable to read reserved data {:?}", e),
495 };
496
497 let control_endpoint = HPAI::from_packet(packet_reader)?;
498
499 Ok(Self {
500 communication_channel_id,
501 control_endpoint,
502 })
503 }
504
505 pub fn packet(&self) -> Vec<u8> {
506 let mut packet = vec![0x06, 0x10, 0x02, 0x09];
507 let mut control_endpoint_packet = self.control_endpoint.packet();
508 let size = packet.len() + 4 + control_endpoint_packet.len();
509 packet.write_u16::<BigEndian>(size as u16).unwrap();
510 packet.write_u8(self.communication_channel_id).unwrap();
511 packet.write_u8(0).unwrap();
512
513 packet.append(&mut control_endpoint_packet);
514
515 packet
516 }
517}
518
519#[derive(Debug)]
523pub struct DisconnectResponse {
524 pub communication_channel_id: u8,
525 pub status: u8,
526}
527
528impl DisconnectResponse {
529 pub fn from_disconnect_request(req: &DisconnectRequest) -> Self {
530 Self {
531 communication_channel_id: req.communication_channel_id,
532 status: 0, }
534 }
535
536 pub fn from_packet(packet_reader: &mut Cursor<&[u8]>) -> Result<Self, Whatever> {
537 let header_size = match packet_reader.read_u8() {
538 Ok(header_size) => {
539 ensure_whatever!(header_size == 6, "Header size should be 6 instead of {}", header_size);
540 header_size
541 }
542 Err(e) => whatever!("Unable to read header size {:?}", e),
543 };
544
545 let _version = match packet_reader.read_u8() {
546 Ok(version) => {
547 ensure_whatever!(version == 0x10, "KNXIP version should be 0x10 instead of {:2X}", header_size);
548 version
549 }
550 Err(e) => whatever!("Unable to read KNXIP version {:?}", e),
551 };
552
553 let _connectionstate_response = match packet_reader.read_u16::<BigEndian>() {
554 Ok(code) => {
555 ensure_whatever!(code == 0x020a, "Disconnect response should be 0x020A instead of {:2X}", code);
556 code
557 }
558 Err(e) => whatever!("Unable to read Disconnect Response {:?}", e),
559 };
560
561 let _size = match packet_reader.read_u16::<BigEndian>() {
562 Ok(size) => {
563 ensure_whatever!(size == 8, "Packet size should be 8, received size {}", size);
564 size
565 }
566 Err(e) => whatever!("Unable to read packet size {:?}", e),
567 };
568
569 let communication_channel_id = match packet_reader.read_u8() {
570 Ok(id) => id,
571 Err(e) => whatever!("Unable to read Communication Channel Id {:?}", e),
572 };
573
574 let status = match packet_reader.read_u8() {
575 Ok(status) => status,
576 Err(e) => whatever!("Unable to read status {:?}", e),
577 };
578
579 Ok(Self {
580 communication_channel_id,
581 status,
582 })
583 }
584
585 pub fn packet(&self) -> Vec<u8> {
586 let mut packet = vec![0x06, 0x10, 0x02, 0x0A];
587 packet.write_u16::<BigEndian>(8).unwrap();
588 packet.write_u8(self.communication_channel_id).unwrap();
589 packet.write_u8(self.status).unwrap();
590
591 packet
592 }
593}
594
595#[derive(Debug)]
599pub struct SearchRequest {
600 discovery_endpoint: HPAI,
601}
602
603impl SearchRequest {
604 pub fn udp() -> Self {
608 let mut discovery_endpoint = HPAI::udp();
609 discovery_endpoint.set_addr(SocketAddrV4::new(SYSTEM_MULTICAST_ADDRESS, DISCOVERY_ENDPOINT_PORT));
610 Self { discovery_endpoint }
611 }
612
613 pub fn udp_unicast(unicast_endpoint: SocketAddrV4) -> Self {
616 let mut discovery_endpoint = HPAI::udp();
617 discovery_endpoint.set_addr(unicast_endpoint);
618 Self { discovery_endpoint }
619 }
620
621 pub fn packet(&self) -> Vec<u8> {
622 let mut packet = vec![0x06, 0x10, 0x02, 0x01];
623 let mut hpai_packet = self.discovery_endpoint.packet();
624 let size = packet.len() + 2 + hpai_packet.len();
625 packet.write_u16::<BigEndian>(size as u16).unwrap();
626 packet.append(&mut hpai_packet);
627
628 packet
629 }
630
631 pub fn from_packet(packet_reader: &mut Cursor<&[u8]>) -> Result<Self, Whatever> {
632 let header = KnxNetIpHeader::from_packet(packet_reader)?;
633 ensure_whatever!(
634 header.service_type_identifier == 0x0201,
635 "Search request should be 0x0201 instead of {:2X}",
636 header.service_type_identifier
637 );
638
639 let discovery_endpoint = HPAI::from_packet(packet_reader)?;
640
641 Ok(SearchRequest { discovery_endpoint })
642 }
643}
644
645#[derive(Debug, Clone)]
649pub struct SearchResponse {
650 pub control_endpoint: HPAI,
651 pub device_hardware: DeviceInformationDIB,
652 pub supported_service_families: SupportedServiceFamiliesDIB,
653}
654
655impl SearchResponse {
656 pub fn packet(&self) -> Vec<u8> {
657 let mut packet = vec![0x06, 0x10, 0x02, 0x02];
658
659 let mut control_endpoint_packet = self.control_endpoint.packet();
660 let mut device_hardware_packet = self.device_hardware.packet();
661 let mut supported_service_families_packet = self.supported_service_families.packet();
662 let size = packet.len() + 2 + control_endpoint_packet.len() + device_hardware_packet.len() + supported_service_families_packet.len();
663
664 packet.write_u16::<BigEndian>(size as u16).unwrap();
665 packet.append(&mut control_endpoint_packet);
666 packet.append(&mut device_hardware_packet);
667 packet.append(&mut supported_service_families_packet);
668
669 packet
670 }
671
672 pub fn from_packet(packet_reader: &mut Cursor<&[u8]>) -> Result<Self, Whatever> {
673 let header = KnxNetIpHeader::from_packet(packet_reader)?;
674 ensure_whatever!(
675 header.service_type_identifier == 0x0202,
676 "Search response should be 0x0202 instead of {:2X}",
677 header.service_type_identifier
678 );
679
680 let control_endpoint = HPAI::from_packet(packet_reader)?;
681
682 let device_hardware: DeviceInformationDIB = match DIB::from_packet(packet_reader)? {
683 DIB::DeviceInformation(device_hardware) => device_hardware,
684 other => whatever!("Expected device information dib instead of {:?}", other),
685 };
686
687 let supported_service_families = match DIB::from_packet(packet_reader)? {
688 DIB::SupportedServiceFamilies(supported_service_families) => supported_service_families,
689 other => whatever!("Expected supported service families dib instead of {:?}", other),
690 };
691
692 Ok(Self {
693 control_endpoint,
694 device_hardware,
695 supported_service_families,
696 })
697 }
698}
699
700pub const HPAI_IPV4_UDP: u8 = 1;
704pub const HPAI_IPV4_TCP: u8 = 2;
705#[derive(Debug, Clone)]
706pub struct HPAI {
707 pub host_protocol_code: u8,
708 pub address: SocketAddrV4,
709}
710
711impl HPAI {
712 pub fn udp() -> Self {
713 Self {
714 host_protocol_code: HPAI_IPV4_UDP,
715 address: "0.0.0.0:0".parse().unwrap(),
716 }
717 }
718
719 pub fn tcp() -> Self {
720 Self {
721 host_protocol_code: HPAI_IPV4_TCP,
722 address: "0.0.0.0:0".parse().unwrap(),
723 }
724 }
725
726 pub fn set_addr(&mut self, address: SocketAddrV4) {
727 self.address = address;
728 }
729
730 pub fn packet(&self) -> Vec<u8> {
731 let mut packet = Vec::new();
732 packet.write_u8(8).unwrap();
733 packet.write_u8(self.host_protocol_code).unwrap();
734 let ip = self.address.ip().octets();
735 packet.extend_from_slice(&ip);
736 packet.write_u16::<BigEndian>(self.address.port()).unwrap();
737 packet
738 }
739
740 pub fn from_packet(packet_reader: &mut Cursor<&[u8]>) -> Result<Self, Whatever> {
741 let _size = match packet_reader.read_u8() {
742 Ok(size) => {
743 ensure_whatever!(size == 8, "HPAI size must be 8 instead of {}", size);
744 size
745 }
746 Err(e) => whatever!("Unable to read HPAI size {:?}", e),
747 };
748
749 let host_protocol_code = match packet_reader.read_u8() {
750 Ok(code) => code,
751 Err(e) => whatever!("Unable to read HPAI host protocol code {:?}", e),
752 };
753
754 let ip_1 = match packet_reader.read_u8() {
755 Ok(ip) => ip,
756 Err(e) => whatever!("Unable to read HPAI IP part 1 {:?}", e),
757 };
758 let ip_2 = match packet_reader.read_u8() {
759 Ok(ip) => ip,
760 Err(e) => whatever!("Unable to read HPAI IP part 2 {:?}", e),
761 };
762 let ip_3 = match packet_reader.read_u8() {
763 Ok(ip) => ip,
764 Err(e) => whatever!("Unable to read HPAI IP part 3 {:?}", e),
765 };
766 let ip_4 = match packet_reader.read_u8() {
767 Ok(ip) => ip,
768 Err(e) => whatever!("Unable to read HPAI IP part 4 {:?}", e),
769 };
770
771 let port = match packet_reader.read_u16::<BigEndian>() {
772 Ok(port) => port,
773 Err(e) => whatever!("Unable to read HPAI IP Port {:?}", e),
774 };
775
776 Ok(Self {
777 host_protocol_code,
778 address: SocketAddrV4::new(Ipv4Addr::new(ip_1, ip_2, ip_3, ip_4), port),
779 })
780 }
781}
782
783#[derive(Debug, Clone, Copy, PartialEq)]
785#[non_exhaustive]
786pub enum DescriptionTypeCode {
787 DeviceInfo = 0x01,
788 SupportedServiceFamilies = 0x02,
789 IpConfig = 0x03,
790 IpCurrentConfig = 0x04,
791 KNXAddresses = 0x05,
792 ManufacturerData = 0xFE,
793}
794
795impl TryFrom<u8> for DescriptionTypeCode {
796 type Error = Whatever;
797
798 fn try_from(value: u8) -> Result<Self, Self::Error> {
799 match value {
800 0x01 => Ok(Self::DeviceInfo),
801 0x02 => Ok(Self::SupportedServiceFamilies),
802 0x03 => Ok(Self::IpConfig),
803 0x04 => Ok(Self::IpCurrentConfig),
804 0x05 => Ok(Self::KNXAddresses),
805 0xFE => Ok(Self::ManufacturerData),
806 _ => whatever!("Unknown DescriptionTypeCode {}", value),
807 }
808 }
809}
810
811#[derive(Debug, Clone)]
814pub enum DIB {
815 DeviceInformation(DeviceInformationDIB),
816 SupportedServiceFamilies(SupportedServiceFamiliesDIB),
817 IpConfig(IpConfigDIB),
818 IpCurrentConfig(IpCurrentConfigDIB),
819 KNXAddresses(KNXAddressesDIB),
820 ManufacturerData(ManufacturerDataDIB),
821}
822
823impl DIB {
824 pub fn structure_length(&self) -> u8 {
825 match self {
826 Self::DeviceInformation(device_information) => device_information.structure_length,
827 Self::SupportedServiceFamilies(supported_service_families) => supported_service_families.structure_length,
828 Self::IpConfig(ip_config) => ip_config.structure_length,
829 Self::IpCurrentConfig(ip_current_config) => ip_current_config.structure_length,
830 Self::KNXAddresses(knx_addresses) => knx_addresses.structure_length,
831 Self::ManufacturerData(manufacturer_data) => manufacturer_data.structure_length,
832 }
833 }
834
835 pub fn packet(&self) -> Vec<u8> {
836 let mut packet = Vec::new();
837
838 let (type_code, data_packet) = match self {
839 Self::DeviceInformation(device_information) => (DescriptionTypeCode::DeviceInfo, device_information.packet()),
840 Self::SupportedServiceFamilies(families) => (DescriptionTypeCode::SupportedServiceFamilies, families.packet()),
841 Self::IpConfig(ip_config) => (DescriptionTypeCode::IpConfig, ip_config.packet()),
842 Self::IpCurrentConfig(ip_current_config) => (DescriptionTypeCode::IpCurrentConfig, ip_current_config.packet()),
843 Self::KNXAddresses(knx_addresses) => (DescriptionTypeCode::KNXAddresses, knx_addresses.packet()),
844 Self::ManufacturerData(manufacturer_data) => (DescriptionTypeCode::ManufacturerData, manufacturer_data.packet()),
845 };
846
847 let structure_length = 2 + data_packet.len();
848 packet.write_u8(structure_length as u8).unwrap();
849 packet.write_u8(type_code as u8).unwrap();
850 packet.extend_from_slice(&data_packet);
851
852 if structure_length % 2 != 0 {
855 packet.write_u8(0x00).unwrap();
856 }
857
858 packet
859 }
860
861 pub fn from_packet(packet_reader: &mut Cursor<&[u8]>) -> Result<Self, Whatever> {
862 let structure_length = packet_reader.read_u8().whatever_context("Unable to read structure length")?;
863 let description_type_code = packet_reader.read_u8().whatever_context("Unable to read structure length")?;
864 let description_type_code = DescriptionTypeCode::try_from(description_type_code)?;
865
866 let dib = match description_type_code {
867 DescriptionTypeCode::DeviceInfo => {
868 let device_info = DeviceInformationDIB::from_packet(packet_reader, structure_length)?;
869 DIB::DeviceInformation(device_info)
870 }
871 DescriptionTypeCode::SupportedServiceFamilies => {
872 let service_families = SupportedServiceFamiliesDIB::from_packet(packet_reader, structure_length)?;
873 DIB::SupportedServiceFamilies(service_families)
874 }
875 DescriptionTypeCode::IpConfig => {
876 let ip_config = IpConfigDIB::from_packet(packet_reader, structure_length)?;
877 DIB::IpConfig(ip_config)
878 }
879 DescriptionTypeCode::IpCurrentConfig => {
880 let ip_current_config = IpCurrentConfigDIB::from_packet(packet_reader, structure_length)?;
881 DIB::IpCurrentConfig(ip_current_config)
882 }
883 DescriptionTypeCode::KNXAddresses => {
884 let knx_addresses = KNXAddressesDIB::from_packet(packet_reader, structure_length)?;
885 DIB::KNXAddresses(knx_addresses)
886 }
887 DescriptionTypeCode::ManufacturerData => {
888 let manufacture_data = ManufacturerDataDIB::from_packet(packet_reader, structure_length)?;
889 DIB::ManufacturerData(manufacture_data)
890 }
891 };
892
893 Ok(dib)
894 }
895}
896
897#[derive(Debug, Clone, Copy, PartialEq)]
898#[non_exhaustive]
899pub enum KnxMedium {
900 TP1 = 0x02,
901 PL110 = 0x03,
902 RF = 0x10,
903 IP = 0x20,
904}
905
906impl TryFrom<u8> for KnxMedium {
907 type Error = Whatever;
908
909 fn try_from(value: u8) -> Result<Self, Self::Error> {
910 match value {
911 0x02 => Ok(Self::TP1),
912 0x03 => Ok(Self::PL110),
913 0x10 => Ok(Self::RF),
914 0x20 => Ok(Self::IP),
915 _ => whatever!("Unknown KnxMedium {}", value),
916 }
917 }
918}
919
920bitflags! {
921 #[derive(Debug, Clone, PartialEq)]
922 pub struct DeviceStatus: u8 {
923 const PROGRAMMING_MODE = 0b0000_0001;
925 }
927}
928
929#[derive(Debug, Clone)]
932pub struct DeviceInformationDIB {
933 pub structure_length: u8,
934 pub description_type_code: DescriptionTypeCode,
935 pub knx_medium: KnxMedium,
936 pub knx_device_status: DeviceStatus,
937 pub knx_individual_address: IndividualAddress,
938 pub project_installation_identifier: u16,
939 pub serial_number: [u8; 6],
940 pub routing_multicast_address: Ipv4Addr,
941 pub mac_address: [u8; 6],
942 pub friendly_name: [u8; 30],
944}
945
946impl DeviceInformationDIB {
947 #[allow(clippy::too_many_arguments)]
948 pub fn new(
949 structure_length: u8,
950 knx_medium: KnxMedium,
951 knx_device_status: DeviceStatus,
952 knx_individual_address: IndividualAddress,
953 project_installation_identifier: u16,
954 serial_number: [u8; 6],
955 routing_multicast_address: Ipv4Addr,
956 mac_address: [u8; 6],
957 friendly_name: String,
958 ) -> Result<Self, Whatever> {
959 let friendly_name = ISO_8859_1
960 .encode(&friendly_name, EncoderTrap::Strict)
961 .whatever_context("Unable to encode device friendly name")?;
962 let friendly_name = friendly_name
963 .try_into()
964 .map_err(|_err| "")
965 .whatever_context("Encoded friendly name length exceeds 30 bytes")?;
966
967 Ok(Self {
968 structure_length,
969 description_type_code: DescriptionTypeCode::DeviceInfo,
970 knx_medium,
971 knx_device_status,
972 knx_individual_address,
973 project_installation_identifier,
974 serial_number,
975 routing_multicast_address,
976 mac_address,
977 friendly_name,
978 })
979 }
980
981 pub fn friendly_name(&self) -> Result<String, Whatever> {
983 ISO_8859_1
984 .decode(&self.friendly_name, DecoderTrap::Strict)
985 .whatever_context("Unable to decode friendly name")
986 }
987
988 pub fn packet(&self) -> Vec<u8> {
989 let mut packet = Vec::new();
990 packet.write_u8(self.knx_medium as u8).unwrap();
991 packet.write_u8(self.knx_device_status.bits()).unwrap();
992 packet.write_u16::<BigEndian>(self.knx_individual_address.to_u16()).unwrap();
993 packet.write_u16::<BigEndian>(self.project_installation_identifier).unwrap();
994 packet.extend_from_slice(&self.serial_number);
995 packet.extend_from_slice(&self.routing_multicast_address.octets());
996 packet.extend_from_slice(&self.mac_address);
997 packet.extend_from_slice(&self.friendly_name);
998 packet
999 }
1000
1001 pub fn from_packet(packet_reader: &mut Cursor<&[u8]>, structure_length: u8) -> Result<Self, Whatever> {
1002 let knx_medium = packet_reader.read_u8().whatever_context("Unable to read knx mediumn")?;
1003 let knx_medium = KnxMedium::try_from(knx_medium)?;
1004 let knx_device_status = packet_reader.read_u8().whatever_context("Unable to read knx device status")?;
1005 let knx_device_status = DeviceStatus::from_bits_truncate(knx_device_status);
1006
1007 let knx_individual_address = packet_reader
1008 .read_u16::<BigEndian>()
1009 .whatever_context("Unable to read knx individual address")?;
1010 let knx_individual_address = IndividualAddress::from_u16(knx_individual_address);
1011
1012 let project_installation_identifier = packet_reader
1013 .read_u16::<BigEndian>()
1014 .whatever_context("Unable to read project installation identifier")?;
1015
1016 let mut serial_number = [0; 6];
1017 packet_reader.read_exact(&mut serial_number).whatever_context("Unable to read serial number")?;
1018
1019 let mut routing_multicast_address = [0; 4];
1020 packet_reader
1021 .read_exact(&mut routing_multicast_address)
1022 .whatever_context("Unable to read routing multicast address")?;
1023
1024 let mut mac_address = [0; 6];
1025 packet_reader.read_exact(&mut mac_address).whatever_context("Unable to read mac address")?;
1026
1027 let mut friendly_name = [0; 30];
1028 packet_reader.read_exact(&mut friendly_name).whatever_context("Unable to read friendly name")?;
1029
1030 Ok(Self {
1031 structure_length,
1032 description_type_code: DescriptionTypeCode::DeviceInfo,
1033 knx_medium,
1034 knx_device_status,
1035 knx_individual_address,
1036 project_installation_identifier,
1037 serial_number,
1038 routing_multicast_address: Ipv4Addr::from(routing_multicast_address),
1039 mac_address,
1040 friendly_name,
1041 })
1042 }
1043}
1044
1045#[derive(Debug, Clone)]
1048pub struct ServiceFamily {
1049 pub service_family: u8,
1050 pub version: u8,
1051}
1052
1053#[derive(Debug, Clone)]
1056pub struct SupportedServiceFamiliesDIB {
1057 pub structure_length: u8,
1058 pub description_type_code: DescriptionTypeCode,
1059 pub service_families: Vec<ServiceFamily>,
1060}
1061
1062impl SupportedServiceFamiliesDIB {
1063 pub fn packet(&self) -> Vec<u8> {
1064 let mut packet = Vec::new();
1065
1066 for service_family in &self.service_families {
1067 packet.write_u8(service_family.service_family).unwrap();
1068 packet.write_u8(service_family.version).unwrap();
1069 }
1070
1071 packet
1072 }
1073
1074 pub fn from_packet(packet_reader: &mut Cursor<&[u8]>, structure_length: u8) -> Result<Self, Whatever> {
1075 let mut service_families = Vec::new();
1076 for _ in 0..(structure_length - 2) / 2 {
1077 let service_family = packet_reader.read_u8().whatever_context("Unable to read service family")?;
1079 let version: u8 = packet_reader.read_u8().whatever_context("Unable to read version")?;
1080 service_families.push(ServiceFamily { service_family, version });
1081 }
1082
1083 Ok(Self {
1084 structure_length,
1085 description_type_code: DescriptionTypeCode::SupportedServiceFamilies,
1086 service_families,
1087 })
1088 }
1089}
1090
1091#[derive(Debug, Clone)]
1094pub struct IpConfigDIB {
1095 pub structure_length: u8,
1096 pub description_type_code: DescriptionTypeCode,
1097 pub ip_address: Ipv4Addr,
1098 pub subnet_mask: Ipv4Addr,
1099 pub default_gateway: Ipv4Addr,
1100 pub ip_capabilities: u8,
1101 pub ip_assignment_method: u8,
1102}
1103
1104impl IpConfigDIB {
1105 pub fn packet(&self) -> Vec<u8> {
1106 let mut packet = Vec::new();
1107 packet.extend_from_slice(&self.ip_address.octets());
1108 packet.extend_from_slice(&self.subnet_mask.octets());
1109 packet.extend_from_slice(&self.default_gateway.octets());
1110 packet.write_u8(self.ip_capabilities).unwrap();
1111 packet.write_u8(self.ip_assignment_method).unwrap();
1112 packet
1113 }
1114
1115 pub fn from_packet(packet_reader: &mut Cursor<&[u8]>, structure_length: u8) -> Result<Self, Whatever> {
1116 let mut ip_address = [0; 4];
1117 packet_reader.read_exact(&mut ip_address).whatever_context("Unable to read ip address")?;
1118 let ip_address = Ipv4Addr::from(ip_address);
1119
1120 let mut subnet_mask = [0; 4];
1121 packet_reader.read_exact(&mut subnet_mask).whatever_context("Unable to read subnet_mask")?;
1122 let subnet_mask = Ipv4Addr::from(subnet_mask);
1123
1124 let mut default_gateway = [0; 4];
1125 packet_reader
1126 .read_exact(&mut default_gateway)
1127 .whatever_context("Unable to read default gateway")?;
1128 let default_gateway = Ipv4Addr::from(default_gateway);
1129
1130 let ip_capabilities = packet_reader.read_u8().whatever_context("Unable to read ip capabilities")?;
1131 let ip_assignment_method = packet_reader.read_u8().whatever_context("Unable to read ip assignment method")?;
1132
1133 Ok(Self {
1134 structure_length,
1135 description_type_code: DescriptionTypeCode::IpConfig,
1136 ip_address,
1137 subnet_mask,
1138 default_gateway,
1139 ip_capabilities,
1140 ip_assignment_method,
1141 })
1142 }
1143}
1144
1145#[derive(Debug, Clone)]
1148pub struct IpCurrentConfigDIB {
1149 pub structure_length: u8,
1150 pub description_type_code: DescriptionTypeCode,
1151 pub current_ip_address: Ipv4Addr,
1152 pub current_subnet_mask: Ipv4Addr,
1153 pub current_default_gateway: Ipv4Addr,
1154 pub dhcp_server: Ipv4Addr,
1155 pub current_ip_assignment_method: u8,
1156 pub reserved: u8,
1157}
1158
1159impl IpCurrentConfigDIB {
1160 pub fn packet(&self) -> Vec<u8> {
1161 let mut packet = Vec::new();
1162 packet.extend_from_slice(&self.current_ip_address.octets());
1163 packet.extend_from_slice(&self.current_subnet_mask.octets());
1164 packet.extend_from_slice(&self.current_default_gateway.octets());
1165 packet.extend_from_slice(&self.dhcp_server.octets());
1166 packet.write_u8(self.current_ip_assignment_method).unwrap();
1167 packet.write_u8(self.reserved).unwrap();
1168 packet
1169 }
1170
1171 pub fn from_packet(packet_reader: &mut Cursor<&[u8]>, structure_length: u8) -> Result<Self, Whatever> {
1172 let mut current_ip_address = [0; 4];
1173 packet_reader
1174 .read_exact(&mut current_ip_address)
1175 .whatever_context("Unable to read current ip address")?;
1176 let current_ip_address = Ipv4Addr::from(current_ip_address);
1177
1178 let mut current_subnet_mask = [0; 4];
1179 packet_reader
1180 .read_exact(&mut current_subnet_mask)
1181 .whatever_context("Unable to read current subnet_mask")?;
1182 let current_subnet_mask = Ipv4Addr::from(current_subnet_mask);
1183
1184 let mut current_default_gateway = [0; 4];
1185 packet_reader
1186 .read_exact(&mut current_default_gateway)
1187 .whatever_context("Unable to read current default gateway")?;
1188 let current_default_gateway = Ipv4Addr::from(current_default_gateway);
1189
1190 let mut dhcp_server = [0; 4];
1191 packet_reader.read_exact(&mut dhcp_server).whatever_context("Unable to read dhcp server")?;
1192 let dhcp_server = Ipv4Addr::from(dhcp_server);
1193
1194 let current_ip_assignment_method = packet_reader.read_u8().whatever_context("Unable to read current ip assignment method")?;
1195 let reserved = packet_reader.read_u8().whatever_context("Unable to read reserved")?;
1196
1197 Ok(Self {
1198 structure_length,
1199 description_type_code: DescriptionTypeCode::IpCurrentConfig,
1200 current_ip_address,
1201 current_subnet_mask,
1202 current_default_gateway,
1203 dhcp_server,
1204 current_ip_assignment_method,
1205 reserved,
1206 })
1207 }
1208}
1209
1210#[derive(Debug, Clone)]
1213pub struct KNXAddressesDIB {
1214 pub structure_length: u8,
1215 pub description_type_code: DescriptionTypeCode,
1216 pub knx_individual_address: Ipv4Addr,
1217 pub additional_individual_addresses: Vec<Ipv4Addr>,
1218}
1219
1220impl KNXAddressesDIB {
1221 pub fn packet(&self) -> Vec<u8> {
1222 let mut packet = Vec::new();
1223 packet.extend_from_slice(&self.knx_individual_address.octets());
1224 for address in &self.additional_individual_addresses {
1225 packet.extend_from_slice(&address.octets());
1226 }
1227 packet
1228 }
1229
1230 pub fn from_packet(packet_reader: &mut Cursor<&[u8]>, structure_length: u8) -> Result<Self, Whatever> {
1231 let mut knx_individual_address = [0; 4];
1232 packet_reader
1233 .read_exact(&mut knx_individual_address)
1234 .whatever_context("Unable to read knx individual address")?;
1235
1236 let mut additional_individual_addresses = Vec::new();
1237
1238 for _ in 0..(structure_length - 4) / 2 {
1239 let mut additional_individual_address = [0; 4];
1241 packet_reader
1242 .read_exact(&mut additional_individual_address)
1243 .whatever_context("Unable to read additional individual address")?;
1244 additional_individual_addresses.push(Ipv4Addr::from(additional_individual_address));
1245 }
1246
1247 Ok(Self {
1248 structure_length,
1249 description_type_code: DescriptionTypeCode::KNXAddresses,
1250 knx_individual_address: Ipv4Addr::from(knx_individual_address),
1251 additional_individual_addresses,
1252 })
1253 }
1254}
1255
1256#[derive(Debug, Clone)]
1259pub struct ManufacturerDataDIB {
1260 pub structure_length: u8,
1261 pub description_type_code: DescriptionTypeCode,
1262 pub knx_manufacturer_id: u16,
1263 pub manufacturer_specific_data: Vec<u8>,
1264}
1265
1266impl ManufacturerDataDIB {
1267 pub fn packet(&self) -> Vec<u8> {
1268 let mut packet = Vec::new();
1269 packet.write_u16::<BigEndian>(self.knx_manufacturer_id).unwrap();
1270 packet.extend_from_slice(&self.manufacturer_specific_data);
1271 packet
1272 }
1273
1274 pub fn from_packet(packet_reader: &mut Cursor<&[u8]>, structure_length: u8) -> Result<Self, Whatever> {
1275 let knx_manufacturer_id = packet_reader.read_u16::<BigEndian>().whatever_context("Unable to read knx manufacturer id")?;
1276
1277 let mut manufacturer_specific_data = vec![0; structure_length as usize];
1278 packet_reader
1279 .read_exact(&mut manufacturer_specific_data)
1280 .whatever_context("Unable to read manufacturer specific data")?;
1281
1282 Ok(Self {
1283 structure_length,
1284 description_type_code: DescriptionTypeCode::ManufacturerData,
1285 knx_manufacturer_id,
1286 manufacturer_specific_data,
1287 })
1288 }
1289}
1290
1291#[cfg(test)]
1292mod tests {
1293 use super::*;
1294 use encoding::all::ISO_8859_1;
1295 use encoding::{EncoderTrap, Encoding};
1296
1297 #[test]
1298 fn parse_search_request() {
1299 let mut packet = Vec::new();
1300 packet.extend_from_slice(&[0x06, 0x10]); packet.extend_from_slice(&[0x02, 0x01]); packet.extend_from_slice(&[0x00, 0x0E]); packet.extend_from_slice(&[0x08]); packet.extend_from_slice(&[0x01]); packet.extend_from_slice(&[192, 168, 200, 12]); packet.extend_from_slice(&[0x0E, 0x57]); let mut c = Cursor::new(packet.as_slice());
1308
1309 let request = SearchRequest::from_packet(&mut c).unwrap();
1310 assert_eq!(request.discovery_endpoint.address, SocketAddrV4::new(Ipv4Addr::new(192, 168, 200, 12), 3671));
1311 }
1312
1313 #[test]
1314 fn parse_search_response() {
1316 let mut packet = Vec::new();
1317
1318 packet.extend_from_slice(&[0x06, 0x10, 0x02, 0x02, 0x00, 0x4E]);
1320
1321 packet.extend_from_slice(&[0x08, 0x01]);
1323
1324 packet.extend_from_slice(&[192, 168, 200, 12]);
1326
1327 packet.extend_from_slice(&[0xC3, 0xB4, 0x36, 0x01, 0x02, 0x01, 0x11, 0x00, 0x00, 0x11]);
1328
1329 packet.extend_from_slice(&[0x00, 0x01, 0x11, 0x11, 0x11, 0x11]);
1331
1332 packet.extend_from_slice(&[224, 0, 23, 12]);
1334
1335 packet.extend_from_slice(&[0x45, 0x49, 0x42, 0x6E, 0x65, 0x74]);
1337
1338 packet.extend_from_slice(&[b'M', b'Y', b'H', b'O', b'M', b'E', b'\n']);
1340 packet.append(&mut vec![0x00; 23]);
1342
1343 packet.extend_from_slice(&[0x0A, 0x02, 0x02, 0x01, 0x03, 0x01, 0x04, 0x01, 0x05, 0x01]);
1344
1345 let mut c = Cursor::new(packet.as_slice());
1346
1347 let result = SearchResponse::from_packet(&mut c).unwrap();
1348
1349 assert_eq!(result.device_hardware.knx_medium, KnxMedium::TP1);
1350 assert_eq!(result.device_hardware.knx_device_status, DeviceStatus::PROGRAMMING_MODE);
1351 assert_eq!(result.device_hardware.knx_individual_address, IndividualAddress::try_from("1.1.0").unwrap());
1352 assert_eq!(result.device_hardware.project_installation_identifier, 0x0011);
1353 assert_eq!(result.device_hardware.serial_number, [0x00, 0x01, 0x11, 0x11, 0x11, 0x11]);
1354 assert_eq!(result.device_hardware.routing_multicast_address, Ipv4Addr::from([224, 0, 23, 12]));
1355 assert_eq!(result.device_hardware.mac_address, [0x45, 0x49, 0x42, 0x6E, 0x65, 0x74]);
1356 let mut friendly_name = ISO_8859_1.encode("MYHOME\n", EncoderTrap::Strict).unwrap();
1357 friendly_name.resize(30, 0x00); assert_eq!(result.device_hardware.friendly_name.to_vec(), friendly_name);
1359
1360 assert_eq!(result.supported_service_families.service_families.len(), 4);
1363 assert_eq!(result.supported_service_families.service_families[0].service_family, 2);
1364 assert_eq!(result.supported_service_families.service_families[0].version, 1);
1365 }
1366}