/* ** tcp6_set_version - sets version for TCP. ** ** Check to see if driver being restricted to IPv4 or IPv6 only. ** Default is both IPv4(AF_INET) + IPv6(AF_INET6) ** ** VERSION -> meaning . . . ** ALL or unspecified -> (default) Use both IPv4 and IPv6 addresses ** with new (IPv6-enabled) driver ** 4 -> Use old IPv4-only driver (ie, back off to old driver) ** 46 -> Use only IPv4 addresses with new (IPv6-enabled) driver ** 6 -> Use only IPv6 addresses with new (IPv6-enabled) driver ** */ static int tcp6_set_version() { char *p; if( tcpip_version == -1 ) /* Only do 1st time in for performance */ { TCP_TRACE(2)("tcp6_set_version: entered first time\n"); tcpip_version = 0; NMgtAt( "II_TCPIP_VERSION", &p ); if ( !(p && *p) && PMget("!.tcp_ip.version", &p) != OK ) ip_family = AF_UNSPEC; else if (STbcompare(p, 0, "ALL", 0, TRUE) == 0) ip_family = AF_UNSPEC; else { tcpip_version = atoi(p); /* 4*=IPv4 or 6=IPv6 */ if ((tcpip_version == 4) || (tcpip_version == 46)) ip_family = AF_INET; else if (tcpip_version == 6) ip_family = AF_INET6; else { TCP_TRACE(2)("tcp6_set_version: failed! II_TCPIP_VERSION=%s\n", p); return(FAIL); } } TCP_TRACE(2)("tcp6_set_version: exiting version=%d, family=%d\n", tcpip_version, ip_family); } /* end if first time */ return(OK); }
/** * @ingroup tcp * * Processes an incoming packet for a TCP connection in the SYNSENT state. * Function based on RFC 763, pg 66-68. * @param pkt incoming packet * @param tcbptr pointer to transmission control block for connection * @return OK or TCP_ERR_SNDRST * @pre-condition TCB mutex is already held */ int tcpRecvSynsent(struct packet *pkt, struct tcb *tcbptr) { struct tcpPkt *tcp; bool ackAccept = FALSE; /* Setup packet pointers */ tcp = (struct tcpPkt *)pkt->curr; /* Process ACK */ if (tcp->control & TCP_CTRL_ACK) { TCP_TRACE("ACK"); /* If ACK is unacceptable send reset */ if (seqlte(tcp->acknum, tcbptr->iss) || seqlt(tcbptr->sndnxt, tcp->acknum)) { if (!(tcp->control & TCP_CTRL_RST)) { tcbptr->sndflg |= TCP_FLG_SNDRST; return OK; } return OK; } /* Check if ACK is acceptable */ if (seqlte(tcbptr->snduna, tcp->acknum) && seqlte(tcp->acknum, tcbptr->sndnxt)) { ackAccept = TRUE; } } /* Process RST */ if (tcp->control & TCP_CTRL_RST) { TCP_TRACE("RST"); if (ackAccept) { /* ERROR: Connection reset */ return TCP_ERR_RESET; } return OK; } /* Process SYN */ if (tcp->control & TCP_CTRL_SYN) { TCP_TRACE("SYN"); tcbptr->sndwnd = tcp->window; tcbptr->sndwl1 = tcp->seqnum; tcbptr->rcvnxt = seqadd(tcp->seqnum, 1); tcbptr->rcvwnd = seqadd(tcp->seqnum, TCP_INIT_WND); tcbptr->rcvflg |= TCP_FLG_SYN; tcbptr->sndflg |= TCP_FLG_SNDACK; if (ackAccept) { tcbptr->snduna = tcp->acknum; tcbptr->sndwl2 = tcp->acknum; } /* Remove any segments from retransmission queue which are ACKed */ tcbptr->rxtcount = 0; tcpTimerPurge(tcbptr, TCP_EVT_RXT); /* If unacknowledged data remains, reschedule retransmit timer */ if (seqlt(tcbptr->snduna, tcbptr->sndnxt)) { tcpTimerSched(tcbptr->rxttime, tcbptr, TCP_EVT_RXT); } if (seqlt(tcbptr->iss, tcbptr->snduna)) { tcbptr->state = TCP_ESTAB; signal(tcbptr->openclose); /* Signal connection open */ tcbptr->sndflg |= TCP_FLG_SNDDATA; return tcpRecvData(pkt, tcbptr); } else { tcbptr->state = TCP_SYNRECV; /* This send is like a retransmission */ tcpSend(tcbptr, TCP_CTRL_SYN | TCP_CTRL_ACK, tcbptr->iss, tcbptr->rcvnxt, NULL, 1); return tcpRecvData(pkt, tcbptr); } } return OK; }
/** * Associate a tcp with a network device. * @param devptr tcp device table entry * @param ap 2nd argument is the local IP address * 3rd argument is the remote IP address * 4th argument is the local port (auto-assigned if zero) * 5th argument is the remote port (ignored if zero) * 6th argument is the mode (TCP_ACTIVE or TCP_PASSIVE) * @return OK if TCP is opened properly, otherwise SYSERR */ devcall tcpOpen(device *devptr, va_list ap) { struct tcb *tcbptr = NULL; uchar mode; ushort localpt; struct netaddr *localip; ushort remotept; struct netaddr *remoteip; /* Setup pointer to tcp */ tcbptr = &tcptab[devptr->minor]; wait(tcbptr->mutex); /* Mark as allocated */ tcbptr->devstate = TCP_ALLOC; /* Verify device is not already open */ if ((tcbptr->state != TCP_CLOSED) && (tcbptr->state != TCP_LISTEN)) { signal(tcbptr->mutex); TCP_TRACE("Already open"); return SYSERR; } /* Obtain remaining arguments */ localip = (struct netaddr *)va_arg(ap, uint); remoteip = (struct netaddr *)va_arg(ap, uint); localpt = va_arg(ap, uint); remotept = va_arg(ap, uint); mode = va_arg(ap, uint); /* Verify local IP is specified */ if (NULL == localip) { tcbptr->devstate = TCP_FREE; signal(tcbptr->mutex); TCP_TRACE("Invalid args"); return SYSERR; } /* Allocate a local port if none is specified */ if (NULL == localpt) { localpt = allocPort(); } /* Mutually link tcp record with device table entry */ tcbptr->dev = devptr->num; /* Initialize port and ip fields */ tcbptr->localpt = localpt; netaddrcpy(&tcbptr->localip, localip); tcbptr->remotept = remotept; if (NULL == remoteip) { tcbptr->remoteip.type = NULL; } else { netaddrcpy(&tcbptr->remoteip, remoteip); } tcbptr->opentype = mode; /* Setup transmission control block */ if (SYSERR == tcpSetup(tcbptr)) { tcpFree(tcbptr); TCP_TRACE("Failed to setup TCB"); return SYSERR; } /* Perform appropriate action and change state */ switch (mode) { case TCP_PASSIVE: tcbptr->state = TCP_LISTEN; break; case TCP_ACTIVE: if (SYSERR == tcpOpenActive(tcbptr)) { tcpFree(tcbptr); TCP_TRACE("Failed to active open"); return SYSERR; } break; default: tcpFree(tcbptr); TCP_TRACE("Unknown mode"); return SYSERR; } signal(tcbptr->mutex); TCP_TRACE("Waiting for other side"); wait(tcbptr->openclose); /* Wait for connection open */ TCP_TRACE("Opened connection"); return OK; }