/ src / libserver / managementclient.cpp
managementclient.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 "managementclient.h"
 21  
 22  #include "loadimage.h"
 23  #include "management.h"
 24  
 25  void
 26  ReadIndividualAddresses (ClientConnPtr c, uint8_t *buf, size_t len)
 27  {
 28    Layer7_Broadcast b (c->t);
 29    if (!b.init (c->l3))
 30      {
 31        c->sendreject (EIB_PROCESSING_ERROR);
 32        return;
 33      }
 34    CArray erg;
 35    std::vector < eibaddr_t > e = b.A_IndividualAddress_Read (c->t);
 36    erg.resize (2 + 2 * e.size());
 37    EIBSETTYPE (erg, EIB_M_INDIVIDUAL_ADDRESS_READ);
 38    for (unsigned i = 0; i < e.size(); i++)
 39      {
 40        erg[2 + i * 2] = (e[i] >> 8) & 0xff;
 41        erg[2 + i * 2 + 1] = (e[i]) & 0xff;
 42      }
 43    c->sendmessage (erg.size(), erg.data());
 44  }
 45  
 46  void
 47  ChangeProgMode (ClientConnPtr c, uint8_t *buf, size_t len)
 48  {
 49    eibaddr_t dest;
 50    uint8_t res[3];
 51    int i;
 52    EIBSETTYPE (res, EIB_PROG_MODE);
 53    res[2] = 0;
 54    if (c->size < 5)
 55      {
 56        c->sendreject ();
 57        return;
 58      }
 59    dest = (c->buf[2] << 8) | (c->buf[3]);
 60    Management_Connection m = Management_Connection (c->t, dest);
 61    if (!m.init (c->l3))
 62      {
 63        c->sendreject (EIB_PROCESSING_ERROR);
 64        return;
 65      }
 66    switch (c->buf[4])
 67      {
 68      case 0:
 69        if (m.X_Progmode_Off () == -1)
 70          c->sendreject ();
 71        else
 72          c->sendmessage (3, res);
 73        break;
 74      case 1:
 75        if (m.X_Progmode_On () == -1)
 76          c->sendreject ();
 77        else
 78          c->sendmessage (3, res);
 79        break;
 80      case 2:
 81        if (m.X_Progmode_Toggle () == -1)
 82          c->sendreject ();
 83        else
 84          c->sendmessage (3, res);
 85        break;
 86      case 3:
 87        if ((i = m.X_Progmode_Status ()) == -1)
 88          c->sendreject ();
 89        else
 90          {
 91            res[2] = i;
 92            c->sendmessage (3, res);
 93          }
 94        break;
 95      default:
 96        c->sendreject ();
 97      }
 98  }
 99  
100  void
101  GetMaskVersion (ClientConnPtr c, uint8_t *buf, size_t len)
102  {
103    eibaddr_t dest;
104    uint8_t res[4];
105    uint16_t maskver;
106    EIBSETTYPE (res, EIB_MASK_VERSION);
107    res[2] = 0;
108    if (c->size < 4)
109      {
110        c->sendreject ();
111        return;
112      }
113  
114    dest = (c->buf[2] << 8) | (c->buf[3]);
115    Management_Connection m = Management_Connection (c->t, dest);
116    if (!m.init (c->l3))
117      {
118        c->sendreject (EIB_PROCESSING_ERROR);
119        return;
120      }
121    if (m.A_Device_Descriptor_Read (maskver) == -1)
122      c->sendreject ();
123    else
124      {
125        res[2] = (maskver >> 8) & 0xff;
126        res[3] = (maskver) & 0xff;
127        c->sendmessage (4, res);
128      }
129  }
130  
131  void
132  WriteIndividualAddress (ClientConnPtr c, uint8_t *buf, size_t len)
133  {
134    eibaddr_t dest;
135    uint16_t maskver;
136    if (c->size < 4)
137      {
138        c->sendreject ();
139        return;
140      }
141  
142    dest = (c->buf[2] << 8) | (c->buf[3]);
143    Layer7_Broadcast b (c->t);
144    if (!b.init (c->l3))
145      {
146        c->sendreject (EIB_PROCESSING_ERROR);
147        return;
148      }
149    {
150      Management_Connection m = Management_Connection (c->t, dest);
151      if (!m.init (c->l3))
152        {
153          c->sendreject (EIB_PROCESSING_ERROR);
154          return;
155        }
156      if (m.A_Device_Descriptor_Read (maskver) != -1)
157        {
158          c->sendreject (EIB_ERROR_ADDR_EXISTS);
159          return;
160        }
161    }
162    std::vector < eibaddr_t > addr = b.A_IndividualAddress_Read (c->t);
163    if (addr.size() > 1)
164      {
165        c->sendreject (EIB_ERROR_MORE_DEVICE);
166        return;
167      }
168    if (addr.size() == 0)
169      {
170        c->sendreject (EIB_ERROR_TIMEOUT);
171        return;
172      }
173    b.A_IndividualAddress_Write (dest);
174    // wait 100ms
175    pth_usleep (100000);
176  
177    Management_Connection m1 = Management_Connection (c->t, dest);
178    if (!m1.init (c->l3))
179      {
180        c->sendreject (EIB_PROCESSING_ERROR);
181        return;
182      }
183    if (m1.A_Device_Descriptor_Read (maskver) == -1)
184      {
185        c->sendreject (EIB_PROCESSING_ERROR);
186        return;
187      }
188    if (m1.X_Progmode_Off () == -1)
189      {
190        c->sendreject (EIB_PROCESSING_ERROR);
191        return;
192      }
193    c->sendreject (EIB_M_INDIVIDUAL_ADDRESS_WRITE);
194  }
195  
196  ManagementConnection::ManagementConnection (ClientConnPtr c, uint8_t *buf, size_t len)
197  {
198    eibaddr_t dest;
199    uint16_t maskver;
200    int16_t val;
201    uint8_t buf[10];
202    int i;
203    eibkey_type key;
204  
205    if (c->size < 4)
206      {
207        c->sendreject ();
208        return;
209      }
210  
211    dest = (c->buf[2] << 8) | (c->buf[3]);
212    Management_Connection m = Management_Connection (c->t, dest);
213    if (!m.init (c->l3))
214      {
215        c->sendreject (EIB_PROCESSING_ERROR);
216        return;
217      }
218    if (m.A_Device_Descriptor_Read (maskver) == -1)
219      {
220        c->sendreject ();
221        return;
222      }
223    c->sendreject (EIB_MC_CONNECTION);
224    do
225      {
226        i = c->readmessage ();
227        if (i != -1)
228          switch (EIBTYPE (c->buf))
229            {
230            case EIB_MC_PROG_MODE:
231              if (c->size < 3)
232                {
233                  c->sendreject ();
234                  break;
235                }
236              EIBSETTYPE (buf, EIB_MC_PROG_MODE);
237              buf[2] = 0;
238              switch (c->buf[2])
239                {
240                case 0:
241                  if (m.X_Progmode_Off () == -1)
242                    c->sendreject ();
243                  else
244                    c->sendmessage (3, buf);
245                  break;
246                case 1:
247                  if (m.X_Progmode_On () == -1)
248                    c->sendreject ();
249                  else
250                    c->sendmessage (3, buf);
251                  break;
252                case 2:
253                  if (m.X_Progmode_Toggle () == -1)
254                    c->sendreject ();
255                  else
256                    c->sendmessage (3, buf);
257                  break;
258                case 3:
259                  if ((i = m.X_Progmode_Status ()) == -1)
260                    c->sendreject ();
261                  else
262                    {
263                      buf[2] = i;
264                      c->sendmessage (3, buf);
265                    }
266                  break;
267                default:
268                  c->sendreject ();
269                }
270              break;
271            case EIB_MC_MASK_VERSION:
272              if (m.A_Device_Descriptor_Read (maskver) == -1)
273                c->sendreject ();
274              else
275                {
276                  EIBSETTYPE (buf, EIB_MC_MASK_VERSION);
277                  buf[2] = (maskver >> 8) & 0xff;
278                  buf[3] = (maskver) & 0xff;
279                  c->sendmessage (4, buf);
280                }
281              break;
282            case EIB_MC_PEI_TYPE:
283              if (m.X_Get_PEIType (val) == -1)
284                c->sendreject ();
285              else
286                {
287                  EIBSETTYPE (buf, EIB_MC_PEI_TYPE);
288                  buf[2] = (val >> 8) & 0xff;
289                  buf[3] = (val) & 0xff;
290                  c->sendmessage (4, buf);
291                }
292              break;
293            case EIB_MC_ADC_READ:
294              if (c->size < 4)
295                {
296                  c->sendreject ();
297                  break;
298                }
299              if (m.A_ADC_Read (c->buf[2], c->buf[3], val) == -1)
300                c->sendreject ();
301              else
302                {
303                  EIBSETTYPE (buf, EIB_MC_ADC_READ);
304                  buf[2] = (val >> 8) & 0xff;
305                  buf[3] = (val) & 0xff;
306                  c->sendmessage (4, buf);
307                }
308              break;
309  
310            case EIB_MC_READ:
311              if (c->size < 6)
312                {
313                  c->sendreject ();
314                  break;
315                }
316              {
317                memaddr_t addr = (c->buf[2] << 8) | (c->buf[3]);
318                unsigned len = (c->buf[4] << 8) | (c->buf[5]);
319                CArray data, erg;
320                if (m.X_Memory_Read_Block (addr, len, data) == -1)
321                  c->sendreject ();
322                else
323                  {
324                    erg.resize (6);
325                    EIBSETTYPE (erg, EIB_MC_READ);
326                    erg.setpart (data, 2);
327                    c->sendmessage (erg.size(), erg.data());
328                  }
329              }
330              break;
331  
332            case EIB_MC_WRITE:
333              if (c->size < 6)
334                {
335                  c->sendreject ();
336                  break;
337                }
338              {
339                memaddr_t addr = (c->buf[2] << 8) | (c->buf[3]);
340                unsigned len = (c->buf[4] << 8) | (c->buf[5]);
341                if (c->size < len + 6)
342                  {
343                    c->sendreject ();
344                    break;
345                  }
346                i = m.X_Memory_Write_Block (addr, CArray (c->buf + 6, len));
347                if (i == -2)
348                  c->sendreject (EIB_ERROR_VERIFY);
349                else if (i != 0)
350                  c->sendreject (EIB_PROCESSING_ERROR);
351                else
352                  c->sendreject (EIB_MC_WRITE);
353              }
354              break;
355  
356            case EIB_MC_PROP_READ:
357              if (c->size < 7)
358                {
359                  c->sendreject ();
360                  break;
361                }
362              {
363                CArray data, erg;
364                if (m.A_Property_Read (c->buf[2], c->buf[3],
365                                       (c->buf[4] << 8) | c->buf[5], c->buf[6],
366                                       data) == -1)
367                  c->sendreject ();
368                else
369                  {
370                    erg.resize (2);
371                    EIBSETTYPE (erg, EIB_MC_PROP_READ);
372                    erg.setpart (data, 2);
373                    c->sendmessage (erg.size(), erg.data());
374                  }
375              }
376              break;
377  
378            case EIB_MC_PROP_WRITE:
379              if (c->size < 7)
380                {
381                  c->sendreject ();
382                  break;
383                }
384              {
385                CArray data, erg;
386                if (m.A_Property_Write (c->buf[2], c->buf[3],
387                                        (c->buf[4] << 8) | c->buf[5], c->buf[6],
388                                        CArray (c->buf + 7, c->size - 7),
389                                        erg) == -1)
390                  c->sendreject ();
391                else
392                  {
393                    erg.resize (2);
394                    EIBSETTYPE (erg, EIB_MC_PROP_WRITE);
395                    erg.setpart (data, 2);
396                    c->sendmessage (erg.size(), erg.data());
397                  }
398              }
399              break;
400  
401            case EIB_MC_AUTHORIZE:
402              if (c->size < 6)
403                {
404                  c->sendreject ();
405                  break;
406                }
407              EIBSETTYPE (buf, EIB_MC_AUTHORIZE);
408              key =
409                (c->buf[2] << 24) | (c->buf[3] << 16) | (c->buf[4] << 8) |
410                (c->buf[5]);
411              if (m.A_Authorize (key, buf[2]) == -1)
412                c->sendreject ();
413              else
414                c->sendmessage (3, buf);
415              break;
416  
417            case EIB_MC_KEY_WRITE:
418              if (c->size < 7)
419                {
420                  c->sendreject ();
421                  break;
422                }
423              key =
424                (c->buf[2] << 24) | (c->buf[3] << 16) | (c->buf[4] << 8) |
425                (c->buf[5]);
426              if (m.A_KeyWrite (key, *(c->buf + 6)) == -1)
427                c->sendreject ();
428              else
429                c->sendreject (EIB_MC_KEY_WRITE);
430              break;
431  
432            case EIB_MC_PROP_DESC:
433              if (c->size < 4)
434                {
435                  c->sendreject ();
436                  break;
437                }
438              if (m.A_Property_Desc (c->buf[2], c->buf[3], 0, buf[2], maskver,
439                                     buf[5]) == -1)
440                c->sendreject ();
441              else
442                {
443                  EIBSETTYPE (buf, EIB_MC_PROP_DESC);
444                  buf[3] = (maskver >> 8) & 0xff;
445                  buf[4] = (maskver) & 0xff;
446                  c->sendmessage (6, buf);
447                }
448              break;
449  
450            case EIB_MC_PROP_SCAN:
451            {
452              std::vector < PropertyInfo > p;
453              if (m.X_PropertyScan (p) == -1)
454                c->sendreject ();
455              else
456                {
457                  CArray erg;
458                  erg.resize (2 + p.size() * 6);
459                  EIBSETTYPE (erg, EIB_MC_PROP_SCAN);
460                  unsigned int ii = 0;
461                  ITER( i,p)
462                  {
463                    erg[ii + 2] = i->obj;
464                    erg[ii + 3] = i->property;
465                    erg[ii + 4] = i->type;
466                    erg[ii + 5] = (i->count >> 8) & 0xff;
467                    erg[ii + 6] = (i->count) & 0xff;
468                    erg[ii + 7] = i->access;
469                    ii += 6;
470                  }
471                  c->sendmessage (erg.size(), erg.data());
472                }
473            }
474            break;
475  
476            case EIB_RESET_CONNECTION:
477              i = -1;
478              break;
479  
480            case EIB_MC_RESTART:
481              m.A_Restart ();
482              c->sendreject (EIB_MC_RESTART);
483              break;
484  
485            case EIB_MC_WRITE_NOVERIFY:
486              if (c->size < 6)
487                {
488                  c->sendreject ();
489                  break;
490                }
491              {
492                memaddr_t addr = (c->buf[2] << 8) | (c->buf[3]);
493                unsigned len = (c->buf[4] << 8) | (c->buf[5]);
494                if (c->size < len + 6)
495                  {
496                    c->sendreject ();
497                    break;
498                  }
499                i = m.A_Memory_Write_Block (addr, CArray (c->buf + 6, len));
500                if (i != 0)
501                  c->sendreject (EIB_PROCESSING_ERROR);
502                else
503                  c->sendreject (EIB_MC_WRITE_NOVERIFY);
504              }
505              break;
506  
507            default:
508              c->sendreject ();
509            }
510      }
511    while (i != -1);
512  }
513  
514  void
515  ManagementIndividual (ClientConnPtr c, uint8_t *buf, size_t len)
516  {
517    eibaddr_t dest;
518    int i;
519  
520    if (c->size < 4)
521      {
522        c->sendreject ();
523        return;
524      }
525  
526    dest = (c->buf[2] << 8) | (c->buf[3]);
527    Management_Individual m (c->t, dest);
528    if (!m.init (c->l3))
529      {
530        c->sendreject (EIB_PROCESSING_ERROR);
531        return;
532      }
533    c->sendreject (EIB_MC_INDIVIDUAL);
534    do
535      {
536        i = c->readmessage ();
537        if (i != -1)
538          switch (EIBTYPE (c->buf))
539            {
540            case EIB_MC_PROP_READ:
541              if (c->size < 7)
542                {
543                  c->sendreject ();
544                  break;
545                }
546              {
547                CArray data, erg;
548                if (m.A_Property_Read (c->buf[2], c->buf[3],
549                                       (c->buf[4] << 8) | c->buf[5], c->buf[6],
550                                       data) == -1)
551                  c->sendreject ();
552                else
553                  {
554                    erg.resize (2);
555                    EIBSETTYPE (erg, EIB_MC_PROP_READ);
556                    erg.setpart (data, 2);
557                    c->sendmessage (erg.size(), erg.data());
558                  }
559              }
560              break;
561  
562            case EIB_MC_PROP_WRITE:
563              if (c->size < 7)
564                {
565                  c->sendreject ();
566                  break;
567                }
568              {
569                CArray data, erg;
570                if (m.A_Property_Write (c->buf[2], c->buf[3],
571                                        (c->buf[4] << 8) | c->buf[5], c->buf[6],
572                                        CArray (c->buf + 7, c->size - 7),
573                                        erg) == -1)
574                  c->sendreject ();
575                else
576                  {
577                    erg.resize (2);
578                    EIBSETTYPE (erg, EIB_MC_PROP_WRITE);
579                    erg.setpart (data, 2);
580                    c->sendmessage (erg.size(), erg.data());
581                  }
582              }
583              break;
584  
585            case EIB_RESET_CONNECTION:
586              i = -1;
587              break;
588  
589            default:
590              c->sendreject ();
591            }
592      }
593    while (i != -1);
594  }
595  
596  void
597  LoadImage (ClientConnPtr c, uint8_t *buf, size_t len)
598  {
599    uint8_t buf[200];
600    CArray img (c->buf + 2, c->size - 2);
601    CArray erg;
602    unsigned int j;
603    BCUImage *i;
604    BCU_LOAD_RESULT r = PrepareLoadImage (img, i);
605    if (r != IMG_IMAGE_LOADABLE)
606      {
607        if (i)
608          delete i;
609        EIBSETTYPE (buf, EIB_LOAD_IMAGE);
610        buf[2] = (r >> 8) & 0xff;
611        buf[3] = (r) & 0xff;
612        c->sendmessage (4, buf);
613        return;
614      }
615    {
616      uint16_t maskver;
617      uint8_t ch;
618      r = IMG_NO_DEVICE_CONNECTION;
619      Management_Connection m = Management_Connection (c->t, i->addr);
620      if (!m.init (c->l3))
621        goto out;
622      r = IMG_MASK_READ_FAILED;
623      if (m.A_Device_Descriptor_Read (maskver) == -1)
624        goto out;
625      r = IMG_WRONG_MASK_VERSION;
626      if (i->BCUType == BCUImage::B_bcu1)
627        {
628          if (maskver != 0x0012)
629            goto out;
630  
631          /* set error flags in BCU (0x10D = 0x00) */
632          r = IMG_CLEAR_ERROR;
633          ch = 0;
634          if (m.X_Memory_Write_Block (0x010d, CArray (&ch, 1)) != 0)
635            goto out;
636  
637          /*set length of the address tab to 1 */
638          r = IMG_RESET_ADDR_TAB;
639          ch = 0x01;
640          if (m.X_Memory_Write_Block (0x0116, CArray (&ch, 1)) != 0)
641            goto out;
642  
643          /*load the data from 0x100 to 0x100 */
644          r = IMG_LOAD_HEADER;
645          ch = 0xff;
646          if (m.X_Memory_Write_Block (0x0100, CArray (&ch, 1)) != 0)
647            goto out;
648  
649          /*load the data from 0x103 to 0x10C */
650          if (m.X_Memory_Write_Block (0x0103,
651                                      CArray (i->code.data() + 0x03,
652                                              10)) != 0)
653            goto out;
654  
655          /*load the data from 0x10E to 0x115 */
656          if (m.X_Memory_Write_Block (0x010E,
657                                      CArray (i->code.data() + 0x0E, 8)) != 0)
658            goto out;
659  
660          /*load the data from 0x119H to eeprom end */
661          r = IMG_LOAD_MAIN;
662          if (m.X_Memory_Write_Block (0x119,
663                                      CArray (i->code.data() + 0x19,
664                                              i->code.size() - 0x19)) != 0)
665            goto out;
666  
667          if (m.X_Memory_Write_Block (0x0100, CArray (i->code.data(), 1)) !=
668              0)
669            goto out;
670  
671          /*erase the user RAM (0x0CE to 0x0DF) */
672          r = IMG_ZERO_RAM;
673          uint8_t zero[18] = { 0 };
674          if (m.X_Memory_Write_Block (0x00ce, CArray (zero, 18)) != 0)
675            goto out;
676  
677          /* set the length of the address table */
678          r = IMG_FINALIZE_ADDR_TAB;
679          if (m.X_Memory_Write_Block (0x0116,
680                                      CArray (i->code.data() + 0x16, 1)) != 0)
681            goto out;
682  
683          /* reset all error flags in the BCU (0x10D = 0xFF) */
684          r = IMG_PREPARE_RUN;
685          ch = 0xff;
686          if (m.X_Memory_Write_Block (0x010d, CArray (&ch, 1)) != 0)
687            goto out;
688  
689          r = IMG_RESTART;
690          m.A_Restart ();
691  
692          r = IMG_LOADED;
693          goto out;
694        }
695      if (i->BCUType == BCUImage::B_bcu20 || i->BCUType == BCUImage::B_bcu21)
696        {
697          if (maskver != 0x0020 && i->BCUType == BCUImage::B_bcu20)
698            goto out;
699  
700          if (maskver != 0x0021 && i->BCUType == BCUImage::B_bcu21)
701            goto out;
702  
703          uint8_t level;
704          r = IMG_AUTHORIZATION_FAILED;
705          if (m.A_Authorize (i->installkey, level) == -1)
706            goto out;
707  
708          if (level)
709            goto out;
710  
711          r = IMG_KEY_WRITE;
712          for (j = 0; j < 3; j++)
713            {
714              level = j;
715              if (m.A_KeyWrite (i->keys[level], level) == -1)
716                goto out;
717              if (j != level)
718                goto out;
719            }
720  
721          ITER (j, i->load)
722          {
723            r = j->error;
724            if (j->obj != 0xff)
725              {
726                if (m.A_Property_Write (j->obj, j->prop,
727                                        j->start, 1, j->req,
728                                        erg) == -1)
729                  goto out;
730                if (erg != j->result)
731                  goto out;
732              }
733            if (j->memaddr != 0xffff)
734              if (m.X_Memory_Write_Block (j->memaddr,
735                                          CArray (i->code.data() +
736                                                  j->memaddr - 0x100,
737                                                  j->len)) != 0)
738                goto out;
739          }
740  
741          r = IMG_RESTART;
742          m.A_Restart ();
743  
744          r = IMG_LOADED;
745          goto out;
746        }
747    }
748  out:
749  
750    if (i)
751      delete i;
752    EIBSETTYPE (buf, EIB_LOAD_IMAGE);
753    buf[2] = (r >> 8) & 0xff;
754    buf[3] = (r) & 0xff;
755    c->sendmessage (4, buf);
756  }
757