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 }