/ src / libserver / eibnetip.cpp
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  }