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; }
static int tftp_send_oack(PNATState pData, struct tftp_session *spt, const char *key, uint32_t value, struct tftp_t *recv_tp) { struct sockaddr_in saddr, daddr; struct mbuf *m; struct tftp_t *tp; int n = 0; 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_OACK); n += RTStrPrintf((char *)tp->x.tp_buf + n, M_TRAILINGSPACE(m), "%s", key) + 1; n += RTStrPrintf((char *)tp->x.tp_buf + n, M_TRAILINGSPACE(m), "%u", value) + 1; 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; m->m_len = sizeof(struct tftp_t) - 514 + n - sizeof(struct ip) - sizeof(struct udphdr); udp_output2(pData, NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); return 0; }
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; }
DECLINLINE(int) tftpSendOACK(PNATState pData, PTFTPSESSION pTftpSession, PCTFTPIPHDR pcTftpIpHeaderRecv) { struct mbuf *m; PTFTPIPHDR pTftpIpHeader; int rc = VINF_SUCCESS; rc = tftpSessionEvaluateOptions(pData, pTftpSession); if (RT_FAILURE(rc)) { tftpSendError(pData, pTftpSession, 2, "Internal Error (blksize evaluation)", pcTftpIpHeaderRecv); LogFlowFuncLeave(); 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) - sizeof(uint16_t); /* no u16TftpOpCode */ pTftpIpHeader->u16TftpOpType = RT_H2N_U16_C(TFTP_OACK); if (pTftpSession->OptionBlkSize.fRequested) { if (pTftpSession->OptionBlkSize.u64Value > UINT16_MAX) rc = VERR_INVALID_PARAMETER; else rc = tftpAddOptionToOACK(pData, m, "blksize", pTftpSession->OptionBlkSize.u64Value); } if ( RT_SUCCESS(rc) && pTftpSession->OptionTSize.fRequested) rc = tftpAddOptionToOACK(pData, m, "tsize", pTftpSession->OptionTSize.u64Value); rc = tftpSend(pData, pTftpSession, m, pcTftpIpHeaderRecv); return RT_SUCCESS(rc) ? 0 : -1; }