2 EIBD eib bus access and management daemon
3 Copyright (C) 2005-2009 Martin Koegler <mkoegler@auto.tuwien.ac.at>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <sys/socket.h>
26 #ifdef HAVE_LINUX_NETLINK
27 #include <asm/types.h>
28 #include <linux/netlink.h>
29 #include <linux/rtnetlink.h>
31 #ifdef HAVE_WINDOWS_IPHELPER
37 #if HAVE_BSD_SOURCEINFO
39 #include <net/route.h>
43 GetHostIP (struct sockaddr_in
*sock
, const char *Name
)
48 memset (sock
, 0, sizeof (*sock
));
49 h
= gethostbyname (Name
);
52 #ifdef HAVE_SOCKADDR_IN_LEN
53 sock
->sin_len
= sizeof (*sock
);
55 sock
->sin_family
= h
->h_addrtype
;
56 sock
->sin_addr
.s_addr
= (*((unsigned long *) h
->h_addr_list
[0]));
60 #ifdef HAVE_LINUX_NETLINK
69 GetSourceAddress (const struct sockaddr_in
*dest
, struct sockaddr_in
*src
)
75 memset (&req
, 0, sizeof (req
));
76 memset (src
, 0, sizeof (*src
));
77 s
= socket (PF_NETLINK
, SOCK_DGRAM
, NETLINK_ROUTE
);
81 NLMSG_SPACE (sizeof (req
.r
)) + RTA_LENGTH (sizeof (*dest
));
82 req
.n
.nlmsg_flags
= NLM_F_REQUEST
;
83 req
.n
.nlmsg_type
= RTM_GETROUTE
;
84 req
.r
.rtm_family
= AF_INET
;
85 req
.r
.rtm_dst_len
= 32;
86 a
= (rtattr
*) ((char *) &req
+ NLMSG_SPACE (sizeof (req
.r
)));
87 a
->rta_type
= RTA_DST
;
88 a
->rta_len
= RTA_LENGTH (sizeof (dest
->sin_addr
.s_addr
));
89 memcpy (RTA_DATA (a
), &dest
->sin_addr
.s_addr
,
90 sizeof (dest
->sin_addr
.s_addr
));
91 if (write (s
, &req
, req
.n
.nlmsg_len
) < 0)
93 if (read (s
, &req
, sizeof (req
)) < 0)
96 if (req
.n
.nlmsg_type
== NLMSG_ERROR
)
98 l
= ((struct nlmsghdr
*) &req
)->nlmsg_len
;
101 if (a
->rta_type
== RTA_PREFSRC
102 && RTA_PAYLOAD (a
) == sizeof (src
->sin_addr
.s_addr
))
104 src
->sin_family
= AF_INET
;
105 memcpy (&src
->sin_addr
.s_addr
, RTA_DATA (a
), RTA_PAYLOAD (a
));
114 #ifdef HAVE_WINDOWS_IPHELPER
116 GetSourceAddress (const struct sockaddr_in
*dest
, struct sockaddr_in
*src
)
119 PMIB_IPADDRTABLE tab
;
122 memset (src
, 0, sizeof (*src
));
123 if (GetBestInterface (dest
->sin_addr
.s_addr
, &d
) != NO_ERROR
)
126 tab
= (MIB_IPADDRTABLE
*) malloc (sizeof (MIB_IPADDRTABLE
));
129 if (GetIpAddrTable (tab
, &s
, 0) == ERROR_INSUFFICIENT_BUFFER
)
131 tab
= (MIB_IPADDRTABLE
*) realloc (tab
, s
);
135 if (GetIpAddrTable (tab
, &s
, 0) != NO_ERROR
)
141 for (int i
= 0; i
< tab
->dwNumEntries
; i
++)
142 if (tab
->table
[i
].dwIndex
== d
)
144 src
->sin_family
= AF_INET
;
145 src
->sin_addr
.s_addr
= tab
->table
[i
].dwAddr
;
154 #if HAVE_BSD_SOURCEINFO
157 struct rt_msghdr hdr
;
163 SA_SIZE (struct sockaddr
*sa
)
165 int align
= sizeof (long);
166 int len
= (sa
->sa_len
? sa
->sa_len
: align
);
167 if (len
& (align
- 1))
169 len
+= align
- (len
& (align
- 1));
176 GetSourceAddress (const struct sockaddr_in
*dest
, struct sockaddr_in
*src
)
181 memset (&req
, 0, sizeof (req
));
182 memset (src
, 0, sizeof (*src
));
183 s
= socket (PF_ROUTE
, SOCK_RAW
, 0);
186 req
.hdr
.rtm_msglen
= sizeof (req
) + sizeof (*dest
);
187 req
.hdr
.rtm_version
= RTM_VERSION
;
188 req
.hdr
.rtm_flags
= RTF_UP
;
189 req
.hdr
.rtm_type
= RTM_GET
;
190 req
.hdr
.rtm_addrs
= RTA_DST
| RTA_IFP
;
191 memcpy (cp
, dest
, sizeof (*dest
));
192 if (write (s
, (char *) &req
, req
.hdr
.rtm_msglen
) < 0)
194 if (read (s
, (char *) &req
, sizeof (req
)) < 0)
198 cp
= (char *) (&req
.hdr
+ 1);
199 for (i
= 1; i
; i
<<= 1)
200 if (i
& req
.hdr
.rtm_addrs
)
202 struct sockaddr
*sa
= (struct sockaddr
*) cp
;
205 src
->sin_len
= sizeof (*src
);
206 src
->sin_family
= AF_INET
;
207 src
->sin_addr
.s_addr
=
208 ((struct sockaddr_in
*) sa
)->sin_addr
.s_addr
;
218 compareIPAddress (const struct sockaddr_in
& a
, const struct sockaddr_in
& b
)
220 if (a
.sin_family
!= AF_INET
)
222 if (b
.sin_family
!= AF_INET
)
224 if (a
.sin_port
!= b
.sin_port
)
226 if (a
.sin_addr
.s_addr
!= b
.sin_addr
.s_addr
)
231 EIBNetIPPacket::EIBNetIPPacket ()
234 memset (&src
, 0, sizeof (src
));
238 EIBNetIPPacket::fromPacket (const CArray
& c
, const struct sockaddr_in src
)
244 if (c
[0] != 0x6 || c
[1] != 0x10)
246 len
= (c
[4] << 8) | c
[5];
249 p
= new EIBNetIPPacket
;
250 p
->service
= (c
[2] << 8) | c
[3];
251 p
->data
.set (c
.array () + 6, len
- 6);
257 EIBNetIPPacket::ToPacket ()
261 c
.resize (6 + data ());
264 c
[2] = (service
>> 8) & 0xff;
265 c
[3] = (service
) & 0xff;
266 c
[4] = ((data () + 6) >> 8) & 0xff;
267 c
[5] = ((data () + 6)) & 0xff;
273 IPtoEIBNetIP (const struct sockaddr_in
* a
)
279 buf
[2] = (ntohl (a
->sin_addr
.s_addr
) >> 24) & 0xff;
280 buf
[3] = (ntohl (a
->sin_addr
.s_addr
) >> 16) & 0xff;
281 buf
[4] = (ntohl (a
->sin_addr
.s_addr
) >> 8) & 0xff;
282 buf
[5] = (ntohl (a
->sin_addr
.s_addr
) >> 0) & 0xff;
283 buf
[6] = (ntohs (a
->sin_port
) >> 8) & 0xff;
284 buf
[7] = (ntohs (a
->sin_port
) >> 0) & 0xff;
289 EIBnettoIP (const CArray
& buf
, struct sockaddr_in
*a
,
290 const struct sockaddr_in
*src
)
293 memset (a
, 0, sizeof (*a
));
294 if (buf
[0] != 0x8 || buf
[1] != 0x1)
296 ip
= (buf
[2] << 24) | (buf
[3] << 16) | (buf
[4] << 8) | (buf
[5]);
297 port
= (buf
[6] << 8) | (buf
[7]);
298 #ifdef HAVE_SOCKADDR_IN_LEN
299 a
->sin_len
= sizeof (*a
);
301 a
->sin_family
= AF_INET
;
302 if (port
== 0 && ip
== 0)
304 a
->sin_port
= src
->sin_port
;
305 a
->sin_addr
.s_addr
= src
->sin_addr
.s_addr
;
309 a
->sin_port
= htons (port
);
310 a
->sin_addr
.s_addr
= htonl (ip
);
315 EIBNetIPSocket::EIBNetIPSocket (struct sockaddr_in bindaddr
, bool reuseaddr
,
320 TRACEPRINTF (t
, 0, this, "Open");
322 pth_sem_init (&insignal
);
323 pth_sem_init (&outsignal
);
324 getwait
= pth_event (PTH_EVENT_SEM
, &outsignal
);
325 memset (&maddr
, 0, sizeof (maddr
));
326 memset (&sendaddr
, 0, sizeof (sendaddr
));
327 memset (&recvaddr
, 0, sizeof (recvaddr
));
328 memset (&recvaddr2
, 0, sizeof (recvaddr2
));
331 fd
= socket (AF_INET
, SOCK_DGRAM
, 0);
338 if (setsockopt (fd
, SOL_SOCKET
, SO_REUSEADDR
, &i
, sizeof (i
)) == -1)
345 if (bind (fd
, (struct sockaddr
*) &bindaddr
, sizeof (bindaddr
)) == -1)
353 TRACEPRINTF (t
, 0, this, "Openend");
356 EIBNetIPSocket::~EIBNetIPSocket ()
358 TRACEPRINTF (t
, 0, this, "Close");
360 pth_event_free (getwait
, PTH_FREE_THIS
);
364 setsockopt (fd
, IPPROTO_IP
, IP_DROP_MEMBERSHIP
, &maddr
,
371 EIBNetIPSocket::init ()
377 EIBNetIPSocket::SetMulticast (struct ip_mreq multicastaddr
)
381 maddr
= multicastaddr
;
382 if (setsockopt (fd
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, &maddr
, sizeof (maddr
))
390 EIBNetIPSocket::Send (EIBNetIPPacket p
)
392 struct _EIBNetIP_Send s
;
393 t
->TracePacket (1, this, "Send", p
.data
);
397 pth_sem_inc (&insignal
, 1);
401 EIBNetIPSocket::Get (pth_event_t stop
)
404 pth_event_concat (getwait
, stop
, NULL
);
409 pth_event_isolate (getwait
);
411 if (pth_event_status (getwait
) == PTH_STATUS_OCCURRED
)
413 pth_sem_dec (&outsignal
);
414 t
->TracePacket (1, this, "Recv", outqueue
.top ().data
);
415 return new EIBNetIPPacket (outqueue
.get ());
422 EIBNetIPSocket::Run (pth_sem_t
* stop1
)
429 pth_event_t stop
= pth_event (PTH_EVENT_SEM
, stop1
);
430 pth_event_t input
= pth_event (PTH_EVENT_SEM
, &insignal
);
431 while (pth_event_status (stop
) != PTH_STATUS_OCCURRED
)
433 pth_event_concat (stop
, input
, NULL
);
435 memset (&r
, 0, sizeof (r
));
437 pth_recvfrom_ev (fd
, buf
, sizeof (buf
), 0, (struct sockaddr
*) &r
,
439 if (i
> 0 && rl
== sizeof (r
))
441 if (recvall
== 1 || !memcmp (&r
, &recvaddr
, sizeof (r
)) ||
442 (recvall
== 2 && memcmp (&r
, &localaddr
, sizeof (r
))) ||
443 (recvall
== 3 && !memcmp (&r
, &recvaddr2
, sizeof (r
))))
445 t
->TracePacket (0, this, "Recv", i
, buf
);
447 EIBNetIPPacket::fromPacket (CArray (buf
, i
), r
);
452 pth_sem_inc (&outsignal
, 1);
456 pth_event_isolate (stop
);
457 if (!inqueue
.isempty ())
459 const struct _EIBNetIP_Send s
= inqueue
.top ();
460 CArray p
= s
.data
.ToPacket ();
461 t
->TracePacket (0, this, "Send", p
);
463 pth_sendto_ev (fd
, p
.array (), p (), 0,
464 (const struct sockaddr
*) &s
.addr
, sizeof (s
.addr
),
468 pth_sem_dec (&insignal
);
476 t
->TracePacket (0, this, "Drop EIBnetSocket", p
);
477 pth_sem_dec (&insignal
);
483 pth_event_free (stop
, PTH_FREE_THIS
);
484 pth_event_free (input
, PTH_FREE_THIS
);
487 EIBnet_ConnectRequest::EIBnet_ConnectRequest ()
489 memset (&caddr
, 0, sizeof (caddr
));
490 memset (&daddr
, 0, sizeof (daddr
));
493 EIBNetIPPacket
EIBnet_ConnectRequest::ToPacket ()CONST
500 ca
= IPtoEIBNetIP (&caddr
);
501 da
= IPtoEIBNetIP (&daddr
);
502 p
.service
= CONNECTION_REQUEST
;
503 p
.data
.resize (ca () + da () + 1 + CRI ());
504 p
.data
.setpart (ca
, 0);
505 p
.data
.setpart (da
, ca ());
506 p
.data
[ca () + da ()] = CRI () + 1;
507 p
.data
.setpart (CRI
, ca () + da () + 1);
512 parseEIBnet_ConnectRequest (const EIBNetIPPacket
& p
,
513 EIBnet_ConnectRequest
& r
)
515 if (p
.service
!= CONNECTION_REQUEST
)
519 if (EIBnettoIP (CArray (p
.data
.array (), 8), &r
.caddr
, &p
.src
))
521 if (EIBnettoIP (CArray (p
.data
.array () + 8, 8), &r
.daddr
, &p
.src
))
523 if (p
.data () - 16 != p
.data
[16])
525 r
.CRI
= CArray (p
.data
.array () + 17, p
.data () - 17);
529 EIBnet_ConnectResponse::EIBnet_ConnectResponse ()
531 memset (&daddr
, 0, sizeof (daddr
));
536 EIBNetIPPacket
EIBnet_ConnectResponse::ToPacket ()CONST
541 da
= IPtoEIBNetIP (&daddr
);
542 p
.service
= CONNECTION_RESPONSE
;
546 p
.data
.resize (da () + CRD () + 3);
551 p
.data
.setpart (da
, 2);
552 p
.data
[da () + 2] = CRD () + 1;
553 p
.data
.setpart (CRD
, da () + 3);
559 parseEIBnet_ConnectResponse (const EIBNetIPPacket
& p
,
560 EIBnet_ConnectResponse
& r
)
562 if (p
.service
!= CONNECTION_RESPONSE
)
570 r
.channel
= p
.data
[0];
571 r
.status
= p
.data
[1];
576 if (EIBnettoIP (CArray (p
.data
.array () + 2, 8), &r
.daddr
, &p
.src
))
578 if (p
.data () - 10 != p
.data
[10])
580 r
.channel
= p
.data
[0];
581 r
.status
= p
.data
[1];
582 r
.CRD
= CArray (p
.data
.array () + 11, p
.data () - 11);
586 EIBnet_ConnectionStateRequest::EIBnet_ConnectionStateRequest ()
588 memset (&caddr
, 0, sizeof (caddr
));
592 EIBNetIPPacket
EIBnet_ConnectionStateRequest::ToPacket ()CONST
597 ca
= IPtoEIBNetIP (&caddr
);
598 p
.service
= CONNECTIONSTATE_REQUEST
;
599 p
.data
.resize (ca () + 2);
602 p
.data
.setpart (ca
, 2);
607 parseEIBnet_ConnectionStateRequest (const EIBNetIPPacket
& p
,
608 EIBnet_ConnectionStateRequest
& r
)
610 if (p
.service
!= CONNECTIONSTATE_REQUEST
)
614 if (EIBnettoIP (CArray (p
.data
.array () + 2, 8), &r
.caddr
, &p
.src
))
616 r
.channel
= p
.data
[0];
620 EIBnet_ConnectionStateResponse::EIBnet_ConnectionStateResponse ()
626 EIBNetIPPacket
EIBnet_ConnectionStateResponse::ToPacket ()CONST
630 p
.service
= CONNECTIONSTATE_RESPONSE
;
638 parseEIBnet_ConnectionStateResponse (const EIBNetIPPacket
& p
,
639 EIBnet_ConnectionStateResponse
& r
)
641 if (p
.service
!= CONNECTIONSTATE_RESPONSE
)
645 r
.channel
= p
.data
[0];
646 r
.status
= p
.data
[1];
650 EIBnet_DisconnectRequest::EIBnet_DisconnectRequest ()
652 memset (&caddr
, 0, sizeof (caddr
));
656 EIBNetIPPacket
EIBnet_DisconnectRequest::ToPacket ()CONST
661 ca
= IPtoEIBNetIP (&caddr
);
662 p
.service
= DISCONNECT_REQUEST
;
663 p
.data
.resize (ca () + 2);
666 p
.data
.setpart (ca
, 2);
671 parseEIBnet_DisconnectRequest (const EIBNetIPPacket
& p
,
672 EIBnet_DisconnectRequest
& r
)
674 if (p
.service
!= DISCONNECT_REQUEST
)
678 if (EIBnettoIP (CArray (p
.data
.array () + 2, 8), &r
.caddr
, &p
.src
))
680 r
.channel
= p
.data
[0];
684 EIBnet_DisconnectResponse::EIBnet_DisconnectResponse ()
690 EIBNetIPPacket
EIBnet_DisconnectResponse::ToPacket ()CONST
694 p
.service
= DISCONNECT_RESPONSE
;
702 parseEIBnet_DisconnectResponse (const EIBNetIPPacket
& p
,
703 EIBnet_DisconnectResponse
& r
)
705 if (p
.service
!= DISCONNECT_RESPONSE
)
709 r
.channel
= p
.data
[0];
710 r
.status
= p
.data
[1];
714 EIBnet_TunnelRequest::EIBnet_TunnelRequest ()
720 EIBNetIPPacket
EIBnet_TunnelRequest::ToPacket ()CONST
724 p
.service
= TUNNEL_REQUEST
;
725 p
.data
.resize (CEMI () + 4);
730 p
.data
.setpart (CEMI
, 4);
735 parseEIBnet_TunnelRequest (const EIBNetIPPacket
& p
, EIBnet_TunnelRequest
& r
)
737 if (p
.service
!= TUNNEL_REQUEST
)
743 r
.channel
= p
.data
[1];
745 r
.CEMI
.set (p
.data
.array () + 4, p
.data () - 4);
749 EIBnet_TunnelACK::EIBnet_TunnelACK ()
756 EIBNetIPPacket
EIBnet_TunnelACK::ToPacket ()CONST
760 p
.service
= TUNNEL_RESPONSE
;
770 parseEIBnet_TunnelACK (const EIBNetIPPacket
& p
, EIBnet_TunnelACK
& r
)
772 if (p
.service
!= TUNNEL_RESPONSE
)
778 r
.channel
= p
.data
[1];
780 r
.status
= p
.data
[3];
784 EIBnet_DescriptionRequest::EIBnet_DescriptionRequest ()
786 memset (&caddr
, 0, sizeof (caddr
));
789 EIBNetIPPacket
EIBnet_DescriptionRequest::ToPacket ()CONST
794 ca
= IPtoEIBNetIP (&caddr
);
795 p
.service
= DESCRIPTION_REQUEST
;
801 parseEIBnet_DescriptionRequest (const EIBNetIPPacket
& p
,
802 EIBnet_DescriptionRequest
& r
)
804 if (p
.service
!= DESCRIPTION_REQUEST
)
808 if (EIBnettoIP (p
.data
, &r
.caddr
, &p
.src
))
814 EIBnet_DescriptionResponse::EIBnet_DescriptionResponse ()
820 memset (&serial
, 0, sizeof (serial
));
821 multicastaddr
.s_addr
= 0;
822 memset (&MAC
, 0, sizeof (MAC
));
823 memset (&name
, 0, sizeof (name
));
826 EIBNetIPPacket
EIBnet_DescriptionResponse::ToPacket ()CONST
830 p
.service
= DESCRIPTION_RESPONSE
;
831 p
.data
.resize (56 + services () * 2);
834 p
.data
[2] = KNXmedium
;
835 p
.data
[3] = devicestatus
;
836 p
.data
[4] = (individual_addr
>> 8) & 0xff;
837 p
.data
[5] = (individual_addr
) & 0xff;
838 p
.data
[6] = (installid
>> 8) & 0xff;
839 p
.data
[7] = (installid
) & 0xff;
840 memcpy (p
.data
.array () + 18, &serial
, 6);
841 memcpy (p
.data
.array () + 14, &multicastaddr
, 4);
842 memcpy (p
.data
.array () + 18, &MAC
, 6);
843 memcpy (p
.data
.array () + 24, &name
, 30);
845 p
.data
[54] = services () * 2 + 2;
847 for (int i
= 0; i
< services (); i
++)
849 p
.data
[56 + i
* 2] = services
[i
].family
;
850 p
.data
[57 + i
* 2] = services
[i
].version
;
852 p
.data
.setpart (optional
, 56 + services () * 2);
857 parseEIBnet_DescriptionResponse (const EIBNetIPPacket
& p
,
858 EIBnet_DescriptionResponse
& r
)
860 if (p
.service
!= DESCRIPTION_RESPONSE
)
868 r
.KNXmedium
= p
.data
[2];
869 r
.devicestatus
= p
.data
[3];
870 r
.individual_addr
= (p
.data
[4] << 8) | p
.data
[5];
871 r
.installid
= (p
.data
[6] << 8) | p
.data
[7];
872 memcpy (&r
.serial
, p
.data
.array () + 8, 6);
873 memcpy (&r
.multicastaddr
, p
.data
.array () + 14, 4);
874 memcpy (&r
.MAC
, p
.data
.array () + 18, 6);
875 memcpy (&r
.name
, p
.data
.array () + 24, 30);
881 if (p
.data
[54] + 54 > p
.data ())
883 r
.services
.resize ((p
.data
[54] / 2) - 1);
884 for (int i
= 0; i
< (p
.data
[54] / 2) - 1; i
++)
886 r
.services
[i
].family
= p
.data
[56 + 2 * i
];
887 r
.services
[i
].version
= p
.data
[57 + 2 * i
];
889 r
.optional
.set (p
.data
.array () + p
.data
[54] + 54,
890 p
.data () - p
.data
[54] - 54);
894 EIBnet_SearchRequest::EIBnet_SearchRequest ()
896 memset (&caddr
, 0, sizeof (caddr
));
899 EIBNetIPPacket
EIBnet_SearchRequest::ToPacket ()CONST
904 ca
= IPtoEIBNetIP (&caddr
);
905 p
.service
= SEARCH_REQUEST
;
911 parseEIBnet_SearchRequest (const EIBNetIPPacket
& p
, EIBnet_SearchRequest
& r
)
913 if (p
.service
!= SEARCH_REQUEST
)
917 if (EIBnettoIP (p
.data
, &r
.caddr
, &p
.src
))
923 EIBnet_SearchResponse::EIBnet_SearchResponse ()
929 memset (&serial
, 0, sizeof (serial
));
930 multicastaddr
.s_addr
= 0;
931 memset (&MAC
, 0, sizeof (MAC
));
932 memset (&name
, 0, sizeof (name
));
935 EIBNetIPPacket
EIBnet_SearchResponse::ToPacket ()CONST
940 ca
= IPtoEIBNetIP (&caddr
);
941 p
.service
= SEARCH_RESPONSE
;
942 p
.data
.resize (64 + services () * 2);
943 p
.data
.setpart (ca
, 0);
946 p
.data
[10] = KNXmedium
;
947 p
.data
[11] = devicestatus
;
948 p
.data
[12] = (individual_addr
>> 8) & 0xff;
949 p
.data
[13] = (individual_addr
) & 0xff;
950 p
.data
[14] = (installid
>> 8) & 0xff;
951 p
.data
[15] = (installid
) & 0xff;
952 memcpy (p
.data
.array () + 16, &serial
, 6);
953 memcpy (p
.data
.array () + 22, &multicastaddr
, 4);
954 memcpy (p
.data
.array () + 26, &MAC
, 6);
955 memcpy (p
.data
.array () + 32, &name
, 30);
957 p
.data
[62] = services () * 2 + 2;
959 for (int i
= 0; i
< services (); i
++)
961 p
.data
[64 + i
* 2] = services
[i
].family
;
962 p
.data
[65 + i
* 2] = services
[i
].version
;
968 parseEIBnet_SearchResponse (const EIBNetIPPacket
& p
,
969 EIBnet_SearchResponse
& r
)
971 if (p
.service
!= SEARCH_RESPONSE
)
975 if (EIBnettoIP (CArray (p
.data
.array () + 0, 8), &r
.caddr
, &p
.src
))
981 r
.KNXmedium
= p
.data
[10];
982 r
.devicestatus
= p
.data
[11];
983 r
.individual_addr
= (p
.data
[12] << 8) | p
.data
[13];
984 r
.installid
= (p
.data
[14] << 8) | p
.data
[15];
985 memcpy (&r
.serial
, p
.data
.array () + 16, 6);
986 memcpy (&r
.multicastaddr
, p
.data
.array () + 22, 4);
987 memcpy (&r
.MAC
, p
.data
.array () + 26, 6);
988 memcpy (&r
.name
, p
.data
.array () + 32, 30);
994 if (p
.data
[62] + 62 > p
.data ())
996 r
.services
.resize ((p
.data
[62] / 2) - 1);
997 for (int i
= 0; i
< (p
.data
[62] / 2) - 1; i
++)
999 r
.services
[i
].family
= p
.data
[64 + 2 * i
];
1000 r
.services
[i
].version
= p
.data
[65 + 2 * i
];