home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 1 / HamRadio.cdr / misc / src0131 / tcpuser.c < prev    next >
C/C++ Source or Header  |  1991-01-26  |  8KB  |  374 lines

  1. /* User calls to TCP
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4. #include <stdio.h>
  5. #include "global.h"
  6. #include "timer.h"
  7. #include "mbuf.h"
  8. #include "netuser.h"
  9. #include "socket.h"
  10. #include "internet.h"
  11. #include "tcp.h"
  12. #include "ip.h"
  13. #include "icmp.h"
  14. #include "proc.h"
  15.  
  16. int16 Tcp_window = DEF_WND;
  17.  
  18. struct tcb *
  19. open_tcp(lsocket,fsocket,mode,window,r_upcall,t_upcall,s_upcall,tos,user)
  20. struct socket *lsocket;    /* Local socket */
  21. struct socket *fsocket;    /* Remote socket */
  22. int mode;        /* Active/passive/server */
  23. int16 window;        /* Receive window (and send buffer) sizes */
  24. void (*r_upcall)();    /* Function to call when data arrives */
  25. void (*t_upcall)();    /* Function to call when ok to send more data */
  26. void (*s_upcall)();    /* Function to call when connection state changes */
  27. int tos;
  28. int user;        /* User linkage area */
  29. {
  30.     struct connection conn;
  31.     register struct tcb *tcb;
  32.  
  33.     if(lsocket == NULLSOCK){
  34.         Net_error = INVALID;
  35.         return NULLTCB;
  36.     }
  37.     conn.local.address = lsocket->address;
  38.     conn.local.port = lsocket->port;
  39.     if(fsocket != NULLSOCK){
  40.         conn.remote.address = fsocket->address;
  41.         conn.remote.port = fsocket->port;
  42.     } else {
  43.         conn.remote.address = 0;
  44.         conn.remote.port = 0;
  45.     }
  46.     if((tcb = lookup_tcb(&conn)) == NULLTCB){
  47.         if((tcb = create_tcb(&conn)) == NULLTCB){
  48.             Net_error = NO_MEM;
  49.             return NULLTCB;
  50.         }
  51.     } else if(tcb->state != TCP_LISTEN){
  52.         Net_error = CON_EXISTS;
  53.         return NULLTCB;
  54.     }
  55.     tcb->user = user;
  56.     if(window != 0)
  57.         tcb->window = tcb->rcv.wnd = window;
  58.     else
  59.         tcb->window = tcb->rcv.wnd = Tcp_window;
  60.     tcb->snd.wnd = 1;    /* Allow space for sending a SYN */
  61.     tcb->r_upcall = r_upcall;
  62.     tcb->t_upcall = t_upcall;
  63.     tcb->s_upcall = s_upcall;
  64.     tcb->tos = tos;
  65.     switch(mode){
  66.     case TCP_SERVER:
  67.         tcb->flags.clone = 1;
  68.     case TCP_PASSIVE:    /* Note fall-thru */
  69.         setstate(tcb,TCP_LISTEN);
  70.         break;
  71.     case TCP_ACTIVE:
  72.         /* Send SYN, go into TCP_SYN_SENT state */
  73.         tcb->flags.active = 1;
  74.         send_syn(tcb);
  75.         setstate(tcb,TCP_SYN_SENT);
  76.         tcp_output(tcb);
  77.         break;
  78.     }
  79.     return tcb;
  80. }
  81. /* User send routine */
  82. int
  83. send_tcp(tcb,bp)
  84. register struct tcb *tcb;
  85. struct mbuf *bp;
  86. {
  87.     int16 cnt;
  88.  
  89.     if(tcb == NULLTCB || bp == NULLBUF){
  90.         free_p(bp);
  91.         Net_error = INVALID;
  92.         return -1;
  93.     }
  94.     cnt = len_p(bp);
  95.     switch(tcb->state){
  96.     case TCP_CLOSED:
  97.         free_p(bp);
  98.         Net_error = NO_CONN;
  99.         return -1;
  100.     case TCP_LISTEN:
  101.         if(tcb->conn.remote.address == 0 && tcb->conn.remote.port == 0){
  102.             /* Save data for later */
  103.             append(&tcb->sndq,bp);
  104.             tcb->sndcnt += cnt;
  105.             break;
  106.         }        
  107.         /* Change state from passive to active */
  108.         tcb->flags.active = 1;
  109.         send_syn(tcb);
  110.         setstate(tcb,TCP_SYN_SENT);    /* Note fall-thru */
  111.     case TCP_SYN_SENT:
  112.     case TCP_SYN_RECEIVED:
  113.     case TCP_ESTABLISHED:
  114.     case TCP_CLOSE_WAIT:
  115.         append(&tcb->sndq,bp);
  116.         tcb->sndcnt += cnt;
  117.         tcp_output(tcb);
  118.         break;
  119.     case TCP_FINWAIT1:
  120.     case TCP_FINWAIT2:
  121.     case TCP_CLOSING:
  122.     case TCP_LAST_ACK:
  123.     case TCP_TIME_WAIT:
  124.         free_p(bp);
  125.         Net_error = CON_CLOS;
  126.         return -1;
  127.     }
  128.     return (int)cnt;
  129. }
  130. /* User receive routine */
  131. int
  132. recv_tcp(tcb,bpp,cnt)
  133. register struct tcb *tcb;
  134. struct mbuf **bpp;
  135. int16 cnt;
  136. {
  137.     if(tcb == NULLTCB || bpp == (struct mbuf **)NULL){
  138.         Net_error = INVALID;
  139.         return -1;
  140.     }
  141.     if(tcb->rcvcnt == 0){
  142.         /* If there's nothing on the queue, our action depends on what state
  143.          * we're in (i.e., whether or not we're expecting any more data).
  144.          * If no more data is expected, then simply return 0; this is
  145.          * interpreted as "end of file". Otherwise return -1.
  146.          */
  147.         switch(tcb->state){
  148.         case TCP_LISTEN:
  149.         case TCP_SYN_SENT:
  150.         case TCP_SYN_RECEIVED:
  151.         case TCP_ESTABLISHED:
  152.         case TCP_FINWAIT1:
  153.         case TCP_FINWAIT2:
  154.             Net_error = WOULDBLK;
  155.             return -1;
  156.         case TCP_CLOSED:
  157.         case TCP_CLOSE_WAIT:
  158.         case TCP_CLOSING:
  159.         case TCP_LAST_ACK:
  160.         case TCP_TIME_WAIT:
  161.             *bpp = NULLBUF;
  162.             return 0;
  163.         }
  164.     }
  165.     /* cnt == 0 means "I want it all" */
  166.     if(cnt == 0)
  167.         cnt = tcb->rcvcnt;
  168.     /* See if the user can take all of it */
  169.     if(tcb->rcvcnt <= cnt){
  170.         cnt = tcb->rcvcnt;
  171.         *bpp = tcb->rcvq;
  172.         tcb->rcvq = NULLBUF;
  173.     } else {
  174.         *bpp = ambufw(cnt);
  175.         pullup(&tcb->rcvq,(*bpp)->data,cnt);
  176.         (*bpp)->cnt = cnt;
  177.     }
  178.     tcb->rcvcnt -= cnt;
  179.     tcb->rcv.wnd += cnt;
  180.     /* Do a window update if it was closed */
  181.     if(cnt == tcb->rcv.wnd){
  182.         tcb->flags.force = 1;
  183.         tcp_output(tcb);
  184.     }
  185.     return (int)cnt;
  186. }
  187. /* This really means "I have no more data to send". It only closes the
  188.  * connection in one direction, and we can continue to receive data
  189.  * indefinitely.
  190.  */
  191. int
  192. close_tcp(tcb)
  193. register struct tcb *tcb;
  194. {
  195.     if(tcb == NULLTCB){
  196.         Net_error = INVALID;
  197.         return -1;
  198.     }
  199.     switch(tcb->state){
  200.     case TCP_CLOSED:
  201.         return 0;    /* Unlikely */
  202.     case TCP_LISTEN:
  203.     case TCP_SYN_SENT:
  204.         close_self(tcb,NORMAL);
  205.         return 0;
  206.     case TCP_SYN_RECEIVED:
  207.     case TCP_ESTABLISHED:
  208.         tcb->sndcnt++;
  209.         tcb->snd.nxt++;
  210.         setstate(tcb,TCP_FINWAIT1);
  211.         tcp_output(tcb);
  212.         return 0;
  213.     case TCP_CLOSE_WAIT:
  214.         tcb->sndcnt++;
  215.         tcb->snd.nxt++;
  216.         setstate(tcb,TCP_LAST_ACK);
  217.         tcp_output(tcb);
  218.         return 0;
  219.     case TCP_FINWAIT1:
  220.     case TCP_FINWAIT2:
  221.     case TCP_CLOSING:
  222.     case TCP_LAST_ACK:
  223.     case TCP_TIME_WAIT:
  224.         Net_error = CON_CLOS;
  225.         return -1;
  226.     }
  227.     return -1;    /* "Can't happen" */
  228. }
  229. /* Delete TCB, free resources. The user is not notified, even if the TCB is
  230.  * not in the TCP_CLOSED state. This function should normally be called by the
  231.  * user only in response to a state change upcall to TCP_CLOSED state.
  232.  */
  233. int
  234. del_tcp(tcb)
  235. register struct tcb *tcb;
  236. {
  237.     struct reseq *rp,*rp1;
  238.  
  239.     if(tcb == NULLTCB){
  240.         Net_error = INVALID;
  241.         return -1;
  242.     }
  243.     unlink_tcb(tcb);
  244.     stop_timer(&tcb->timer);
  245.     for(rp = tcb->reseq;rp != NULLRESEQ;rp = rp1){
  246.         rp1 = rp->next;
  247.         free_p(rp->bp);
  248.         free((char *)rp);
  249.     }
  250.     tcb->reseq = NULLRESEQ;
  251.     free_p(tcb->rcvq);
  252.     free_p(tcb->sndq);
  253.     free((char *)tcb);
  254.     return 0;
  255. }
  256. /* Return 1 if arg is a valid TCB, 0 otherwise */
  257. int
  258. tcpval(tcb)
  259. struct tcb *tcb;
  260. {
  261.     register int i;
  262.     register struct tcb *tcb1;
  263.  
  264.     if(tcb == NULLTCB)
  265.         return 0;    /* Null pointer can't be valid */
  266.     for(i=0;i<NTCB;i++){
  267.         for(tcb1=Tcbs[i];tcb1 != NULLTCB;tcb1 = tcb1->next){
  268.             if(tcb1 == tcb)
  269.                 return 1;
  270.         }
  271.     }
  272.     return 0;
  273. }
  274. /* Kick a particular TCP connection */
  275. int
  276. kick_tcp(tcb)
  277. register struct tcb *tcb;
  278. {
  279.     if(!tcpval(tcb))
  280.         return -1;
  281.     tcp_timeout(tcb);
  282.     return 0;
  283. }
  284. /* Kick all TCP connections to specified address; return number kicked */
  285. int
  286. kick(addr)
  287. int32 addr;
  288. {
  289.     register int i;
  290.     register struct tcb *tcb;
  291.     int cnt = 0;
  292.  
  293.     for(i=0;i<NTCB;i++){
  294.         for(tcb=Tcbs[i];tcb != NULLTCB;tcb = tcb->next){
  295.             if(tcb->conn.remote.address == addr){
  296.                 kick_tcp(tcb);
  297.                 cnt++;
  298.             }
  299.         }
  300.     }
  301.     return cnt;
  302. }
  303. /* Clear all TCP connections */
  304. void
  305. reset_all()
  306. {
  307.     register int i;
  308.     register struct tcb *tcb;
  309.  
  310.     for(i=0;i<NTCB;i++){
  311.         for(tcb=Tcbs[i];tcb != NULLTCB;tcb = tcb->next)
  312.             reset_tcp(tcb);
  313.     }
  314.     pwait(NULL);    /* Let the RSTs go forth */
  315. }
  316. void
  317. reset_tcp(tcb)
  318. register struct tcb *tcb;
  319. {
  320.     struct tcp fakeseg;
  321.     struct ip fakeip;
  322.  
  323.     if(tcb == NULLTCB)
  324.         return;
  325.     if(tcb->state != TCP_LISTEN){
  326.         /* Compose a fake segment with just enough info to generate the
  327.          * correct RST reply
  328.          */
  329.         fakeseg.flags.rst = 0;
  330.         fakeseg.dest = tcb->conn.local.port;
  331.         fakeseg.source = tcb->conn.remote.port;
  332.         fakeseg.flags.ack = 1;
  333.         /* Here we try to pick a sequence number with the greatest likelihood
  334.          * of being in his receive window.
  335.          */
  336.         fakeseg.ack = tcb->snd.nxt + tcb->snd.wnd - 1;
  337.         fakeip.dest = tcb->conn.local.address;
  338.         fakeip.source = tcb->conn.remote.address;
  339.         fakeip.tos = tcb->tos;
  340.         reset(&fakeip,&fakeseg);
  341.     }
  342.     close_self(tcb,RESET);
  343. }
  344. #ifdef    notused
  345. /* Return character string corresponding to a TCP well-known port, or
  346.  * the decimal number if unknown.
  347.  */
  348. char *
  349. tcp_port(n)
  350. int16 n;
  351. {
  352.     static char buf[32];
  353.  
  354.     switch(n){
  355.     case IPPORT_ECHO:
  356.         return "echo";
  357.     case IPPORT_DISCARD:
  358.         return "discard";
  359.     case IPPORT_FTPD:
  360.         return "ftp_data";
  361.     case IPPORT_FTP:
  362.         return "ftp";    
  363.     case IPPORT_TELNET:
  364.         return "telnet";
  365.     case IPPORT_SMTP:
  366.         return "smtp";
  367.     default:
  368.         sprintf(buf,"%u",n);
  369.         return buf;
  370.     }
  371. }
  372. #endif
  373.  
  374.