knx_ip_client/packets/
core.rs

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
13/// 03.08.02 Core section - 2.3.2 Header length
14pub const KNX_NET_IP_HEADER_LENGTH: u8 = 6;
15/// 03.08.02 Core section - 2.3.3 Protocol version = 1.0
16pub const KNX_NET_IP_PROTOCOL_VERSION: u8 = 0x10;
17
18// Connection request information
19// 03.08.04 Tunneling section 4.4.3
20//
21pub 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
30/// 03.08.02 Core section 8.5.2.1 KNXnet/IP system setup multicast address
31pub const SYSTEM_MULTICAST_ADDRESS: Ipv4Addr = Ipv4Addr::new(224, 0, 23, 12);
32/// 03.08.02 Core section 8.6.3.2 Discovery Endpoint
33pub const DISCOVERY_ENDPOINT_PORT: u16 = 3671;
34
35/// 03.08.02 Core section 8.5.2 Header
36///
37/// Version 1.0
38pub 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// Connection response data block
115// 03.08.04 Tunneling section 4.4.4
116#[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// Connection request
156// 03.08.02 Core section 7.8.1
157//
158#[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]; // Header
184        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// Connection response
203// 03.08.02 Core section 7.8.2
204//
205#[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// Connectionstate Request
304// 03.08.02 Core section 7.8.3
305//
306#[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
387// Connectionstate Response
388// 03.08.02 Core section 7.8.4
389//
390pub 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// Disconnect request
456// 03.08.02 Core section 7.8.5
457//
458#[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// Disconnect Response
520// 03.08.02 Core section 7.8.6
521//
522#[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, // No error
533        }
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/// Search request
596/// 03.08.02 Core section 7.6.1
597///
598#[derive(Debug)]
599pub struct SearchRequest {
600    discovery_endpoint: HPAI,
601}
602
603impl SearchRequest {
604    /// UDP search request, expecting responses on the default discovery multicast address.
605    /// This ensures, reception from KNXNet/IP Servers on different subnets.
606    /// 03.08.02 Core section 4.2 Discovery
607    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    /// UDP search request providing a unicast IP address to receive the response via point-to-point communication (unicast).
614    /// 03.08.02 Core section 4.2 Discovery
615    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/// Search response
646/// 03.08.02 Core section 7.6.2
647///
648#[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
700// Host Protocol Address Information
701// 03.08.02 Core section 8.6.2
702//
703pub 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/// 03.08.02 Core section 7.5.4.1
784#[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/// Description Information Block (DIB)
812/// 03.08.02 Core section 7.5.4.1
813#[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        // 7.5.4.1
853        // Structure length must be even. Add a padding of 0x00 if necessary.
854        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        /// Is device in programming mode?
924        const PROGRAMMING_MODE = 0b0000_0001;
925        // remaining bits are reserved but undefined so far
926    }
927}
928
929/// Device information DIB
930/// 03.08.02 Core section 7.5.4.2
931#[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    /// ISO 8859-1 string
943    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    /// Device friendly name decoded from ISO 8859-1
982    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/// Supported service families DIB
1046/// 03.08.02 Core section 7.5.4.3
1047#[derive(Debug, Clone)]
1048pub struct ServiceFamily {
1049    pub service_family: u8,
1050    pub version: u8,
1051}
1052
1053/// Supported service families DIB
1054/// 03.08.02 Core section 7.5.4.3
1055#[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            // -2 because of length and type
1078            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/// IP Config DIB
1092/// 03.08.02 Core section 7.5.4.4
1093#[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/// IP Current Config DIB
1146/// 03.08.02 Core section 7.5.4.5
1147#[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/// KNX Addresses DIB
1211/// 03.08.02 Core section 7.5.4.6
1212#[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            // - 1 byte structure length - 2 byte description type code  - 2 bytes knx individual address
1240            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/// Manufacturer data DIB
1257/// 03.08.02 Core section 7.5.4.7
1258#[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]); // header size + version
1301        packet.extend_from_slice(&[0x02, 0x01]); // service type identifier
1302        packet.extend_from_slice(&[0x00, 0x0E]); // total length
1303        packet.extend_from_slice(&[0x08]); // structure length
1304        packet.extend_from_slice(&[0x01]); // host protocol code - UDP over ipv4
1305        packet.extend_from_slice(&[192, 168, 200, 12]); // ip address of control endpoint
1306        packet.extend_from_slice(&[0x0E, 0x57]); // port control endpoint 3671
1307        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    /// 8.8.2 Binary examples of KNXnet/IP IP frames - SEARCH_RESPONSE
1315    fn parse_search_response() {
1316        let mut packet = Vec::new();
1317
1318        // header
1319        packet.extend_from_slice(&[0x06, 0x10, 0x02, 0x02, 0x00, 0x4E]);
1320
1321        // hpai
1322        packet.extend_from_slice(&[0x08, 0x01]);
1323
1324        // ip address of control endpoint
1325        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        // knx device serial number
1330        packet.extend_from_slice(&[0x00, 0x01, 0x11, 0x11, 0x11, 0x11]);
1331
1332        // device routing multicast address
1333        packet.extend_from_slice(&[224, 0, 23, 12]);
1334
1335        // Mac Address
1336        packet.extend_from_slice(&[0x45, 0x49, 0x42, 0x6E, 0x65, 0x74]);
1337
1338        // Device Friendly Name
1339        packet.extend_from_slice(&[b'M', b'Y', b'H', b'O', b'M', b'E', b'\n']);
1340        // Device Friendly Name Padding (total 30 bytes)
1341        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); // pad it
1358        assert_eq!(result.device_hardware.friendly_name.to_vec(), friendly_name);
1359
1360        // service families
1361
1362        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}