]> git.proxmox.com Git - qemu.git/blobdiff - slirp/udp.c
rng-egd: remove redundant free
[qemu.git] / slirp / udp.c
index 240e1bf38aa9fc35c8a32941983299beee69fccd..8cc6cb66da5e5b666402207cb0af06f95efc8971 100644 (file)
 #include <slirp.h>
 #include "ip_icmp.h"
 
-struct socket udb;
-
-static u_int8_t udp_tos(struct socket *so);
-static void udp_emu(struct socket *so, struct mbuf *m);
-
-struct socket *udp_last_so = &udb;
+static uint8_t udp_tos(struct socket *so);
 
 void
-udp_init(void)
+udp_init(Slirp *slirp)
+{
+    slirp->udb.so_next = slirp->udb.so_prev = &slirp->udb;
+    slirp->udp_last_so = &slirp->udb;
+}
+
+void udp_cleanup(Slirp *slirp)
 {
-       udb.so_next = udb.so_prev = &udb;
+    while (slirp->udb.so_next != &slirp->udb) {
+        udp_detach(slirp->udb.so_next);
+    }
 }
+
 /* m->m_data  points at ip packet header
  * m->m_len   length ip packet
  * ip->ip_len length data (IPDU)
@@ -60,6 +64,7 @@ udp_init(void)
 void
 udp_input(register struct mbuf *m, int iphlen)
 {
+       Slirp *slirp = m->slirp;
        register struct ip *ip;
        register struct udphdr *uh;
        int len;
@@ -91,7 +96,7 @@ udp_input(register struct mbuf *m, int iphlen)
         * Make mbuf data length reflect UDP length.
         * If not enough data to reflect UDP length, drop.
         */
-       len = ntohs((u_int16_t)uh->uh_ulen);
+       len = ntohs((uint16_t)uh->uh_ulen);
 
        if (ip->ip_len != len) {
                if (len > ip->ip_len) {
@@ -123,41 +128,46 @@ udp_input(register struct mbuf *m, int iphlen)
         /*
          *  handle DHCP/BOOTP
          */
-        if (ntohs(uh->uh_dport) == BOOTP_SERVER) {
-            bootp_input(m);
-            goto bad;
-        }
-
-        if (slirp_restrict)
-            goto bad;
+        if (ntohs(uh->uh_dport) == BOOTP_SERVER &&
+            (ip->ip_dst.s_addr == slirp->vhost_addr.s_addr ||
+             ip->ip_dst.s_addr == 0xffffffff)) {
+                bootp_input(m);
+                goto bad;
+            }
 
         /*
          *  handle TFTP
          */
-        if (ntohs(uh->uh_dport) == TFTP_SERVER) {
+        if (ntohs(uh->uh_dport) == TFTP_SERVER &&
+            ip->ip_dst.s_addr == slirp->vhost_addr.s_addr) {
             tftp_input(m);
             goto bad;
         }
 
+        if (slirp->restricted) {
+            goto bad;
+        }
+
        /*
         * Locate pcb for datagram.
         */
-       so = udp_last_so;
+       so = slirp->udp_last_so;
        if (so->so_lport != uh->uh_sport ||
            so->so_laddr.s_addr != ip->ip_src.s_addr) {
                struct socket *tmp;
 
-               for (tmp = udb.so_next; tmp != &udb; tmp = tmp->so_next) {
+               for (tmp = slirp->udb.so_next; tmp != &slirp->udb;
+                    tmp = tmp->so_next) {
                        if (tmp->so_lport == uh->uh_sport &&
                            tmp->so_laddr.s_addr == ip->ip_src.s_addr) {
                                so = tmp;
                                break;
                        }
                }
-               if (tmp == &udb) {
+               if (tmp == &slirp->udb) {
                  so = NULL;
                } else {
-                 udp_last_so = so;
+                 slirp->udp_last_so = so;
                }
        }
 
@@ -166,7 +176,10 @@ udp_input(register struct mbuf *m, int iphlen)
           * If there's no socket for this packet,
           * create one
           */
-         if ((so = socreate()) == NULL) goto bad;
+         so = socreate(slirp);
+         if (!so) {
+             goto bad;
+         }
          if(udp_attach(so) == -1) {
            DEBUG_MISC((dfd," udp_attach errno = %d-%s\n",
                        errno,strerror(errno)));
@@ -199,9 +212,6 @@ udp_input(register struct mbuf *m, int iphlen)
        /*
         * Now we sendto() the packet.
         */
-       if (so->so_emu)
-          udp_emu(so, m);
-
        if(sosendto(so,m) == -1) {
          m->m_len += iphlen;
          m->m_data -= iphlen;
@@ -220,8 +230,7 @@ udp_input(register struct mbuf *m, int iphlen)
 
        return;
 bad:
-       m_freem(m);
-       return;
+       m_free(m);
 }
 
 int udp_output2(struct socket *so, struct mbuf *m,
@@ -279,15 +288,18 @@ int udp_output(struct socket *so, struct mbuf *m,
                struct sockaddr_in *addr)
 
 {
+    Slirp *slirp = so->slirp;
     struct sockaddr_in saddr, daddr;
 
     saddr = *addr;
-    if ((so->so_faddr.s_addr & vnetwork_mask.s_addr) == vnetwork_addr.s_addr) {
-        if ((so->so_faddr.s_addr & ~vnetwork_mask.s_addr) ==
-            ~vnetwork_mask.s_addr) {
-            saddr.sin_addr = vhost_addr;
+    if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
+        slirp->vnetwork_addr.s_addr) {
+        uint32_t inv_mask = ~slirp->vnetwork_mask.s_addr;
+
+        if ((so->so_faddr.s_addr & inv_mask) == inv_mask) {
+            saddr.sin_addr = slirp->vhost_addr;
         } else if (addr->sin_addr.s_addr == loopback_addr.s_addr ||
-                   so->so_faddr.s_addr != vhost_addr.s_addr) {
+                   so->so_faddr.s_addr != slirp->vhost_addr.s_addr) {
             saddr.sin_addr = so->so_faddr;
         }
     }
@@ -300,31 +312,9 @@ int udp_output(struct socket *so, struct mbuf *m,
 int
 udp_attach(struct socket *so)
 {
-  struct sockaddr_in addr;
-
-  if((so->s = socket(AF_INET,SOCK_DGRAM,0)) != -1) {
-    /*
-     * Here, we bind() the socket.  Although not really needed
-     * (sendto() on an unbound socket will bind it), it's done
-     * here so that emulation of ytalk etc. don't have to do it
-     */
-    addr.sin_family = AF_INET;
-    addr.sin_port = 0;
-    addr.sin_addr.s_addr = INADDR_ANY;
-    if(bind(so->s, (struct sockaddr *)&addr, sizeof(addr))<0) {
-      int lasterrno=errno;
-      closesocket(so->s);
-      so->s=-1;
-#ifdef _WIN32
-      WSASetLastError(lasterrno);
-#else
-      errno=lasterrno;
-#endif
-    } else {
-      /* success, insert in queue */
-      so->so_expire = curtime + SO_EXPIRE;
-      insque(so,&udb);
-    }
+  if((so->s = qemu_socket(AF_INET,SOCK_DGRAM,0)) != -1) {
+    so->so_expire = curtime + SO_EXPIRE;
+    insque(so, &so->slirp->udb);
   }
   return(so->s);
 }
@@ -338,13 +328,10 @@ udp_detach(struct socket *so)
 
 static const struct tos_t udptos[] = {
        {0, 53, IPTOS_LOWDELAY, 0},                     /* DNS */
-       {517, 517, IPTOS_LOWDELAY, EMU_TALK},   /* talk */
-       {518, 518, IPTOS_LOWDELAY, EMU_NTALK},  /* ntalk */
-       {0, 7648, IPTOS_LOWDELAY, EMU_CUSEEME}, /* Cu-Seeme */
        {0, 0, 0, 0}
 };
 
-static u_int8_t
+static uint8_t
 udp_tos(struct socket *so)
 {
        int i = 0;
@@ -361,254 +348,21 @@ udp_tos(struct socket *so)
        return 0;
 }
 
-#ifdef EMULATE_TALK
-#include "talkd.h"
-#endif
-
-/*
- * Here, talk/ytalk/ntalk requests must be emulated
- */
-static void
-udp_emu(struct socket *so, struct mbuf *m)
-{
-       struct sockaddr_in addr;
-       socklen_t addrlen = sizeof(addr);
-#ifdef EMULATE_TALK
-       CTL_MSG_OLD *omsg;
-       CTL_MSG *nmsg;
-       char buff[sizeof(CTL_MSG)];
-       u_char type;
-
-struct talk_request {
-       struct talk_request *next;
-       struct socket *udp_so;
-       struct socket *tcp_so;
-} *req;
-
-       static struct talk_request *req_tbl = 0;
-
-#endif
-
-struct cu_header {
-       uint16_t        d_family;               // destination family
-       uint16_t        d_port;                 // destination port
-       uint32_t        d_addr;                 // destination address
-       uint16_t        s_family;               // source family
-       uint16_t        s_port;                 // source port
-       uint32_t        so_addr;                // source address
-       uint32_t        seqn;                   // sequence number
-       uint16_t        message;                // message
-       uint16_t        data_type;              // data type
-       uint16_t        pkt_len;                // packet length
-} *cu_head;
-
-       switch(so->so_emu) {
-
-#ifdef EMULATE_TALK
-        case EMU_TALK:
-        case EMU_NTALK:
-               /*
-                * Talk emulation. We always change the ctl_addr to get
-                * some answers from the daemon. When an ANNOUNCE comes,
-                * we send LEAVE_INVITE to the local daemons. Also when a
-                * DELETE comes, we send copies to the local daemons.
-                */
-               if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0)
-                       return;
-
-#define        IS_OLD  (so->so_emu == EMU_TALK)
-
-#define COPY_MSG(dest, src) { dest->type = src->type; \
-                             dest->id_num = src->id_num; \
-                             dest->pid = src->pid; \
-                             dest->addr = src->addr; \
-                             dest->ctl_addr = src->ctl_addr; \
-                             memcpy(&dest->l_name, &src->l_name, NAME_SIZE_OLD); \
-                             memcpy(&dest->r_name, &src->r_name, NAME_SIZE_OLD); \
-                             memcpy(&dest->r_tty, &src->r_tty, TTY_SIZE); }
-
-#define OTOSIN(ptr, field) ((struct sockaddr_in *)&ptr->field)
-/* old_sockaddr to sockaddr_in */
-
-
-               if (IS_OLD) {           /* old talk */
-                       omsg = mtod(m, CTL_MSG_OLD*);
-                       nmsg = (CTL_MSG *) buff;
-                       type = omsg->type;
-                       OTOSIN(omsg, ctl_addr)->sin_port = addr.sin_port;
-                       OTOSIN(omsg, ctl_addr)->sin_addr = our_addr;
-                        pstrcpy(omsg->l_name, NAME_SIZE_OLD, getlogin());
-               } else {                /* new talk */
-                       omsg = (CTL_MSG_OLD *) buff;
-                       nmsg = mtod(m, CTL_MSG *);
-                       type = nmsg->type;
-                       OTOSIN(nmsg, ctl_addr)->sin_port = addr.sin_port;
-                       OTOSIN(nmsg, ctl_addr)->sin_addr = our_addr;
-                        pstrcpy(nmsg->l_name, NAME_SIZE_OLD, getlogin());
-               }
-
-               if (type == LOOK_UP)
-                       return;         /* for LOOK_UP this is enough */
-
-               if (IS_OLD) {           /* make a copy of the message */
-                       COPY_MSG(nmsg, omsg);
-                       nmsg->vers = 1;
-                       nmsg->answer = 0;
-               } else
-                       COPY_MSG(omsg, nmsg);
-
-               /*
-                * If if is an ANNOUNCE message, we go through the
-                * request table to see if a tcp port has already
-                * been redirected for this socket. If not, we solisten()
-                * a new socket and add this entry to the table.
-                * The port number of the tcp socket and our IP
-                * are put to the addr field of the message structures.
-                * Then a LEAVE_INVITE is sent to both local daemon
-                * ports, 517 and 518. This is why we have two copies
-                * of the message, one in old talk and one in new talk
-                * format.
-                */
-
-               if (type == ANNOUNCE) {
-                       int s;
-                       u_short temp_port;
-
-                       for(req = req_tbl; req; req = req->next)
-                               if (so == req->udp_so)
-                                       break;          /* found it */
-
-                       if (!req) {     /* no entry for so, create new */
-                               req = (struct talk_request *)
-                                       malloc(sizeof(struct talk_request));
-                               req->udp_so = so;
-                               req->tcp_so = solisten(0,
-                                       OTOSIN(omsg, addr)->sin_addr.s_addr,
-                                       OTOSIN(omsg, addr)->sin_port,
-                                       SS_FACCEPTONCE);
-                               req->next = req_tbl;
-                               req_tbl = req;
-                       }
-
-                       /* replace port number in addr field */
-                       addrlen = sizeof(addr);
-                       getsockname(req->tcp_so->s,
-                                       (struct sockaddr *) &addr,
-                                       &addrlen);
-                       OTOSIN(omsg, addr)->sin_port = addr.sin_port;
-                       OTOSIN(omsg, addr)->sin_addr = our_addr;
-                       OTOSIN(nmsg, addr)->sin_port = addr.sin_port;
-                       OTOSIN(nmsg, addr)->sin_addr = our_addr;
-
-                       /* send LEAVE_INVITEs */
-                       temp_port = OTOSIN(omsg, ctl_addr)->sin_port;
-                       OTOSIN(omsg, ctl_addr)->sin_port = 0;
-                       OTOSIN(nmsg, ctl_addr)->sin_port = 0;
-                       omsg->type = nmsg->type = LEAVE_INVITE;
-
-                       s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
-                       addr.sin_addr = our_addr;
-                       addr.sin_family = AF_INET;
-                       addr.sin_port = htons(517);
-                       sendto(s, (char *)omsg, sizeof(*omsg), 0,
-                               (struct sockaddr *)&addr, sizeof(addr));
-                       addr.sin_port = htons(518);
-                       sendto(s, (char *)nmsg, sizeof(*nmsg), 0,
-                               (struct sockaddr *) &addr, sizeof(addr));
-                       closesocket(s) ;
-
-                       omsg->type = nmsg->type = ANNOUNCE;
-                       OTOSIN(omsg, ctl_addr)->sin_port = temp_port;
-                       OTOSIN(nmsg, ctl_addr)->sin_port = temp_port;
-               }
-
-               /*
-                * If it is a DELETE message, we send a copy to the
-                * local daemons. Then we delete the entry corresponding
-                * to our socket from the request table.
-                */
-
-               if (type == DELETE) {
-                       struct talk_request *temp_req, *req_next;
-                       int s;
-                       u_short temp_port;
-
-                       temp_port = OTOSIN(omsg, ctl_addr)->sin_port;
-                       OTOSIN(omsg, ctl_addr)->sin_port = 0;
-                       OTOSIN(nmsg, ctl_addr)->sin_port = 0;
-
-                       s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
-                       addr.sin_addr = our_addr;
-                       addr.sin_family = AF_INET;
-                       addr.sin_port = htons(517);
-                       sendto(s, (char *)omsg, sizeof(*omsg), 0,
-                               (struct sockaddr *)&addr, sizeof(addr));
-                       addr.sin_port = htons(518);
-                       sendto(s, (char *)nmsg, sizeof(*nmsg), 0,
-                               (struct sockaddr *)&addr, sizeof(addr));
-                       closesocket(s);
-
-                       OTOSIN(omsg, ctl_addr)->sin_port = temp_port;
-                       OTOSIN(nmsg, ctl_addr)->sin_port = temp_port;
-
-                       /* delete table entry */
-                       if (so == req_tbl->udp_so) {
-                               temp_req = req_tbl;
-                               req_tbl = req_tbl->next;
-                               free(temp_req);
-                       } else {
-                               temp_req = req_tbl;
-                               for(req = req_tbl->next; req; req = req_next) {
-                                       req_next = req->next;
-                                       if (so == req->udp_so) {
-                                               temp_req->next = req_next;
-                                               free(req);
-                                               break;
-                                       } else {
-                                               temp_req = req;
-                                       }
-                               }
-                       }
-               }
-
-               return;
-#endif
-
-       case EMU_CUSEEME:
-
-               /*
-                * Cu-SeeMe emulation.
-                * Hopefully the packet is more that 16 bytes long. We don't
-                * do any other tests, just replace the address and port
-                * fields.
-                */
-               if (m->m_len >= sizeof (*cu_head)) {
-                       if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0)
-                               return;
-                       cu_head = mtod(m, struct cu_header *);
-                       cu_head->s_port = addr.sin_port;
-                       cu_head->so_addr = our_addr.s_addr;
-               }
-
-               return;
-       }
-}
-
 struct socket *
-udp_listen(u_int32_t haddr, u_int hport, u_int32_t laddr, u_int lport,
-           int flags)
+udp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr,
+           u_int lport, int flags)
 {
        struct sockaddr_in addr;
        struct socket *so;
-       socklen_t addrlen = sizeof(struct sockaddr_in), opt = 1;
+       socklen_t addrlen = sizeof(struct sockaddr_in);
 
-       if ((so = socreate()) == NULL) {
-               free(so);
-               return NULL;
+       so = socreate(slirp);
+       if (!so) {
+           return NULL;
        }
-       so->s = socket(AF_INET,SOCK_DGRAM,0);
+       so->s = qemu_socket(AF_INET,SOCK_DGRAM,0);
        so->so_expire = curtime + SO_EXPIRE;
-       insque(so,&udb);
+       insque(so, &slirp->udb);
 
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = haddr;
@@ -618,13 +372,13 @@ udp_listen(u_int32_t haddr, u_int hport, u_int32_t laddr, u_int lport,
                udp_detach(so);
                return NULL;
        }
-       setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
+       socket_set_fast_reuse(so->s);
 
        getsockname(so->s,(struct sockaddr *)&addr,&addrlen);
        so->so_fport = addr.sin_port;
        if (addr.sin_addr.s_addr == 0 ||
            addr.sin_addr.s_addr == loopback_addr.s_addr) {
-          so->so_faddr = vhost_addr;
+          so->so_faddr = slirp->vhost_addr;
        } else {
           so->so_faddr = addr.sin_addr;
        }