diff --git a/driver.c b/driver.c index a51a72f..b3bcec0 100644 --- a/driver.c +++ b/driver.c @@ -32,9 +32,6 @@ int queue_command(Entry *e, Word command, LongWord cookie, LongWord timeout) - - - #pragma databank 1 int driver( @@ -52,6 +49,7 @@ int driver( { return mattach(socknum, p1, p2, p3, p4, p5); } + e = find_entry(socknum); if (!e) @@ -153,9 +151,11 @@ int driver( break; case PRU_CO_GETOPT: + return mgetsockopt(e, p1, p2, p3, p4, p5); break; case PRU_CO_SETOPT: + return msetsockopt(e, p1, p2, p3, p4, p5); break; case PRU_SELECT: diff --git a/marignotti.h b/marignotti.h index fd93c43..626ed26 100644 --- a/marignotti.h +++ b/marignotti.h @@ -39,7 +39,8 @@ typedef struct Entry { LongWord _SNDLOWAT; LongWord _RCVLOWAT; - Word _RCVTIMEO; + LongWord _RCVTIMEO; + LongWord _SNDTIMEO; Word _LINGER_SEC; diff --git a/mgetsockopt.c b/mgetsockopt.c new file mode 100644 index 0000000..5ed7792 --- /dev/null +++ b/mgetsockopt.c @@ -0,0 +1,179 @@ +#include "marignotti.h" +#include +#include + +#include +#include + +#pragma noroot +#pragma optimize 79 + +static void ticks_to_timeval(LongWord ticks, struct timeval *tv) +{ + LongDivRec qr; + + if (ticks == 0) + { + tv->tv_sec = 0; + tv->tv_usec = 0; + } + else + { + qr = LongDivide(ticks, 60); + + tv->tv_sec = qr.quotient; + tv->tv_usec = Multiply(qr.remainder, 16667); + // qr.remainder * 1,000,000 / 60 + } + +} + +int mgetsockopt(Entry *e, void *p1, void *p2, void *p3, void *p4, void *p5) +{ + Word terr; + Word t; + + int level = *(int *)p1; + int optname = *(int *)p2; + void *optval = (void *)p3; + int optlen = p4 ? *(int *)p4 : 0; + + if (level != SOL_SOCKET) return EINVAL; + if (!optval) return EINVAL; + + + // todo -- linger + switch (optname) + { + + case SO_TYPE: + // todo... non-stream + if (optlen == 4) + { + *(LongWord *)optval = SOCK_STREAM; + return 0; + } + if (optlen == 2) + { + *(Word *)optval = SOCK_STREAM; + return 0; + } + break; + + + case SO_OOBINLINE: + if (optlen == 4) + { + *(LongWord *)optval = 1; + return 0; + } + if (optlen == 2) + { + *(Word *)optval = 1; + return 0; + } + if (optlen == 1) + { + *(char *)optval = 1; + return 0; + } + break; + + + case SO_SNDLOWAT: + if (optlen == 4) + { + *(LongWord *)optval = e->_SNDLOWAT; + return 0; + } + if (optlen == 2) + { + *(Word *)optval = e->_SNDLOWAT; + return 0; + } + break; + + case SO_RCVLOWAT: + if (optlen == 4) + { + *(LongWord *)optval = e->_RCVLOWAT; + return 0; + } + if (optlen == 2) + { + *(Word *)optval = e->_RCVLOWAT; + return 0; + } + break; + + case SO_SNDTIMEO: + if (optlen == sizeof(struct timeval)) + { + // stored as ticks aka seconds * 60. + struct timeval *tv = (struct timeval *)optval; + + ticks_to_timeval(e->_SNDTIMEO, tv); + return 0; + } + break; + + case SO_RCVTIMEO: + if (optlen == sizeof(struct timeval)) + { + // stored as ticks aka seconds * 60. + struct timeval *tv = (struct timeval *)optval; + + ticks_to_timeval(e->_RCVTIMEO, tv); + return 0; + } + break; + + #ifdef SO_NREAD + case SO_NREAD: + IncBusy(); + terr = TCPIPStatusTCP(e->ipid, &e->sr); + t = _toolErr; + DecBusy(); + if (t) terr = t; + + if (optlen == 4) + { + *(LongWord *)optval = e->sr.srRcvQueued; + return 0; + } + if (optlen == 2) + { + *(Word *)optval = e->sr.srRcvQueued; + return 0; + } + break; + + #endif + + #ifdef SO_NWRITE + case SO_NWRITE: + IncBusy(); + terr = TCPIPStatusTCP(e->ipid, &e->sr); + t = _toolErr; + DecBusy(); + if (t) terr = t; + + if (optlen == 4) + { + *(LongWord *)optval = e->sr.srSndQueued; + return 0; + } + if (optlen == 2) + { + *(Word *)optval = e->sr.srSndQueued; + return 0; + } + return EINVAL; + break; + #endif + + } + + return EINVAL; + +} diff --git a/msetsockopt.c b/msetsockopt.c new file mode 100644 index 0000000..8df0e72 --- /dev/null +++ b/msetsockopt.c @@ -0,0 +1,125 @@ +#include "marignotti.h" +#include +#include + +#include +#include + +#pragma noroot +#pragma optimize 79 + +static LongWord timeval_to_ticks(struct timeval tv) +{ + LongWord rv; + + rv = 0; + if (tv.tv_usec || tv.tv_sec) + { + + if (tv.tv_sec) + rv = 60 * tv.tv_sec; + + // usec = 1/1,000,000 + // split into 60 + if (tv.tv_usec) + rv += ((tv.tv_usec + 16666) / 16667); + + if (!rv) rv = 1; + } + + return rv; +} + + +int msetsockopt(Entry *e, void *p1, void *p2, void *p3, void *p4, void *p5) +{ + Word terr; + Word t; + + int level = *(int *)p1; + int optname = *(int *)p2; + void *optval = (void *)p3; + int optlen = p4 ? *(int *)p4 : 0; + + if (level != SOL_SOCKET) return EINVAL; + if (!optval) return EINVAL; + + // todo -- linger. + // todo -- oobinline (error if 0?) + switch(optname) + { + + case SO_OOBINLINE: + if (optlen == 4) + { + Word flag = *(LongWord *)optval; + if (!flag) return EINVAL; + return 0; + } + if (optlen == 2) + { + Word flag = *(Word *)optval; + if (!flag) return EINVAL; + return 0; + } + if (optlen == 1) + { + Word flag = *(char *)optval; + if (!flag) return EINVAL; + return 0; + } + break; + + case SO_SNDLOWAT: + if (optlen == 4) + { + e->_SNDLOWAT = *(LongWord *)optval; + return 0; + } + if (optlen == 2) + { + e->_SNDLOWAT = *(Word *)optval; + return 0; + } + break; + + + case SO_RCVLOWAT: + if (optlen == 4) + { + e->_RCVLOWAT = *(LongWord *)optval; + return 0; + } + if (optlen == 2) + { + e->_RCVLOWAT = *(Word *)optval; + return 0; + } + break; + + case SO_SNDTIMEO: + if (optlen == sizeof(struct timeval)) + { + // stored as ticks aka seconds * 60. + struct timeval *tv = (struct timeval *)optval; + + e->_SNDTIMEO = timeval_to_ticks(*tv); + return 0; + } + break; + + case SO_RCVTIMEO: + if (optlen == sizeof(struct timeval)) + { + // stored as ticks aka seconds * 60. + struct timeval *tv = (struct timeval *)optval; + + e->_RCVTIMEO = timeval_to_ticks(*tv); + return 0; + } + break; + + } + + return EINVAL; +} \ No newline at end of file