1 /*****************************************************************************\
2 
3   mlc.c - MLC support for multi-point tranport driver
4 
5   (c) 2004-2007 Copyright HP Development Company, LP
6 
7   Permission is hereby granted, free of charge, to any person obtaining a copy
8   of this software and associated documentation files (the "Software"), to deal
9   in the Software without restriction, including without limitation the rights
10   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
11   of the Software, and to permit persons to whom the Software is furnished to do
12   so, subject to the following conditions:
13 
14   The above copyright notice and this permission notice shall be included in all
15   copies or substantial portions of the Software.
16 
17   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19   FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20   COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22   WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 
24 \*****************************************************************************/
25 
26 #include "hpmud.h"
27 #include "hpmudi.h"
28 
cut_buf(mud_channel * pc,char * buf,int size)29 int __attribute__ ((visibility ("hidden"))) cut_buf(mud_channel *pc, char *buf, int size)
30 {
31    int len;
32 
33    if (pc->rcnt > size)
34    {
35       /* Return part of rbuf. */
36       len = size;
37       memcpy(buf, &pc->rbuf[pc->rindex], len);
38       pc->rindex += len;
39       pc->rcnt -= len;
40    }
41    else
42    {
43       /* Return all of rbuf. */
44       len = pc->rcnt;
45       memcpy(buf, &pc->rbuf[pc->rindex], len);
46       pc->rindex = pc->rcnt = 0;
47    }
48 
49    return len;
50 }
51 
52 /* Write command reply back to peripheral. */
MlcForwardReply(mud_channel * pc,int fd,unsigned char * buf,int size)53 static int MlcForwardReply(mud_channel *pc, int fd, unsigned char *buf, int size)
54 {
55    mud_device *pd = &msp->device[pc->dindex];
56    int len=0;
57 
58    if ((len = (pd->vf.write)(fd, buf, size, HPMUD_EXCEPTION_TIMEOUT)) != size)
59    {
60       BUG("unable to MlcForwarReply: %m\n");
61    }
62    return len;
63 }
64 
65 /* Execute command from peripheral. */
MlcExecReverseCmd(mud_channel * pc,int fd,unsigned char * buf)66 static int MlcExecReverseCmd(mud_channel *pc, int fd, unsigned char *buf)
67 {
68    mud_device *pd = &msp->device[pc->dindex];
69    mud_channel *out_of_bound_channel;
70    MLCCmd *pCmd;
71    MLCReply *pReply;
72    MLCCredit *pCredit;
73    MLCCreditReply *pCreditReply;
74    MLCCreditRequest *pCreditReq;
75    MLCCreditRequestReply *pCreditReqReply;
76    MLCError *pError;
77    int len, size;
78    static int cnt;
79 
80    pCmd = (MLCCmd *)buf;
81 
82    /* See if this packet is a command packet. */
83    if (!(pCmd->h.hsid == 0 && pCmd->h.psid == 0))
84    {
85       if (pCmd->h.hsid == pCmd->h.psid)
86       {
87          /* Got a valid data packet handle it. This can happen when channel_read timeouts and p2hcredit=1. */
88          out_of_bound_channel = &pd->channel[pCmd->h.hsid];
89 
90          if (out_of_bound_channel->ta.p2hcredit <= 0)
91          {
92             BUG("invalid data packet credit=%d\n", out_of_bound_channel->ta.p2hcredit);
93             return 0;
94          }
95 
96          size = ntohs(pCmd->h.length) - sizeof(MLCHeader);
97          if (size > (HPMUD_BUFFER_SIZE - out_of_bound_channel->rcnt))
98          {
99             BUG("invalid data packet size=%d\n", size);
100             return 0;
101          }
102          memcpy(&out_of_bound_channel->rbuf[out_of_bound_channel->rcnt], buf+sizeof(MLCHeader), size);
103          out_of_bound_channel->rcnt += size;
104          if (pCmd->h.credit)
105             out_of_bound_channel->ta.h2pcredit += pCmd->h.credit;  /* note, piggy back credit is 1 byte wide */
106          out_of_bound_channel->ta.p2hcredit--; /* one data packet was read, decrement credit count */
107       }
108       else
109       {
110          len = ntohs(pCmd->h.length);
111          BUG("unsolicited data packet: hsid=%x, psid=%x, length=%d, credit=%d, status=%x\n", pCmd->h.hsid,
112                                      pCmd->h.psid, len, pCmd->h.credit, pCmd->h.status);
113          DBG_DUMP(buf, len);
114       }
115       return 0;
116    }
117 
118    /* Process any command. */
119    switch (pCmd->cmd)
120    {
121       case MLC_CREDIT:
122          pCredit = (MLCCredit *)buf;
123          out_of_bound_channel = &pd->channel[pCredit->hsocket];
124          out_of_bound_channel->ta.h2pcredit += ntohs(pCredit->credit);
125          pCreditReply = (MLCCreditReply *)buf;
126          pCreditReply->h.length = htons(sizeof(MLCCreditReply));
127          pCreditReply->cmd |= 0x80;
128          pCreditReply->result = 0;
129          MlcForwardReply(pc, fd, (unsigned char *)pCreditReply, sizeof(MLCCreditReply));
130          break;
131       case MLC_CREDIT_REQUEST:
132          pCreditReq = (MLCCreditRequest *)buf;
133          if (cnt++ < 5)
134             BUG("unexpected MLCCreditRequest: cmd=%x, hid=%x, pid=%x, credit=%d\n", pCreditReq->cmd,
135                                          pCreditReq->hsocket, pCreditReq->psocket, ntohs(pCreditReq->credit));
136          pCreditReqReply = (MLCCreditRequestReply *)buf;
137          pCreditReqReply->h.length = htons(sizeof(MLCCreditRequestReply));
138          pCreditReqReply->cmd |= 0x80;
139          pCreditReqReply->result = 0;
140          pCreditReqReply->credit = 0;
141          MlcForwardReply(pc, fd, (unsigned char *)pCreditReqReply, sizeof(MLCCreditRequestReply));
142          break;
143       case MLC_ERROR:
144          pError = (MLCError *)buf;
145          BUG("unexpected MLCError: cmd=%x, result=%x\n", pError->cmd, pError->result);
146          return 1;
147       default:
148          pReply = (MLCReply *)buf;
149          BUG("unexpected command: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
150          pReply->h.length = htons(sizeof(MLCReply));
151          pReply->cmd |= 0x80;
152          pReply->result = 1;
153          MlcForwardReply(pc, fd, (unsigned char *)pReply, sizeof(MLCReply));
154          break;
155    }
156    return 0;
157 }
158 
159 /* Get command from peripheral and processes the reverse command. */
MlcReverseCmd(mud_channel * pc,int fd)160 int __attribute__ ((visibility ("hidden"))) MlcReverseCmd(mud_channel *pc, int fd)
161 {
162    mud_device *pd = &msp->device[pc->dindex];
163    unsigned char buf[HPMUD_BUFFER_SIZE];
164    int stat=0, len, size;
165    unsigned int pklen;
166    unsigned char *pBuf;
167    MLCReply *pPk;
168 
169    pPk = (MLCReply *)buf;
170 
171    pBuf = buf;
172 
173    /* Read packet header. */
174    size = sizeof(MLCHeader);
175    while (size > 0)
176    {
177       if ((len = (pd->vf.read)(fd, pBuf, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
178       {
179          BUG("unable to read MlcReverseCmd header: %m\n");
180          stat = 1;
181          goto bugout;
182       }
183       size-=len;
184       pBuf+=len;
185    }
186 
187    /* Determine packet size. */
188    if ((pklen = ntohs(pPk->h.length)) > sizeof(buf))
189    {
190       BUG("invalid MlcReverseCmd packet size: size=%d\n", pklen);
191       stat = 1;
192       goto bugout;
193    }
194 
195    /* Read packet data field. */
196    size = pklen - sizeof(MLCHeader);
197    while (size > 0)
198    {
199       if ((len = (pd->vf.read)(fd, pBuf, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
200       {
201          BUG("unable to read MlcReverseCmd data: %m\n");
202          stat = 1;
203          goto bugout;
204       }
205       size-=len;
206       pBuf+=len;
207    }
208 
209    stat = MlcExecReverseCmd(pc, fd, buf);
210 
211 bugout:
212    return stat;
213 }
214 
215 /*
216  * Get command reply from peripheral. Waits for reply then returns. Processes any reverse commands
217  * while waiting for a reply.
218  */
MlcReverseReply(mud_channel * pc,int fd,unsigned char * buf,int bufsize)219 static int MlcReverseReply(mud_channel *pc, int fd, unsigned char *buf, int bufsize)
220 {
221    mud_device *pd = &msp->device[pc->dindex];
222    int stat=0, len, size, pklen;
223    unsigned char *pBuf;
224    MLCReply *pPk;
225 
226    pPk = (MLCReply *)buf;
227 
228    while (1)
229    {
230       pBuf = buf;
231 
232       /* Read packet header. */
233       size = sizeof(MLCHeader);
234       while (size > 0)
235       {
236          if ((len = (pd->vf.read)(fd, pBuf, size, 4000000)) < 0)   /* wait 4 seconds, same as dot4 */
237          {
238             BUG("unable to read MlcReverseReply header: %m bytesRead=%zd\n", sizeof(MLCHeader)-size);
239             stat = 2;  /* short timeout */
240             goto bugout;
241          }
242          size-=len;
243          pBuf+=len;
244       }
245 
246       /* Determine packet size. */
247       pklen = ntohs(pPk->h.length);
248       if (pklen < 0 || pklen > bufsize)
249       {
250          BUG("invalid MlcReverseReply packet size: size=%d, buf=%d\n", pklen, bufsize);
251          stat = 1;
252          goto bugout;
253       }
254 
255       if (pklen == 0)
256       {
257          /* Got invalid MLC header from peripheral, try this "off-by-one" firmware hack (ie: OJ600). */
258          BUG("trying MlcReverseReply firmware hack\n");
259          memcpy(buf, &buf[1], sizeof(MLCHeader)-1);
260          pklen = ntohs(pPk->h.length);
261          if (pklen <= 0 || pklen > bufsize)
262          {
263             BUG("invalid MlcReverseReply packet size: size=%d, buf=%d\n", pklen, bufsize);
264             stat = 1;
265             goto bugout;
266          }
267          if ((len = (pd->vf.read)(fd, --pBuf, 1, 1000000)) < 0)   /* wait 1 second */
268          {
269             BUG("unable to read MlcReverseReply header: %m\n");
270             stat = 1;
271             goto bugout;
272          }
273          pBuf++;
274          DBG_DUMP(buf, sizeof(MLCHeader));
275       }
276 
277       /* Read packet data field. */
278       size = pklen - sizeof(MLCHeader);
279       while (size > 0)
280       {
281          if ((len = (pd->vf.read)(fd, pBuf, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
282          {
283             BUG("unable to read MlcReverseReply data: %m exp=%zd act=%zd\n", pklen-sizeof(MLCHeader), pklen-sizeof(MLCHeader)-size);
284             stat = 1;
285             goto bugout;
286          }
287          size-=len;
288          pBuf+=len;
289       }
290 
291       /* Check for reply. */
292       if (pPk->cmd & 0x80)
293          break;
294 
295       stat = MlcExecReverseCmd(pc, fd, buf);
296 
297       if (stat != 0)
298          break;
299 
300    } /* while (1) */
301 
302 bugout:
303    return stat;
304 }
305 
MlcInit(mud_channel * pc,int fd)306 int __attribute__ ((visibility ("hidden"))) MlcInit(mud_channel *pc, int fd)
307 {
308    mud_device *pd = &msp->device[pc->dindex];
309    unsigned char buf[HPMUD_BUFFER_SIZE];
310    int stat=0, len, n, cnt;
311    MLCInit *pCmd;
312    MLCInitReply *pReply;
313 
314    memset(buf, 0, sizeof(MLCInit));
315    pCmd = (MLCInit *)buf;
316    n = sizeof(MLCInit);
317    pCmd->h.length = htons(n);
318    pCmd->cmd = MLC_INIT;
319    pCmd->rev = 3;
320 
321    if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
322    {
323       BUG("unable to write MLCInit: %m\n");
324       stat = 1;
325       goto bugout;
326    }
327 
328    cnt=0;
329    while(1)
330    {
331       stat = MlcReverseReply(pc, fd, buf, sizeof(buf));
332       pReply = (MLCInitReply *)buf;
333 
334       if ((stat != 0) || (pReply->cmd != (0x80 | MLC_INIT)) || (pReply->result != 0))
335       {
336          if (errno == EIO && cnt<1)
337          {
338             /* hack for usblp.c 2.6.5 */
339             BUG("invalid MLCInitReply retrying...\n");
340             sleep(1);
341             cnt++;
342             continue;
343          }
344          if (stat == 2 && cnt<1)
345          {
346             /* hack for Tahoe */
347             BUG("invalid MLCInitReply retrying command...\n");
348             memset(buf, 0, sizeof(MLCInit));
349             n = sizeof(MLCInit);
350             pCmd->h.length = htons(n);
351             pCmd->cmd = MLC_INIT;
352             pCmd->rev = 3;
353             (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT);
354             cnt++;
355             continue;
356          }
357          BUG("invalid MLCInitReply: cmd=%x, result=%x\n, revision=%x\n", pReply->cmd, pReply->result, pReply->rev);
358          stat = 1;
359          goto bugout;
360       }
361       break;
362    }
363 
364 bugout:
365    return stat;
366 }
367 
MlcExit(mud_channel * pc,int fd)368 int __attribute__ ((visibility ("hidden"))) MlcExit(mud_channel *pc, int fd)
369 {
370    mud_device *pd = &msp->device[pc->dindex];
371    unsigned char buf[HPMUD_BUFFER_SIZE];
372    int stat=0, len, n;
373    MLCExit *pCmd;
374    MLCExitReply *pReply;
375 
376    memset(buf, 0, sizeof(MLCExit));
377    pCmd = (MLCExit *)buf;
378    n = sizeof(MLCExit);
379    pCmd->h.length = htons(n);
380    pCmd->cmd = MLC_EXIT;
381 
382    if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
383    {
384       BUG("unable to write MLCExit: %m\n");
385       stat = 1;
386       goto bugout;
387    }
388 
389    stat = MlcReverseReply(pc, fd, buf, sizeof(buf));
390    pReply = (MLCExitReply *)buf;
391 
392    if ((stat != 0) || (pReply->cmd != (0x80 | MLC_EXIT)) || (pReply->result != 0))
393    {
394       BUG("invalid MLCExitReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
395       stat = 1;
396       goto bugout;
397    }
398 
399 bugout:
400    return stat;
401 }
402 
MlcConfigSocket(mud_channel * pc,int fd)403 int __attribute__ ((visibility ("hidden"))) MlcConfigSocket(mud_channel *pc, int fd)
404 {
405    mud_device *pd = &msp->device[pc->dindex];
406    unsigned char buf[HPMUD_BUFFER_SIZE];
407    int stat=0, len, n;
408    MLCConfigSocket *pCmd;
409    MLCConfigSocketReply *pReply;
410 
411    if (pc->ta.h2psize > 0)
412      return stat;   /* already got host/peripheral packet sizes */
413 
414    memset(buf, 0, sizeof(MLCConfigSocket));
415    pCmd = (MLCConfigSocket *)buf;
416    n = sizeof(MLCConfigSocket);
417    pCmd->h.length = htons(n);
418    pCmd->cmd = MLC_CONFIG_SOCKET;
419    pCmd->socket = pc->sockid;
420    pCmd->h2psize = htons(HPMUD_BUFFER_SIZE);
421    pCmd->p2hsize = htons(HPMUD_BUFFER_SIZE);
422    pCmd->status = 0;   /* status level?? */
423 
424    if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
425    {
426       BUG("unable to write MLCConfigSocket: %m\n");
427       stat = 1;
428       goto bugout;
429    }
430 
431    stat = MlcReverseReply(pc, fd, buf, sizeof(buf));
432    pReply = (MLCConfigSocketReply *)buf;
433 
434    if ((stat != 0) || (pReply->cmd != (0x80 | MLC_CONFIG_SOCKET)) || (pReply->result != 0))
435    {
436       BUG("invalid MLCConfigSocketReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
437       stat = 1;
438       goto bugout;
439    }
440 
441    pc->ta.h2psize = ntohs(pReply->h2psize);
442    pc->ta.p2hsize = ntohs(pReply->p2hsize);
443 
444 bugout:
445    return stat;
446 }
447 
448 /* Write data to peripheral. */
MlcForwardData(mud_channel * pc,int fd,const void * buf,int size,int usec_timeout)449 int __attribute__ ((visibility ("hidden"))) MlcForwardData(mud_channel *pc, int fd, const void *buf, int size, int usec_timeout)
450 {
451    mud_device *pd = &msp->device[pc->dindex];
452    int stat=0, len, n;
453    MLCHeader h;
454 
455    memset(&h, 0, sizeof(h));
456    n = sizeof(MLCHeader) + size;
457    h.length = htons(n);
458    h.hsid = pc->sockid;
459    h.psid = pc->sockid;
460 
461    if ((len = (pd->vf.write)(fd, &h, sizeof(MLCHeader),  usec_timeout)) != sizeof(MLCHeader))
462    {
463       BUG("unable to write MlcForwardData header: %m\n");
464       stat = 1;
465       goto bugout;
466    }
467 
468    if ((len = (pd->vf.write)(fd, buf, size, usec_timeout)) != size)
469    {
470       BUG("unable to write MlcForwardData: %m\n");
471       stat = 1;
472       goto bugout;
473    }
474 
475 bugout:
476    return stat;
477 }
478 
479 /* Read data from peripheral. */
MlcReverseData(mud_channel * pc,int fd,void * buf,int length,int usec_timeout)480 int __attribute__ ((visibility ("hidden"))) MlcReverseData(mud_channel *pc, int fd, void *buf, int length, int usec_timeout)
481 {
482    mud_device *pd = &msp->device[pc->dindex];
483    mud_channel *out_of_bound_channel;
484    int len, size, total;
485    MLCHeader *pPk;
486 
487    pPk = (MLCHeader *)buf;
488 
489    while (1)
490    {
491       total = 0;
492 
493       /* Read packet header. */
494       size = sizeof(MLCHeader);
495       while (size > 0)
496       {
497          /* Use requested client timeout until we start reading. */
498          if (total == 0)
499             len = (pd->vf.read)(fd, buf+total, size, usec_timeout);
500          else
501             len = (pd->vf.read)(fd, buf+total, size, HPMUD_EXCEPTION_TIMEOUT);
502 
503          if (len < 0)
504          {
505             /* Got a timeout, if exception timeout or timeout occured after read started thats an error. */
506             if (usec_timeout >= HPMUD_EXCEPTION_TIMEOUT || total > 0)
507                BUG("unable to read MlcReverseData header: %m %s\n", pd->uri);
508             goto bugout;
509          }
510          size-=len;
511          total+=len;
512       }
513 
514       /* Determine data size. */
515       size = ntohs(pPk->length) - sizeof(MLCHeader);
516 
517       if (size > length)
518       {
519          BUG("invalid MlcReverseData size: size=%d, buf=%d\n", size, length);
520          goto bugout;
521       }
522 
523       /* Make sure data packet is for this channel. */
524       if (pPk->hsid != pc->sockid && pPk->psid != pc->sockid)
525       {
526          if (pPk->hsid == 0 && pPk->psid == 0)
527          {
528             /* Ok, got a command channel packet instead of a data packet, handle it... */
529             while (size > 0)
530             {
531                if ((len = (pd->vf.read)(fd, buf+total, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
532                {
533                   BUG("unable to read MlcReverseData command: %m\n");
534                   goto bugout;
535                }
536                size-=len;
537                total=len;
538             }
539             MlcExecReverseCmd(pc, fd, buf);
540             continue;   /* try again for data packet */
541          }
542          else if (pPk->hsid == pPk->psid)
543          {
544             /* Got a valid data packet for another channel handle it. This can happen when ReadData timeouts and p2hcredit=1. */
545             out_of_bound_channel = &pd->channel[pPk->hsid];
546             unsigned char *pBuf;
547 
548             if (out_of_bound_channel->ta.p2hcredit <= 0)
549             {
550                BUG("invalid data packet credit=%d\n", out_of_bound_channel->ta.p2hcredit);
551                goto bugout;
552             }
553 
554             if (size > (HPMUD_BUFFER_SIZE - out_of_bound_channel->rcnt))
555             {
556                BUG("invalid data packet size=%d\n", size);
557                goto bugout;
558             }
559 
560             total = 0;
561             pBuf = &out_of_bound_channel->rbuf[out_of_bound_channel->rcnt];
562             while (size > 0)
563             {
564                if ((len = (pd->vf.read)(fd, pBuf+total, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
565                {
566                   BUG("unable to read MlcReverseData: %m\n");
567                   goto bugout;
568                }
569                size-=len;
570                total+=len;
571             }
572 
573             out_of_bound_channel->rcnt += total;
574             if (pPk->credit)
575                out_of_bound_channel->ta.h2pcredit += pPk->credit;  /* note, piggy back credit is 1 byte wide */
576             out_of_bound_channel->ta.p2hcredit--; /* one data packet was read, decrement credit count */
577             continue;   /* try again for data packet */
578          }
579          else
580          {
581             MLCCmd *pCmd = (MLCCmd *)buf;
582             BUG("invalid MlcReverseData state: exp hsid=%x, act hsid=%x, psid=%x, length=%d, credit=%d, status=%x, cmd=%x\n", pc->sockid,
583                                                 pPk->hsid, pPk->psid, ntohs(pPk->length), pPk->credit, pPk->status, pCmd->cmd);
584             goto bugout;
585          }
586       }
587 
588       if (pPk->credit)
589       {
590          pc->ta.h2pcredit += pPk->credit;  /* note, piggy back credit is 1 byte wide */
591       }
592 
593       total = 0;  /* eat packet header */
594 
595       /* Read packet data field with exception_timeout. */
596       while (size > 0)
597       {
598          if ((len = (pd->vf.read)(fd, buf+total, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
599          {
600             BUG("unable to read MlcReverseData: %m\n");
601             goto bugout;
602          }
603          size-=len;
604          total+=len;
605       }
606       break; /* done reading data packet */
607    }  /* while (1) */
608 
609 bugout:
610    return total;
611 }
612 
MlcOpenChannel(mud_channel * pc,int fd)613 int __attribute__ ((visibility ("hidden"))) MlcOpenChannel(mud_channel *pc, int fd)
614 {
615    mud_device *pd = &msp->device[pc->dindex];
616    unsigned char buf[HPMUD_BUFFER_SIZE];
617    int stat=0, len, n;
618    MLCOpenChannel *pCmd;
619    MLCOpenChannelReply *pReply;
620 
621    memset(buf, 0, sizeof(MLCOpenChannel));
622    pCmd = (MLCOpenChannel *)buf;
623    n = sizeof(MLCOpenChannel);
624    pCmd->h.length = htons(n);
625    pCmd->cmd = MLC_OPEN_CHANNEL;
626    pCmd->hsocket = pc->sockid;   /* assume static socket ids */
627    pCmd->psocket = pc->sockid;
628    pCmd->credit = htons(0);             /* credit sender will accept from receiver (set by MlcDevice::ReadData) */
629    //   SetH2PCredit(0);                    /* initialize sender to receiver credit */
630 
631    if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
632    {
633       BUG("unable to write MlcOpenChannel: %m\n");
634       stat = 1;
635       goto bugout;
636    }
637 
638    stat = MlcReverseReply(pc, fd, buf, sizeof(buf));
639    pReply = (MLCOpenChannelReply *)buf;
640 
641    if ((stat != 0) || (pReply->cmd != (0x80 | MLC_OPEN_CHANNEL)) || (pReply->result != 0))
642    {
643       BUG("invalid MlcOpenChannelReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
644       stat = 1;
645       goto bugout;
646    }
647 
648    pc->ta.h2pcredit = ntohs(pReply->credit);
649 
650 bugout:
651    return stat;
652 }
653 
MlcCloseChannel(mud_channel * pc,int fd)654 int __attribute__ ((visibility ("hidden"))) MlcCloseChannel(mud_channel *pc, int fd)
655 {
656    mud_device *pd = &msp->device[pc->dindex];
657    unsigned char buf[HPMUD_BUFFER_SIZE];
658    int stat=0, len, n;
659    MLCCloseChannel *pCmd;
660    MLCCloseChannelReply *pReply;
661 
662    memset(buf, 0, sizeof(MLCCloseChannel));
663    pCmd = (MLCCloseChannel *)buf;
664    n = sizeof(MLCCloseChannel);
665    pCmd->h.length = htons(n);
666    pCmd->cmd = MLC_CLOSE_CHANNEL;
667    pCmd->hsocket = pc->sockid;   /* assume static socket ids */
668    pCmd->psocket = pc->sockid;
669 
670    if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
671    {
672       BUG("unable to write MlcCloseChannel: %m\n");
673       stat = 1;
674       goto bugout;
675    }
676 
677    stat = MlcReverseReply(pc, fd, buf, sizeof(buf));
678    pReply = (MLCCloseChannelReply *)buf;
679 
680    if ((stat != 0) || (pReply->cmd != (0x80 | MLC_CLOSE_CHANNEL)) || (pReply->result != 0))
681    {
682       BUG("invalid MlcCloseChannelReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
683       stat = 1;
684       goto bugout;
685    }
686 
687 bugout:
688    return stat;
689 }
690 
MlcCredit(mud_channel * pc,int fd,unsigned short credit)691 int __attribute__ ((visibility ("hidden"))) MlcCredit(mud_channel *pc, int fd, unsigned short credit)
692 {
693    mud_device *pd = &msp->device[pc->dindex];
694    unsigned char buf[HPMUD_BUFFER_SIZE];
695    int stat=0, len, n;
696    MLCCredit *pCmd;
697    MLCCreditReply *pReply;
698 
699    memset(buf, 0, sizeof(MLCCredit));
700    pCmd = (MLCCredit *)buf;
701    n = sizeof(MLCCredit);
702    pCmd->h.length = htons(n);
703    pCmd->cmd = MLC_CREDIT;
704    pCmd->hsocket = pc->sockid;   /* assume static socket ids */
705    pCmd->psocket = pc->sockid;
706    pCmd->credit = htons(credit);                /* set peripheral to host credit */
707 
708    if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
709    {
710       BUG("unable to write MlcCredit: %m\n");
711       stat = 1;
712       goto bugout;
713    }
714 
715    stat = MlcReverseReply(pc, fd, buf, sizeof(buf));
716    pReply = (MLCCreditReply *)buf;
717 
718    if ((stat != 0) || (pReply->cmd != (0x80 | MLC_CREDIT)) || (pReply->result != 0))
719    {
720       BUG("invalid MlcCreditReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
721       stat = 1;
722       goto bugout;
723    }
724 
725    pc->ta.p2hcredit += credit;
726 
727 bugout:
728    return stat;
729 }
730 
MlcCreditRequest(mud_channel * pc,int fd,unsigned short credit)731 int __attribute__ ((visibility ("hidden"))) MlcCreditRequest(mud_channel *pc, int fd, unsigned short credit)
732 {
733    mud_device *pd = &msp->device[pc->dindex];
734    unsigned char buf[HPMUD_BUFFER_SIZE];
735    int stat=0, len, n;
736    MLCCreditRequest *pCmd;
737    MLCCreditRequestReply *pReply;
738 
739    memset(buf, 0, sizeof(MLCCreditRequest));
740    pCmd = (MLCCreditRequest *)buf;
741    n = sizeof(MLCCreditRequest);
742    pCmd->h.length = htons(n);
743    pCmd->cmd = MLC_CREDIT_REQUEST;
744    pCmd->hsocket = pc->sockid;   /* assume static socket ids */
745    pCmd->psocket = pc->sockid;
746    pCmd->credit = htons(credit);                /* request host to peripheral credit */
747 
748    if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
749    {
750       BUG("unable to write MlcCreditRequest: %m\n");
751       stat = 1;
752       goto bugout;
753    }
754 
755    stat = MlcReverseReply(pc, fd, buf, sizeof(buf));
756    pReply = (MLCCreditRequestReply *)buf;
757 
758    if ((stat != 0) || (pReply->cmd != (0x80 | MLC_CREDIT_REQUEST)) || (pReply->result != 0))
759    {
760       BUG("invalid MlcCreditRequestReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
761       stat = 1;
762       goto bugout;
763    }
764 
765    pc->ta.h2pcredit += ntohs(pReply->credit);
766 
767 bugout:
768    return stat;
769 }
770 
771 
772 
773