1 /*
2     EIBD client library
3     Copyright (C) 2005-2006 Martin K�gler <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     In addition to the permissions in the GNU General Public License,
11     you may link the compiled version of this file into combinations
12     with other programs, and distribute those combinations without any
13     restriction coming from the use of this file. (The General Public
14     License restrictions do apply in other respects; for example, they
15     cover modification of the file, and distribution when not linked into
16     a combine executable.)
17 
18     This program is distributed in the hope that it will be useful,
19     but WITHOUT ANY WARRANTY; without even the implied warranty of
20     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21     GNU General Public License for more details.
22 
23     You should have received a copy of the GNU General Public License
24     along with this program; if not, write to the Free Software
25     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26 */
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <unistd.h>
30 #include <sys/socket.h>
31 #include <sys/un.h>
32 #include <netinet/in.h>
33 #include <netdb.h>
34 #include <errno.h>
35 #include <string.h>
36 
37 #include "config.h"
38 
39 #include "eibclient.h"
40 #include "eibtypes.h"
41 
42 /** unsigned char */
43 typedef uint8_t uchar;
44 
45 /** EIB Connection internal */
46 struct _EIBConnection
47 {
48     int (*complete) (EIBConnection *);
49     /** file descriptor */
50     int fd;
51     pth_event_t ev;
52     unsigned readlen;
53     /** buffer */
54     uchar *buf;
55     /** buffer size */
56     unsigned buflen;
57     /** used buffer */
58     unsigned size;
59     struct
60     {
61         int len;
62         uint8_t *buf;
63         int16_t *ptr1;
64         uint8_t *ptr2;
65         uint8_t *ptr3;
66         uint16_t *ptr4;
67     }
68     req;
69 };
70 
71 /** extracts TYPE code of an eibd packet */
72 #define EIBTYPE(con) (((con)->buf[0]<<8)|((con)->buf[1]))
73 /** sets TYPE code for an eibd packet*/
74 #define EIBSETTYPE(buf,type) do{(buf)[0]=(type>>8)&0xff;(buf)[1]=(type)&0xff;}while(0)
75 
76 /** set EIB address */
77 #define EIBSETADDR(buf,type) do{(buf)[0]=(type>>8)&0xff;(buf)[1]=(type)&0xff;}while(0)
78 
79 /** resolve host name */
80 static int
GetHostIP(struct sockaddr_in * sock,const char * Name)81 GetHostIP (struct sockaddr_in *sock, const char *Name)
82 {
83 #ifdef HAVE_GETHOSTBYNAME_R
84     int len = 2000;
85     struct hostent host;
86     char *buf = (char *) malloc (len);
87     int res;
88     int err;
89 #endif
90 
91     struct hostent *h;
92     if (!Name)
93         return 0;
94     memset (sock, 0, sizeof (*sock));
95 #ifdef HAVE_GETHOSTBYNAME_R
96 
97     do
98     {
99         res = gethostbyname_r (Name, &host, buf, len, &h, &err);
100         if (res == ERANGE)
101         {
102             len += 2000;
103             buf = (char *) realloc (buf, len);
104         }
105         if (!buf)
106             return 0;
107     }
108     while (res == ERANGE);
109 
110     if (res || !h)
111     {
112         free (buf);
113         return 0;
114     }
115 #else
116     h = gethostbyname (Name);
117     if (!h)
118         return 0;
119 #endif
120 
121     sock->sin_family = h->h_addrtype;
122     sock->sin_addr.s_addr = (*((unsigned long *) h->h_addr_list[0]));
123 #ifdef HAVE_GETHOSTBYNAME_R
124 
125     if (buf)
126         free (buf);
127 #endif
128 
129     return 1;
130 }
131 
132 int
EIBClose(EIBConnection * con)133 EIBClose (EIBConnection * con)
134 {
135     if (!con)
136     {
137         errno = EINVAL;
138         return -1;
139     }
140     close (con->fd);
141     if (con->buf)
142         free (con->buf);
143     free (con);
144     return 0;
145 }
146 
EIBSetEvent(EIBConnection * con,pth_event_t ev)147 void EIBSetEvent (EIBConnection * con, pth_event_t ev)
148 {
149     con->ev = ev;
150 }
151 
152 EIBConnection *
EIBSocketLocal(const char * path)153 EIBSocketLocal (const char *path)
154 {
155     EIBConnection *con = (EIBConnection *) malloc (sizeof (EIBConnection));
156     struct sockaddr_un addr;
157     if (!con)
158     {
159         errno = ENOMEM;
160         return 0;
161     }
162     addr.sun_family = AF_LOCAL;
163     strncpy (addr.sun_path, path, sizeof (addr.sun_path));
164     addr.sun_path[sizeof (addr.sun_path) - 1] = 0;
165 
166     con->fd = socket (AF_LOCAL, SOCK_STREAM, 0);
167     con->ev = 0;
168     if (con->fd == -1)
169     {
170         free (con);
171         return 0;
172     }
173 
174     if (pth_connect_ev (con->fd, (struct sockaddr *) &addr, sizeof (addr), con->ev) == -1)
175     {
176         int saveerr = errno;
177         close (con->fd);
178         free (con);
179         errno = saveerr;
180         return 0;
181     }
182     con->buflen = 0;
183     con->buf = 0;
184     con->readlen = 0;
185 
186     return con;
187 }
188 
189 EIBConnection *
EIBSocketRemote(const char * host,int port)190 EIBSocketRemote (const char *host, int port)
191 {
192     EIBConnection *con = (EIBConnection *) malloc (sizeof (EIBConnection));
193     struct sockaddr_in addr;
194     if (!con)
195     {
196         errno = ENOMEM;
197         return 0;
198     }
199 
200     if (!GetHostIP (&addr, host))
201     {
202         free (con);
203         errno = ECONNREFUSED;
204         return 0;
205     }
206     addr.sin_port = htons (port);
207 
208     con->fd = socket (addr.sin_family, SOCK_STREAM, 0);
209     con->ev = 0;
210     if (con->fd == -1)
211     {
212         free (con);
213         return 0;
214     }
215 
216     if (pth_connect_ev (con->fd, (struct sockaddr *) &addr, sizeof (addr), con->ev) == -1)
217     {
218         int saveerr = errno;
219         close (con->fd);
220         free (con);
221         errno = saveerr;
222         return 0;
223     }
224     con->buflen = 0;
225     con->buf = 0;
226     con->readlen = 0;
227 
228     return con;
229 }
230 
231 EIBConnection *
EIBSocketURL(const char * url)232 EIBSocketURL (const char *url)
233 {
234     if (!url)
235     {
236         errno = EINVAL;
237         return 0;
238     }
239     if (!strncmp (url, "local:", 6))
240     {
241         return EIBSocketLocal (url + 6);
242     }
243     if (!strncmp (url, "ip:", 3))
244     {
245         char *a = strdup (url + 3);
246         char *b;
247         int port;
248         EIBConnection *c;
249         if (!a)
250         {
251             errno = ENOMEM;
252             return 0;
253         }
254         for (b = a; *b; b++)
255             if (*b == ':')
256                 break;
257         if (*b == ':')
258         {
259             *b = 0;
260             port = atoi (b + 1);
261         }
262         else
263             port = 6720;
264         c = EIBSocketRemote (a, port);
265         free (a);
266         return c;
267     }
268     errno = EINVAL;
269     return 0;
270 }
271 
272 /** send a request to eibd */
273 static int
SendRequest(EIBConnection * con,unsigned int size,uchar * data)274 SendRequest (EIBConnection * con, unsigned int size, uchar * data)
275 {
276     uchar head[2];
277     int i, start;
278 
279     if (size > 0xffff || size < 2)
280     {
281         errno = EINVAL;
282         return -1;
283     }
284     head[0] = (size >> 8) & 0xff;
285     head[1] = (size) & 0xff;
286 
287 lp1:
288     i = pth_write_ev (con->fd, &head, 2, con->ev);
289     if (i == -1 && errno == EINTR)
290         goto lp1;
291     if (i == -1)
292         return -1;
293     if (i != 2)
294     {
295         errno = ECONNRESET;
296         return -1;
297     }
298     start = 0;
299 lp2:
300     i = pth_write_ev (con->fd, data + start, size - start, con->ev);
301     if (i == -1 && errno == EINTR)
302         goto lp2;
303     if (i == -1)
304         return -1;
305     if (i == 0)
306     {
307         errno = ECONNRESET;
308         return -1;
309     }
310     start += i;
311     if (start < size)
312         goto lp2;
313     return 0;
314 }
315 
316 static int
CheckRequest(EIBConnection * con)317 CheckRequest (EIBConnection * con)
318 {
319     int i;
320     if (con->readlen < 2)
321     {
322         uchar head[2];
323         head[0] = (con->size >> 8) & 0xff;
324         i = pth_read_ev (con->fd, &head + con->readlen, 2 - con->readlen, con->ev);
325         if (i == -1 && errno == EINTR && (pth_event_status (con->ev) != PTH_STATUS_OCCURRED))
326             return 0;
327         if (i == -1)
328             return -1;
329         if (i == 0)
330         {
331             errno = ECONNRESET;
332             return -1;
333         }
334         con->readlen += i;
335         con->size = (head[0] << 8) | (head[1]);
336         if (con->size < 2)
337         {
338             errno = ECONNRESET;
339             return -1;
340         }
341 
342         if (con->size > con->buflen)
343         {
344             con->buf = (uchar *) realloc (con->buf, con->size);
345             if (con->buf == 0)
346             {
347                 con->buflen = 0;
348                 errno = ENOMEM;
349                 return -1;
350             }
351             con->buflen = con->size;
352         }
353         return 0;
354     }
355 
356     if (con->readlen < con->size + 2)
357     {
358         i =
359             pth_read_ev (con->fd, con->buf + (con->readlen - 2),
360                          con->size - (con->readlen - 2), con->ev);
361         if (i == -1 && errno == EINTR)
362             return 0;
363         if (i == -1)
364             return -1;
365         if (i == 0)
366         {
367             errno = ECONNRESET;
368             return -1;
369         }
370         con->readlen += i;
371     }
372     return 0;
373 }
374 
375 /** receive packet from eibd */
376 static int
GetRequest(EIBConnection * con)377 GetRequest (EIBConnection * con)
378 {
379     do
380     {
381         if (CheckRequest (con) == -1)
382             return -1;
383     }
384     while (con->readlen < 2
385             || (con->readlen >= 2 && con->readlen < con->size + 2));
386 
387     con->readlen = 0;
388 
389     return 0;
390 }
391 
392 int
EIB_Poll_Complete(EIBConnection * con)393 EIB_Poll_Complete (EIBConnection * con)
394 {
395     if (!con)
396     {
397         errno = EINVAL;
398         return -1;
399     }
400     if (CheckRequest (con) == -1)
401         return -1;
402     return (con->readlen >= 2 && con->readlen >= con->size + 2) ? 1 : 0;
403 }
404 
405 int
EIB_Poll_FD(EIBConnection * con)406 EIB_Poll_FD (EIBConnection * con)
407 {
408     if (!con)
409     {
410         errno = EINVAL;
411         return -1;
412     }
413     return con->fd;
414 }
415 
416 int
EIBComplete(EIBConnection * con)417 EIBComplete (EIBConnection * con)
418 {
419     if (!con)
420     {
421         errno = EINVAL;
422         return -1;
423     }
424     return con->complete (con);
425 }
426 
427 static int
OpenBusmonitor_complete(EIBConnection * con)428 OpenBusmonitor_complete (EIBConnection * con)
429 {
430     int i;
431     i = GetRequest (con);
432     if (i == -1)
433         return -1;
434 
435     if (EIBTYPE (con) != EIB_OPEN_BUSMONITOR)
436     {
437         errno = ECONNRESET;
438         return -1;
439     }
440     return 0;
441 }
442 
443 int
EIBOpenBusmonitor_async(EIBConnection * con)444 EIBOpenBusmonitor_async (EIBConnection * con)
445 {
446     uchar head[2];
447     int i;
448     if (!con)
449     {
450         errno = EINVAL;
451         return -1;
452     }
453     EIBSETTYPE (head, EIB_OPEN_BUSMONITOR);
454     i = SendRequest (con, 2, head);
455     if (i == -1)
456         return -1;
457 
458     con->complete = OpenBusmonitor_complete;
459     return 0;
460 }
461 
462 int
EIBOpenBusmonitor(EIBConnection * con)463 EIBOpenBusmonitor (EIBConnection * con)
464 {
465     if (EIBOpenBusmonitor_async (con) == -1)
466         return -1;
467     return EIBComplete (con);
468 }
469 
470 static int
OpenBusmonitorText_complete(EIBConnection * con)471 OpenBusmonitorText_complete (EIBConnection * con)
472 {
473     int i;
474     i = GetRequest (con);
475     if (i == -1)
476         return -1;
477 
478     if (EIBTYPE (con) != EIB_OPEN_BUSMONITOR_TEXT)
479     {
480         errno = ECONNRESET;
481         return -1;
482     }
483     return 0;
484 }
485 
486 int
EIBOpenBusmonitorText_async(EIBConnection * con)487 EIBOpenBusmonitorText_async (EIBConnection * con)
488 {
489     uchar head[2];
490     int i;
491     if (!con)
492     {
493         errno = EINVAL;
494         return -1;
495     }
496     EIBSETTYPE (head, EIB_OPEN_BUSMONITOR_TEXT);
497     i = SendRequest (con, 2, head);
498     if (i == -1)
499         return -1;
500     con->complete = OpenBusmonitorText_complete;
501     return 0;
502 }
503 
504 int
EIBOpenBusmonitorText(EIBConnection * con)505 EIBOpenBusmonitorText (EIBConnection * con)
506 {
507     if (EIBOpenBusmonitorText_async (con) == -1)
508         return -1;
509     return EIBComplete (con);
510 }
511 
512 static int
OpenVBusmonitor_complete(EIBConnection * con)513 OpenVBusmonitor_complete (EIBConnection * con)
514 {
515     int i;
516     i = GetRequest (con);
517     if (i == -1)
518         return -1;
519 
520     if (EIBTYPE (con) != EIB_OPEN_VBUSMONITOR)
521     {
522         errno = ECONNRESET;
523         return -1;
524     }
525     return 0;
526 }
527 
528 int
EIBOpenVBusmonitor_async(EIBConnection * con)529 EIBOpenVBusmonitor_async (EIBConnection * con)
530 {
531     uchar head[2];
532     int i;
533     if (!con)
534     {
535         errno = EINVAL;
536         return -1;
537     }
538     EIBSETTYPE (head, EIB_OPEN_VBUSMONITOR);
539     i = SendRequest (con, 2, head);
540     if (i == -1)
541         return -1;
542     con->complete = OpenVBusmonitor_complete;
543     return 0;
544 }
545 
546 int
EIBOpenVBusmonitor(EIBConnection * con)547 EIBOpenVBusmonitor (EIBConnection * con)
548 {
549     if (EIBOpenVBusmonitor_async (con) == -1)
550         return -1;
551     return EIBComplete (con);
552 }
553 
554 static int
OpenVBusmonitorText_complete(EIBConnection * con)555 OpenVBusmonitorText_complete (EIBConnection * con)
556 {
557     int i;
558     i = GetRequest (con);
559     if (i == -1)
560         return -1;
561 
562     if (EIBTYPE (con) != EIB_OPEN_VBUSMONITOR_TEXT)
563     {
564         errno = ECONNRESET;
565         return -1;
566     }
567     return 0;
568 }
569 
570 int
EIBOpenVBusmonitorText_async(EIBConnection * con)571 EIBOpenVBusmonitorText_async (EIBConnection * con)
572 {
573     uchar head[2];
574     int i;
575     if (!con)
576     {
577         errno = EINVAL;
578         return -1;
579     }
580     EIBSETTYPE (head, EIB_OPEN_VBUSMONITOR_TEXT);
581     i = SendRequest (con, 2, head);
582     if (i == -1)
583         return -1;
584     con->complete = OpenVBusmonitorText_complete;
585     return 0;
586 }
587 
588 int
EIBOpenVBusmonitorText(EIBConnection * con)589 EIBOpenVBusmonitorText (EIBConnection * con)
590 {
591     if (EIBOpenVBusmonitorText_async (con) == -1)
592         return -1;
593     return EIBComplete (con);
594 }
595 
596 int
EIBGetBusmonitorPacket(EIBConnection * con,int maxlen,uint8_t * buf)597 EIBGetBusmonitorPacket (EIBConnection * con, int maxlen, uint8_t * buf)
598 {
599     int i;
600     if (!con || !buf)
601     {
602         errno = EINVAL;
603         return -1;
604     }
605 
606     i = GetRequest (con);
607     if (i == -1)
608         return -1;
609 
610     if (EIBTYPE (con) != EIB_BUSMONITOR_PACKET)
611     {
612         errno = ECONNRESET;
613         return -1;
614     }
615     i = con->size - 2;
616     if (i > maxlen)
617         i = maxlen;
618     memcpy (buf, con->buf + 2, i);
619     return i;
620 }
621 
622 static int
OpenT_Connection_complete(EIBConnection * con)623 OpenT_Connection_complete (EIBConnection * con)
624 {
625     int i;
626     i = GetRequest (con);
627     if (i == -1)
628         return -1;
629 
630     if (EIBTYPE (con) != EIB_OPEN_T_CONNECTION)
631     {
632         errno = ECONNRESET;
633         return -1;
634     }
635     return 0;
636 }
637 
638 int
EIBOpenT_Connection_async(EIBConnection * con,eibaddr_t dest)639 EIBOpenT_Connection_async (EIBConnection * con, eibaddr_t dest)
640 {
641     uchar head[5];
642     int i;
643     if (!con)
644     {
645         errno = EINVAL;
646         return -1;
647     }
648     EIBSETTYPE (head, EIB_OPEN_T_CONNECTION);
649     EIBSETADDR (head + 2, dest);
650     i = SendRequest (con, 5, head);
651     if (i == -1)
652         return -1;
653     con->complete = OpenT_Connection_complete;
654     return 0;
655 }
656 
657 int
EIBOpenT_Connection(EIBConnection * con,eibaddr_t dest)658 EIBOpenT_Connection (EIBConnection * con, eibaddr_t dest)
659 {
660     if (EIBOpenT_Connection_async (con, dest) == -1)
661         return -1;
662     return EIBComplete (con);
663 }
664 
665 static int
OpenT_TPDU_complete(EIBConnection * con)666 OpenT_TPDU_complete (EIBConnection * con)
667 {
668     int i;
669     i = GetRequest (con);
670     if (i == -1)
671         return -1;
672 
673     if (EIBTYPE (con) != EIB_OPEN_T_TPDU)
674     {
675         errno = ECONNRESET;
676         return -1;
677     }
678     return 0;
679 }
680 
681 int
EIBOpenT_TPDU_async(EIBConnection * con,eibaddr_t src)682 EIBOpenT_TPDU_async (EIBConnection * con, eibaddr_t src)
683 {
684     uchar head[5];
685     int i;
686     if (!con)
687     {
688         errno = EINVAL;
689         return -1;
690     }
691     EIBSETTYPE (head, EIB_OPEN_T_TPDU);
692     EIBSETADDR (head + 2, src);
693     i = SendRequest (con, 5, head);
694     if (i == -1)
695         return -1;
696     con->complete = OpenT_TPDU_complete;
697     return 0;
698 }
699 
700 int
EIBOpenT_TPDU(EIBConnection * con,eibaddr_t src)701 EIBOpenT_TPDU (EIBConnection * con, eibaddr_t src)
702 {
703     if (EIBOpenT_TPDU_async (con, src) == -1)
704         return -1;
705     return EIBComplete (con);
706 }
707 
708 static int
OpenT_Individual_complete(EIBConnection * con)709 OpenT_Individual_complete (EIBConnection * con)
710 {
711     int i;
712     i = GetRequest (con);
713     if (i == -1)
714         return -1;
715 
716     if (EIBTYPE (con) != EIB_OPEN_T_INDIVIDUAL)
717     {
718         errno = ECONNRESET;
719         return -1;
720     }
721     return 0;
722 }
723 
724 int
EIBOpenT_Individual_async(EIBConnection * con,eibaddr_t dest,int write_only)725 EIBOpenT_Individual_async (EIBConnection * con, eibaddr_t dest,
726                            int write_only)
727 {
728     uchar head[5];
729     int i;
730     if (!con)
731     {
732         errno = EINVAL;
733         return -1;
734     }
735     EIBSETTYPE (head, EIB_OPEN_T_INDIVIDUAL);
736     EIBSETADDR (head + 2, dest);
737     head[4] = (write_only ? 0xff : 0);
738     i = SendRequest (con, 5, head);
739     if (i == -1)
740         return -1;
741     con->complete = OpenT_Individual_complete;
742     return 0;
743 }
744 
745 int
EIBOpenT_Individual(EIBConnection * con,eibaddr_t dest,int write_only)746 EIBOpenT_Individual (EIBConnection * con, eibaddr_t dest, int write_only)
747 {
748     if (EIBOpenT_Individual_async (con, dest, write_only) == -1)
749         return -1;
750     return EIBComplete (con);
751 }
752 
753 static int
OpenT_Group_complete(EIBConnection * con)754 OpenT_Group_complete (EIBConnection * con)
755 {
756     int i;
757     i = GetRequest (con);
758     if (i == -1)
759         return -1;
760 
761     if (EIBTYPE (con) != EIB_OPEN_T_GROUP)
762     {
763         errno = ECONNRESET;
764         return -1;
765     }
766     return 0;
767 }
768 
769 int
EIBOpenT_Group_async(EIBConnection * con,eibaddr_t dest,int write_only)770 EIBOpenT_Group_async (EIBConnection * con, eibaddr_t dest, int write_only)
771 {
772     uchar head[5];
773     int i;
774     if (!con)
775     {
776         errno = EINVAL;
777         return -1;
778     }
779     EIBSETTYPE (head, EIB_OPEN_T_GROUP);
780     EIBSETADDR (head + 2, dest);
781     head[4] = (write_only ? 0xff : 0);
782     i = SendRequest (con, 5, head);
783     if (i == -1)
784         return -1;
785     con->complete = OpenT_Group_complete;
786     return 0;
787 }
788 
789 int
EIBOpenT_Group(EIBConnection * con,eibaddr_t dest,int write_only)790 EIBOpenT_Group (EIBConnection * con, eibaddr_t dest, int write_only)
791 {
792     if (EIBOpenT_Group_async (con, dest, write_only) == -1)
793         return -1;
794     return EIBComplete (con);
795 }
796 
797 static int
OpenT_Broadcast_complete(EIBConnection * con)798 OpenT_Broadcast_complete (EIBConnection * con)
799 {
800     int i;
801     i = GetRequest (con);
802     if (i == -1)
803         return -1;
804 
805     if (EIBTYPE (con) != EIB_OPEN_T_BROADCAST)
806     {
807         errno = ECONNRESET;
808         return -1;
809     }
810     return 0;
811 }
812 
813 int
EIBOpenT_Broadcast_async(EIBConnection * con,int write_only)814 EIBOpenT_Broadcast_async (EIBConnection * con, int write_only)
815 {
816     uchar head[5];
817     int i;
818     if (!con)
819     {
820         errno = EINVAL;
821         return -1;
822     }
823     EIBSETTYPE (head, EIB_OPEN_T_BROADCAST);
824     head[4] = (write_only ? 0xff : 0);
825     i = SendRequest (con, 5, head);
826     if (i == -1)
827         return -1;
828     con->complete = OpenT_Broadcast_complete;
829     return 0;
830 }
831 
832 int
EIBOpenT_Broadcast(EIBConnection * con,int write_only)833 EIBOpenT_Broadcast (EIBConnection * con, int write_only)
834 {
835     if (EIBOpenT_Broadcast_async (con, write_only) == -1)
836         return -1;
837     return EIBComplete (con);
838 }
839 
840 int
EIBSendTPDU(EIBConnection * con,eibaddr_t dest,int len,uint8_t * data)841 EIBSendTPDU (EIBConnection * con, eibaddr_t dest, int len, uint8_t * data)
842 {
843     uchar *ibuf;
844     int i;
845     if (!con)
846     {
847         errno = EINVAL;
848         return -1;
849     }
850     if (len < 2 || !data)
851     {
852         errno = EINVAL;
853         return -1;
854     }
855     ibuf = (uchar *) malloc (len + 4);
856     if (!ibuf)
857     {
858         errno = ENOMEM;
859         return -1;
860     }
861     EIBSETTYPE (ibuf, EIB_APDU_PACKET);
862     EIBSETADDR (ibuf + 2, dest);
863     memcpy (ibuf + 4, data, len);
864     i = SendRequest (con, len + 4, ibuf);
865     free (ibuf);
866     return i;
867 }
868 
869 int
EIBSendAPDU(EIBConnection * con,int len,uint8_t * data)870 EIBSendAPDU (EIBConnection * con, int len, uint8_t * data)
871 {
872     uchar *ibuf;
873     int i;
874     if (!con)
875     {
876         errno = EINVAL;
877         return -1;
878     }
879     if (len < 2 || !data)
880     {
881         errno = EINVAL;
882         return -1;
883     }
884     ibuf = (uchar *) malloc (len + 2);
885     if (!ibuf)
886     {
887         errno = ENOMEM;
888         return -1;
889     }
890     EIBSETTYPE (ibuf, EIB_APDU_PACKET);
891     memcpy (ibuf + 2, data, len);
892     i = SendRequest (con, len + 2, ibuf);
893     free (ibuf);
894     return i;
895 }
896 
897 int
EIBGetAPDU(EIBConnection * con,int maxlen,uint8_t * buf)898 EIBGetAPDU (EIBConnection * con, int maxlen, uint8_t * buf)
899 {
900     int i;
901     if (!con || !buf)
902     {
903         errno = EINVAL;
904         return -1;
905     }
906 
907     i = GetRequest (con);
908     if (i == -1)
909         return -1;
910 
911     if (EIBTYPE (con) != EIB_APDU_PACKET)
912     {
913         errno = ECONNRESET;
914         return -1;
915     }
916     i = con->size - 2;
917     if (i > maxlen)
918         i = maxlen;
919     memcpy (buf, con->buf + 2, i);
920     return i;
921 }
922 
923 int
EIBGetAPDU_Src(EIBConnection * con,int maxlen,uint8_t * buf,eibaddr_t * src)924 EIBGetAPDU_Src (EIBConnection * con, int maxlen, uint8_t * buf,
925                 eibaddr_t * src)
926 {
927     int i;
928     if (!con || !buf)
929     {
930         errno = EINVAL;
931         return -1;
932     }
933 
934     i = GetRequest (con);
935     if (i == -1)
936         return -1;
937 
938     if (EIBTYPE (con) != EIB_APDU_PACKET || con->size < 4)
939     {
940         errno = ECONNRESET;
941         return -1;
942     }
943     i = con->size - 4;
944     if (i > maxlen)
945         i = maxlen;
946     memcpy (buf, con->buf + 4, i);
947     if (src)
948         *src = (con->buf[2] << 8) | (con->buf[3]);
949     return i;
950 }
951 
952 static int
Open_GroupSocket_complete(EIBConnection * con)953 Open_GroupSocket_complete (EIBConnection * con)
954 {
955     int i;
956     i = GetRequest (con);
957     if (i == -1)
958         return -1;
959 
960     if (EIBTYPE (con) != EIB_OPEN_GROUPCON)
961     {
962         errno = ECONNRESET;
963         return -1;
964     }
965     return 0;
966 }
967 
968 int
EIBOpen_GroupSocket_async(EIBConnection * con,int write_only)969 EIBOpen_GroupSocket_async (EIBConnection * con, int write_only)
970 {
971     uchar head[5];
972     int i;
973     if (!con)
974     {
975         errno = EINVAL;
976         return -1;
977     }
978     EIBSETTYPE (head, EIB_OPEN_GROUPCON);
979     head[4] = (write_only ? 0xff : 0);
980     i = SendRequest (con, 5, head);
981     if (i == -1)
982         return -1;
983     con->complete = Open_GroupSocket_complete;
984     return 0;
985 }
986 
987 int
EIBOpen_GroupSocket(EIBConnection * con,int write_only)988 EIBOpen_GroupSocket (EIBConnection * con, int write_only)
989 {
990     if (EIBOpen_GroupSocket_async (con, write_only) == -1)
991         return -1;
992     return EIBComplete (con);
993 }
994 
995 int
EIBGetGroup_Src(EIBConnection * con,int maxlen,uint8_t * buf,eibaddr_t * src,eibaddr_t * dest)996 EIBGetGroup_Src (EIBConnection * con, int maxlen, uint8_t * buf,
997                  eibaddr_t * src, eibaddr_t * dest)
998 {
999     int i;
1000     if (!con || !buf)
1001     {
1002         errno = EINVAL;
1003         return -1;
1004     }
1005 
1006     i = GetRequest (con);
1007     if (i == -1)
1008         return -1;
1009 
1010     if (EIBTYPE (con) != EIB_GROUP_PACKET || con->size < 6)
1011     {
1012         errno = ECONNRESET;
1013         return -1;
1014     }
1015     i = con->size - 6;
1016     if (i > maxlen)
1017         i = maxlen;
1018     memcpy (buf, con->buf + 6, i);
1019     if (src)
1020         *src = (con->buf[2] << 8) | (con->buf[3]);
1021     if (dest)
1022         *dest = (con->buf[4] << 8) | (con->buf[5]);
1023     return i;
1024 }
1025 
1026 int
EIBSendGroup(EIBConnection * con,eibaddr_t dest,int len,uint8_t * data)1027 EIBSendGroup (EIBConnection * con, eibaddr_t dest, int len, uint8_t * data)
1028 {
1029     uchar *ibuf;
1030     int i;
1031     if (!con)
1032     {
1033         errno = EINVAL;
1034         return -1;
1035     }
1036     if (len < 2 || !data)
1037     {
1038         errno = EINVAL;
1039         return -1;
1040     }
1041     ibuf = (uchar *) malloc (len + 4);
1042     if (!ibuf)
1043     {
1044         errno = ENOMEM;
1045         return -1;
1046     }
1047     EIBSETTYPE (ibuf, EIB_GROUP_PACKET);
1048     EIBSETADDR (ibuf + 2, dest);
1049     memcpy (ibuf + 4, data, len);
1050     i = SendRequest (con, len + 4, ibuf);
1051     free (ibuf);
1052     return i;
1053 }
1054 
1055 static int
M_ReadIndividualAddresses_complete(EIBConnection * con)1056 M_ReadIndividualAddresses_complete (EIBConnection * con)
1057 {
1058     int i;
1059     i = GetRequest (con);
1060     if (i == -1)
1061         return -1;
1062     if (EIBTYPE (con) != EIB_M_INDIVIDUAL_ADDRESS_READ)
1063     {
1064         errno = ECONNRESET;
1065         return -1;
1066     }
1067     i = con->size - 2;
1068     if (i > con->req.len)
1069         i = con->req.len;
1070     memcpy (con->req.buf, con->buf + 2, i);
1071     return i;
1072 }
1073 
1074 int
EIB_M_ReadIndividualAddresses_async(EIBConnection * con,int maxlen,uint8_t * buf)1075 EIB_M_ReadIndividualAddresses_async (EIBConnection * con, int maxlen,
1076                                      uint8_t * buf)
1077 {
1078     uchar head[2];
1079     if (!con)
1080     {
1081         errno = EINVAL;
1082         return -1;
1083     }
1084     con->req.len = maxlen;
1085     con->req.buf = buf;
1086     EIBSETTYPE (head, EIB_M_INDIVIDUAL_ADDRESS_READ);
1087     if (SendRequest (con, 2, head) == -1)
1088         return -1;
1089     con->complete = M_ReadIndividualAddresses_complete;
1090     return 0;
1091 }
1092 
1093 int
EIB_M_ReadIndividualAddresses(EIBConnection * con,int maxlen,uint8_t * buf)1094 EIB_M_ReadIndividualAddresses (EIBConnection * con, int maxlen, uint8_t * buf)
1095 {
1096     if (EIB_M_ReadIndividualAddresses_async (con, maxlen, buf) == -1)
1097         return -1;
1098     return EIBComplete (con);
1099 }
1100 
1101 static int
M_Progmode_On_complete(EIBConnection * con)1102 M_Progmode_On_complete (EIBConnection * con)
1103 {
1104     int i;
1105     i = GetRequest (con);
1106     if (i == -1)
1107         return -1;
1108     if (EIBTYPE (con) != EIB_PROG_MODE)
1109     {
1110         errno = ECONNRESET;
1111         return -1;
1112     }
1113     return 0;
1114 }
1115 
1116 int
EIB_M_Progmode_On_async(EIBConnection * con,eibaddr_t dest)1117 EIB_M_Progmode_On_async (EIBConnection * con, eibaddr_t dest)
1118 {
1119     uchar head[5];
1120     if (!con)
1121     {
1122         errno = EINVAL;
1123         return -1;
1124     }
1125     EIBSETTYPE (head, EIB_PROG_MODE);
1126     EIBSETADDR (head + 2, dest);
1127     head[4] = 1;
1128     if (SendRequest (con, 5, head) == -1)
1129         return -1;
1130     con->complete = M_Progmode_On_complete;
1131     return 0;
1132 }
1133 
1134 int
EIB_M_Progmode_On(EIBConnection * con,eibaddr_t dest)1135 EIB_M_Progmode_On (EIBConnection * con, eibaddr_t dest)
1136 {
1137     if (EIB_M_Progmode_On_async (con, dest) == -1)
1138         return -1;
1139     return EIBComplete (con);
1140 }
1141 
1142 static int
M_Progmode_Off_complete(EIBConnection * con)1143 M_Progmode_Off_complete (EIBConnection * con)
1144 {
1145     int i;
1146     i = GetRequest (con);
1147     if (i == -1)
1148         return -1;
1149     if (EIBTYPE (con) != EIB_PROG_MODE)
1150     {
1151         errno = ECONNRESET;
1152         return -1;
1153     }
1154     return 0;
1155 }
1156 
1157 int
EIB_M_Progmode_Off_async(EIBConnection * con,eibaddr_t dest)1158 EIB_M_Progmode_Off_async (EIBConnection * con, eibaddr_t dest)
1159 {
1160     uchar head[5];
1161     if (!con)
1162     {
1163         errno = EINVAL;
1164         return -1;
1165     }
1166     EIBSETTYPE (head, EIB_PROG_MODE);
1167     EIBSETADDR (head + 2, dest);
1168     head[4] = 0;
1169     if (SendRequest (con, 5, head) == -1)
1170         return -1;
1171     con->complete = M_Progmode_Off_complete;
1172     return 0;
1173 }
1174 
1175 int
EIB_M_Progmode_Off(EIBConnection * con,eibaddr_t dest)1176 EIB_M_Progmode_Off (EIBConnection * con, eibaddr_t dest)
1177 {
1178     if (EIB_M_Progmode_Off_async (con, dest) == -1)
1179         return -1;
1180     return EIBComplete (con);
1181 }
1182 
1183 static int
M_Progmode_Toggle_complete(EIBConnection * con)1184 M_Progmode_Toggle_complete (EIBConnection * con)
1185 {
1186     int i;
1187     i = GetRequest (con);
1188     if (i == -1)
1189         return -1;
1190     if (EIBTYPE (con) != EIB_PROG_MODE)
1191     {
1192         errno = ECONNRESET;
1193         return -1;
1194     }
1195     return 0;
1196 }
1197 
1198 int
EIB_M_Progmode_Toggle_async(EIBConnection * con,eibaddr_t dest)1199 EIB_M_Progmode_Toggle_async (EIBConnection * con, eibaddr_t dest)
1200 {
1201     uchar head[5];
1202     if (!con)
1203     {
1204         errno = EINVAL;
1205         return -1;
1206     }
1207     EIBSETTYPE (head, EIB_PROG_MODE);
1208     EIBSETADDR (head + 2, dest);
1209     head[4] = 2;
1210     if (SendRequest (con, 5, head) == -1)
1211         return -1;
1212     con->complete = M_Progmode_Toggle_complete;
1213     return 0;
1214 }
1215 
1216 int
EIB_M_Progmode_Toggle(EIBConnection * con,eibaddr_t dest)1217 EIB_M_Progmode_Toggle (EIBConnection * con, eibaddr_t dest)
1218 {
1219     if (EIB_M_Progmode_Toggle (con, dest) == -1)
1220         return -1;
1221     return EIBComplete (con);
1222 }
1223 
1224 static int
M_Progmode_Status_complete(EIBConnection * con)1225 M_Progmode_Status_complete (EIBConnection * con)
1226 {
1227     int i;
1228     i = GetRequest (con);
1229     if (i == -1)
1230         return -1;
1231     if (EIBTYPE (con) != EIB_PROG_MODE || con->size < 3)
1232     {
1233         errno = ECONNRESET;
1234         return -1;
1235     }
1236     return con->buf[2];
1237 }
1238 
1239 int
EIB_M_Progmode_Status_async(EIBConnection * con,eibaddr_t dest)1240 EIB_M_Progmode_Status_async (EIBConnection * con, eibaddr_t dest)
1241 {
1242     uchar head[5];
1243     if (!con)
1244     {
1245         errno = EINVAL;
1246         return -1;
1247     }
1248     EIBSETTYPE (head, EIB_PROG_MODE);
1249     EIBSETADDR (head + 2, dest);
1250     head[4] = 3;
1251     if (SendRequest (con, 5, head) == -1)
1252         return -1;
1253     con->complete = M_Progmode_Status_complete;
1254     return 0;
1255 }
1256 
1257 int
EIB_M_Progmode_Status(EIBConnection * con,eibaddr_t dest)1258 EIB_M_Progmode_Status (EIBConnection * con, eibaddr_t dest)
1259 {
1260     if (EIB_M_Progmode_Status (con, dest) == -1)
1261         return -1;
1262     return EIBComplete (con);
1263 }
1264 
1265 static int
M_GetMaskVersion_complete(EIBConnection * con)1266 M_GetMaskVersion_complete (EIBConnection * con)
1267 {
1268     int i;
1269     i = GetRequest (con);
1270     if (i == -1)
1271         return -1;
1272     if (EIBTYPE (con) != EIB_MASK_VERSION || con->size < 4)
1273     {
1274         errno = ECONNRESET;
1275         return -1;
1276     }
1277     return (con->buf[2] << 8) | (con->buf[3]);
1278 }
1279 
1280 int
EIB_M_GetMaskVersion_async(EIBConnection * con,eibaddr_t dest)1281 EIB_M_GetMaskVersion_async (EIBConnection * con, eibaddr_t dest)
1282 {
1283     uchar head[4];
1284     if (!con)
1285     {
1286         errno = EINVAL;
1287         return -1;
1288     }
1289     EIBSETTYPE (head, EIB_MASK_VERSION);
1290     EIBSETADDR (head + 2, dest);
1291     if (SendRequest (con, 4, head) == -1)
1292         return -1;
1293     con->complete = M_GetMaskVersion_complete;
1294     return 0;
1295 }
1296 
1297 int
EIB_M_GetMaskVersion(EIBConnection * con,eibaddr_t dest)1298 EIB_M_GetMaskVersion (EIBConnection * con, eibaddr_t dest)
1299 {
1300     if (EIB_M_GetMaskVersion_async (con, dest) == -1)
1301         return -1;
1302     return EIBComplete (con);
1303 }
1304 
1305 static int
M_WriteIndividualAddress_complete(EIBConnection * con)1306 M_WriteIndividualAddress_complete (EIBConnection * con)
1307 {
1308     int i;
1309     i = GetRequest (con);
1310     if (i == -1)
1311         return -1;
1312     if (EIBTYPE (con) == EIB_ERROR_ADDR_EXISTS)
1313     {
1314         errno = EADDRINUSE;
1315         return -1;
1316     }
1317     if (EIBTYPE (con) == EIB_M_INDIVIDUAL_ADDRESS_WRITE)
1318     {
1319         return 0;
1320     }
1321     if (EIBTYPE (con) == EIB_ERROR_TIMEOUT)
1322     {
1323         errno = ETIMEDOUT;
1324         return -1;
1325     }
1326     if (EIBTYPE (con) == EIB_ERROR_MORE_DEVICE)
1327     {
1328         errno = EADDRNOTAVAIL;
1329         return -1;
1330     }
1331     errno = ECONNRESET;
1332     return -1;
1333 }
1334 
1335 int
EIB_M_WriteIndividualAddress_async(EIBConnection * con,eibaddr_t dest)1336 EIB_M_WriteIndividualAddress_async (EIBConnection * con, eibaddr_t dest)
1337 {
1338     uchar head[4];
1339     if (!con)
1340     {
1341         errno = EINVAL;
1342         return -1;
1343     }
1344     EIBSETTYPE (head, EIB_M_INDIVIDUAL_ADDRESS_WRITE);
1345     EIBSETADDR (head + 2, dest);
1346     if (SendRequest (con, 4, head) == -1)
1347         return -1;
1348     con->complete = M_WriteIndividualAddress_complete;
1349     return 0;
1350 }
1351 
1352 int
EIB_M_WriteIndividualAddress(EIBConnection * con,eibaddr_t dest)1353 EIB_M_WriteIndividualAddress (EIBConnection * con, eibaddr_t dest)
1354 {
1355     if (EIB_M_WriteIndividualAddress_async (con, dest) == -1)
1356         return -1;
1357     return EIBComplete (con);
1358 }
1359 
1360 static int
MC_Connect_complete(EIBConnection * con)1361 MC_Connect_complete (EIBConnection * con)
1362 {
1363     int i;
1364     i = GetRequest (con);
1365     if (i == -1)
1366         return -1;
1367 
1368     if (EIBTYPE (con) != EIB_MC_CONNECTION)
1369     {
1370         errno = ECONNRESET;
1371         return -1;
1372     }
1373     return 0;
1374 }
1375 
1376 int
EIB_MC_Connect_async(EIBConnection * con,eibaddr_t dest)1377 EIB_MC_Connect_async (EIBConnection * con, eibaddr_t dest)
1378 {
1379     uchar head[4];
1380     int i;
1381     if (!con)
1382     {
1383         errno = EINVAL;
1384         return -1;
1385     }
1386     EIBSETTYPE (head, EIB_MC_CONNECTION);
1387     EIBSETADDR (head + 2, dest);
1388     i = SendRequest (con, 4, head);
1389     if (i == -1)
1390         return -1;
1391 
1392     con->complete = MC_Connect_complete;
1393     return 0;
1394 }
1395 
1396 int
EIB_MC_Connect(EIBConnection * con,eibaddr_t dest)1397 EIB_MC_Connect (EIBConnection * con, eibaddr_t dest)
1398 {
1399     if (EIB_MC_Connect_async (con, dest) == -1)
1400         return -1;
1401     return EIBComplete (con);
1402 }
1403 
1404 static int
MC_Progmode_On_complete(EIBConnection * con)1405 MC_Progmode_On_complete (EIBConnection * con)
1406 {
1407     int i;
1408     i = GetRequest (con);
1409     if (i == -1)
1410         return -1;
1411     if (EIBTYPE (con) != EIB_MC_PROG_MODE)
1412     {
1413         errno = ECONNRESET;
1414         return -1;
1415     }
1416     return 0;
1417 }
1418 
1419 int
EIB_MC_Progmode_On_async(EIBConnection * con)1420 EIB_MC_Progmode_On_async (EIBConnection * con)
1421 {
1422     uchar head[3];
1423     if (!con)
1424     {
1425         errno = EINVAL;
1426         return -1;
1427     }
1428     EIBSETTYPE (head, EIB_MC_PROG_MODE);
1429     head[2] = 1;
1430     if (SendRequest (con, 3, head) == -1)
1431         return -1;
1432     con->complete = MC_Progmode_On_complete;
1433     return 0;
1434 }
1435 
1436 int
EIB_MC_Progmode_On(EIBConnection * con)1437 EIB_MC_Progmode_On (EIBConnection * con)
1438 {
1439     if (EIB_MC_Progmode_On_async (con) == -1)
1440         return -1;
1441     return EIBComplete (con);
1442 }
1443 
1444 static int
MC_Progmode_Off_complete(EIBConnection * con)1445 MC_Progmode_Off_complete (EIBConnection * con)
1446 {
1447     int i;
1448     i = GetRequest (con);
1449     if (i == -1)
1450         return -1;
1451     if (EIBTYPE (con) != EIB_MC_PROG_MODE)
1452     {
1453         errno = ECONNRESET;
1454         return -1;
1455     }
1456     return 0;
1457 }
1458 
1459 int
EIB_MC_Progmode_Off_async(EIBConnection * con)1460 EIB_MC_Progmode_Off_async (EIBConnection * con)
1461 {
1462     uchar head[3];
1463     if (!con)
1464     {
1465         errno = EINVAL;
1466         return -1;
1467     }
1468     EIBSETTYPE (head, EIB_MC_PROG_MODE);
1469     head[2] = 0;
1470     if (SendRequest (con, 3, head) == -1)
1471         return -1;
1472     con->complete = MC_Progmode_Off_complete;
1473     return 0;
1474 }
1475 
1476 int
EIB_MC_Progmode_Off(EIBConnection * con)1477 EIB_MC_Progmode_Off (EIBConnection * con)
1478 {
1479     if (EIB_MC_Progmode_Off_async (con) == -1)
1480         return -1;
1481     return EIBComplete (con);
1482 }
1483 
1484 static int
MC_Progmode_Toggle_complete(EIBConnection * con)1485 MC_Progmode_Toggle_complete (EIBConnection * con)
1486 {
1487     int i;
1488     i = GetRequest (con);
1489     if (i == -1)
1490         return -1;
1491     if (EIBTYPE (con) != EIB_MC_PROG_MODE)
1492     {
1493         errno = ECONNRESET;
1494         return -1;
1495     }
1496     return 0;
1497 }
1498 
1499 int
EIB_MC_Progmode_Toggle_async(EIBConnection * con)1500 EIB_MC_Progmode_Toggle_async (EIBConnection * con)
1501 {
1502     uchar head[3];
1503     if (!con)
1504     {
1505         errno = EINVAL;
1506         return -1;
1507     }
1508     EIBSETTYPE (head, EIB_MC_PROG_MODE);
1509     head[2] = 2;
1510     if (SendRequest (con, 3, head) == -1)
1511         return -1;
1512     con->complete = MC_Progmode_Toggle_complete;
1513     return 0;
1514 }
1515 
1516 int
EIB_MC_Progmode_Toggle(EIBConnection * con)1517 EIB_MC_Progmode_Toggle (EIBConnection * con)
1518 {
1519     if (EIB_MC_Progmode_Toggle_async (con) == -1)
1520         return -1;
1521     return EIBComplete (con);
1522 }
1523 
1524 static int
MC_Progmode_Status_complete(EIBConnection * con)1525 MC_Progmode_Status_complete (EIBConnection * con)
1526 {
1527     int i;
1528     i = GetRequest (con);
1529     if (i == -1)
1530         return -1;
1531     if (EIBTYPE (con) != EIB_MC_PROG_MODE || con->size < 3)
1532     {
1533         errno = ECONNRESET;
1534         return -1;
1535     }
1536     return con->buf[2];
1537 }
1538 
1539 int
EIB_MC_Progmode_Status_async(EIBConnection * con)1540 EIB_MC_Progmode_Status_async (EIBConnection * con)
1541 {
1542     uchar head[3];
1543     if (!con)
1544     {
1545         errno = EINVAL;
1546         return -1;
1547     }
1548     EIBSETTYPE (head, EIB_MC_PROG_MODE);
1549     head[2] = 3;
1550     if (SendRequest (con, 3, head) == -1)
1551         return -1;
1552     con->complete = MC_Progmode_Status_complete;
1553     return 0;
1554 }
1555 
1556 int
EIB_MC_Progmode_Status(EIBConnection * con)1557 EIB_MC_Progmode_Status (EIBConnection * con)
1558 {
1559     if (EIB_MC_Progmode_Status_async (con) == -1)
1560         return -1;
1561     return EIBComplete (con);
1562 }
1563 
1564 static int
MC_GetMaskVersion_complete(EIBConnection * con)1565 MC_GetMaskVersion_complete (EIBConnection * con)
1566 {
1567     int i;
1568     i = GetRequest (con);
1569     if (i == -1)
1570         return -1;
1571     if (EIBTYPE (con) != EIB_MC_MASK_VERSION || con->size < 4)
1572     {
1573         errno = ECONNRESET;
1574         return -1;
1575     }
1576     return (con->buf[2] << 8) | (con->buf[3]);
1577 }
1578 
1579 int
EIB_MC_GetMaskVersion_async(EIBConnection * con)1580 EIB_MC_GetMaskVersion_async (EIBConnection * con)
1581 {
1582     uchar head[2];
1583     if (!con)
1584     {
1585         errno = EINVAL;
1586         return -1;
1587     }
1588     EIBSETTYPE (head, EIB_MC_MASK_VERSION);
1589     if (SendRequest (con, 2, head) == -1)
1590         return -1;
1591     con->complete = MC_GetMaskVersion_complete;
1592     return 0;
1593 }
1594 
1595 int
EIB_MC_GetMaskVersion(EIBConnection * con)1596 EIB_MC_GetMaskVersion (EIBConnection * con)
1597 {
1598     if (EIB_MC_GetMaskVersion_async (con) == -1)
1599         return -1;
1600     return EIBComplete (con);
1601 }
1602 
1603 static int
MC_GetPEIType_complete(EIBConnection * con)1604 MC_GetPEIType_complete (EIBConnection * con)
1605 {
1606     int i;
1607     i = GetRequest (con);
1608     if (i == -1)
1609         return -1;
1610     if (EIBTYPE (con) != EIB_MC_PEI_TYPE || con->size < 4)
1611     {
1612         errno = ECONNRESET;
1613         return -1;
1614     }
1615     return (con->buf[2] << 8) | (con->buf[3]);
1616 }
1617 
1618 int
EIB_MC_GetPEIType_async(EIBConnection * con)1619 EIB_MC_GetPEIType_async (EIBConnection * con)
1620 {
1621     uchar head[2];
1622     if (!con)
1623     {
1624         errno = EINVAL;
1625         return -1;
1626     }
1627     EIBSETTYPE (head, EIB_MC_PEI_TYPE);
1628     if (SendRequest (con, 2, head) == -1)
1629         return -1;
1630     con->complete = MC_GetPEIType_complete;
1631     return 0;
1632 }
1633 
1634 int
EIB_MC_GetPEIType(EIBConnection * con)1635 EIB_MC_GetPEIType (EIBConnection * con)
1636 {
1637     if (EIB_MC_GetPEIType_async (con) == -1)
1638         return -1;
1639     return EIBComplete (con);
1640 }
1641 
1642 static int
MC_ReadADC_complete(EIBConnection * con)1643 MC_ReadADC_complete (EIBConnection * con)
1644 {
1645     int i;
1646     i = GetRequest (con);
1647     if (i == -1)
1648         return -1;
1649     if (EIBTYPE (con) != EIB_MC_ADC_READ || con->size < 4)
1650     {
1651         errno = ECONNRESET;
1652         return -1;
1653     }
1654     if (con->req.ptr1)
1655         *con->req.ptr1 = (con->buf[2] << 8) | (con->buf[3]);
1656     return 0;
1657 }
1658 
1659 int
EIB_MC_ReadADC_async(EIBConnection * con,uint8_t channel,uint8_t count,int16_t * val)1660 EIB_MC_ReadADC_async (EIBConnection * con, uint8_t channel, uint8_t count,
1661                       int16_t * val)
1662 {
1663     uchar head[4];
1664     if (!con)
1665     {
1666         errno = EINVAL;
1667         return -1;
1668     }
1669     con->req.ptr1 = val;
1670     EIBSETTYPE (head, EIB_MC_ADC_READ);
1671     head[2] = channel;
1672     head[3] = count;
1673     if (SendRequest (con, 4, head) == -1)
1674         return -1;
1675     con->complete = MC_ReadADC_complete;
1676     return 0;
1677 }
1678 
1679 int
EIB_MC_ReadADC(EIBConnection * con,uint8_t channel,uint8_t count,int16_t * val)1680 EIB_MC_ReadADC (EIBConnection * con, uint8_t channel, uint8_t count,
1681                 int16_t * val)
1682 {
1683     if (EIB_MC_ReadADC_async (con, channel, count, val) == -1)
1684         return -1;
1685     return EIBComplete (con);
1686 }
1687 
1688 static int
MC_PropertyRead_complete(EIBConnection * con)1689 MC_PropertyRead_complete (EIBConnection * con)
1690 {
1691     int i;
1692     i = GetRequest (con);
1693     if (i == -1)
1694         return -1;
1695     if (EIBTYPE (con) != EIB_MC_PROP_READ)
1696     {
1697         errno = ECONNRESET;
1698         return -1;
1699     }
1700     i = con->size - 2;
1701     if (i > con->req.len)
1702         i = con->req.len;
1703     memcpy (con->req.buf, con->buf + 2, i);
1704     return i;
1705 }
1706 
1707 int
EIB_MC_PropertyRead_async(EIBConnection * con,uint8_t obj,uint8_t property,uint16_t start,uint8_t nr_of_elem,int max_len,uint8_t * buf)1708 EIB_MC_PropertyRead_async (EIBConnection * con, uint8_t obj, uint8_t property,
1709                            uint16_t start, uint8_t nr_of_elem, int max_len,
1710                            uint8_t * buf)
1711 {
1712     uchar head[7];
1713     if (!con)
1714     {
1715         errno = EINVAL;
1716         return -1;
1717     }
1718     con->req.buf = buf;
1719     con->req.len = max_len;
1720     if (!buf)
1721     {
1722         errno = EINVAL;
1723         return -1;
1724     }
1725     EIBSETTYPE (head, EIB_MC_PROP_READ);
1726     head[2] = obj;
1727     head[3] = property;
1728     head[4] = (start >> 8) & 0xff;
1729     head[5] = (start) & 0xff;
1730     head[6] = nr_of_elem;
1731     if (SendRequest (con, 7, head) == -1)
1732         return -1;
1733     con->complete = MC_PropertyRead_complete;
1734     return 0;
1735 }
1736 
1737 int
EIB_MC_PropertyRead(EIBConnection * con,uint8_t obj,uint8_t property,uint16_t start,uint8_t nr_of_elem,int max_len,uint8_t * buf)1738 EIB_MC_PropertyRead (EIBConnection * con, uint8_t obj, uint8_t property,
1739                      uint16_t start, uint8_t nr_of_elem, int max_len,
1740                      uint8_t * buf)
1741 {
1742     if (EIB_MC_PropertyRead_async
1743             (con, obj, property, start, nr_of_elem, max_len, buf) == -1)
1744         return -1;
1745     return EIBComplete (con);
1746 }
1747 
1748 static int
MC_Read_complete(EIBConnection * con)1749 MC_Read_complete (EIBConnection * con)
1750 {
1751     int i;
1752     i = GetRequest (con);
1753     if (i == -1)
1754         return -1;
1755     if (EIBTYPE (con) != EIB_MC_READ)
1756     {
1757         errno = ECONNRESET;
1758         return -1;
1759     }
1760     i = con->size - 2;
1761     if (i > con->req.len)
1762         i = con->req.len;
1763     memcpy (con->req.buf, con->buf + 2, i);
1764     return i;
1765 }
1766 
1767 int
EIB_MC_Read_async(EIBConnection * con,uint16_t addr,int len,uint8_t * buf)1768 EIB_MC_Read_async (EIBConnection * con, uint16_t addr, int len, uint8_t * buf)
1769 {
1770     uchar head[6];
1771     if (!con)
1772     {
1773         errno = EINVAL;
1774         return -1;
1775     }
1776     if (!buf)
1777     {
1778         errno = EINVAL;
1779         return -1;
1780     }
1781     con->req.len = len;
1782     con->req.buf = buf;
1783     EIBSETTYPE (head, EIB_MC_READ);
1784     head[2] = (addr >> 8) & 0xff;
1785     head[3] = (addr) & 0xff;
1786     head[4] = (len >> 8) & 0xff;
1787     head[5] = (len) & 0xff;
1788     if (SendRequest (con, 6, head) == -1)
1789         return -1;
1790     con->complete = MC_Read_complete;
1791     return 0;
1792 }
1793 
1794 int
EIB_MC_Read(EIBConnection * con,uint16_t addr,int len,uint8_t * buf)1795 EIB_MC_Read (EIBConnection * con, uint16_t addr, int len, uint8_t * buf)
1796 {
1797     if (EIB_MC_Read_async (con, addr, len, buf) == -1)
1798         return -1;
1799     return EIBComplete (con);
1800 }
1801 
1802 static int
MC_PropertyWrite_complete(EIBConnection * con)1803 MC_PropertyWrite_complete (EIBConnection * con)
1804 {
1805     int i;
1806     i = GetRequest (con);
1807     if (i == -1)
1808         return -1;
1809     if (EIBTYPE (con) != EIB_MC_PROP_WRITE)
1810     {
1811         errno = ECONNRESET;
1812         return -1;
1813     }
1814     i = con->size - 2;
1815     if (i > con->req.len)
1816         i = con->req.len;
1817     memcpy (con->req.buf, con->buf + 2, i);
1818     return i;
1819 }
1820 
1821 int
EIB_MC_PropertyWrite_async(EIBConnection * con,uint8_t obj,uint8_t property,uint16_t start,uint8_t nr_of_elem,int len,const uint8_t * buf,int max_len,uint8_t * res)1822 EIB_MC_PropertyWrite_async (EIBConnection * con, uint8_t obj,
1823                             uint8_t property, uint16_t start,
1824                             uint8_t nr_of_elem, int len, const uint8_t * buf,
1825                             int max_len, uint8_t * res)
1826 {
1827     uchar *ibuf;
1828     int i;
1829     if (!con)
1830     {
1831         errno = EINVAL;
1832         return -1;
1833     }
1834     if (!buf || !res)
1835     {
1836         errno = EINVAL;
1837         return -1;
1838     }
1839     con->req.len = max_len;
1840     con->req.buf = res;
1841     ibuf = (uchar *) malloc (len + 7);
1842     if (!ibuf)
1843     {
1844         errno = ENOMEM;
1845         return -1;
1846     }
1847     EIBSETTYPE (ibuf, EIB_MC_PROP_WRITE);
1848     ibuf[2] = obj;
1849     ibuf[3] = property;
1850     ibuf[4] = (start >> 8) & 0xff;
1851     ibuf[5] = (start) & 0xff;
1852     ibuf[6] = nr_of_elem;
1853     memcpy (ibuf + 7, buf, len);
1854     i = SendRequest (con, len + 7, ibuf);
1855     free (ibuf);
1856     if (i == -1)
1857         return -1;
1858     con->complete = MC_PropertyWrite_complete;
1859     return 0;
1860 }
1861 
1862 int
EIB_MC_PropertyWrite(EIBConnection * con,uint8_t obj,uint8_t property,uint16_t start,uint8_t nr_of_elem,int len,const uint8_t * buf,int max_len,uint8_t * res)1863 EIB_MC_PropertyWrite (EIBConnection * con, uint8_t obj, uint8_t property,
1864                       uint16_t start, uint8_t nr_of_elem, int len,
1865                       const uint8_t * buf, int max_len, uint8_t * res)
1866 {
1867     if (EIB_MC_PropertyWrite_async
1868             (con, obj, property, start, nr_of_elem, len, buf, max_len, res) == -1)
1869         return -1;
1870     return EIBComplete (con);
1871 }
1872 static int
MC_Write_complete(EIBConnection * con)1873 MC_Write_complete (EIBConnection * con)
1874 {
1875     int i;
1876     i = GetRequest (con);
1877     if (i == -1)
1878         return -1;
1879     if (EIBTYPE (con) == EIB_ERROR_VERIFY)
1880     {
1881         errno = EIO;
1882         return -1;
1883     }
1884     if (EIBTYPE (con) != EIB_MC_WRITE)
1885     {
1886         errno = ECONNRESET;
1887         return -1;
1888     }
1889     return con->req.len;
1890 }
1891 
1892 int
EIB_MC_Write_async(EIBConnection * con,uint16_t addr,int len,const uint8_t * buf)1893 EIB_MC_Write_async (EIBConnection * con, uint16_t addr, int len,
1894                     const uint8_t * buf)
1895 {
1896     uchar *ibuf;
1897     int i;
1898     if (!con)
1899     {
1900         errno = EINVAL;
1901         return -1;
1902     }
1903     con->req.len = len;
1904     if (!buf)
1905     {
1906         errno = EINVAL;
1907         return -1;
1908     }
1909     ibuf = (uchar *) malloc (len + 6);
1910     if (!ibuf)
1911     {
1912         errno = ENOMEM;
1913         return -1;
1914     }
1915     EIBSETTYPE (ibuf, EIB_MC_WRITE);
1916     ibuf[2] = (addr >> 8) & 0xff;
1917     ibuf[3] = (addr) & 0xff;
1918     ibuf[4] = (len >> 8) & 0xff;
1919     ibuf[5] = (len) & 0xff;
1920     memcpy (ibuf + 6, buf, len);
1921     i = SendRequest (con, len + 6, ibuf);
1922     free (ibuf);
1923     if (i == -1)
1924         return -1;
1925     con->complete = MC_Write_complete;
1926     return 0;
1927 }
1928 
1929 int
EIB_MC_Write(EIBConnection * con,uint16_t addr,int len,const uint8_t * buf)1930 EIB_MC_Write (EIBConnection * con, uint16_t addr, int len,
1931               const uint8_t * buf)
1932 {
1933     if (EIB_MC_Write_async (con, addr, len, buf) == -1)
1934         return -1;
1935     return EIBComplete (con);
1936 }
1937 
1938 static int
MC_PropertyDesc_complete(EIBConnection * con)1939 MC_PropertyDesc_complete (EIBConnection * con)
1940 {
1941     int i;
1942     i = GetRequest (con);
1943     if (i == -1)
1944         return -1;
1945     if (EIBTYPE (con) != EIB_MC_PROP_DESC || con->size < 6)
1946     {
1947         errno = ECONNRESET;
1948         return -1;
1949     }
1950     /* Type */
1951     if (con->req.ptr2)
1952         *con->req.ptr2 = con->buf[2];
1953     /* max_nr_of_elem */
1954     if (con->req.ptr4)
1955         *con->req.ptr4 = (con->buf[3] << 8) | (con->buf[4]);
1956     /* access */
1957     if (con->req.ptr3)
1958         *con->req.ptr3 = con->buf[5];
1959     return 0;
1960 }
1961 
1962 int
EIB_MC_PropertyDesc_async(EIBConnection * con,uint8_t obj,uint8_t property,uint8_t * type,uint16_t * max_nr_of_elem,uint8_t * access)1963 EIB_MC_PropertyDesc_async (EIBConnection * con, uint8_t obj, uint8_t property,
1964                            uint8_t * type, uint16_t * max_nr_of_elem,
1965                            uint8_t * access)
1966 {
1967     uchar head[5];
1968     if (!con)
1969     {
1970         errno = EINVAL;
1971         return -1;
1972     }
1973     con->req.ptr2 = type;
1974     con->req.ptr4 = max_nr_of_elem;
1975     con->req.ptr3 = access;
1976     EIBSETTYPE (head, EIB_MC_PROP_DESC);
1977     head[2] = obj;
1978     head[3] = property;
1979     if (SendRequest (con, 4, head) == -1)
1980         return -1;
1981     con->complete = MC_PropertyDesc_complete;
1982     return 0;
1983 }
1984 
1985 int
EIB_MC_PropertyDesc(EIBConnection * con,uint8_t obj,uint8_t property,uint8_t * type,uint16_t * max_nr_of_elem,uint8_t * access)1986 EIB_MC_PropertyDesc (EIBConnection * con, uint8_t obj, uint8_t property,
1987                      uint8_t * type, uint16_t * max_nr_of_elem,
1988                      uint8_t * access)
1989 {
1990     if (EIB_MC_PropertyDesc_async
1991             (con, obj, property, type, max_nr_of_elem, access) == -1)
1992         return -1;
1993     return EIBComplete (con);
1994 }
1995 
1996 static int
MC_Authorize_complete(EIBConnection * con)1997 MC_Authorize_complete (EIBConnection * con)
1998 {
1999     int i;
2000     i = GetRequest (con);
2001     if (i == -1)
2002         return -1;
2003     if (EIBTYPE (con) != EIB_MC_AUTHORIZE || con->size < 3)
2004     {
2005         errno = ECONNRESET;
2006         return -1;
2007     }
2008     return con->buf[2];
2009 }
2010 
2011 int
EIB_MC_Authorize_async(EIBConnection * con,uint8_t key[4])2012 EIB_MC_Authorize_async (EIBConnection * con, uint8_t key[4])
2013 {
2014     uchar head[6];
2015     if (!con)
2016     {
2017         errno = EINVAL;
2018         return -1;
2019     }
2020     EIBSETTYPE (head, EIB_MC_AUTHORIZE);
2021     memcpy (head + 2, key, 4);
2022     if (SendRequest (con, 6, head) == -1)
2023         return -1;
2024     con->complete = MC_Authorize_complete;
2025     return 0;
2026 }
2027 
2028 int
EIB_MC_Authorize(EIBConnection * con,uint8_t key[4])2029 EIB_MC_Authorize (EIBConnection * con, uint8_t key[4])
2030 {
2031     if (EIB_MC_Authorize_async (con, key) == -1)
2032         return -1;
2033     return EIBComplete (con);
2034 }
2035 
2036 static int
MC_SetKey_complete(EIBConnection * con)2037 MC_SetKey_complete (EIBConnection * con)
2038 {
2039     int i;
2040     i = GetRequest (con);
2041     if (i == -1)
2042         return -1;
2043     if (EIBTYPE (con) == EIB_PROCESSING_ERROR)
2044     {
2045         errno = EPERM;
2046         return -1;
2047     }
2048     if (EIBTYPE (con) != EIB_MC_KEY_WRITE)
2049     {
2050         errno = ECONNRESET;
2051         return -1;
2052     }
2053     return 0;
2054 }
2055 
2056 int
EIB_MC_SetKey_async(EIBConnection * con,uint8_t key[4],uint8_t level)2057 EIB_MC_SetKey_async (EIBConnection * con, uint8_t key[4], uint8_t level)
2058 {
2059     uchar head[7];
2060     if (!con)
2061     {
2062         errno = EINVAL;
2063         return -1;
2064     }
2065     EIBSETTYPE (head, EIB_MC_KEY_WRITE);
2066     memcpy (head + 2, key, 4);
2067     head[6] = level;
2068     if (SendRequest (con, 7, head) == -1)
2069         return -1;
2070     con->complete = MC_SetKey_complete;
2071     return 0;
2072 }
2073 
2074 int
EIB_MC_SetKey(EIBConnection * con,uint8_t key[4],uint8_t level)2075 EIB_MC_SetKey (EIBConnection * con, uint8_t key[4], uint8_t level)
2076 {
2077     if (EIB_MC_SetKey_async (con, key, level) == -1)
2078         return -1;
2079     return EIBComplete (con);
2080 }
2081 
2082 static int
MC_PropertyScan_complete(EIBConnection * con)2083 MC_PropertyScan_complete (EIBConnection * con)
2084 {
2085     int i;
2086     i = GetRequest (con);
2087     if (i == -1)
2088         return -1;
2089     if (EIBTYPE (con) != EIB_MC_PROP_SCAN)
2090     {
2091         errno = ECONNRESET;
2092         return -1;
2093     }
2094     i = con->size - 2;
2095     if (i > con->req.len)
2096         i = con->req.len;
2097     memcpy (con->req.buf, con->buf + 2, i);
2098     return i;
2099 }
2100 
2101 int
EIB_MC_PropertyScan_async(EIBConnection * con,int maxlen,uint8_t * buf)2102 EIB_MC_PropertyScan_async (EIBConnection * con, int maxlen, uint8_t * buf)
2103 {
2104     uchar head[2];
2105     if (!con)
2106     {
2107         errno = EINVAL;
2108         return -1;
2109     }
2110     con->req.len = maxlen;
2111     con->req.buf = buf;
2112     EIBSETTYPE (head, EIB_MC_PROP_SCAN);
2113     if (SendRequest (con, 2, head) == -1)
2114         return -1;
2115     con->complete = MC_PropertyScan_complete;
2116     return 0;
2117 }
2118 
2119 int
EIB_MC_PropertyScan(EIBConnection * con,int maxlen,uint8_t * buf)2120 EIB_MC_PropertyScan (EIBConnection * con, int maxlen, uint8_t * buf)
2121 {
2122     if (EIB_MC_PropertyScan_async (con, maxlen, buf) == -1)
2123         return -1;
2124     return EIBComplete (con);
2125 }
2126 
2127 static int
LoadImage_complete(EIBConnection * con)2128 LoadImage_complete (EIBConnection * con)
2129 {
2130     int i;
2131     i = GetRequest (con);
2132     if (i == -1)
2133         return -1;
2134     if (EIBTYPE (con) != EIB_LOAD_IMAGE || con->size < 4)
2135     {
2136         errno = ECONNRESET;
2137         return IMG_UNKNOWN_ERROR;
2138     }
2139     return (con->buf[2] << 8) | con->buf[3];
2140 }
2141 
2142 int
EIB_LoadImage_async(EIBConnection * con,const uint8_t * image,int len)2143 EIB_LoadImage_async (EIBConnection * con, const uint8_t * image, int len)
2144 {
2145     uchar *ibuf;
2146     int i;
2147     if (!con)
2148     {
2149         errno = EINVAL;
2150         return -1;
2151     }
2152     if (!image)
2153     {
2154         errno = EINVAL;
2155         return -1;
2156     }
2157     ibuf = (uchar *) malloc (len + 2);
2158     if (!ibuf)
2159     {
2160         errno = ENOMEM;
2161         return -1;
2162     }
2163     EIBSETTYPE (ibuf, EIB_LOAD_IMAGE);
2164     memcpy (ibuf + 2, image, len);
2165     i = SendRequest (con, len + 2, ibuf);
2166     free (ibuf);
2167     if (i == -1)
2168         return -1;
2169     con->complete = LoadImage_complete;
2170     return 0;
2171 }
2172 
2173 BCU_LOAD_RESULT
EIB_LoadImage(EIBConnection * con,const uint8_t * image,int len)2174 EIB_LoadImage (EIBConnection * con, const uint8_t * image, int len)
2175 {
2176     if (EIB_LoadImage_async (con, image, len) == -1)
2177         return -1;
2178     return EIBComplete (con);
2179 }
2180