2 EIBD eib bus access and management daemon
3 Copyright (C) 2005-2011 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "eibnettunnel.h"
24 EIBNetIPTunnel::addAddress (eibaddr_t addr
)
30 EIBNetIPTunnel::removeAddress (eibaddr_t addr
)
36 EIBNetIPTunnel::addGroupAddress (eibaddr_t addr
)
42 EIBNetIPTunnel::removeGroupAddress (eibaddr_t addr
)
48 EIBNetIPTunnel::getDefaultAddr ()
53 EIBNetIPTunnel::EIBNetIPTunnel (const char *dest
, int port
, int sport
,
54 const char *srcip
, int Dataport
, int flags
,
58 TRACEPRINTF (t
, 2, this, "Open");
59 pth_sem_init (&insignal
);
60 pth_sem_init (&outsignal
);
61 getwait
= pth_event (PTH_EVENT_SEM
, &outsignal
);
62 noqueue
= flags
& FLAG_B_TUNNEL_NOQUEUE
;
64 if (!GetHostIP (&caddr
, dest
))
66 caddr
.sin_port
= htons (port
);
67 if (!GetSourceAddress (&caddr
, &raddr
))
69 raddr
.sin_port
= htons (sport
);
72 sock
= new EIBNetIPSocket (raddr
, 0, t
);
81 if (!GetHostIP (&saddr
, srcip
))
87 saddr
.sin_port
= htons (sport
);
92 sock
->sendaddr
= caddr
;
93 sock
->recvaddr
= caddr
;
97 support_busmonitor
= 1;
98 connect_busmonitor
= 0;
100 TRACEPRINTF (t
, 2, this, "Opened");
103 EIBNetIPTunnel::~EIBNetIPTunnel ()
105 TRACEPRINTF (t
, 2, this, "Close");
107 while (!outqueue
.isempty ())
108 delete outqueue
.get ();
109 pth_event_free (getwait
, PTH_FREE_THIS
);
114 bool EIBNetIPTunnel::init ()
120 EIBNetIPTunnel::Send_L_Data (LPDU
* l
)
122 TRACEPRINTF (t
, 2, this, "Send %s", l
->Decode ()());
123 if (l
->getType () != L_Data
)
128 L_Data_PDU
*l1
= (L_Data_PDU
*) l
;
129 inqueue
.put (L_Data_ToCEMI (0x11, *l1
));
130 pth_sem_inc (&insignal
, 1);
133 L_Busmonitor_PDU
*l2
= new L_Busmonitor_PDU
;
134 l2
->pdu
.set (l
->ToPacket ());
136 pth_sem_inc (&outsignal
, 1);
139 pth_sem_inc (&outsignal
, 1);
143 EIBNetIPTunnel::Get_L_Data (pth_event_t stop
)
146 pth_event_concat (getwait
, stop
, NULL
);
151 pth_event_isolate (getwait
);
153 if (pth_event_status (getwait
) == PTH_STATUS_OCCURRED
)
155 pth_sem_dec (&outsignal
);
156 LPDU
*c
= outqueue
.get ();
158 TRACEPRINTF (t
, 2, this, "Recv %s", c
->Decode ()());
166 EIBNetIPTunnel::Send_Queue_Empty ()
168 return inqueue
.isempty ();
172 EIBNetIPTunnel::openVBusmonitor ()
179 EIBNetIPTunnel::closeVBusmonitor ()
186 EIBNetIPTunnel::enterBusmonitor ()
189 if (support_busmonitor
)
190 connect_busmonitor
= 1;
191 inqueue
.put (CArray ());
192 pth_sem_inc (&insignal
, 1);
197 EIBNetIPTunnel::leaveBusmonitor ()
200 connect_busmonitor
= 0;
201 inqueue
.put (CArray ());
202 pth_sem_inc (&insignal
, 1);
207 EIBNetIPTunnel::Open ()
213 EIBNetIPTunnel::Close ()
219 EIBNetIPTunnel::Connection_Lost ()
225 EIBNetIPTunnel::Run (pth_sem_t
* stop1
)
235 pth_event_t stop
= pth_event (PTH_EVENT_SEM
, stop1
);
236 pth_event_t input
= pth_event (PTH_EVENT_SEM
, &insignal
);
237 pth_event_t timeout
= pth_event (PTH_EVENT_RTIME
, pth_time (0, 0));
238 pth_event_t timeout1
= pth_event (PTH_EVENT_RTIME
, pth_time (10, 0));
243 EIBnet_ConnectRequest creq
;
244 creq
.nat
= saddr
.sin_addr
.s_addr
== 0;
245 EIBnet_ConnectResponse cresp
;
246 EIBnet_ConnectionStateRequest csreq
;
247 csreq
.nat
= saddr
.sin_addr
.s_addr
== 0;
248 EIBnet_ConnectionStateResponse csresp
;
249 EIBnet_TunnelRequest treq
;
250 EIBnet_TunnelACK tresp
;
251 EIBnet_DisconnectRequest dreq
;
252 dreq
.nat
= saddr
.sin_addr
.s_addr
== 0;
253 EIBnet_DisconnectResponse dresp
;
260 p
= creq
.ToPacket ();
261 sock
->sendaddr
= caddr
;
264 while (pth_event_status (stop
) != PTH_STATUS_OCCURRED
)
267 pth_event_concat (stop
, input
, NULL
);
268 if (mod
== 2 || mod
== 3)
269 pth_event_concat (stop
, timeout
, NULL
);
271 pth_event_concat (stop
, timeout1
, NULL
);
273 p1
= sock
->Get (stop
);
274 pth_event_isolate (stop
);
275 pth_event_isolate (timeout
);
276 pth_event_isolate (timeout1
);
281 case CONNECTION_RESPONSE
:
284 if (parseEIBnet_ConnectResponse (*p1
, cresp
))
286 TRACEPRINTF (t
, 1, this, "Recv wrong connection response");
289 if (cresp
.status
!= 0)
291 TRACEPRINTF (t
, 1, this, "Connect failed with error %02X",
293 if (cresp
.status
== 0x23 && support_busmonitor
== 1
294 && connect_busmonitor
== 1)
296 TRACEPRINTF (t
, 1, this, "Disable busmonitor support");
297 support_busmonitor
= 0;
298 connect_busmonitor
= 0;
300 pth_event (PTH_EVENT_RTIME
| PTH_MODE_REUSE
, timeout1
,
302 p
= creq
.ToPacket ();
303 TRACEPRINTF (t
, 1, this, "Connectretry");
304 sock
->sendaddr
= caddr
;
309 if (cresp
.CRD () != 3)
311 TRACEPRINTF (t
, 1, this, "Recv wrong connection response");
314 myaddr
= (cresp
.CRD
[1] << 8) | cresp
.CRD
[2];
319 daddr
.sin_addr
= caddr
.sin_addr
;
321 daddr
.sin_port
= htons (dataport
);
323 channel
= cresp
.channel
;
327 sock
->recvaddr2
= daddr
;
329 pth_event (PTH_EVENT_RTIME
| PTH_MODE_REUSE
, timeout1
,
337 TRACEPRINTF (t
, 1, this, "Not connected");
340 if (parseEIBnet_TunnelRequest (*p1
, treq
))
342 TRACEPRINTF (t
, 1, this, "Invalid request");
345 if (treq
.channel
!= channel
)
347 TRACEPRINTF (t
, 1, this, "Not for us");
350 if (((treq
.seqno
+ 1) & 0xff) == rno
)
353 tresp
.channel
= channel
;
354 tresp
.seqno
= treq
.seqno
;
355 p
= tresp
.ToPacket ();
356 sock
->sendaddr
= daddr
;
361 if (treq
.seqno
!= rno
)
363 TRACEPRINTF (t
, 1, this, "Wrong sequence %d<->%d",
365 if (treq
.seqno
< rno
)
367 if (treq
.seqno
>= rno
+ 5)
370 dreq
.channel
= channel
;
371 p
= dreq
.ToPacket ();
372 sock
->sendaddr
= caddr
;
383 tresp
.channel
= channel
;
384 tresp
.seqno
= treq
.seqno
;
385 p
= tresp
.ToPacket ();
386 sock
->sendaddr
= daddr
;
389 if (treq
.CEMI
[0] == 0x2E)
395 if (treq
.CEMI
[0] == 0x2B)
397 L_Busmonitor_PDU
*l2
= CEMI_to_Busmonitor (treq
.CEMI
);
399 pth_sem_inc (&outsignal
, 1);
402 if (treq
.CEMI
[0] != 0x29)
404 TRACEPRINTF (t
, 1, this, "Unexpected CEMI Type %02X",
408 c
= CEMI_to_L_Data (treq
.CEMI
);
412 TRACEPRINTF (t
, 1, this, "Recv %s", c
->Decode ()());
417 L_Busmonitor_PDU
*l2
= new L_Busmonitor_PDU
;
418 l2
->pdu
.set (c
->ToPacket ());
420 pth_sem_inc (&outsignal
, 1);
422 if (c
->AddrType
== IndividualAddress
423 && c
->dest
== myaddr
)
426 pth_sem_inc (&outsignal
, 1);
429 L_Busmonitor_PDU
*p1
= new L_Busmonitor_PDU
;
430 p1
->pdu
= c
->ToPacket ();
433 pth_sem_inc (&outsignal
, 1);
436 TRACEPRINTF (t
, 1, this, "Unknown CEMI");
438 case TUNNEL_RESPONSE
:
441 TRACEPRINTF (t
, 1, this, "Not connected");
444 if (parseEIBnet_TunnelACK (*p1
, tresp
))
446 TRACEPRINTF (t
, 1, this, "Invalid response");
449 if (tresp
.channel
!= channel
)
451 TRACEPRINTF (t
, 1, this, "Not for us");
454 if (tresp
.seqno
!= sno
)
456 TRACEPRINTF (t
, 1, this, "Wrong sequence %d<->%d",
462 TRACEPRINTF (t
, 1, this, "Error in ACK %d", tresp
.status
);
470 pth_sem_dec (&insignal
);
475 pth_event (PTH_EVENT_RTIME
| PTH_MODE_REUSE
, timeout
,
484 TRACEPRINTF (t
, 1, this, "Unexpected ACK");
486 case CONNECTIONSTATE_RESPONSE
:
487 if (parseEIBnet_ConnectionStateResponse (*p1
, csresp
))
489 TRACEPRINTF (t
, 1, this, "Invalid response");
492 if (csresp
.channel
!= channel
)
494 TRACEPRINTF (t
, 1, this, "Not for us");
497 if (csresp
.status
== 0)
502 TRACEPRINTF (t
, 1, this,
503 "Duplicate Connection State Response");
505 else if (csresp
.status
== 0x21)
507 TRACEPRINTF (t
, 1, this,
508 "Connection State Response not connected");
510 dreq
.channel
= channel
;
511 p
= dreq
.ToPacket ();
512 sock
->sendaddr
= caddr
;
518 TRACEPRINTF (t
, 1, this,
519 "Connection State Response Error %02x",
522 case DISCONNECT_REQUEST
:
525 TRACEPRINTF (t
, 1, this, "Not connected");
528 if (parseEIBnet_DisconnectRequest (*p1
, dreq
))
530 TRACEPRINTF (t
, 1, this, "Invalid request");
533 if (dreq
.channel
!= channel
)
535 TRACEPRINTF (t
, 1, this, "Not for us");
538 dresp
.channel
= channel
;
540 p
= dresp
.ToPacket ();
541 t
->TracePacket (1, this, "SendDis", p
.data
);
542 sock
->sendaddr
= caddr
;
547 case DISCONNECT_RESPONSE
:
550 TRACEPRINTF (t
, 1, this, "Not connected");
553 if (parseEIBnet_DisconnectResponse (*p1
, dresp
))
555 TRACEPRINTF (t
, 1, this, "Invalid request");
558 if (dresp
.channel
!= channel
)
560 TRACEPRINTF (t
, 1, this, "Not for us");
565 TRACEPRINTF (t
, 1, this, "Disconnected");
566 pth_event (PTH_EVENT_RTIME
| PTH_MODE_REUSE
, timeout1
,
571 TRACEPRINTF (t
, 1, this, "Recv unexpected service %04X",
576 if (mod
== 2 && pth_event_status (timeout
) == PTH_STATUS_OCCURRED
)
582 TRACEPRINTF (t
, 1, this, "Drop");
583 pth_sem_dec (&insignal
);
590 dreq
.channel
= channel
;
591 p
= dreq
.ToPacket ();
592 sock
->sendaddr
= caddr
;
599 if (mod
== 3 && pth_event_status (timeout
) == PTH_STATUS_OCCURRED
)
601 if (mod
!= 0 && pth_event_status (timeout1
) == PTH_STATUS_OCCURRED
)
603 pth_event (PTH_EVENT_RTIME
| PTH_MODE_REUSE
, timeout1
,
608 csreq
.channel
= channel
;
609 p
= csreq
.ToPacket ();
610 TRACEPRINTF (t
, 1, this, "Heartbeat");
611 sock
->sendaddr
= caddr
;
617 TRACEPRINTF (t
, 1, this, "Disconnection because of errors");
619 dreq
.channel
= channel
;
620 p
= dreq
.ToPacket ();
621 sock
->sendaddr
= caddr
;
628 if (mod
== 0 && pth_event_status (timeout1
) == PTH_STATUS_OCCURRED
)
630 pth_event (PTH_EVENT_RTIME
| PTH_MODE_REUSE
, timeout1
,
633 ((connect_busmonitor
&& support_busmonitor
) ? 0x80 : 0x02);
634 p
= creq
.ToPacket ();
635 TRACEPRINTF (t
, 1, this, "Connectretry");
636 sock
->sendaddr
= caddr
;
640 if (!inqueue
.isempty () && inqueue
.top ()() == 0)
642 pth_sem_dec (&insignal
);
644 if (support_busmonitor
)
647 dreq
.channel
= channel
;
648 p
= dreq
.ToPacket ();
649 sock
->sendaddr
= caddr
;
654 if (!inqueue
.isempty () && mod
== 1)
656 treq
.channel
= channel
;
658 treq
.CEMI
= inqueue
.top ();
659 p
= treq
.ToPacket ();
660 t
->TracePacket (1, this, "SendTunnel", p
.data
);
661 sock
->sendaddr
= daddr
;
664 pth_event (PTH_EVENT_RTIME
| PTH_MODE_REUSE
, timeout
,
670 dreq
.channel
= channel
;
671 p
= dreq
.ToPacket ();
672 sock
->sendaddr
= caddr
;
676 pth_event_free (stop
, PTH_FREE_THIS
);
677 pth_event_free (input
, PTH_FREE_THIS
);
678 pth_event_free (timeout
, PTH_FREE_THIS
);
679 pth_event_free (timeout1
, PTH_FREE_THIS
);