/** * Initiates a new List Exported Devices request. * * @returns VBox status code. */ int USBProxyBackendUsbIp::startListExportedDevicesReq() { int rc = VINF_SUCCESS; /* * Reset the current state and reconnect in case we were called in the middle * of another transfer (which should not happen). */ Assert(m->enmRecvState == kUsbIpRecvState_None); if (m->enmRecvState != kUsbIpRecvState_None) rc = reconnect(); if (RT_SUCCESS(rc)) { /* Send of the request. */ UsbIpReqDevList ReqDevList; ReqDevList.u16Version = RT_H2N_U16(USBIP_VERSION); ReqDevList.u16Cmd = RT_H2N_U16(USBIP_INDICATOR_REQ | USBIP_REQ_RET_DEVLIST); ReqDevList.u32Status = RT_H2N_U32(0); rc = RTTcpWrite(m->hSocket, &ReqDevList, sizeof(ReqDevList)); if (RT_SUCCESS(rc)) advanceState(kUsbIpRecvState_Hdr); } return rc; }
DECLINLINE(int) tftpSendError(PNATState pData, PTFTPSESSION pTftpSession, uint16_t errorcode, const char *msg, PCTFTPIPHDR pcTftpIpHeaderRecv) { struct mbuf *m = NULL; PTFTPIPHDR pTftpIpHeader = NULL; LogFlowFunc(("ENTER: errorcode: %RX16, msg: %s\n", errorcode, msg)); m = slirpTftpMbufAlloc(pData); if (!m) { LogFlowFunc(("LEAVE: Can't allocate mbuf\n")); return -1; } m->m_data += if_maxlinkhdr; m->m_len = sizeof(TFTPIPHDR) + strlen(msg) + 1; /* ending zero */ m->m_pkthdr.header = mtod(m, void *); pTftpIpHeader = mtod(m, PTFTPIPHDR); pTftpIpHeader->u16TftpOpType = RT_H2N_U16_C(TFTP_ERROR); pTftpIpHeader->Core.u16TftpOpCode = RT_H2N_U16(errorcode); m_copyback(pData, m, sizeof(TFTPIPHDR), strlen(msg) + 1 /* copy ending zerro*/, (c_caddr_t)msg); tftpSend(pData, pTftpSession, m, pcTftpIpHeaderRecv); tftpSessionTerminate(pTftpSession); LogFlowFuncLeave(); return 0; }
/** * @note This function will free m! */ int udp_output(PNATState pData, struct socket *so, struct mbuf *m, struct sockaddr_in *addr) { struct sockaddr_in saddr, daddr; Assert(so->so_type == IPPROTO_UDP); LogFlowFunc(("ENTER: so = %R[natsock], m = %p, saddr = %RTnaipv4\n", so, m, addr->sin_addr.s_addr)); if (so->so_laddr.s_addr == INADDR_ANY) { if (pData->guest_addr_guess.s_addr != INADDR_ANY) { LogRel2(("NAT: port-forward: using %RTnaipv4 for %R[natsock]\n", pData->guest_addr_guess.s_addr, so)); so->so_laddr = pData->guest_addr_guess; } else { LogRel2(("NAT: port-forward: guest address unknown for %R[natsock]\n", so)); m_freem(pData, m); return 0; } } saddr = *addr; if ((so->so_faddr.s_addr & RT_H2N_U32(pData->netmask)) == pData->special_addr.s_addr) { saddr.sin_addr.s_addr = so->so_faddr.s_addr; if (slirpIsWideCasting(pData, so->so_faddr.s_addr)) { /** * We haven't got real firewall but have got its submodule libalias. */ m->m_flags |= M_SKIP_FIREWALL; /** * udp/137 port is Name Service in NetBIOS protocol. for some reasons Windows guest rejects * accept data from non-aliased server. */ if ( (so->so_fport == so->so_lport) && (so->so_fport == RT_H2N_U16(137))) saddr.sin_addr.s_addr = alias_addr.s_addr; else saddr.sin_addr.s_addr = addr->sin_addr.s_addr; so->so_faddr.s_addr = addr->sin_addr.s_addr; } } /* Any UDP packet to the loopback address must be translated to be from * the forwarding address, i.e. 10.0.2.2. */ if ( (saddr.sin_addr.s_addr & RT_H2N_U32_C(IN_CLASSA_NET)) == RT_H2N_U32_C(INADDR_LOOPBACK & IN_CLASSA_NET)) saddr.sin_addr.s_addr = alias_addr.s_addr; daddr.sin_addr = so->so_laddr; daddr.sin_port = so->so_lport; return udp_output2(pData, so, m, &saddr, &daddr, so->so_iptos); }
/** * Output a UDP packet. * * @note This function will finally free m! */ int udp_output2(PNATState pData, struct socket *so, struct mbuf *m, struct sockaddr_in *saddr, struct sockaddr_in *daddr, int iptos) { register struct udpiphdr *ui; int error; int mlen = 0; LogFlowFunc(("ENTER: so = %R[natsock], m = %p, saddr = %RTnaipv4, daddr = %RTnaipv4\n", so, m, saddr->sin_addr.s_addr, daddr->sin_addr.s_addr)); /* in case of built-in service so might be NULL */ if (so) Assert(so->so_type == IPPROTO_UDP); /* * Adjust for header */ m->m_data -= sizeof(struct udpiphdr); m->m_len += sizeof(struct udpiphdr); mlen = m_length(m, NULL); /* * Fill in mbuf with extended UDP header * and addresses and length put into network format. */ ui = mtod(m, struct udpiphdr *); memset(ui->ui_x1, 0, 9); ui->ui_pr = IPPROTO_UDP; ui->ui_len = RT_H2N_U16((uint16_t)(mlen - sizeof(struct ip))); /* XXXXX Check for from-one-location sockets, or from-any-location sockets */ ui->ui_src = saddr->sin_addr; ui->ui_dst = daddr->sin_addr; ui->ui_sport = saddr->sin_port; ui->ui_dport = daddr->sin_port; ui->ui_ulen = ui->ui_len; /* * Stuff checksum and output datagram. */ ui->ui_sum = 0; if (udpcksum) { if ((ui->ui_sum = cksum(m, /* sizeof (struct udpiphdr) + */ mlen)) == 0) ui->ui_sum = 0xffff; } ((struct ip *)ui)->ip_len = mlen; ((struct ip *)ui)->ip_ttl = ip_defttl; ((struct ip *)ui)->ip_tos = iptos; udpstat.udps_opackets++; error = ip_output(pData, so, m); return error; }
/** * @note This function will free m! */ int udp_output(PNATState pData, struct socket *so, struct mbuf *m, struct sockaddr_in *addr) { struct sockaddr_in saddr, daddr; #ifdef VBOX_WITH_NAT_UDP_SOCKET_CLONE struct socket *pSocketClone = NULL; #endif Assert(so->so_type == IPPROTO_UDP); LogFlowFunc(("ENTER: so = %R[natsock], m = %p, saddr = %RTnaipv4\n", so, (long)m, addr->sin_addr.s_addr)); saddr = *addr; if ((so->so_faddr.s_addr & RT_H2N_U32(pData->netmask)) == pData->special_addr.s_addr) { saddr.sin_addr.s_addr = so->so_faddr.s_addr; if (slirpIsWideCasting(pData, so->so_faddr.s_addr)) { /** * We haven't got real firewall but have got its submodule libalias. */ m->m_flags |= M_SKIP_FIREWALL; /** * udp/137 port is Name Service in NetBIOS protocol. for some reasons Windows guest rejects * accept data from non-aliased server. */ if ( (so->so_fport == so->so_lport) && (so->so_fport == RT_H2N_U16(137))) saddr.sin_addr.s_addr = alias_addr.s_addr; else saddr.sin_addr.s_addr = addr->sin_addr.s_addr; /* we shouldn't override initial socket */ #ifdef VBOX_WITH_NAT_UDP_SOCKET_CLONE if (so->so_cCloneCounter) pSocketClone = soLookUpClonedUDPSocket(pData, so, addr->sin_addr.s_addr); if (!pSocketClone) pSocketClone = soCloneUDPSocketWithForegnAddr(pData, false, so, addr->sin_addr.s_addr); Assert((pSocketClone)); so = pSocketClone; #else so->so_faddr.s_addr = addr->sin_addr.s_addr; #endif } } /* Any UDP packet to the loopback address must be translated to be from * the forwarding address, i.e. 10.0.2.2. */ if ( (saddr.sin_addr.s_addr & RT_H2N_U32_C(IN_CLASSA_NET)) == RT_H2N_U32_C(INADDR_LOOPBACK & IN_CLASSA_NET)) saddr.sin_addr.s_addr = alias_addr.s_addr; daddr.sin_addr = so->so_laddr; daddr.sin_port = so->so_lport; return udp_output2(pData, so, m, &saddr, &daddr, so->so_iptos); }
static int tftp_send_data(PNATState pData, struct tftp_session *spt, u_int16_t block_nr, struct tftp_t *recv_tp) { struct sockaddr_in saddr, daddr; struct mbuf *m; struct tftp_t *tp; int nobytes; if (block_nr < 1) return -1; m = slirpTftpMbufAlloc(pData); if (!m) return -1; m->m_data += if_maxlinkhdr; m->m_pkthdr.header = mtod(m, void *); tp = mtod(m, void *); m->m_data += sizeof(struct udpiphdr); tp->tp_op = RT_H2N_U16_C(TFTP_DATA); tp->x.tp_data.tp_block_nr = RT_H2N_U16(block_nr); saddr.sin_addr = recv_tp->ip.ip_dst; saddr.sin_port = recv_tp->udp.uh_dport; daddr.sin_addr = spt->client_ip; daddr.sin_port = spt->client_port; nobytes = tftp_read_data(pData, spt, block_nr - 1, tp->x.tp_data.tp_buf, 512); if (nobytes < 0) { m_freem(pData, m); /* send "file not found" error back */ tftp_send_error(pData, spt, 1, "File not found", tp); return -1; } m->m_len = sizeof(struct tftp_t) - (512 - nobytes) - sizeof(struct ip) - sizeof(struct udphdr); udp_output2(pData, NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); if (nobytes == 512) tftp_session_update(pData, spt); else tftp_session_terminate(spt); return 0; }
static int tftpSendData(PNATState pData, PTFTPSESSION pTftpSession, uint16_t u16Block, PCTFTPIPHDR pcTftpIpHeaderRecv) { struct mbuf *m; PTFTPIPHDR pTftpIpHeader; int cbRead = 0; int rc = VINF_SUCCESS; if (u16Block == pTftpSession->cTftpAck) pTftpSession->cTftpAck++; else { tftpSendError(pData, pTftpSession, 6, "ACK is wrong", pcTftpIpHeaderRecv); tftpSessionTerminate(pTftpSession); return -1; } m = slirpTftpMbufAlloc(pData); if (!m) return -1; m->m_data += if_maxlinkhdr; m->m_pkthdr.header = mtod(m, void *); pTftpIpHeader = mtod(m, PTFTPIPHDR); m->m_len = sizeof(TFTPIPHDR); pTftpIpHeader->u16TftpOpType = RT_H2N_U16_C(TFTP_DATA); pTftpIpHeader->Core.u16TftpOpCode = RT_H2N_U16(pTftpSession->cTftpAck); rc = tftpReadDataBlock(pData, pTftpSession, (uint8_t *)&pTftpIpHeader->Core.u16TftpOpCode + sizeof(uint16_t), &cbRead); if (RT_SUCCESS(rc)) { pTftpSession->cbTransfered += cbRead; m->m_len += cbRead; tftpSend(pData, pTftpSession, m, pcTftpIpHeaderRecv); if (cbRead > 0) tftpSessionUpdate(pData, pTftpSession); else tftpSessionTerminate(pTftpSession); } else { m_freem(pData, m); tftpSendError(pData, pTftpSession, 1, "File not found", pcTftpIpHeaderRecv); /* send "file not found" error back */ return -1; } return 0; }
static int tftp_send_error(PNATState pData, struct tftp_session *spt, u_int16_t errorcode, const char *msg, struct tftp_t *recv_tp) { struct sockaddr_in saddr, daddr; struct mbuf *m; struct tftp_t *tp; int nobytes; m = slirpTftpMbufAlloc(pData); if (!m) return -1; m->m_data += if_maxlinkhdr; m->m_pkthdr.header = mtod(m, void *); tp = (void *)m->m_data; m->m_data += sizeof(struct udpiphdr); tp->tp_op = RT_H2N_U16_C(TFTP_ERROR); tp->x.tp_error.tp_error_code = RT_H2N_U16(errorcode); strcpy((char *)tp->x.tp_error.tp_msg, msg); saddr.sin_addr = recv_tp->ip.ip_dst; saddr.sin_port = recv_tp->udp.uh_dport; daddr.sin_addr = spt->client_ip; daddr.sin_port = spt->client_port; nobytes = 2; m->m_len = sizeof(struct tftp_t) - 514 + 3 + strlen(msg) - sizeof(struct ip) - sizeof(struct udphdr); udp_output2(pData, NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); tftp_session_terminate(spt); return 0; }
/* struct tcpiphdr * */ void tcp_template(struct tcpcb *tp) { struct socket *so = tp->t_socket; register struct tcpiphdr *n = &tp->t_template; memset(n->ti_x1, 0, 9); n->ti_pr = IPPROTO_TCP; n->ti_len = RT_H2N_U16(sizeof (struct tcpiphdr) - sizeof (struct ip)); n->ti_src = so->so_faddr; n->ti_dst = so->so_laddr; n->ti_sport = so->so_fport; n->ti_dport = so->so_lport; n->ti_seq = 0; n->ti_ack = 0; n->ti_x2 = 0; n->ti_off = 5; n->ti_flags = 0; n->ti_win = 0; n->ti_sum = 0; n->ti_urp = 0; }
/* This function will free m0! */ int ip_output0(PNATState pData, struct socket *so, struct mbuf *m0, int urg) { register struct ip *ip; register struct mbuf *m = m0; register int hlen = sizeof(struct ip); int len, off, error = 0; struct ethhdr *eh = NULL; uint8_t eth_dst[ETH_ALEN]; int rc = 1; STAM_PROFILE_START(&pData->StatIP_output, a); #ifdef LOG_ENABLED LogFlowFunc(("ip_output: so = %R[natsock], m0 = %lx\n", so, (long)m0)); #else NOREF(so); #endif M_ASSERTPKTHDR(m); Assert(m->m_pkthdr.header); #if 0 /* We do no options */ if (opt) { m = ip_insertoptions(m, opt, &len); hlen = len; } #endif ip = mtod(m, struct ip *); LogFunc(("ip(src:%RTnaipv4, dst:%RTnaipv4)\n", ip->ip_src, ip->ip_dst)); /* * Fill in IP header. */ ip->ip_v = IPVERSION; ip->ip_off &= IP_DF; ip->ip_id = RT_H2N_U16(ip_currid++); ip->ip_hl = hlen >> 2; ipstat.ips_localout++; /* Current TCP/IP stack hasn't routing information at * all so we need to calculate destination ethernet address */ rc = rt_lookup_in_cache(pData, ip->ip_dst.s_addr, eth_dst); if (RT_FAILURE(rc)) goto exit_drop_package; eh = (struct ethhdr *)(m->m_data - ETH_HLEN); /* * If small enough for interface, can just send directly. */ if ((u_int16_t)ip->ip_len <= if_mtu) { ip->ip_len = RT_H2N_U16((u_int16_t)ip->ip_len); ip->ip_off = RT_H2N_U16((u_int16_t)ip->ip_off); ip->ip_sum = 0; ip->ip_sum = cksum(m, hlen); if (!(m->m_flags & M_SKIP_FIREWALL)){ struct m_tag *t; STAM_PROFILE_START(&pData->StatALIAS_output, b); if ((t = m_tag_find(m, PACKET_TAG_ALIAS, NULL)) != 0) rc = LibAliasOut((struct libalias *)&t[1], mtod(m, char *), m_length(m, NULL)); else rc = LibAliasOut(pData->proxy_alias, mtod(m, char *), m_length(m, NULL)); if (rc == PKT_ALIAS_IGNORED) { Log(("NAT: packet was droppped\n")); goto exit_drop_package; } STAM_PROFILE_STOP(&pData->StatALIAS_output, b); }
DECLINLINE(int) tftpSessionOptionParse(PTFTPSESSION pTftpSession, PCTFTPIPHDR pcTftpIpHeader) { int rc = VINF_SUCCESS; char *pszTftpRRQRaw; size_t idxTftpRRQRaw = 0; int cbTftpRRQRaw = 0; int fWithArg = 0; int idxOptionArg = 0; AssertPtrReturn(pTftpSession, VERR_INVALID_PARAMETER); AssertPtrReturn(pcTftpIpHeader, VERR_INVALID_PARAMETER); AssertReturn(RT_N2H_U16(pcTftpIpHeader->u16TftpOpType) == TFTP_RRQ, VERR_INVALID_PARAMETER); LogFlowFunc(("pTftpSession:%p, pcTftpIpHeader:%p\n", pTftpSession, pcTftpIpHeader)); pszTftpRRQRaw = (char *)&pcTftpIpHeader->Core; cbTftpRRQRaw = RT_H2N_U16(pcTftpIpHeader->UdpHdr.uh_ulen) + sizeof(struct ip) - RT_OFFSETOF(TFTPIPHDR, Core); while(cbTftpRRQRaw) { idxTftpRRQRaw = RTStrNLen(pszTftpRRQRaw, 512 - idxTftpRRQRaw) + 1; if (RTStrNLen((char *)pTftpSession->pszFilename, TFTP_FILENAME_MAX) == 0) { rc = RTStrCopy((char *)pTftpSession->pszFilename, TFTP_FILENAME_MAX, pszTftpRRQRaw); if (RT_FAILURE(rc)) { LogFlowFuncLeaveRC(rc); AssertRCReturn(rc,rc); } } else if (pTftpSession->enmTftpFmt == TFTPFMT_NONE) { int idxFmt = 0; rc = tftpFindTransferFormatIdxbyName(&idxFmt, pszTftpRRQRaw); if (RT_FAILURE(rc)) { LogFlowFuncLeaveRC(VERR_INTERNAL_ERROR); return VERR_INTERNAL_ERROR; } AssertReturn( g_TftpTransferFmtDesc[idxFmt].enmType != TFTPFMT_NONE && g_TftpTransferFmtDesc[idxFmt].enmType != TFTPFMT_NOT_FMT, VERR_INTERNAL_ERROR); pTftpSession->enmTftpFmt = g_TftpTransferFmtDesc[idxFmt].enmType; } else if (fWithArg) { if (!RTStrICmp("blksize", g_TftpDesc[idxOptionArg].pszName)) { rc = tftpSessionParseAndMarkOption(pszTftpRRQRaw, &pTftpSession->OptionBlkSize); if (pTftpSession->OptionBlkSize.u64Value > UINT16_MAX) rc = VERR_INVALID_PARAMETER; } if ( RT_SUCCESS(rc) && !RTStrICmp("tsize", g_TftpDesc[idxOptionArg].pszName)) rc = tftpSessionParseAndMarkOption(pszTftpRRQRaw, &pTftpSession->OptionTSize); /* @todo: we don't use timeout, but its value in the range 0-255 */ if ( RT_SUCCESS(rc) && !RTStrICmp("timeout", g_TftpDesc[idxOptionArg].pszName)) rc = tftpSessionParseAndMarkOption(pszTftpRRQRaw, &pTftpSession->OptionTimeout); /* @todo: unknown option detection */ if (RT_FAILURE(rc)) { LogFlowFuncLeaveRC(rc); AssertRCReturn(rc,rc); } fWithArg = 0; idxOptionArg = 0; } else { rc = tftpFindOptionIdxbyName(&idxOptionArg, pszTftpRRQRaw); if (RT_SUCCESS(rc)) fWithArg = 1; else { LogFlowFuncLeaveRC(rc); AssertRCReturn(rc,rc); } } pszTftpRRQRaw += idxTftpRRQRaw; cbTftpRRQRaw -= idxTftpRRQRaw; } LogFlowFuncLeaveRC(rc); return rc; }
/* * Tcp output routine: figure out what should be sent and send it. */ int tcp_output(PNATState pData, register struct tcpcb *tp) { register struct socket *so = tp->t_socket; register long len, win; int off, flags, error; register struct mbuf *m = NULL; register struct tcpiphdr *ti; u_char opt[MAX_TCPOPTLEN]; unsigned optlen, hdrlen; int idle, sendalot; int size = 0; LogFlowFunc(("ENTER: tcp_output: tp = %R[tcpcb793]\n", tp)); /* * Determine length of data that should be transmitted, * and flags that will be used. * If there is some data or critical controls (SYN, RST) * to send, then transmit; otherwise, investigate further. */ idle = (tp->snd_max == tp->snd_una); if (idle && tp->t_idle >= tp->t_rxtcur) /* * We have been idle for "a while" and no acks are * expected to clock out any data we send -- * slow start to get ack "clock" running again. */ tp->snd_cwnd = tp->t_maxseg; again: sendalot = 0; off = tp->snd_nxt - tp->snd_una; win = min(tp->snd_wnd, tp->snd_cwnd); flags = tcp_outflags[tp->t_state]; Log2((" --- tcp_output flags = 0x%x\n", flags)); /* * If in persist timeout with window of 0, send 1 byte. * Otherwise, if window is small but nonzero * and timer expired, we will send what we can * and go to transmit state. */ if (tp->t_force) { if (win == 0) { /* * If we still have some data to send, then * clear the FIN bit. Usually this would * happen below when it realizes that we * aren't sending all the data. However, * if we have exactly 1 byte of unset data, * then it won't clear the FIN bit below, * and if we are in persist state, we wind * up sending the packet without recording * that we sent the FIN bit. * * We can't just blindly clear the FIN bit, * because if we don't have any more data * to send then the probe will be the FIN * itself. */ if (off < SBUF_LEN(&so->so_snd)) flags &= ~TH_FIN; win = 1; } else { tp->t_timer[TCPT_PERSIST] = 0; tp->t_rxtshift = 0; } } len = min(SBUF_LEN(&so->so_snd), win) - off; if (len < 0) { /* * If FIN has been sent but not acked, * but we haven't been called to retransmit, * len will be -1. Otherwise, window shrank * after we sent into it. If window shrank to 0, * cancel pending retransmit and pull snd_nxt * back to (closed) window. We will enter persist * state below. If the window didn't close completely, * just wait for an ACK. */ len = 0; if (win == 0) { tp->t_timer[TCPT_REXMT] = 0; tp->snd_nxt = tp->snd_una; } } if (len > tp->t_maxseg) { len = tp->t_maxseg; sendalot = 1; } if (SEQ_LT(tp->snd_nxt + len, tp->snd_una + SBUF_LEN(&so->so_snd))) flags &= ~TH_FIN; win = sbspace(&so->so_rcv); /* * Sender silly window avoidance. If connection is idle * and can send all data, a maximum segment, * at least a maximum default-size segment do it, * or are forced, do it; otherwise don't bother. * If peer's buffer is tiny, then send * when window is at least half open. * If retransmitting (possibly after persist timer forced us * to send into a small window), then must resend. */ if (len) { if (len == tp->t_maxseg) goto send; if ((1 || idle || tp->t_flags & TF_NODELAY) && len + off >= SBUF_LEN(&so->so_snd)) goto send; if (tp->t_force) goto send; if (len >= tp->max_sndwnd / 2 && tp->max_sndwnd > 0) goto send; if (SEQ_LT(tp->snd_nxt, tp->snd_max)) goto send; } /* * Compare available window to amount of window * known to peer (as advertised window less * next expected input). If the difference is at least two * max size segments, or at least 50% of the maximum possible * window, then want to send a window update to peer. */ if (win > 0) { /* * "adv" is the amount we can increase the window, * taking into account that we are limited by * TCP_MAXWIN << tp->rcv_scale. */ long adv = min(win, (long)TCP_MAXWIN << tp->rcv_scale); if (SEQ_GT(tp->rcv_adv, tp->rcv_nxt)) adv -= tp->rcv_adv - tp->rcv_nxt; if (adv >= (long) (2 * tp->t_maxseg)) goto send; if (2 * adv >= (long) SBUF_SIZE(&so->so_rcv)) goto send; } /* * Send if we owe peer an ACK. */ if (tp->t_flags & TF_ACKNOW) goto send; if (flags & (TH_SYN|TH_RST)) goto send; if (SEQ_GT(tp->snd_up, tp->snd_una)) goto send; /* * If our state indicates that FIN should be sent * and we have not yet done so, or we're retransmitting the FIN, * then we need to send. */ if ( flags & TH_FIN && ((tp->t_flags & TF_SENTFIN) == 0 || tp->snd_nxt == tp->snd_una)) goto send; /* * TCP window updates are not reliable, rather a polling protocol * using ``persist'' packets is used to insure receipt of window * updates. The three ``states'' for the output side are: * idle not doing retransmits or persists * persisting to move a small or zero window * (re)transmitting and thereby not persisting * * tp->t_timer[TCPT_PERSIST] * is set when we are in persist state. * tp->t_force * is set when we are called to send a persist packet. * tp->t_timer[TCPT_REXMT] * is set when we are retransmitting * The output side is idle when both timers are zero. * * If send window is too small, there is data to transmit, and no * retransmit or persist is pending, then go to persist state. * If nothing happens soon, send when timer expires: * if window is nonzero, transmit what we can, * otherwise force out a byte. */ if ( SBUF_LEN(&so->so_snd) && tp->t_timer[TCPT_REXMT] == 0 && tp->t_timer[TCPT_PERSIST] == 0) { tp->t_rxtshift = 0; tcp_setpersist(tp); } /* * No reason to send a segment, just return. */ tcpstat.tcps_didnuttin++; LogFlowFuncLeave(); return (0); send: LogFlowFunc(("send\n")); /* * Before ESTABLISHED, force sending of initial options * unless TCP set not to do any options. * NOTE: we assume that the IP/TCP header plus TCP options * always fit in a single mbuf, leaving room for a maximum * link header, i.e. * max_linkhdr + sizeof (struct tcpiphdr) + optlen <= MHLEN */ optlen = 0; hdrlen = sizeof (struct tcpiphdr); if (flags & TH_SYN) { tp->snd_nxt = tp->iss; if ((tp->t_flags & TF_NOOPT) == 0) { u_int16_t mss; opt[0] = TCPOPT_MAXSEG; opt[1] = 4; mss = RT_H2N_U16((u_int16_t) tcp_mss(pData, tp, 0)); memcpy((caddr_t)(opt + 2), (caddr_t)&mss, sizeof(mss)); optlen = 4; #if 0 if ( (tp->t_flags & TF_REQ_SCALE) && ( (flags & TH_ACK) == 0 || (tp->t_flags & TF_RCVD_SCALE))) { *((u_int32_t *) (opt + optlen)) = RT_H2N_U32( TCPOPT_NOP << 24 | TCPOPT_WINDOW << 16 | TCPOLEN_WINDOW << 8 | tp->request_r_scale); optlen += 4; } #endif } } /* * Send a timestamp and echo-reply if this is a SYN and our side * wants to use timestamps (TF_REQ_TSTMP is set) or both our side * and our peer have sent timestamps in our SYN's. */ #if 0 if ( (tp->t_flags & (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP && (flags & TH_RST) == 0 && ( (flags & (TH_SYN|TH_ACK)) == TH_SYN || (tp->t_flags & TF_RCVD_TSTMP))) { u_int32_t *lp = (u_int32_t *)(opt + optlen); /* Form timestamp option as shown in appendix A of RFC 1323. */ *lp++ = RT_H2N_U32_C(TCPOPT_TSTAMP_HDR); *lp++ = RT_H2N_U32(tcp_now); *lp = RT_H2N_U32(tp->ts_recent); optlen += TCPOLEN_TSTAMP_APPA; } #endif hdrlen += optlen; /* * Adjust data length if insertion of options will * bump the packet length beyond the t_maxseg length. */ if (len > tp->t_maxseg - optlen) { len = tp->t_maxseg - optlen; sendalot = 1; } /* * Grab a header mbuf, attaching a copy of data to * be transmitted, and initialize the header from * the template for sends on this connection. */ if (len) { if (tp->t_force && len == 1) tcpstat.tcps_sndprobe++; else if (SEQ_LT(tp->snd_nxt, tp->snd_max)) { tcpstat.tcps_sndrexmitpack++; tcpstat.tcps_sndrexmitbyte += len; } else { tcpstat.tcps_sndpack++; tcpstat.tcps_sndbyte += len; } size = MCLBYTES; if ((len + hdrlen + ETH_HLEN) < MSIZE) size = MCLBYTES; else if ((len + hdrlen + ETH_HLEN) < MCLBYTES) size = MCLBYTES; else if((len + hdrlen + ETH_HLEN) < MJUM9BYTES) size = MJUM9BYTES; else if ((len + hdrlen + ETH_HLEN) < MJUM16BYTES) size = MJUM16BYTES; else AssertMsgFailed(("Unsupported size")); m = m_getjcl(pData, M_NOWAIT, MT_HEADER, M_PKTHDR, size); if (m == NULL) { /* error = ENOBUFS; */ error = 1; goto out; } m->m_data += if_maxlinkhdr; m->m_pkthdr.header = mtod(m, void *); m->m_len = hdrlen; /* * This will always succeed, since we make sure our mbufs * are big enough to hold one MSS packet + header + ... etc. */ #if 0 if (len <= MHLEN - hdrlen - max_linkhdr) { #endif sbcopy(&so->so_snd, off, (int) len, mtod(m, caddr_t) + hdrlen); m->m_len += len; #if 0 } else { m->m_next = m_copy(so->so_snd.sb_mb, off, (int) len); if (m->m_next == 0) len = 0; } #endif /* * If we're sending everything we've got, set PUSH. * (This will keep happy those implementations which only * give data to the user when a buffer fills or * a PUSH comes in.) */ if (off + len == SBUF_LEN(&so->so_snd)) flags |= TH_PUSH; } else {
/* * This function deals only with the hex-group IPv6 address syntax * proper (with possible embedded IPv4). */ DECLHIDDEN(int) rtNetStrToIPv6AddrBase(const char *pcszAddr, PRTNETADDRIPV6 pAddrResult, char **ppszNext) { RTNETADDRIPV6 ipv6; RTNETADDRIPV4 ipv4; const char *pcszPos; char *pszNext; int iGroup; uint16_t u16; int rc; memset(&ipv6, 0, sizeof(ipv6)); pcszPos = pcszAddr; if (pcszPos[0] == ':') /* compressed zero run at the beginning? */ { if (pcszPos[1] != ':') return VERR_PARSE_ERROR; pcszPos += 2; /* skip over "::" */ pszNext = (/* UNCONST */ char *)pcszPos; iGroup = 1; } else { /* * Scan forward until we either get complete address or find * "::" compressed zero run. */ for (iGroup = 0; iGroup < 8; ++iGroup) { /* check for embedded IPv4 at the end */ if (iGroup == 6) { rc = rtNetStrToIPv4AddrEx(pcszPos, &ipv4, &pszNext); if (rc == VINF_SUCCESS) { ipv6.au32[3] = ipv4.au32[0]; iGroup = 8; /* filled 6 and 7 */ break; /* we are done */ } } rc = rtNetStrToHexGroup(pcszPos, &pszNext, &u16); if (RT_FAILURE(rc)) return VERR_PARSE_ERROR; ipv6.au16[iGroup] = RT_H2N_U16(u16); if (iGroup == 7) pcszPos = pszNext; else { /* skip the colon that delimits this group */ if (*pszNext != ':') return VERR_PARSE_ERROR; pcszPos = pszNext + 1; /* compressed zero run? */ if (*pcszPos == ':') { ++pcszPos; /* skip over :: */ pszNext += 2; /* skip over :: (in case we are done) */ iGroup += 2; /* current field and the zero in the next */ break; } } } } if (iGroup != 8) { /* * iGroup is the first group that can be filled by the part of * the address after "::". */ RTNETADDRIPV6 ipv6Tail; const int iMaybeStart = iGroup; int j; memset(&ipv6Tail, 0, sizeof(ipv6Tail)); /* * We try to accept longest match; we'll shift if necessary. * Unlike the first loop, a failure to parse a group doesn't * mean invalid address. */ for (; iGroup < 8; ++iGroup) { /* check for embedded IPv4 at the end */ if (iGroup <= 6) { rc = rtNetStrToIPv4AddrEx(pcszPos, &ipv4, &pszNext); if (rc == VINF_SUCCESS) { ipv6Tail.au16[iGroup] = ipv4.au16[0]; ipv6Tail.au16[iGroup + 1] = ipv4.au16[1]; iGroup = iGroup + 2; /* these two are done */ break; /* the rest is trailer */ } } rc = rtNetStrToHexGroup(pcszPos, &pszNext, &u16); if (RT_FAILURE(rc)) break; ipv6Tail.au16[iGroup] = RT_H2N_U16(u16); if (iGroup == 7) pcszPos = pszNext; else { if (*pszNext != ':') { ++iGroup; /* this one is done */ break; /* the rest is trailer */ } pcszPos = pszNext + 1; } } for (j = 7, --iGroup; iGroup >= iMaybeStart; --j, --iGroup) ipv6.au16[j] = ipv6Tail.au16[iGroup]; } if (pAddrResult != NULL) memcpy(pAddrResult, &ipv6, sizeof(ipv6)); if (ppszNext != NULL) *ppszNext = pszNext; return VINF_SUCCESS; }