qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Samuel Thibault <samuel.thibault@gnu.org>
To: Thomas Huth <thuth@redhat.com>
Cc: jan.kiszka@siemens.com, jasowang@redhat.com, qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [PATCH v2] slirp: Add IPv6 support to the TFTP code
Date: Wed, 17 Feb 2016 09:42:25 +0100	[thread overview]
Message-ID: <20160217084225.GO2656@var.home> (raw)
In-Reply-To: <1455698410-13191-1-git-send-email-thuth@redhat.com>

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 <thuth@redhat.com>

Reviewed-by: Samuel Thibault <samuel.thibault@ens-lyon.org>

> ---
>  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

      reply	other threads:[~2016-02-17  8:42 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-02-14 17:47 [Qemu-devel] [PATCHv8 0/9] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 1/9] slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration Samuel Thibault
2016-02-16 11:36   ` Thomas Huth
2016-02-19 13:57   ` Thomas Huth
2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 2/9] slirp: Adding ICMPv6 error sending Samuel Thibault
2016-02-16 12:21   ` Thomas Huth
2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 3/9] slirp: Adding IPv6 UDP support Samuel Thibault
2016-02-16 12:28   ` Thomas Huth
2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 4/9] slirp: Factorizing tcpiphdr structure with an union Samuel Thibault
2016-02-19  0:36   ` Samuel Thibault
2016-02-19 13:44   ` Thomas Huth
2016-02-22  1:48     ` Samuel Thibault
2016-02-22  7:56       ` Thomas Huth
2016-02-22 10:20         ` Samuel Thibault
2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 5/9] slirp: Generalizing and neutralizing various TCP functions before adding IPv6 stuff Samuel Thibault
2016-02-17  8:25   ` Thomas Huth
2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 6/9] slirp: Reindent after refactoring Samuel Thibault
2016-02-17  9:03   ` Thomas Huth
2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 7/9] slirp: Handle IPv6 in TCP functions Samuel Thibault
2016-02-17  9:18   ` Thomas Huth
2016-02-17  9:30     ` Samuel Thibault
2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 8/9] slirp: Adding IPv6 address for DNS relay Samuel Thibault
2016-02-17  9:28   ` Thomas Huth
2016-02-17  9:36     ` Samuel Thibault
2016-02-19  0:26       ` Samuel Thibault
2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 9/9] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses Samuel Thibault
2016-02-17 11:59   ` Thomas Huth
2016-02-19  0:35     ` Samuel Thibault
2016-02-16  8:47 ` [Qemu-devel] [PATCH] slirp: Add IPv6 support to the TFTP code Thomas Huth
2016-02-16 10:30   ` Samuel Thibault
2016-02-16 12:09     ` Thomas Huth
2016-02-17  8:40   ` [Qemu-devel] [PATCH v2] " Thomas Huth
2016-02-17  8:42     ` Samuel Thibault [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20160217084225.GO2656@var.home \
    --to=samuel.thibault@gnu.org \
    --cc=jan.kiszka@siemens.com \
    --cc=jasowang@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=thuth@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).