1 /*****************************************************************************\
3 mlc.c - MLC support for multi-point tranport driver
5 (c) 2004-2007 Copyright Hewlett-Packard Development Company, LP
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:
14 The above copyright notice and this permission notice shall be included in all
15 copies or substantial portions of the Software.
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.
24 \*****************************************************************************/
29 int __attribute__ ((visibility ("hidden"))) cut_buf(mud_channel *pc, char *buf, int size)
35 /* Return part of rbuf. */
37 memcpy(buf, &pc->rbuf[pc->rindex], len);
43 /* Return all of rbuf. */
45 memcpy(buf, &pc->rbuf[pc->rindex], len);
46 pc->rindex = pc->rcnt = 0;
52 /* Write command reply back to peripheral. */
53 static int MlcForwardReply(mud_channel *pc, int fd, unsigned char *buf, int size)
55 mud_device *pd = &msp->device[pc->dindex];
58 if ((len = (pd->vf.write)(fd, buf, size, HPMUD_EXCEPTION_TIMEOUT)) != size)
60 BUG("unable to MlcForwarReply: %m\n");
65 /* Execute command from peripheral. */
66 static int MlcExecReverseCmd(mud_channel *pc, int fd, unsigned char *buf)
68 mud_device *pd = &msp->device[pc->dindex];
69 mud_channel *out_of_bound_channel;
73 MLCCreditReply *pCreditReply;
74 MLCCreditRequest *pCreditReq;
75 MLCCreditRequestReply *pCreditReqReply;
82 /* See if this packet is a command packet. */
83 if (!(pCmd->h.hsid == 0 && pCmd->h.psid == 0))
85 if (pCmd->h.hsid == pCmd->h.psid)
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];
90 if (out_of_bound_channel->ta.p2hcredit <= 0)
92 BUG("invalid data packet credit=%d\n", out_of_bound_channel->ta.p2hcredit);
96 size = ntohs(pCmd->h.length) - sizeof(MLCHeader);
97 if (size > (HPMUD_BUFFER_SIZE - out_of_bound_channel->rcnt))
99 BUG("invalid data packet size=%d\n", size);
102 memcpy(&out_of_bound_channel->rbuf[out_of_bound_channel->rcnt], buf+sizeof(MLCHeader), size);
103 out_of_bound_channel->rcnt += size;
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 */
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);
118 /* Process any command. */
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));
131 case MLC_CREDIT_REQUEST:
132 pCreditReq = (MLCCreditRequest *)buf;
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));
144 pError = (MLCError *)buf;
145 BUG("unexpected MLCError: cmd=%x, result=%x\n", pError->cmd, pError->result);
148 pReply = (MLCReply *)buf;
149 BUG("unexpected command: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
150 pReply->h.length = htons(sizeof(MLCReply));
153 MlcForwardReply(pc, fd, (unsigned char *)pReply, sizeof(MLCReply));
159 /* Get command from peripheral and processes the reverse command. */
160 int __attribute__ ((visibility ("hidden"))) MlcReverseCmd(mud_channel *pc, int fd)
162 mud_device *pd = &msp->device[pc->dindex];
163 unsigned char buf[HPMUD_BUFFER_SIZE];
164 int stat=0, len, size;
169 pPk = (MLCReply *)buf;
173 /* Read packet header. */
174 size = sizeof(MLCHeader);
177 if ((len = (pd->vf.read)(fd, pBuf, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
179 BUG("unable to read MlcReverseCmd header: %m\n");
187 /* Determine packet size. */
188 if ((pklen = ntohs(pPk->h.length)) > sizeof(buf))
190 BUG("invalid MlcReverseCmd packet size: size=%d\n", pklen);
195 /* Read packet data field. */
196 size = pklen - sizeof(MLCHeader);
199 if ((len = (pd->vf.read)(fd, pBuf, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
201 BUG("unable to read MlcReverseCmd data: %m\n");
209 stat = MlcExecReverseCmd(pc, fd, buf);
216 * Get command reply from peripheral. Waits for reply then returns. Processes any reverse commands
217 * while waiting for a reply.
219 static int MlcReverseReply(mud_channel *pc, int fd, unsigned char *buf, int bufsize)
221 mud_device *pd = &msp->device[pc->dindex];
222 int stat=0, len, size, pklen;
226 pPk = (MLCReply *)buf;
232 /* Read packet header. */
233 size = sizeof(MLCHeader);
236 if ((len = (pd->vf.read)(fd, pBuf, size, 4000000)) < 0) /* wait 4 seconds, same as dot4 */
238 BUG("unable to read MlcReverseReply header: %m bytesRead=%zd\n", sizeof(MLCHeader)-size);
239 stat = 2; /* short timeout */
246 /* Determine packet size. */
247 pklen = ntohs(pPk->h.length);
248 if (pklen < 0 || pklen > bufsize)
250 BUG("invalid MlcReverseReply packet size: size=%d, buf=%d\n", pklen, bufsize);
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)
263 BUG("invalid MlcReverseReply packet size: size=%d, buf=%d\n", pklen, bufsize);
267 if ((len = (pd->vf.read)(fd, --pBuf, 1, 1000000)) < 0) /* wait 1 second */
269 BUG("unable to read MlcReverseReply header: %m\n");
274 DBG_DUMP(buf, sizeof(MLCHeader));
277 /* Read packet data field. */
278 size = pklen - sizeof(MLCHeader);
281 if ((len = (pd->vf.read)(fd, pBuf, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
283 BUG("unable to read MlcReverseReply data: %m exp=%zd act=%zd\n", pklen-sizeof(MLCHeader), pklen-sizeof(MLCHeader)-size);
291 /* Check for reply. */
295 stat = MlcExecReverseCmd(pc, fd, buf);
306 int __attribute__ ((visibility ("hidden"))) MlcInit(mud_channel *pc, int fd)
308 mud_device *pd = &msp->device[pc->dindex];
309 unsigned char buf[HPMUD_BUFFER_SIZE];
310 int stat=0, len, n, cnt;
312 MLCInitReply *pReply;
314 memset(buf, 0, sizeof(MLCInit));
315 pCmd = (MLCInit *)buf;
317 pCmd->h.length = htons(n);
318 pCmd->cmd = MLC_INIT;
321 if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
323 BUG("unable to write MLCInit: %m\n");
331 stat = MlcReverseReply(pc, fd, buf, sizeof(buf));
332 pReply = (MLCInitReply *)buf;
334 if ((stat != 0) || (pReply->cmd != (0x80 | MLC_INIT)) || (pReply->result != 0))
336 if (errno == EIO && cnt<1)
338 /* hack for usblp.c 2.6.5 */
339 BUG("invalid MLCInitReply retrying...\n");
344 if (stat == 2 && cnt<1)
347 BUG("invalid MLCInitReply retrying command...\n");
348 memset(buf, 0, sizeof(MLCInit));
350 pCmd->h.length = htons(n);
351 pCmd->cmd = MLC_INIT;
353 (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT);
357 BUG("invalid MLCInitReply: cmd=%x, result=%x\n, revision=%x\n", pReply->cmd, pReply->result, pReply->rev);
368 int __attribute__ ((visibility ("hidden"))) MlcExit(mud_channel *pc, int fd)
370 mud_device *pd = &msp->device[pc->dindex];
371 unsigned char buf[HPMUD_BUFFER_SIZE];
374 MLCExitReply *pReply;
376 memset(buf, 0, sizeof(MLCExit));
377 pCmd = (MLCExit *)buf;
379 pCmd->h.length = htons(n);
380 pCmd->cmd = MLC_EXIT;
382 if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
384 BUG("unable to write MLCExit: %m\n");
389 stat = MlcReverseReply(pc, fd, buf, sizeof(buf));
390 pReply = (MLCExitReply *)buf;
392 if ((stat != 0) || (pReply->cmd != (0x80 | MLC_EXIT)) || (pReply->result != 0))
394 BUG("invalid MLCExitReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
403 int __attribute__ ((visibility ("hidden"))) MlcConfigSocket(mud_channel *pc, int fd)
405 mud_device *pd = &msp->device[pc->dindex];
406 unsigned char buf[HPMUD_BUFFER_SIZE];
408 MLCConfigSocket *pCmd;
409 MLCConfigSocketReply *pReply;
411 if (pc->ta.h2psize > 0)
412 return stat; /* already got host/peripheral packet sizes */
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?? */
424 if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
426 BUG("unable to write MLCConfigSocket: %m\n");
431 stat = MlcReverseReply(pc, fd, buf, sizeof(buf));
432 pReply = (MLCConfigSocketReply *)buf;
434 if ((stat != 0) || (pReply->cmd != (0x80 | MLC_CONFIG_SOCKET)) || (pReply->result != 0))
436 BUG("invalid MLCConfigSocketReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
441 pc->ta.h2psize = ntohs(pReply->h2psize);
442 pc->ta.p2hsize = ntohs(pReply->p2hsize);
448 /* Write data to peripheral. */
449 int __attribute__ ((visibility ("hidden"))) MlcForwardData(mud_channel *pc, int fd, const void *buf, int size, int usec_timeout)
451 mud_device *pd = &msp->device[pc->dindex];
455 memset(&h, 0, sizeof(h));
456 n = sizeof(MLCHeader) + size;
461 if ((len = (pd->vf.write)(fd, &h, sizeof(MLCHeader), usec_timeout)) != sizeof(MLCHeader))
463 BUG("unable to write MlcForwardData header: %m\n");
468 if ((len = (pd->vf.write)(fd, buf, size, usec_timeout)) != size)
470 BUG("unable to write MlcForwardData: %m\n");
479 /* Read data from peripheral. */
480 int __attribute__ ((visibility ("hidden"))) MlcReverseData(mud_channel *pc, int fd, void *buf, int length, int usec_timeout)
482 mud_device *pd = &msp->device[pc->dindex];
483 mud_channel *out_of_bound_channel;
484 int len, size, total;
487 pPk = (MLCHeader *)buf;
493 /* Read packet header. */
494 size = sizeof(MLCHeader);
497 /* Use requested client timeout until we start reading. */
499 len = (pd->vf.read)(fd, buf+total, size, usec_timeout);
501 len = (pd->vf.read)(fd, buf+total, size, HPMUD_EXCEPTION_TIMEOUT);
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);
514 /* Determine data size. */
515 size = ntohs(pPk->length) - sizeof(MLCHeader);
519 BUG("invalid MlcReverseData size: size=%d, buf=%d\n", size, length);
523 /* Make sure data packet is for this channel. */
524 if (pPk->hsid != pc->sockid && pPk->psid != pc->sockid)
526 if (pPk->hsid == 0 && pPk->psid == 0)
528 /* Ok, got a command channel packet instead of a data packet, handle it... */
531 if ((len = (pd->vf.read)(fd, buf+total, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
533 BUG("unable to read MlcReverseData command: %m\n");
539 MlcExecReverseCmd(pc, fd, buf);
540 continue; /* try again for data packet */
542 else if (pPk->hsid == pPk->psid)
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];
548 if (out_of_bound_channel->ta.p2hcredit <= 0)
550 BUG("invalid data packet credit=%d\n", out_of_bound_channel->ta.p2hcredit);
554 if (size > (HPMUD_BUFFER_SIZE - out_of_bound_channel->rcnt))
556 BUG("invalid data packet size=%d\n", size);
561 pBuf = &out_of_bound_channel->rbuf[out_of_bound_channel->rcnt];
564 if ((len = (pd->vf.read)(fd, pBuf+total, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
566 BUG("unable to read MlcReverseData: %m\n");
573 out_of_bound_channel->rcnt += total;
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 */
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);
590 pc->ta.h2pcredit += pPk->credit; /* note, piggy back credit is 1 byte wide */
593 total = 0; /* eat packet header */
595 /* Read packet data field with exception_timeout. */
598 if ((len = (pd->vf.read)(fd, buf+total, size, HPMUD_EXCEPTION_TIMEOUT)) < 0)
600 BUG("unable to read MlcReverseData: %m\n");
606 break; /* done reading data packet */
613 int __attribute__ ((visibility ("hidden"))) MlcOpenChannel(mud_channel *pc, int fd)
615 mud_device *pd = &msp->device[pc->dindex];
616 unsigned char buf[HPMUD_BUFFER_SIZE];
618 MLCOpenChannel *pCmd;
619 MLCOpenChannelReply *pReply;
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 */
631 if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
633 BUG("unable to write MlcOpenChannel: %m\n");
638 stat = MlcReverseReply(pc, fd, buf, sizeof(buf));
639 pReply = (MLCOpenChannelReply *)buf;
641 if ((stat != 0) || (pReply->cmd != (0x80 | MLC_OPEN_CHANNEL)) || (pReply->result != 0))
643 BUG("invalid MlcOpenChannelReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
648 pc->ta.h2pcredit = ntohs(pReply->credit);
654 int __attribute__ ((visibility ("hidden"))) MlcCloseChannel(mud_channel *pc, int fd)
656 mud_device *pd = &msp->device[pc->dindex];
657 unsigned char buf[HPMUD_BUFFER_SIZE];
659 MLCCloseChannel *pCmd;
660 MLCCloseChannelReply *pReply;
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;
670 if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
672 BUG("unable to write MlcCloseChannel: %m\n");
677 stat = MlcReverseReply(pc, fd, buf, sizeof(buf));
678 pReply = (MLCCloseChannelReply *)buf;
680 if ((stat != 0) || (pReply->cmd != (0x80 | MLC_CLOSE_CHANNEL)) || (pReply->result != 0))
682 BUG("invalid MlcCloseChannelReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
691 int __attribute__ ((visibility ("hidden"))) MlcCredit(mud_channel *pc, int fd, unsigned short credit)
693 mud_device *pd = &msp->device[pc->dindex];
694 unsigned char buf[HPMUD_BUFFER_SIZE];
697 MLCCreditReply *pReply;
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 */
708 if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
710 BUG("unable to write MlcCredit: %m\n");
715 stat = MlcReverseReply(pc, fd, buf, sizeof(buf));
716 pReply = (MLCCreditReply *)buf;
718 if ((stat != 0) || (pReply->cmd != (0x80 | MLC_CREDIT)) || (pReply->result != 0))
720 BUG("invalid MlcCreditReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
725 pc->ta.p2hcredit += credit;
731 int __attribute__ ((visibility ("hidden"))) MlcCreditRequest(mud_channel *pc, int fd, unsigned short credit)
733 mud_device *pd = &msp->device[pc->dindex];
734 unsigned char buf[HPMUD_BUFFER_SIZE];
736 MLCCreditRequest *pCmd;
737 MLCCreditRequestReply *pReply;
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 */
748 if ((len = (pd->vf.write)(fd, pCmd, n, HPMUD_EXCEPTION_TIMEOUT)) != n)
750 BUG("unable to write MlcCreditRequest: %m\n");
755 stat = MlcReverseReply(pc, fd, buf, sizeof(buf));
756 pReply = (MLCCreditRequestReply *)buf;
758 if ((stat != 0) || (pReply->cmd != (0x80 | MLC_CREDIT_REQUEST)) || (pReply->result != 0))
760 BUG("invalid MlcCreditRequestReply: cmd=%x, result=%x\n", pReply->cmd, pReply->result);
765 pc->ta.h2pcredit += ntohs(pReply->credit);