/ src / libserver / tunchannel.cpp
tunchannel.cpp
  1  /*
  2      EIBD eib bus access and management daemon
  3      Copyright (C) 2005-2011 Martin Koegler <mkoegler@auto.tuwien.ac.at>
  4  
  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.
  9  
 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.
 14  
 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.
 18  */
 19  
 20  #include "tunchannel.h"
 21  #include "tcptunserver.h"
 22  
 23  TunChannel::TunChannel(const TcpTunConnPtr& connection, uint8_t channelID)
 24    : t(TracePtr(new Trace(*connection->t)))
 25    , connection(connection)
 26    , channelID(channelID)
 27  {
 28    char buf[10];
 29    snprintf(buf, sizeof(buf), "-%02x", channelID);
 30    t->setAuxName(connection->t->auxname + buf);
 31  }
 32  
 33  TunChannel::~TunChannel()
 34  {
 35    TRACEPRINTF (t, 8, "Close TunChannel");
 36  }
 37  
 38  void TunChannel::setService(const TunServicePtr& service)
 39  {
 40    if (this->service)
 41      {
 42        TRACEPRINTF (t, 8, "Service is already set");
 43        return;
 44      }
 45  
 46    TRACEPRINTF (t, 8, "Setting service");
 47  
 48    this->service = service;
 49  }
 50  
 51  bool TunChannel::setupChannel()
 52  {
 53    if (!this->service)
 54      {
 55        TRACEPRINTF (t, 8, "Service not set");
 56        return false;
 57      }
 58  
 59    return service->setupService();
 60  }
 61  
 62  void TunChannel::start()
 63  {
 64    service->start();
 65  }
 66  
 67  void TunChannel::stop(bool err)
 68  {
 69    service->stop(err);
 70  }
 71  
 72  void TunChannel::sendTunnelRequest(const CArray& cemi)
 73  {
 74    auto connection = this->connection.lock();
 75    if (!connection)
 76      {
 77        TRACEPRINTF (t, 8, "Attempt to send tunnel request without a connection");
 78        return;
 79      }
 80  
 81    EIBnet_TunnelRequest r;
 82    r.channel = channelID;
 83    r.seqno = sno;
 84    r.CEMI = cemi;
 85    connection->send(r.ToPacket(IPV4_TCP));
 86    sno = (sno + 1) & 0xff;
 87  }
 88  
 89  void TunChannel::sendConfigRequest(const CArray& cemi)
 90  {
 91    auto connection = this->connection.lock();
 92    if (!connection)
 93      {
 94        TRACEPRINTF (t, 8, "Attempt to send config request without a connection");
 95        return;
 96      }
 97  
 98    EIBnet_ConfigRequest r;
 99    r.channel = channelID;
100    r.seqno = sno;
101    r.CEMI = cemi;
102    connection->send(r.ToPacket(IPV4_TCP));
103    sno = (sno + 1) & 0xff;
104  }
105  
106  void TunChannel::receiveTunnelRequest(EIBnet_TunnelRequest &r1)
107  {
108    // On UDP, the sequence number would be checked here, but for TCP the sequence
109    // number is not checked. See ISO 22510:2019 section 5.2.5.3.4
110    // if (rno != r1.seqno)
111    //   {
112    //     TRACEPRINTF (t, 8, "Wrong tunnel sequence number %d<->%d",
113    //                  r1.seqno, rno);
114    //   }
115    rno++;
116  
117    if (!service)
118      {
119        TRACEPRINTF (t, 8, "No tunnel service set");
120        return;
121      }
122  
123    uint8_t status = service->handleTunnelRequest(r1);
124  
125    // Note: There are no TUNNELLING_ACKs with TCP, so no way to return the status
126    if (status)
127      TRACEPRINTF (t, 8, "TCP TUNNELLING_REQUEST failed (%d)", status);
128  }
129  
130  void TunChannel::receiveConfigRequest(EIBnet_ConfigRequest &r1)
131  {
132    // On UDP, the sequence number would be checked here, but for TCP the sequence
133    // number is not checked. See ISO 22510:2019 section 5.2.5.3.4
134    // if (rno != r1.seqno)
135    //   {
136    //     TRACEPRINTF (t, 8, "Wrong config sequence number %d<->%d",
137    //                  r1.seqno, rno);
138    //   }
139    rno++;
140  
141    if (!service)
142      {
143        TRACEPRINTF (t, 8, "No tunnel service set");
144        return;
145      }
146  
147    uint8_t status = service->handleConfigRequest(r1);
148  
149    // Note: There are no DEVICE_CONFIGURATION_ACKs with TCP, so no way to return
150    // the status
151    if (status)
152      TRACEPRINTF (t, 8, "TCP DEVICE_CONFIGURATION_REQUEST failed (%d)", status);
153  }
154  
155  TunService::TunService(const TunChannelPtr& channel)
156    : t(channel->t)
157    , channel(channel)
158  {
159  }
160  
161  TunService::~TunService()
162  {
163  }
164  
165  // This method is overwritten on channel classes which expect to receive
166  // TUNNELLING_REQUEST packets
167  ErrorCode TunService::handleTunnelRequest(EIBnet_TunnelRequest &r1)
168  {
169    TRACEPRINTF (t, 8, "Got unexpected TUNNELLING_REQUEST");
170    return E_TUNNELING_LAYER;
171  }
172  
173  // This method is overwritten on channel classes which expect to receive
174  // DEVICE_CONFIGURATION_REQUEST packets
175  ErrorCode TunService::handleConfigRequest(EIBnet_ConfigRequest &r1)
176  {
177    TRACEPRINTF (t, 8, "Got unexpected DEVICE_CONFIGURATION_REQUEST");
178    return E_KNX_CONNECTION;
179  }
180  
181  TunServiceLinkLayer::TunServiceLinkLayer(const TunChannelPtr& channel, Router& router, LinkConnectClientPtr c)
182    : SubDriver(c)
183    , TunService(channel)
184    , router(router)
185  {
186    SubDriver::t->setAuxName(channel->t->auxname);
187  }
188  
189  TunServiceLinkLayer::~TunServiceLinkLayer()
190  {
191  }
192  
193  bool TunServiceLinkLayer::setupService()
194  {
195    addAddress(knxaddr);
196  
197    return true;
198  }
199  
200  bool TunServiceLinkLayer::setup()
201  {
202    if (!SubDriver::setup())
203      return false;
204  
205    return true;
206  }
207  
208  void TunServiceLinkLayer::start()
209  {
210    SubDriver::start();
211  }
212  
213  void TunServiceLinkLayer::stop(bool err)
214  {
215    freeAddress();
216  
217    auto c = std::dynamic_pointer_cast<LinkConnect>(conn.lock());
218    if (c != nullptr)
219      router.unregisterLink(c);
220  
221    SubDriver::stop(err);
222  }
223  
224  void TunServiceLinkLayer::send_L_Data (LDataPtr l)
225  {
226    auto channel_ptr = this->channel.lock();
227    if (channel_ptr)
228      channel_ptr->sendTunnelRequest(L_Data_ToCEMI(0x29, l));
229  
230    send_Next();
231  }
232  
233  ErrorCode TunServiceLinkLayer::handleTunnelRequest(EIBnet_TunnelRequest &r1)
234  {
235    TRACEPRINTF (t, 8, "TUNNEL_REQ");
236  
237    LDataPtr c = CEMI_to_L_Data(r1.CEMI, t);
238    if (!c)
239      return E_DATA_CONNECTION;
240  
241    if (c->source_address == 0)
242      c->source_address = knxaddr;
243  
244    if (r1.CEMI[0] == 0x11)
245      {
246        // Send L_Data.con message
247        auto channel_ptr = this->channel.lock();
248        if (channel_ptr)
249          channel_ptr->sendTunnelRequest(L_Data_ToCEMI(0x2E, c));
250      }
251  
252    if (r1.CEMI[0] == 0x11 || r1.CEMI[0] == 0x29)
253      {
254        recv_L_Data(std::move(c));
255        return E_NO_ERROR;
256      }
257    else
258      {
259        TRACEPRINTF (t, 8, "Wrong leader x%02x", r1.CEMI[0]);
260        return E_TUNNELING_LAYER;
261      }
262  }
263  
264  bool TunServiceLinkLayer::allocAddress()
265  {
266    // Channel can have only one address
267    if (knxaddr)
268      return false;
269  
270    knxaddr = router.get_client_addr(t);
271    if (!knxaddr)
272      // Out of addresses
273      return false;
274  
275    t->setAuxName(FormatEIBAddr(knxaddr));
276  
277    return true;
278  }
279  
280  void TunServiceLinkLayer::freeAddress()
281  {
282    if (!knxaddr)
283      return;
284  
285    router.release_client_addr(knxaddr);
286    knxaddr = 0;
287    t->setAuxName("no-addr");
288  }
289  
290  TunServiceBusMonitor::TunServiceBusMonitor(const TunChannelPtr& channel, Router& router)
291    : TunService(channel)
292    , L_Busmonitor_CallBack(channel->t->name)
293    , router(router)
294  {
295  }
296  
297  TunServiceBusMonitor::~TunServiceBusMonitor()
298  {
299  }
300  
301  bool TunServiceBusMonitor::setupService()
302  {
303    if (!router.registerVBusmonitor(this))
304      return false;
305  
306    return true;
307  }
308  
309  void TunServiceBusMonitor::start()
310  {
311  }
312  
313  void TunServiceBusMonitor::stop(bool err)
314  {
315    router.deregisterVBusmonitor(this);
316  }
317  
318  void TunServiceBusMonitor::send_L_Busmonitor(LBusmonPtr l)
319  {
320    auto channel_ptr = this->channel.lock();
321    if (channel_ptr)
322      channel_ptr->sendTunnelRequest(Busmonitor_to_CEMI(0x2B, l, no));
323  
324    no++;
325  }
326  
327  TunServiceConfig::TunServiceConfig(const TunChannelPtr& channel)
328    : TunService(channel)
329  {
330  }
331  
332  TunServiceConfig::~TunServiceConfig()
333  {
334  }
335  
336  bool TunServiceConfig::setupService()
337  {
338    return true;
339  }
340  
341  void TunServiceConfig::start()
342  {
343  }
344  
345  void TunServiceConfig::stop(bool err)
346  {
347  }
348  
349  ErrorCode TunServiceConfig::handleConfigRequest(EIBnet_ConfigRequest &r1)
350  {
351    if (r1.CEMI.size() == 0)
352      return E_DATA_CONNECTION;
353  
354    if (r1.CEMI[0] == 0xFC) // M_PropRead.req
355      {
356        if (r1.CEMI.size() == 7)
357          {
358            CArray res, CEMI;
359            int obj = (r1.CEMI[1] << 8) | r1.CEMI[2];
360            int objno = r1.CEMI[3];
361            int prop = r1.CEMI[4];
362            int count = (r1.CEMI[5] >> 4) & 0x0f;
363            int start = (r1.CEMI[5] & 0x0f) | r1.CEMI[6];
364            res.resize(1);
365            res[0] = 0;
366            if (obj == 0 && objno == 0)
367              {
368                if (prop == 0)
369                  {
370                    res.resize(2);
371                    res[0] = 0;
372                    res[1] = 0;
373                    start = 0;
374                  }
375                else
376                  count = 0;
377              }
378            else
379              count = 0;
380            CEMI.resize(6 + res.size());
381            CEMI[0] = 0xFB;
382            CEMI[1] = (obj >> 8) & 0xff;
383            CEMI[2] = obj & 0xff;
384            CEMI[3] = objno;
385            CEMI[4] = prop;
386            CEMI[5] = ((count & 0x0f) << 4) | (start >> 8);
387            CEMI[6] = start & 0xff;
388            CEMI.setpart(res, 7);
389  
390            auto channel_ptr = this->channel.lock();
391            if (channel_ptr)
392              channel_ptr->sendConfigRequest(CEMI);
393  
394            return E_NO_ERROR;
395          }
396        else
397          return E_DATA_CONNECTION;
398      }
399    else
400      return E_DATA_CONNECTION;
401  }