00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192 #include <cfg/os.h>
00193 #include <sys/types.h>
00194 #include <string.h>
00195
00196 #include <sys/atom.h>
00197 #include <sys/heap.h>
00198 #include <sys/thread.h>
00199 #include <sys/event.h>
00200 #include <sys/timer.h>
00201
00202 #include <net/errno.h>
00203 #include <net/route.h>
00204 #include <netinet/in.h>
00205 #include <netinet/ip.h>
00206 #include <netinet/icmp.h>
00207 #include <netinet/ip_icmp.h>
00208 #include <netinet/ipcsum.h>
00209 #include <sys/socket.h>
00210 #include <netinet/tcp.h>
00211 #include <stdio.h>
00212 #include <io.h>
00213
00214 #ifdef NUTDEBUG
00215 #include <net/netdebug.h>
00216 #endif
00217
00218 #define TICK_RATE 1
00219
00224
00225 TCPSOCKET *tcpSocketList = 0;
00227 static volatile uint16_t last_local_port = 4096;
00228
00229 static uint_fast8_t registered;
00230
00231 void NutTcpDiscardBuffers(TCPSOCKET * sock)
00232 {
00233 NETBUF *nb;
00234 while ((nb = sock->so_rx_buf) != 0) {
00235 sock->so_rx_buf = nb->nb_next;
00236 NutNetBufFree(nb);
00237 }
00238 while ((nb = sock->so_tx_nbq) != 0) {
00239 sock->so_tx_nbq = nb->nb_next;
00240 NutNetBufFree(nb);
00241 }
00242 while ((nb = sock->so_rx_nbq) != 0) {
00243 sock->so_rx_nbq = nb->nb_next;
00244 NutNetBufFree(nb);
00245 }
00246 }
00247
00248
00260 void NutTcpDestroySocket(TCPSOCKET * sock)
00261 {
00262 TCPSOCKET *sp;
00263 TCPSOCKET *volatile *spp;
00264
00265
00266
00267
00268
00269
00270 sp = tcpSocketList;
00271 spp = &tcpSocketList;
00272 while (sp) {
00273 if (sp == sock) {
00274 *spp = sp->so_next;
00275 break;
00276 }
00277 spp = &sp->so_next;
00278 sp = sp->so_next;
00279 }
00280
00281
00282
00283
00284 if (sp) {
00285 NutTcpDiscardBuffers(sock);
00286 if (sock->so_devocnt)
00287 {
00288 NutHeapFree(sock->so_devobuf);
00289 sock->so_devocnt = 0;
00290 }
00291 memset(sock, 0, sizeof(TCPSOCKET));
00292 NutHeapFree(sock);
00293 }
00294 }
00295
00310 TCPSOCKET *NutTcpFindSocket(uint16_t lport, uint16_t rport, uint32_t raddr)
00311 {
00312 TCPSOCKET *sp;
00313 TCPSOCKET *sock = 0;
00314
00315
00316
00317
00318
00319 for (sp = tcpSocketList; sp; sp = sp->so_next) {
00320 if (sp->so_local_port == lport) {
00321 if (sp->so_remote_addr == raddr && sp->so_remote_port == rport && sp->so_state != TCPS_CLOSED) {
00322 sock = sp;
00323 break;
00324 }
00325 }
00326 }
00327
00328
00329
00330
00331
00332
00333
00334
00335 if (sock == 0) {
00336 for (sp = tcpSocketList; sp; sp = sp->so_next) {
00337 if (sp->so_state == TCPS_LISTEN && sp->so_local_port == lport) {
00338 sock = sp;
00339 break;
00340 }
00341 }
00342 }
00343
00344 return sock;
00345 }
00346
00347
00362 TCPSOCKET *NutTcpCreateSocket(void)
00363 {
00364 TCPSOCKET *sock = 0;
00365
00366 if (!registered) {
00367 if (NutRegisterIpHandler(IPPROTO_TCP, NutTcpInput) || NutTcpInitStateMachine()) {
00368 return NULL;
00369 }
00370 registered = 1;
00371 }
00372 if ((sock = NutHeapAllocClear(sizeof(TCPSOCKET))) != 0) {
00373 sock->so_state = TCPS_CLOSED;
00374
00375
00376
00377
00378 sock->so_devtype = IFTYP_TCPSOCK;
00379 sock->so_devread = NutTcpDeviceRead;
00380 sock->so_devwrite = NutTcpDeviceWrite;
00381 #ifdef __HARVARD_ARCH__
00382 sock->so_devwrite_P = NutTcpDeviceWrite_P;
00383 #endif
00384 sock->so_devioctl = NutTcpDeviceIOCtl;
00385
00386 sock->so_tx_isn = NutGetTickCount();
00387 sock->so_tx_una = sock->so_tx_isn;
00388 sock->so_tx_nxt = sock->so_tx_isn;
00389 sock->so_rx_bsz = sock->so_rx_win = TCP_WINSIZE;
00390
00391 sock->so_mss = TCP_MSS;
00392 sock->so_rtto = 1000;
00393
00394 sock->so_next = tcpSocketList;
00395
00396 sock->so_devobsz = TCP_MSS;
00397
00398 tcpSocketList = sock;
00399 }
00400 return sock;
00401 }
00402
00422 int NutTcpSetSockOpt(TCPSOCKET * sock, int optname, CONST void *optval, int optlen)
00423 {
00424 int rc = -1;
00425
00426 if (sock == 0)
00427 return -1;
00428 switch (optname) {
00429
00430 case TCP_MAXSEG:
00431 if (optval == 0 || optlen != sizeof(uint16_t))
00432 sock->so_last_error = EINVAL;
00433 else if (sock->so_state != TCPS_CLOSED)
00434 sock->so_last_error = EISCONN;
00435 else {
00436 sock->so_mss = *((uint16_t *) optval);
00437 rc = 0;
00438 }
00439 break;
00440
00441 case SO_RCVBUF:
00442 if (optval == 0 || optlen != sizeof(uint16_t))
00443 sock->so_last_error = EINVAL;
00444 else {
00445 sock->so_rx_bsz = *((uint16_t *) optval);
00446 sock->so_rx_win = sock->so_rx_bsz;
00447 rc = 0;
00448 }
00449 break;
00450
00451 case SO_SNDTIMEO:
00452 if (optval == 0 || optlen != sizeof(uint32_t))
00453 sock->so_last_error = EINVAL;
00454 else {
00455 sock->so_write_to = *((uint32_t *) optval);
00456 rc = 0;
00457 }
00458 break;
00459
00460 case SO_RCVTIMEO:
00461 if (optval == 0 || optlen != sizeof(uint32_t))
00462 sock->so_last_error = EINVAL;
00463 else {
00464 sock->so_read_to = *((uint32_t *) optval);
00465 rc = 0;
00466 }
00467 break;
00468
00469 case SO_SNDBUF:
00470 if (optval == 0 || optlen != sizeof(uint16_t))
00471 sock->so_last_error = EINVAL;
00472 else {
00473 NutTcpDeviceWrite(sock, 0, 0);
00474 sock->so_devobsz = *((uint16_t *) optval);
00475 rc = 0;
00476 }
00477 break;
00478
00479 default:
00480 sock->so_last_error = ENOPROTOOPT;
00481 break;
00482 }
00483 return rc;
00484 }
00485
00505 int NutTcpGetSockOpt(TCPSOCKET * sock, int optname, void *optval, int optlen)
00506 {
00507 int rc = -1;
00508
00509 if (sock == 0)
00510 return -1;
00511 switch (optname) {
00512
00513 case TCP_MAXSEG:
00514 if (optval == 0 || optlen != sizeof(uint16_t))
00515 sock->so_last_error = EINVAL;
00516 else {
00517 *((uint16_t *) optval) = sock->so_mss;
00518 rc = 0;
00519 }
00520 break;
00521
00522 case SO_RCVBUF:
00523 if (optval == 0 || optlen != sizeof(uint16_t))
00524 sock->so_last_error = EINVAL;
00525 else {
00526 *((uint16_t *) optval) = sock->so_rx_bsz;
00527 rc = 0;
00528 }
00529 break;
00530
00531 case SO_SNDTIMEO:
00532 if (optval == 0 || optlen != sizeof(uint32_t))
00533 sock->so_last_error = EINVAL;
00534 else {
00535 *((uint32_t *) optval) = sock->so_write_to;
00536 rc = 0;
00537 }
00538 break;
00539
00540 case SO_RCVTIMEO:
00541 if (optval == 0 || optlen != sizeof(uint32_t))
00542 sock->so_last_error = EINVAL;
00543 else {
00544 *((uint32_t *) optval) = sock->so_read_to;
00545 rc = 0;
00546 }
00547 break;
00548
00549 case SO_SNDBUF:
00550 if (optval == 0 || optlen != sizeof(uint16_t))
00551 sock->so_last_error = EINVAL;
00552 else {
00553 *((uint16_t *) optval) = sock->so_devobsz;
00554 rc = 0;
00555 }
00556 break;
00557 default:
00558 sock->so_last_error = ENOPROTOOPT;
00559 break;
00560 }
00561 return rc;
00562 }
00563
00582 int NutTcpConnect(TCPSOCKET * sock, uint32_t addr, uint16_t port)
00583 {
00584 TCPSOCKET *sp;
00585 NUTDEVICE *dev;
00586
00587 if (sock == 0)
00588 return -1;
00589
00590
00591
00592
00593 if (sock->so_state == TCPS_LISTEN) {
00594 sock->so_last_error = EOPNOTSUPP;
00595 return -1;
00596 } else if (sock->so_state != TCPS_CLOSED) {
00597 sock->so_last_error = EISCONN;
00598 return -1;
00599 }
00600
00601
00602
00603
00604 do {
00605 if (++last_local_port == 0)
00606 last_local_port = 4096;
00607
00608 sp = tcpSocketList;
00609 while (sp) {
00610
00611 if (sp->so_local_port == htons(last_local_port))
00612 break;
00613 sp = sp->so_next;
00614 }
00615 } while (sp);
00616
00617
00618
00619
00620
00621 sock->so_local_port = htons(last_local_port);
00622 sock->so_remote_port = htons(port);
00623 sock->so_remote_addr = addr;
00624
00625
00626
00627
00628 if ((dev = NutIpRouteQuery(addr, 0)) != 0) {
00629 IFNET *nif = dev->dev_icb;
00630 sock->so_local_addr = nif->if_local_ip;
00631 } else {
00632 sock->so_last_error = EHOSTUNREACH;
00633 return -1;
00634 }
00635
00636
00637
00638
00639
00640 return NutTcpStateActiveOpenEvent(sock);
00641 }
00642
00658 int NutTcpAccept(TCPSOCKET * sock, uint16_t port)
00659 {
00660 sock->so_local_port = htons(port);
00661
00662 return NutTcpStatePassiveOpenEvent(sock);
00663 }
00664
00681 int NutTcpSend(TCPSOCKET * sock, CONST void *data, int len)
00682 {
00683 uint16_t unacked;
00684
00685
00686
00687
00688 NutThreadYield();
00689
00690 if (sock == 0)
00691 return -1;
00692 if (data == 0 || len == 0)
00693 return 0;
00694
00695
00696
00697
00698 if (len > sock->so_mss)
00699 len = sock->so_mss;
00700
00701 for (;;) {
00702
00703
00704
00705 if (sock->so_state != TCPS_ESTABLISHED) {
00706 sock->so_last_error = ENOTCONN;
00707 return -1;
00708 }
00709
00710
00711
00712
00713
00714
00715 unacked = sock->so_tx_nxt - sock->so_tx_una;
00716 if ((unacked >> 2) < sock->so_mss && len <= sock->so_tx_win - unacked) {
00717 break;
00718 }
00719 if (NutEventWait(&sock->so_tx_tq, sock->so_write_to)) {
00720 return 0;
00721 }
00722 }
00723
00724
00725
00726
00727
00728 sock->so_tx_flags |= SO_ACK;
00729 if (NutTcpOutput(sock, data, len))
00730 return -1;
00731 return len;
00732 }
00733
00751 int NutTcpReceive(TCPSOCKET * sock, void *data, int size)
00752 {
00753 int i;
00754
00755 NutThreadYield();
00756
00757
00758
00759 if (sock == 0)
00760 return -1;
00761 if (sock->so_state != TCPS_ESTABLISHED && sock->so_state != TCPS_CLOSE_WAIT) {
00762 sock->so_last_error = ENOTCONN;
00763 return -1;
00764 }
00765 if (data == 0 || size == 0)
00766 return 0;
00767
00768
00769
00770
00771
00772 while (sock->so_rx_cnt - sock->so_rd_cnt == 0) {
00773 if (sock->so_state != TCPS_ESTABLISHED) {
00774 sock->so_last_error = ENOTCONN;
00775 return -1;
00776 }
00777 if (NutEventWait(&sock->so_rx_tq, sock->so_read_to))
00778 return 0;
00779 }
00780
00781 if (size > sock->so_rx_cnt - sock->so_rd_cnt)
00782 size = sock->so_rx_cnt - sock->so_rd_cnt;
00783 if (size) {
00784 NETBUF *nb;
00785 uint16_t rd_cnt;
00786 uint16_t nb_cnt;
00787 uint16_t ab_cnt;
00788 uint16_t mv_cnt;
00789
00790 rd_cnt = sock->so_rd_cnt;
00791
00792 ab_cnt = 0;
00793 while (ab_cnt < size) {
00794 nb = sock->so_rx_buf;
00795 nb_cnt = nb->nb_ap.sz - rd_cnt;
00796 mv_cnt = size - ab_cnt;
00797 if (mv_cnt > nb_cnt)
00798 mv_cnt = nb_cnt;
00799 memcpy((char *) data + ab_cnt, (char *) (nb->nb_ap.vp) + rd_cnt, mv_cnt);
00800 ab_cnt += mv_cnt;
00801 rd_cnt += mv_cnt;
00802 if (mv_cnt >= nb_cnt) {
00803 sock->so_rx_buf = nb->nb_next;
00804 sock->so_rx_cnt -= rd_cnt;
00805 NutNetBufFree(nb);
00806 nb = sock->so_rx_buf;
00807 rd_cnt = 0;
00808 }
00809 }
00810 sock->so_rd_cnt = rd_cnt;
00811
00812
00813
00814
00815 if (sock->so_state == TCPS_ESTABLISHED) {
00816 i = sock->so_rx_win;
00817 if ((i += size) > sock->so_rx_bsz)
00818 i = sock->so_rx_bsz;
00819
00820 if (sock->so_rx_win <= sock->so_mss && i > sock->so_mss) {
00821 sock->so_rx_win = i;
00822 NutTcpStateWindowEvent(sock);
00823 } else {
00824 sock->so_rx_win = i;
00825 }
00826 }
00827 }
00828 return size;
00829 }
00830
00843 int NutTcpCloseSocket(TCPSOCKET * sock)
00844 {
00845
00846
00847 NutTcpDeviceWrite(sock, 0, 0);
00848 return NutTcpStateCloseEvent(sock);
00849 }
00850
00899 int NutTcpError(TCPSOCKET * sock)
00900 {
00901 if (sock == 0)
00902 return ENOTSOCK;
00903 return sock->so_last_error;
00904 }
00905
00925 int NutTcpDeviceRead(TCPSOCKET * sock, void *buffer, int size)
00926 {
00927 return NutTcpReceive(sock, buffer, size);
00928 }
00929
00930 static int SendBuffer(TCPSOCKET * sock, CONST void *buffer, int size)
00931 {
00932 int rc;
00933 int bite;
00934
00935 for (rc = 0; rc < size; rc += bite) {
00936 if ((bite = NutTcpSend(sock, (uint8_t *) buffer + rc, size - rc)) <= 0) {
00937 return -1;
00938 }
00939 }
00940 return rc;
00941 }
00942
00965 int NutTcpDeviceWrite(TCPSOCKET * sock, CONST void *buf, int size)
00966 {
00967 int rc;
00968 uint16_t sz;
00969
00970 uint8_t *buffer = (uint8_t*) buf;
00971
00972
00973
00974
00975 if (sock == 0)
00976 return -1;
00977 if (sock->so_state != TCPS_ESTABLISHED) {
00978 sock->so_last_error = ENOTCONN;
00979 return -1;
00980 }
00981
00982
00983 if (size == 0) {
00984 if (sock->so_devocnt) {
00985 if (SendBuffer(sock, sock->so_devobuf, sock->so_devocnt) < 0) {
00986 NutHeapFree(sock->so_devobuf);
00987 sock->so_devocnt = 0;
00988 return -1;
00989 }
00990 NutHeapFree(sock->so_devobuf);
00991 sock->so_devocnt = 0;
00992 }
00993 return 0;
00994 }
00995
00996
00997 if (sock->so_devocnt == 0) {
00998
00999
01000
01001
01002 if ((uint16_t) size >= sock->so_devobsz) {
01003 rc = size % sock->so_devobsz;
01004 if (SendBuffer(sock, buffer, size - rc) < 0)
01005 return -1;
01006 buffer += size - rc;
01007 } else
01008 rc = size;
01009
01010
01011
01012
01013 if (rc) {
01014 if (!(sock->so_devobuf = NutHeapAlloc(sock->so_devobsz)))
01015 return -1;
01016 memcpy(sock->so_devobuf, buffer, rc);
01017 sock->so_devocnt = rc;
01018 }
01019 return size;
01020 }
01021
01022
01023 if (sock->so_devocnt + size < sock->so_devobsz) {
01024 memcpy(sock->so_devobuf + sock->so_devocnt, buffer, size);
01025 sock->so_devocnt += size;
01026 return size;
01027 }
01028
01029
01030
01031
01032 sz = sock->so_devobsz - sock->so_devocnt;
01033 memcpy(sock->so_devobuf + sock->so_devocnt, buffer, sz);
01034 buffer += sz;
01035 if (SendBuffer(sock, sock->so_devobuf, sock->so_devobsz) < 0) {
01036 NutHeapFree(sock->so_devobuf);
01037 sock->so_devocnt = 0;
01038 return -1;
01039 }
01040
01041
01042
01043
01044
01045 sz = size - sz;
01046 if (sz >= sock->so_devobsz) {
01047 rc = size % sock->so_devobsz;
01048 if (SendBuffer(sock, buffer, sz - rc) < 0) {
01049 NutHeapFree(sock->so_devobuf);
01050 sock->so_devocnt = 0;
01051 return -1;
01052 }
01053 buffer += sz - rc;
01054 } else
01055 rc = sz;
01056
01057
01058
01059 if (rc)
01060 memcpy(sock->so_devobuf, buffer, rc);
01061 else
01062 NutHeapFree(sock->so_devobuf);
01063 sock->so_devocnt = rc;
01064
01065 return size;
01066 }
01067
01092 #ifdef __HARVARD_ARCH__
01093 int NutTcpDeviceWrite_P(TCPSOCKET * sock, PGM_P buffer, int size)
01094 {
01095 int rc;
01096 char *rp = 0;
01097
01098
01099
01100
01101
01102 if (size && (rp = NutHeapAlloc(size)) != 0)
01103 memcpy_P(rp, buffer, size);
01104 rc = NutTcpDeviceWrite(sock, rp, size);
01105 if (rp)
01106 NutHeapFree(rp);
01107
01108 return rc;
01109 }
01110 #endif
01111
01131 int NutTcpDeviceIOCtl(TCPSOCKET * sock, int cmd, void *param)
01132 {
01133 uint32_t *lvp = (uint32_t *) param;
01134 int rc = 0;
01135
01136 switch (cmd) {
01137 case IOCTL_GETFILESIZE:
01138 case IOCTL_GETINBUFCOUNT:
01139 *lvp = (sock->so_rx_cnt - sock->so_rd_cnt);
01140 break;
01141 case IOCTL_GETOUTBUFCOUNT:
01142 *lvp = (sock->so_devocnt);
01143 break;
01144 default:
01145 rc = -1;
01146 }
01147
01148 return rc;
01149 }
01150