eibnetip.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 "eibnetip.h" 21 #include "config.h" 22 23 #include <cerrno> 24 #include <cstring> 25 #include <net/if.h> 26 #include <netdb.h> 27 #include <sys/socket.h> 28 #include <unistd.h> 29 30 EIBNetIPPacket::EIBNetIPPacket () 31 { 32 service = 0; 33 memset (&src, 0, sizeof (src)); 34 } 35 36 EIBNetIPPacket * 37 EIBNetIPPacket::fromPacket (const CArray & c, const struct sockaddr_in src, HostProtocolCode protocol) 38 { 39 EIBNetIPPacket *p; 40 if (c.size() < 6) 41 return 0; 42 if (c[0] != 0x6 || c[1] != 0x10) 43 return 0; 44 unsigned len = (c[4] << 8) | c[5]; 45 if (len != c.size()) 46 return 0; 47 p = new EIBNetIPPacket; 48 p->service = (c[2] << 8) | c[3]; 49 p->data.set (c.data() + 6, len - 6); 50 p->src = src; 51 p->protocol = protocol; 52 return p; 53 } 54 55 CArray 56 EIBNetIPPacket::ToPacket () 57 const 58 { 59 CArray c; 60 c.resize (6 + data.size()); 61 c[0] = 0x06; 62 c[1] = 0x10; 63 c[2] = (service >> 8) & 0xff; 64 c[3] = (service) & 0xff; 65 c[4] = ((data.size() + 6) >> 8) & 0xff; 66 c[5] = ((data.size() + 6)) & 0xff; 67 c.setpart (data, 6); 68 return c; 69 } 70 71 EIBNetIPSocket::EIBNetIPSocket (struct sockaddr_in bindaddr, bool reuseaddr, 72 TracePtr tr, SockMode mode) 73 { 74 int i; 75 t = tr; 76 TRACEPRINTF (t, 0, "Open"); 77 multicast = false; 78 memset (&maddr, 0, sizeof (maddr)); 79 memset (&sendaddr, 0, sizeof (sendaddr)); 80 memset (&recvaddr, 0, sizeof (recvaddr)); 81 memset (&recvaddr2, 0, sizeof (recvaddr2)); 82 recvall = 0; 83 84 io_send.set<EIBNetIPSocket, &EIBNetIPSocket::io_send_cb>(this); 85 io_recv.set<EIBNetIPSocket, &EIBNetIPSocket::io_recv_cb>(this); 86 on_recv.set<EIBNetIPSocket, &EIBNetIPSocket::recv_cb>(this); // dummy 87 on_error.set<EIBNetIPSocket, &EIBNetIPSocket::error_cb>(this); // dummy 88 on_next.set<EIBNetIPSocket, &EIBNetIPSocket::next_cb>(this); // dummy 89 90 fd = socket (AF_INET, SOCK_DGRAM, 0); 91 if (fd == -1) 92 return; 93 set_non_blocking(fd); 94 95 if (reuseaddr) 96 { 97 i = 1; 98 if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof (i)) == -1) 99 { 100 ERRORPRINTF (t, E_ERROR | 45, "cannot reuse address: %s", strerror(errno)); 101 close (fd); 102 fd = -1; 103 return; 104 } 105 } 106 if (bind (fd, (struct sockaddr *) &bindaddr, sizeof (bindaddr)) == -1) 107 { 108 ERRORPRINTF (t, E_ERROR | 38, "cannot bind to address: %s", strerror(errno)); 109 close (fd); 110 fd = -1; 111 return; 112 } 113 114 // Enable loopback so processes on the same host see each other. 115 { 116 char loopch=1; 117 118 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, 119 (char *)&loopch, sizeof(loopch)) < 0) 120 { 121 ERRORPRINTF (t, E_ERROR | 39, "cannot turn on multicast loopback: %s", strerror(errno)); 122 close(fd); 123 fd = -1; 124 return; 125 } 126 } 127 128 // don't really care if this fails 129 if (mode == S_RD) 130 shutdown (fd, SHUT_WR); 131 if (mode == S_WR) 132 shutdown (fd, SHUT_RD); 133 else 134 io_recv.start(fd, ev::READ); 135 136 TRACEPRINTF (t, 0, "Opened"); 137 } 138 139 EIBNetIPSocket::~EIBNetIPSocket () 140 { 141 TRACEPRINTF (t, 0, "Close D"); 142 stop(false); 143 } 144 145 void 146 EIBNetIPSocket::stop(bool err) 147 { 148 if (fd != -1) 149 { 150 io_recv.stop(); 151 io_send.stop(); 152 if (multicast) 153 setsockopt (fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &maddr, 154 sizeof (maddr)); 155 close (fd); 156 fd = -1; 157 } 158 } 159 160 void 161 EIBNetIPSocket::pause() 162 { 163 if (paused) 164 return; 165 paused = true; 166 io_recv.stop(); 167 } 168 169 void 170 EIBNetIPSocket::unpause() 171 { 172 if (! paused) 173 return; 174 paused = false; 175 io_recv.start(fd, ev::READ); 176 } 177 178 bool 179 EIBNetIPSocket::init () 180 { 181 if (fd < 0) 182 return false; 183 io_recv.start(fd, ev::READ); 184 return true; 185 } 186 187 int 188 EIBNetIPSocket::port () 189 { 190 struct sockaddr_in sa; 191 socklen_t saLen = sizeof(sa); 192 if (getsockname(fd, (struct sockaddr *) &sa, &saLen) < 0) 193 return -1; 194 if (sa.sin_family != AF_INET) 195 { 196 errno = EAFNOSUPPORT; 197 return -1; 198 } 199 return sa.sin_port; 200 } 201 202 bool 203 EIBNetIPSocket::SetMulticast (struct ip_mreqn multicastaddr) 204 { 205 if (multicast) 206 return false; 207 maddr = multicastaddr; 208 if (setsockopt (fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &maddr, sizeof (maddr)) 209 == -1) 210 return false; 211 multicast = true; 212 return true; 213 } 214 215 void 216 EIBNetIPSocket::Send (EIBNetIPPacket p, struct sockaddr_in addr) 217 { 218 struct _EIBNetIP_Send s; 219 t->TracePacket (1, "Send", p.data); 220 s.data = p; 221 s.addr = addr; 222 223 if (send_q.empty()) 224 io_send.start(fd, ev::WRITE); 225 send_q.put (std::move(s)); 226 } 227 228 void 229 EIBNetIPSocket::io_send_cb (ev::io &, int) 230 { 231 if (send_q.empty ()) 232 { 233 io_send.stop(); 234 on_next(); 235 return; 236 } 237 const struct _EIBNetIP_Send s = send_q.front (); 238 CArray p = s.data.ToPacket (); 239 t->TracePacket (0, "Send", p); 240 int i = sendto (fd, p.data(), p.size(), 0, 241 (const struct sockaddr *) &s.addr, sizeof (s.addr)); 242 if (i > 0) 243 { 244 send_q.get (); 245 send_error = 0; 246 } 247 else 248 { 249 if (i == 0 || (errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)) 250 { 251 TRACEPRINTF (t, 0, "Send: %s", strerror(errno)); 252 if (send_error++ > 5) 253 { 254 t->TracePacket (0, "EIBnetSocket:drop", p); 255 send_q.get (); 256 send_error = 0; 257 on_error(); 258 } 259 } 260 } 261 } 262 263 void 264 EIBNetIPSocket::io_recv_cb (ev::io &, int) 265 { 266 uint8_t buf[255]; 267 socklen_t rl; 268 sockaddr_in r; 269 rl = sizeof (r); 270 memset (&r, 0, sizeof (r)); 271 272 int i = recvfrom (fd, buf, sizeof (buf), 0, (struct sockaddr *) &r, &rl); 273 if (i < 0 && errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) 274 on_error(); 275 else if (i >= 0 && rl == sizeof (r)) 276 { 277 if (recvall == 1 || !memcmp (&r, &recvaddr, sizeof (r)) || 278 (recvall == 2 && memcmp (&r, &localaddr, sizeof (r))) || 279 (recvall == 3 && !memcmp (&r, &recvaddr2, sizeof (r)))) 280 { 281 t->TracePacket (0, "Recv", i, buf); 282 EIBNetIPPacket *p = 283 EIBNetIPPacket::fromPacket (CArray (buf, i), r); 284 if (p) 285 on_recv(p); 286 else 287 t->TracePacket (0, "Parse?", i, buf); 288 } 289 else 290 t->TracePacket (0, "Dropped", i, buf); 291 } 292 } 293 294 bool 295 EIBNetIPSocket::SetInterface(std::string& iface) 296 { 297 struct sockaddr_in sa; 298 struct ip_mreqn addr; 299 300 memset (&sa, 0, sizeof(sa)); 301 memset (&addr, 0, sizeof(addr)); 302 303 if (iface.size() == 0) 304 return true; 305 addr.imr_ifindex = if_nametoindex(iface.c_str()); 306 return 307 setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &addr, sizeof(addr)) >= 0; 308 } 309 310 EIBnet_SearchRequest::EIBnet_SearchRequest () 311 { 312 memset (&caddr, 0, sizeof (caddr)); 313 } 314 315 EIBNetIPPacket EIBnet_SearchRequest::ToPacket (HostProtocolCode protocol)const 316 { 317 EIBNetIPPacket 318 p; 319 CArray 320 ca = IPtoEIBNetIP (&caddr, nat, protocol); 321 p.service = SEARCH_REQUEST; 322 p.data = ca; 323 return p; 324 } 325 326 int 327 parseEIBnet_SearchRequest (const EIBNetIPPacket & p, EIBnet_SearchRequest & r) 328 { 329 if (p.service != SEARCH_REQUEST) 330 return 1; 331 if (p.data.size() != 8) 332 return 1; 333 if (EIBnettoIP (p.data, &r.caddr, &p.src, r.nat, p.protocol)) 334 return 1; 335 return 0; 336 } 337 338 339 EIBnet_SearchResponse::EIBnet_SearchResponse () 340 { 341 serial.fill(0); 342 multicastaddr.s_addr = 0; 343 memset (&MAC, 0, sizeof (MAC)); 344 memset (&name, 0, sizeof (name)); 345 } 346 347 EIBNetIPPacket EIBnet_SearchResponse::ToPacket (HostProtocolCode protocol)const 348 { 349 EIBNetIPPacket p; 350 CArray ca = IPtoEIBNetIP (&caddr, nat, protocol); 351 p.service = SEARCH_RESPONSE; 352 p.data.resize (64 + services.size() * 2); 353 p.data.setpart (ca, 0); 354 p.data[8] = 54; 355 p.data[9] = 1; 356 p.data[10] = KNXmedium; 357 p.data[11] = devicestatus; 358 p.data[12] = (individual_addr >> 8) & 0xff; 359 p.data[13] = (individual_addr) & 0xff; 360 p.data[14] = (installid >> 8) & 0xff; 361 p.data[15] = (installid) & 0xff; 362 p.data.setpart((uint8_t *)&serial, 16, 6); 363 p.data.setpart((uint8_t *)&multicastaddr, 22, 4); 364 p.data.setpart((uint8_t *)&MAC, 26, 6); 365 p.data.setpart((uint8_t *)&name, 32, 30); 366 p.data[61] = 0; 367 p.data[62] = services.size() * 2 + 2; 368 p.data[63] = 2; 369 for (unsigned int i = 0; i < services.size(); i++) 370 { 371 p.data[64 + i * 2] = services[i].family; 372 p.data[65 + i * 2] = services[i].version; 373 } 374 return p; 375 } 376 377 int 378 parseEIBnet_SearchResponse (const EIBNetIPPacket & p, 379 EIBnet_SearchResponse & r) 380 { 381 if (p.service != SEARCH_RESPONSE) 382 return 1; 383 if (p.data.size() < 64) 384 return 1; 385 if (EIBnettoIP (CArray (p.data.data() + 0, 8), &r.caddr, &p.src, r.nat, p.protocol)) 386 return 1; 387 if (p.data[8] != 54) 388 return 1; 389 if (p.data[9] != 1) 390 return 1; 391 r.KNXmedium = p.data[10]; 392 r.devicestatus = p.data[11]; 393 r.individual_addr = (p.data[12] << 8) | p.data[13]; 394 r.installid = (p.data[14] << 8) | p.data[15]; 395 memcpy (&r.serial, p.data.data() + 16, 6); 396 memcpy (&r.multicastaddr, p.data.data() + 22, 4); 397 memcpy (&r.MAC, p.data.data() + 26, 6); 398 memcpy (&r.name, p.data.data() + 32, 30); 399 r.name[29] = 0; 400 if (p.data[63] != 2) 401 return 1; 402 if (p.data[62] % 2) 403 return 1; 404 if (p.data[62] + 62U > p.data.size()) 405 return 1; 406 r.services.resize ((p.data[62] / 2) - 1); 407 for (int i = 0; i < (p.data[62] / 2) - 1; i++) 408 { 409 r.services[i].family = p.data[64 + 2 * i]; 410 r.services[i].version = p.data[65 + 2 * i]; 411 } 412 return 0; 413 } 414 415 EIBnet_DescriptionRequest::EIBnet_DescriptionRequest () 416 { 417 memset (&caddr, 0, sizeof (caddr)); 418 } 419 420 EIBNetIPPacket EIBnet_DescriptionRequest::ToPacket (HostProtocolCode protocol)const 421 { 422 EIBNetIPPacket 423 p; 424 CArray 425 ca = IPtoEIBNetIP (&caddr, nat, protocol); 426 p.service = DESCRIPTION_REQUEST; 427 p.data = ca; 428 return p; 429 } 430 431 int 432 parseEIBnet_DescriptionRequest (const EIBNetIPPacket & p, 433 EIBnet_DescriptionRequest & r) 434 { 435 if (p.service != DESCRIPTION_REQUEST) 436 return 1; 437 if (p.data.size() != 8) 438 return 1; 439 if (EIBnettoIP (p.data, &r.caddr, &p.src, r.nat, p.protocol)) 440 return 1; 441 return 0; 442 } 443 444 EIBnet_DescriptionResponse::EIBnet_DescriptionResponse () 445 { 446 memset (&serial, 0, sizeof (serial)); 447 multicastaddr.s_addr = 0; 448 memset (&MAC, 0, sizeof (MAC)); 449 memset (&name, 0, sizeof (name)); 450 } 451 452 EIBNetIPPacket EIBnet_DescriptionResponse::ToPacket (HostProtocolCode protocol)const 453 { 454 EIBNetIPPacket 455 p; 456 p.service = DESCRIPTION_RESPONSE; 457 p.data.resize (56 + services.size() * 2); 458 p.data[0] = 54; 459 p.data[1] = 1; 460 p.data[2] = KNXmedium; 461 p.data[3] = devicestatus; 462 p.data[4] = (individual_addr >> 8) & 0xff; 463 p.data[5] = (individual_addr) & 0xff; 464 p.data[6] = (installid >> 8) & 0xff; 465 p.data[7] = (installid) & 0xff; 466 p.data.setpart((const uint8_t *)&serial, 8, 6); 467 p.data.setpart((const uint8_t *)&multicastaddr, 14, 4); 468 p.data.setpart((const uint8_t *)&MAC, 18, 6); 469 p.data.setpart((const uint8_t *)&name, 24, 30); 470 p.data[53] = 0; 471 p.data[54] = services.size() * 2 + 2; 472 p.data[55] = 2; 473 for (unsigned int i = 0; i < services.size(); i++) 474 { 475 p.data[56 + i * 2] = services[i].family; 476 p.data[57 + i * 2] = services[i].version; 477 } 478 p.data.setpart (optional, 56 + services.size() * 2); 479 return p; 480 } 481 482 int 483 parseEIBnet_DescriptionResponse (const EIBNetIPPacket & p, 484 EIBnet_DescriptionResponse & r) 485 { 486 if (p.service != DESCRIPTION_RESPONSE) 487 return 1; 488 if (p.data.size() < 56) 489 return 1; 490 if (p.data[0] != 54) 491 return 1; 492 if (p.data[1] != 1) 493 return 1; 494 r.KNXmedium = p.data[2]; 495 r.devicestatus = p.data[3]; 496 r.individual_addr = (p.data[4] << 8) | p.data[5]; 497 r.installid = (p.data[6] << 8) | p.data[7]; 498 memcpy (&r.serial, p.data.data() + 8, 6); 499 memcpy (&r.multicastaddr, p.data.data() + 14, 4); 500 memcpy (&r.MAC, p.data.data() + 18, 6); 501 memcpy (&r.name, p.data.data() + 24, 30); 502 r.name[29] = 0; 503 if (p.data[55] != 2) 504 return 1; 505 if (p.data[54] % 2) 506 return 1; 507 if (p.data[54] + 54U > p.data.size()) 508 return 1; 509 r.services.resize ((p.data[54] / 2) - 1); 510 for (int i = 0; i < (p.data[54] / 2) - 1; i++) 511 { 512 r.services[i].family = p.data[56 + 2 * i]; 513 r.services[i].version = p.data[57 + 2 * i]; 514 } 515 r.optional.set (p.data.data() + p.data[54] + 54, 516 p.data.size() - p.data[54] - 54); 517 return 0; 518 } 519 520 EIBnet_ConnectRequest::EIBnet_ConnectRequest () 521 { 522 memset (&caddr, 0, sizeof (caddr)); 523 memset (&daddr, 0, sizeof (daddr)); 524 } 525 526 EIBNetIPPacket EIBnet_ConnectRequest::ToPacket (HostProtocolCode protocol)const 527 { 528 EIBNetIPPacket p; 529 CArray ca, da; 530 ca = IPtoEIBNetIP (&caddr, nat, protocol); 531 da = IPtoEIBNetIP (&daddr, nat, protocol); 532 p.service = CONNECTION_REQUEST; 533 p.data.resize (ca.size() + da.size() + 1 + CRI.size()); 534 p.data.setpart (ca, 0); 535 p.data.setpart (da, ca.size()); 536 p.data[ca.size() + da.size()] = CRI.size() + 1; 537 p.data.setpart (CRI, ca.size() + da.size() + 1); 538 return p; 539 } 540 541 int 542 parseEIBnet_ConnectRequest (const EIBNetIPPacket & p, 543 EIBnet_ConnectRequest & r) 544 { 545 if (p.service != CONNECTION_REQUEST) 546 return 1; 547 if (p.data.size() < 18) 548 return 1; 549 if (EIBnettoIP (CArray (p.data.data(), 8), &r.caddr, &p.src, r.nat, p.protocol)) 550 return 1; 551 if (EIBnettoIP (CArray (p.data.data() + 8, 8), &r.daddr, &p.src, r.nat, p.protocol)) 552 return 1; 553 if (p.data.size() - 16 != p.data[16]) 554 return 1; 555 r.CRI = CArray (p.data.data() + 17, p.data.size() - 17); 556 return 0; 557 } 558 559 EIBnet_ConnectResponse::EIBnet_ConnectResponse () 560 { 561 memset (&daddr, 0, sizeof (daddr)); 562 } 563 564 EIBNetIPPacket EIBnet_ConnectResponse::ToPacket (HostProtocolCode protocol)const 565 { 566 EIBNetIPPacket p; 567 CArray da = IPtoEIBNetIP (&daddr, nat, protocol); 568 p.service = CONNECTION_RESPONSE; 569 if (status != 0) 570 p.data.resize (2); 571 else 572 p.data.resize (da.size() + CRD.size() + 3); 573 p.data[0] = channel; 574 p.data[1] = status; 575 if (status == 0) 576 { 577 p.data.setpart (da, 2); 578 p.data[da.size() + 2] = CRD.size() + 1; 579 p.data.setpart (CRD, da.size() + 3); 580 } 581 return p; 582 } 583 584 int 585 parseEIBnet_ConnectResponse (const EIBNetIPPacket & p, 586 EIBnet_ConnectResponse & r) 587 { 588 if (p.service != CONNECTION_RESPONSE) 589 return 1; 590 if (p.data.size() < 2) 591 return 1; 592 if (p.data[1] != 0) 593 { 594 if (p.data.size() != 2) 595 return 1; 596 r.channel = p.data[0]; 597 r.status = p.data[1]; 598 return 0; 599 } 600 if (p.data.size() < 12) 601 return 1; 602 if (EIBnettoIP (CArray (p.data.data() + 2, 8), &r.daddr, &p.src, r.nat, p.protocol)) 603 return 1; 604 if (p.data.size() - 10 != p.data[10]) 605 return 1; 606 r.channel = p.data[0]; 607 r.status = p.data[1]; 608 r.CRD = CArray (p.data.data() + 11, p.data.size() - 11); 609 return 0; 610 } 611 612 EIBnet_ConnectionStateRequest::EIBnet_ConnectionStateRequest () 613 { 614 memset (&caddr, 0, sizeof (caddr)); 615 } 616 617 EIBNetIPPacket EIBnet_ConnectionStateRequest::ToPacket (HostProtocolCode protocol)const 618 { 619 EIBNetIPPacket p; 620 CArray ca = IPtoEIBNetIP (&caddr, nat, protocol); 621 p.service = CONNECTIONSTATE_REQUEST; 622 p.data.resize (ca.size() + 2); 623 p.data[0] = channel; 624 p.data[1] = 0; 625 p.data.setpart (ca, 2); 626 return p; 627 } 628 629 int 630 parseEIBnet_ConnectionStateRequest (const EIBNetIPPacket & p, 631 EIBnet_ConnectionStateRequest & r) 632 { 633 if (p.service != CONNECTIONSTATE_REQUEST) 634 return 1; 635 if (p.data.size() != 10) 636 return 1; 637 if (EIBnettoIP (CArray (p.data.data() + 2, 8), &r.caddr, &p.src, r.nat, p.protocol)) 638 return 1; 639 r.channel = p.data[0]; 640 return 0; 641 } 642 643 EIBNetIPPacket EIBnet_ConnectionStateResponse::ToPacket (HostProtocolCode protocol)const 644 { 645 EIBNetIPPacket p; 646 p.service = CONNECTIONSTATE_RESPONSE; 647 p.data.resize (2); 648 p.data[0] = channel; 649 p.data[1] = status; 650 return p; 651 } 652 653 int 654 parseEIBnet_ConnectionStateResponse (const EIBNetIPPacket & p, 655 EIBnet_ConnectionStateResponse & r) 656 { 657 if (p.service != CONNECTIONSTATE_RESPONSE) 658 return 1; 659 if (p.data.size() != 2) 660 return 1; 661 r.channel = p.data[0]; 662 r.status = p.data[1]; 663 return 0; 664 } 665 666 EIBnet_DisconnectRequest::EIBnet_DisconnectRequest () 667 { 668 memset (&caddr, 0, sizeof (caddr)); 669 } 670 671 EIBNetIPPacket EIBnet_DisconnectRequest::ToPacket (HostProtocolCode protocol)const 672 { 673 EIBNetIPPacket p; 674 CArray ca = IPtoEIBNetIP (&caddr, nat, protocol); 675 p.service = DISCONNECT_REQUEST; 676 p.data.resize (ca.size() + 2); 677 p.data[0] = channel; 678 p.data[1] = 0; 679 p.data.setpart (ca, 2); 680 return p; 681 } 682 683 int 684 parseEIBnet_DisconnectRequest (const EIBNetIPPacket & p, 685 EIBnet_DisconnectRequest & r) 686 { 687 if (p.service != DISCONNECT_REQUEST) 688 return 1; 689 if (p.data.size() != 10) 690 return 1; 691 if (EIBnettoIP (CArray (p.data.data() + 2, 8), &r.caddr, &p.src, r.nat, p.protocol)) 692 return 1; 693 r.channel = p.data[0]; 694 return 0; 695 } 696 697 EIBNetIPPacket EIBnet_DisconnectResponse::ToPacket (HostProtocolCode protocol)const 698 { 699 EIBNetIPPacket p; 700 p.service = DISCONNECT_RESPONSE; 701 p.data.resize (2); 702 p.data[0] = channel; 703 p.data[1] = status; 704 return p; 705 } 706 707 int 708 parseEIBnet_DisconnectResponse (const EIBNetIPPacket & p, 709 EIBnet_DisconnectResponse & r) 710 { 711 if (p.service != DISCONNECT_RESPONSE) 712 return 1; 713 if (p.data.size() != 2) 714 return 1; 715 r.channel = p.data[0]; 716 r.status = p.data[1]; 717 return 0; 718 } 719 720 EIBNetIPPacket EIBnet_ConfigRequest::ToPacket (HostProtocolCode protocol)const 721 { 722 EIBNetIPPacket p; 723 p.service = DEVICE_CONFIGURATION_REQUEST; 724 p.data.resize (CEMI.size() + 4); 725 p.data[0] = 4; 726 p.data[1] = channel; 727 p.data[2] = seqno; 728 p.data[3] = 0; 729 p.data.setpart (CEMI, 4); 730 return p; 731 } 732 733 int 734 parseEIBnet_ConfigRequest (const EIBNetIPPacket & p, EIBnet_ConfigRequest & r) 735 { 736 if (p.service != DEVICE_CONFIGURATION_REQUEST) 737 return 1; 738 if (p.data.size() < 6) 739 return 1; 740 if (p.data[0] != 4) 741 return 1; 742 r.channel = p.data[1]; 743 r.seqno = p.data[2]; 744 r.CEMI.set (p.data.data() + 4, p.data.size() - 4); 745 return 0; 746 } 747 748 EIBNetIPPacket EIBnet_ConfigACK::ToPacket (HostProtocolCode protocol)const 749 { 750 EIBNetIPPacket p; 751 p.service = DEVICE_CONFIGURATION_ACK; 752 p.data.resize (4); 753 p.data[0] = 4; 754 p.data[1] = channel; 755 p.data[2] = seqno; 756 p.data[3] = status; 757 return p; 758 } 759 760 int 761 parseEIBnet_ConfigACK (const EIBNetIPPacket & p, EIBnet_ConfigACK & r) 762 { 763 if (p.service != DEVICE_CONFIGURATION_ACK) 764 return 1; 765 if (p.data.size() != 4) 766 return 1; 767 if (p.data[0] != 4) 768 return 1; 769 r.channel = p.data[1]; 770 r.seqno = p.data[2]; 771 r.status = p.data[3]; 772 return 0; 773 } 774 775 EIBNetIPPacket EIBnet_TunnelRequest::ToPacket (HostProtocolCode protocol)const 776 { 777 EIBNetIPPacket p; 778 p.service = TUNNEL_REQUEST; 779 p.data.resize (CEMI.size() + 4); 780 p.data[0] = 4; 781 p.data[1] = channel; 782 p.data[2] = seqno; 783 p.data[3] = 0; 784 p.data.setpart (CEMI, 4); 785 return p; 786 } 787 788 int 789 parseEIBnet_TunnelRequest (const EIBNetIPPacket & p, EIBnet_TunnelRequest & r) 790 { 791 if (p.service != TUNNEL_REQUEST) 792 return 1; 793 if (p.data.size() < 6) 794 return 1; 795 if (p.data[0] != 4) 796 return 1; 797 r.channel = p.data[1]; 798 r.seqno = p.data[2]; 799 r.CEMI.set (p.data.data() + 4, p.data.size() - 4); 800 return 0; 801 } 802 803 EIBNetIPPacket EIBnet_TunnelACK::ToPacket (HostProtocolCode protocol)const 804 { 805 EIBNetIPPacket p; 806 p.service = TUNNEL_RESPONSE; 807 p.data.resize (4); 808 p.data[0] = 4; 809 p.data[1] = channel; 810 p.data[2] = seqno; 811 p.data[3] = status; 812 return p; 813 } 814 815 int 816 parseEIBnet_TunnelACK (const EIBNetIPPacket & p, EIBnet_TunnelACK & r) 817 { 818 if (p.service != TUNNEL_RESPONSE) 819 return 1; 820 if (p.data.size() != 4) 821 return 1; 822 if (p.data[0] != 4) 823 return 1; 824 r.channel = p.data[1]; 825 r.seqno = p.data[2]; 826 r.status = p.data[3]; 827 return 0; 828 } 829 830 EIBNetIPPacket EIBnet_RoutingIndication::ToPacket (HostProtocolCode protocol) const 831 { 832 // @todo 833 abort(); 834 } 835 836 int 837 parseEIBnet_RoutingIndication (const EIBNetIPPacket & p, EIBnet_RoutingIndication & r) 838 { 839 return 0; 840 } 841 842 EIBNetIPPacket EIBnet_RoutingLostMessage::ToPacket (HostProtocolCode protocol) const 843 { 844 // @todo 845 abort(); 846 } 847 848 int 849 parseEIBnet_RoutingLostMessage (const EIBNetIPPacket & p, EIBnet_RoutingLostMessage & r) 850 { 851 return 0; 852 }