[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH v2] slirp: Add IPv6 support to the TFTP code
From: |
Samuel Thibault |
Subject: |
Re: [Qemu-devel] [PATCH v2] slirp: Add IPv6 support to the TFTP code |
Date: |
Wed, 17 Feb 2016 09:42:25 +0100 |
User-agent: |
Mutt/1.5.21+34 (58baf7c9f32f) (2010-12-30) |
Thomas Huth, on Wed 17 Feb 2016 09:40:10 +0100, wrote:
> Add the handler code for incoming TFTP packets to udp6_input(),
> and make sure that the TFTP code can send packets with both,
> udp_output() and udp6_output() by introducing a wrapper function
> called tftp_udp_output().
>
> Signed-off-by: Thomas Huth <address@hidden>
Reviewed-by: Samuel Thibault <address@hidden>
> ---
> v2: Changes according to the review of Samuel Thibault:
> - Use the "slirp" parameter as the first parameter
> - Use structure assignments instead of memcpy()
>
> This patch has to be applied on top of Samuel's "slirp: Adding IPv6
> support to Qemu -net user mode" patch series.
> Samuel, if you respin your patch series and if you think this patch
> is ok, feel free to also include it in your series.
>
> Code has been tested with network booting in SLOF:
>
> qemu-system-ppc64 -vga none -device virtio-net,netdev=mynet \
> -netdev user,id=mynet,tftp=/home/thuth/tmp/tftp -nographic
>
> ... and then, at the Open Firmware prompt, type:
>
> boot net:ipv6,fec0::2,zImage,fec0::1234
> ---
> slirp/tftp.c | 133
> +++++++++++++++++++++++++++++++++--------------------------
> slirp/tftp.h | 7 ++--
> slirp/udp.c | 16 ++++---
> slirp/udp6.c | 16 +++++--
> 4 files changed, 100 insertions(+), 72 deletions(-)
>
> diff --git a/slirp/tftp.c b/slirp/tftp.c
> index abb0106..7d70504 100644
> --- a/slirp/tftp.c
> +++ b/slirp/tftp.c
> @@ -46,7 +46,8 @@ static void tftp_session_terminate(struct tftp_session *spt)
> spt->slirp = NULL;
> }
>
> -static int tftp_session_allocate(Slirp *slirp, struct tftp_t *tp)
> +static int tftp_session_allocate(Slirp *slirp, struct sockaddr_storage
> *srcsas,
> + struct tftp_t *tp)
> {
> struct tftp_session *spt;
> int k;
> @@ -68,7 +69,7 @@ static int tftp_session_allocate(Slirp *slirp, struct
> tftp_t *tp)
>
> found:
> memset(spt, 0, sizeof(*spt));
> - memcpy(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip));
> + spt->client_addr = *srcsas;
> spt->fd = -1;
> spt->client_port = tp->udp.uh_sport;
> spt->slirp = slirp;
> @@ -78,7 +79,8 @@ static int tftp_session_allocate(Slirp *slirp, struct
> tftp_t *tp)
> return k;
> }
>
> -static int tftp_session_find(Slirp *slirp, struct tftp_t *tp)
> +static int tftp_session_find(Slirp *slirp, struct sockaddr_storage *srcsas,
> + struct tftp_t *tp)
> {
> struct tftp_session *spt;
> int k;
> @@ -87,7 +89,7 @@ static int tftp_session_find(Slirp *slirp, struct tftp_t
> *tp)
> spt = &slirp->tftp_sessions[k];
>
> if (tftp_session_in_use(spt)) {
> - if (!memcmp(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip))) {
> + if (sockaddr_equal(&spt->client_addr, srcsas)) {
> if (spt->client_port == tp->udp.uh_sport) {
> return k;
> }
> @@ -120,11 +122,53 @@ static int tftp_read_data(struct tftp_session *spt,
> uint32_t block_nr,
> return bytes_read;
> }
>
> +static struct tftp_t *tftp_prep_mbuf_data(struct tftp_session *spt,
> + struct mbuf *m)
> +{
> + struct tftp_t *tp;
> +
> + memset(m->m_data, 0, m->m_size);
> +
> + m->m_data += IF_MAXLINKHDR;
> + if (spt->client_addr.ss_family == AF_INET6) {
> + m->m_data += sizeof(struct ip6);
> + } else {
> + m->m_data += sizeof(struct ip);
> + }
> + tp = (void *)m->m_data;
> + m->m_data += sizeof(struct udphdr);
> +
> + return tp;
> +}
> +
> +static void tftp_udp_output(struct tftp_session *spt, struct mbuf *m,
> + struct tftp_t *recv_tp)
> +{
> + if (spt->client_addr.ss_family == AF_INET6) {
> + struct sockaddr_in6 sa6, da6;
> +
> + sa6.sin6_addr = spt->slirp->vhost_addr6;
> + sa6.sin6_port = recv_tp->udp.uh_dport;
> + da6.sin6_addr = ((struct sockaddr_in6
> *)&spt->client_addr)->sin6_addr;
> + da6.sin6_port = spt->client_port;
> +
> + udp6_output(NULL, m, &sa6, &da6);
> + } else {
> + struct sockaddr_in sa4, da4;
> +
> + sa4.sin_addr = spt->slirp->vhost_addr;
> + sa4.sin_port = recv_tp->udp.uh_dport;
> + da4.sin_addr = ((struct sockaddr_in *)&spt->client_addr)->sin_addr;
> + da4.sin_port = spt->client_port;
> +
> + udp_output(NULL, m, &sa4, &da4, IPTOS_LOWDELAY);
> + }
> +}
> +
> static int tftp_send_oack(struct tftp_session *spt,
> const char *keys[], uint32_t values[], int nb,
> struct tftp_t *recv_tp)
> {
> - struct sockaddr_in saddr, daddr;
> struct mbuf *m;
> struct tftp_t *tp;
> int i, n = 0;
> @@ -132,13 +176,9 @@ static int tftp_send_oack(struct tftp_session *spt,
> m = m_get(spt->slirp);
>
> if (!m)
> - return -1;
> -
> - memset(m->m_data, 0, m->m_size);
> + return -1;
>
> - m->m_data += IF_MAXLINKHDR;
> - tp = (void *)m->m_data;
> - m->m_data += sizeof(struct udpiphdr);
> + tp = tftp_prep_mbuf_data(spt, m);
>
> tp->tp_op = htons(TFTP_OACK);
> for (i = 0; i < nb; i++) {
> @@ -148,15 +188,8 @@ static int tftp_send_oack(struct tftp_session *spt,
> values[i]) + 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_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
> + m->m_len = sizeof(struct tftp_t) - 514 + n - sizeof(struct udphdr);
> + tftp_udp_output(spt, m, recv_tp);
>
> return 0;
> }
> @@ -165,7 +198,6 @@ static void tftp_send_error(struct tftp_session *spt,
> uint16_t errorcode, const char *msg,
> struct tftp_t *recv_tp)
> {
> - struct sockaddr_in saddr, daddr;
> struct mbuf *m;
> struct tftp_t *tp;
>
> @@ -177,24 +209,15 @@ static void tftp_send_error(struct tftp_session *spt,
>
> memset(m->m_data, 0, m->m_size);
>
> - m->m_data += IF_MAXLINKHDR;
> - tp = (void *)m->m_data;
> - m->m_data += sizeof(struct udpiphdr);
> + tp = tftp_prep_mbuf_data(spt, m);
>
> tp->tp_op = htons(TFTP_ERROR);
> tp->x.tp_error.tp_error_code = htons(errorcode);
> pstrcpy((char *)tp->x.tp_error.tp_msg, sizeof(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;
> -
> - m->m_len = sizeof(struct tftp_t) - 514 + 3 + strlen(msg) -
> - sizeof(struct ip) - sizeof(struct udphdr);
> -
> - udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
> + m->m_len = sizeof(struct tftp_t) - 514 + 3 + strlen(msg)
> + - sizeof(struct udphdr);
> + tftp_udp_output(spt, m, recv_tp);
>
> out:
> tftp_session_terminate(spt);
> @@ -203,7 +226,6 @@ out:
> static void tftp_send_next_block(struct tftp_session *spt,
> struct tftp_t *recv_tp)
> {
> - struct sockaddr_in saddr, daddr;
> struct mbuf *m;
> struct tftp_t *tp;
> int nobytes;
> @@ -216,19 +238,11 @@ static void tftp_send_next_block(struct tftp_session
> *spt,
>
> memset(m->m_data, 0, m->m_size);
>
> - m->m_data += IF_MAXLINKHDR;
> - tp = (void *)m->m_data;
> - m->m_data += sizeof(struct udpiphdr);
> + tp = tftp_prep_mbuf_data(spt, m);
>
> tp->tp_op = htons(TFTP_DATA);
> tp->x.tp_data.tp_block_nr = htons((spt->block_nr + 1) & 0xffff);
>
> - 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(spt, spt->block_nr, tp->x.tp_data.tp_buf, 512);
>
> if (nobytes < 0) {
> @@ -241,10 +255,8 @@ static void tftp_send_next_block(struct tftp_session
> *spt,
> return;
> }
>
> - m->m_len = sizeof(struct tftp_t) - (512 - nobytes) -
> - sizeof(struct ip) - sizeof(struct udphdr);
> -
> - udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
> + m->m_len = sizeof(struct tftp_t) - (512 - nobytes) - sizeof(struct udphdr);
> + tftp_udp_output(spt, m, recv_tp);
>
> if (nobytes == 512) {
> tftp_session_update(spt);
> @@ -256,7 +268,8 @@ static void tftp_send_next_block(struct tftp_session *spt,
> spt->block_nr++;
> }
>
> -static void tftp_handle_rrq(Slirp *slirp, struct tftp_t *tp, int pktlen)
> +static void tftp_handle_rrq(Slirp *slirp, struct sockaddr_storage *srcsas,
> + struct tftp_t *tp, int pktlen)
> {
> struct tftp_session *spt;
> int s, k;
> @@ -267,12 +280,12 @@ static void tftp_handle_rrq(Slirp *slirp, struct tftp_t
> *tp, int pktlen)
> int nb_options = 0;
>
> /* check if a session already exists and if so terminate it */
> - s = tftp_session_find(slirp, tp);
> + s = tftp_session_find(slirp, srcsas, tp);
> if (s >= 0) {
> tftp_session_terminate(&slirp->tftp_sessions[s]);
> }
>
> - s = tftp_session_allocate(slirp, tp);
> + s = tftp_session_allocate(slirp, srcsas, tp);
>
> if (s < 0) {
> return;
> @@ -397,11 +410,12 @@ static void tftp_handle_rrq(Slirp *slirp, struct tftp_t
> *tp, int pktlen)
> tftp_send_next_block(spt, tp);
> }
>
> -static void tftp_handle_ack(Slirp *slirp, struct tftp_t *tp, int pktlen)
> +static void tftp_handle_ack(Slirp *slirp, struct sockaddr_storage *srcsas,
> + struct tftp_t *tp, int pktlen)
> {
> int s;
>
> - s = tftp_session_find(slirp, tp);
> + s = tftp_session_find(slirp, srcsas, tp);
>
> if (s < 0) {
> return;
> @@ -410,11 +424,12 @@ static void tftp_handle_ack(Slirp *slirp, struct tftp_t
> *tp, int pktlen)
> tftp_send_next_block(&slirp->tftp_sessions[s], tp);
> }
>
> -static void tftp_handle_error(Slirp *slirp, struct tftp_t *tp, int pktlen)
> +static void tftp_handle_error(Slirp *slirp, struct sockaddr_storage *srcsas,
> + struct tftp_t *tp, int pktlen)
> {
> int s;
>
> - s = tftp_session_find(slirp, tp);
> + s = tftp_session_find(slirp, srcsas, tp);
>
> if (s < 0) {
> return;
> @@ -423,21 +438,21 @@ static void tftp_handle_error(Slirp *slirp, struct
> tftp_t *tp, int pktlen)
> tftp_session_terminate(&slirp->tftp_sessions[s]);
> }
>
> -void tftp_input(struct mbuf *m)
> +void tftp_input(struct sockaddr_storage *srcsas, struct mbuf *m)
> {
> struct tftp_t *tp = (struct tftp_t *)m->m_data;
>
> switch(ntohs(tp->tp_op)) {
> case TFTP_RRQ:
> - tftp_handle_rrq(m->slirp, tp, m->m_len);
> + tftp_handle_rrq(m->slirp, srcsas, tp, m->m_len);
> break;
>
> case TFTP_ACK:
> - tftp_handle_ack(m->slirp, tp, m->m_len);
> + tftp_handle_ack(m->slirp, srcsas, tp, m->m_len);
> break;
>
> case TFTP_ERROR:
> - tftp_handle_error(m->slirp, tp, m->m_len);
> + tftp_handle_error(m->slirp, srcsas, tp, m->m_len);
> break;
> }
> }
> diff --git a/slirp/tftp.h b/slirp/tftp.h
> index e1cc24b..1cb1adf 100644
> --- a/slirp/tftp.h
> +++ b/slirp/tftp.h
> @@ -16,7 +16,6 @@
> #define TFTP_FILENAME_MAX 512
>
> struct tftp_t {
> - struct ip ip;
> struct udphdr udp;
> uint16_t tp_op;
> union {
> @@ -30,20 +29,20 @@ struct tftp_t {
> } tp_error;
> char tp_buf[512 + 2];
> } x;
> -};
> +} __attribute__((packed));
>
> struct tftp_session {
> Slirp *slirp;
> char *filename;
> int fd;
>
> - struct in_addr client_ip;
> + struct sockaddr_storage client_addr;
> uint16_t client_port;
> uint32_t block_nr;
>
> int timestamp;
> };
>
> -void tftp_input(struct mbuf *m);
> +void tftp_input(struct sockaddr_storage *srcsas, struct mbuf *m);
>
> #endif
> diff --git a/slirp/udp.c b/slirp/udp.c
> index be012fb..247024f 100644
> --- a/slirp/udp.c
> +++ b/slirp/udp.c
> @@ -128,6 +128,11 @@ udp_input(register struct mbuf *m, int iphlen)
> }
> }
>
> + lhost.ss_family = AF_INET;
> + lhost4 = (struct sockaddr_in *) &lhost;
> + lhost4->sin_addr = ip->ip_src;
> + lhost4->sin_port = uh->uh_sport;
> +
> /*
> * handle DHCP/BOOTP
> */
> @@ -143,7 +148,11 @@ udp_input(register struct mbuf *m, int iphlen)
> */
> if (ntohs(uh->uh_dport) == TFTP_SERVER &&
> ip->ip_dst.s_addr == slirp->vhost_addr.s_addr) {
> - tftp_input(m);
> + m->m_data += iphlen;
> + m->m_len -= iphlen;
> + tftp_input(&lhost, m);
> + m->m_data -= iphlen;
> + m->m_len += iphlen;
> goto bad;
> }
>
> @@ -154,11 +163,6 @@ udp_input(register struct mbuf *m, int iphlen)
> /*
> * Locate pcb for datagram.
> */
> - lhost.ss_family = AF_INET;
> - lhost4 = (struct sockaddr_in *) &lhost;
> - lhost4->sin_addr = ip->ip_src;
> - lhost4->sin_port = uh->uh_sport;
> -
> so = solookup(&slirp->udp_last_so, &slirp->udb, &lhost, NULL);
>
> if (so == NULL) {
> diff --git a/slirp/udp6.c b/slirp/udp6.c
> index 6c0d55f..820192a 100644
> --- a/slirp/udp6.c
> +++ b/slirp/udp6.c
> @@ -55,14 +55,24 @@ void udp6_input(struct mbuf *m)
> */
> save_ip = *ip;
>
> - /* TODO handle DHCP/BOOTP */
> - /* TODO handle TFTP */
> -
> /* Locate pcb for datagram. */
> lhost.sin6_family = AF_INET6;
> lhost.sin6_addr = ip->ip_src;
> lhost.sin6_port = uh->uh_sport;
>
> + /* TODO handle DHCP/BOOTP */
> +
> + /* handle TFTP */
> + if (ntohs(uh->uh_dport) == TFTP_SERVER &&
> + !memcmp(ip->ip_dst.s6_addr, slirp->vhost_addr6.s6_addr, 16)) {
> + m->m_data += hlen;
> + m->m_len -= hlen;
> + tftp_input((struct sockaddr_storage *)&lhost, m);
> + m->m_data -= hlen;
> + m->m_len += hlen;
> + goto bad;
> + }
> +
> so = solookup(&slirp->udp_last_so, &slirp->udb,
> (struct sockaddr_storage *) &lhost, NULL);
>
> --
> 1.8.3.1
>
--
Samuel
In mutt, type cthis
Dans mutt, taper cceci