]> Git Repo - qemu.git/blob - slirp/udp.c
slirp: Drop dead code
[qemu.git] / slirp / udp.c
1 /*
2  * Copyright (c) 1982, 1986, 1988, 1990, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  *      @(#)udp_usrreq.c        8.4 (Berkeley) 1/21/94
30  * udp_usrreq.c,v 1.4 1994/10/02 17:48:45 phk Exp
31  */
32
33 /*
34  * Changes and additions relating to SLiRP
35  * Copyright (c) 1995 Danny Gasparovski.
36  *
37  * Please read the file COPYRIGHT for the
38  * terms and conditions of the copyright.
39  */
40
41 #include <slirp.h>
42 #include "ip_icmp.h"
43
44 #ifdef LOG_ENABLED
45 struct udpstat udpstat;
46 #endif
47
48 struct socket udb;
49
50 static u_int8_t udp_tos(struct socket *so);
51 static void udp_emu(struct socket *so, struct mbuf *m);
52
53 struct  socket *udp_last_so = &udb;
54
55 void
56 udp_init(void)
57 {
58         udb.so_next = udb.so_prev = &udb;
59 }
60 /* m->m_data  points at ip packet header
61  * m->m_len   length ip packet
62  * ip->ip_len length data (IPDU)
63  */
64 void
65 udp_input(register struct mbuf *m, int iphlen)
66 {
67         register struct ip *ip;
68         register struct udphdr *uh;
69         int len;
70         struct ip save_ip;
71         struct socket *so;
72
73         DEBUG_CALL("udp_input");
74         DEBUG_ARG("m = %lx", (long)m);
75         DEBUG_ARG("iphlen = %d", iphlen);
76
77         STAT(udpstat.udps_ipackets++);
78
79         /*
80          * Strip IP options, if any; should skip this,
81          * make available to user, and use on returned packets,
82          * but we don't yet have a way to check the checksum
83          * with options still present.
84          */
85         if(iphlen > sizeof(struct ip)) {
86                 ip_stripoptions(m, (struct mbuf *)0);
87                 iphlen = sizeof(struct ip);
88         }
89
90         /*
91          * Get IP and UDP header together in first mbuf.
92          */
93         ip = mtod(m, struct ip *);
94         uh = (struct udphdr *)((caddr_t)ip + iphlen);
95
96         /*
97          * Make mbuf data length reflect UDP length.
98          * If not enough data to reflect UDP length, drop.
99          */
100         len = ntohs((u_int16_t)uh->uh_ulen);
101
102         if (ip->ip_len != len) {
103                 if (len > ip->ip_len) {
104                         STAT(udpstat.udps_badlen++);
105                         goto bad;
106                 }
107                 m_adj(m, len - ip->ip_len);
108                 ip->ip_len = len;
109         }
110
111         /*
112          * Save a copy of the IP header in case we want restore it
113          * for sending an ICMP error message in response.
114          */
115         save_ip = *ip;
116         save_ip.ip_len+= iphlen;         /* tcp_input subtracts this */
117
118         /*
119          * Checksum extended UDP header and data.
120          */
121         if (uh->uh_sum) {
122       memset(&((struct ipovly *)ip)->ih_mbuf, 0, sizeof(struct mbuf_ptr));
123           ((struct ipovly *)ip)->ih_x1 = 0;
124           ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
125           if(cksum(m, len + sizeof(struct ip))) {
126             STAT(udpstat.udps_badsum++);
127             goto bad;
128           }
129         }
130
131         /*
132          *  handle DHCP/BOOTP
133          */
134         if (ntohs(uh->uh_dport) == BOOTP_SERVER) {
135             bootp_input(m);
136             goto bad;
137         }
138
139         if (slirp_restrict)
140             goto bad;
141
142         /*
143          *  handle TFTP
144          */
145         if (ntohs(uh->uh_dport) == TFTP_SERVER) {
146             tftp_input(m);
147             goto bad;
148         }
149
150         /*
151          * Locate pcb for datagram.
152          */
153         so = udp_last_so;
154         if (so->so_lport != uh->uh_sport ||
155             so->so_laddr.s_addr != ip->ip_src.s_addr) {
156                 struct socket *tmp;
157
158                 for (tmp = udb.so_next; tmp != &udb; tmp = tmp->so_next) {
159                         if (tmp->so_lport == uh->uh_sport &&
160                             tmp->so_laddr.s_addr == ip->ip_src.s_addr) {
161                                 so = tmp;
162                                 break;
163                         }
164                 }
165                 if (tmp == &udb) {
166                   so = NULL;
167                 } else {
168                   STAT(udpstat.udpps_pcbcachemiss++);
169                   udp_last_so = so;
170                 }
171         }
172
173         if (so == NULL) {
174           /*
175            * If there's no socket for this packet,
176            * create one
177            */
178           if ((so = socreate()) == NULL) goto bad;
179           if(udp_attach(so) == -1) {
180             DEBUG_MISC((dfd," udp_attach errno = %d-%s\n",
181                         errno,strerror(errno)));
182             sofree(so);
183             goto bad;
184           }
185
186           /*
187            * Setup fields
188            */
189           so->so_laddr = ip->ip_src;
190           so->so_lport = uh->uh_sport;
191
192           if ((so->so_iptos = udp_tos(so)) == 0)
193             so->so_iptos = ip->ip_tos;
194
195           /*
196            * XXXXX Here, check if it's in udpexec_list,
197            * and if it is, do the fork_exec() etc.
198            */
199         }
200
201         so->so_faddr = ip->ip_dst; /* XXX */
202         so->so_fport = uh->uh_dport; /* XXX */
203
204         iphlen += sizeof(struct udphdr);
205         m->m_len -= iphlen;
206         m->m_data += iphlen;
207
208         /*
209          * Now we sendto() the packet.
210          */
211         if (so->so_emu)
212            udp_emu(so, m);
213
214         if(sosendto(so,m) == -1) {
215           m->m_len += iphlen;
216           m->m_data -= iphlen;
217           *ip=save_ip;
218           DEBUG_MISC((dfd,"udp tx errno = %d-%s\n",errno,strerror(errno)));
219           icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
220         }
221
222         m_free(so->so_m);   /* used for ICMP if error on sorecvfrom */
223
224         /* restore the orig mbuf packet */
225         m->m_len += iphlen;
226         m->m_data -= iphlen;
227         *ip=save_ip;
228         so->so_m=m;         /* ICMP backup */
229
230         return;
231 bad:
232         m_freem(m);
233         return;
234 }
235
236 int udp_output2(struct socket *so, struct mbuf *m,
237                 struct sockaddr_in *saddr, struct sockaddr_in *daddr,
238                 int iptos)
239 {
240         register struct udpiphdr *ui;
241         int error = 0;
242
243         DEBUG_CALL("udp_output");
244         DEBUG_ARG("so = %lx", (long)so);
245         DEBUG_ARG("m = %lx", (long)m);
246         DEBUG_ARG("saddr = %lx", (long)saddr->sin_addr.s_addr);
247         DEBUG_ARG("daddr = %lx", (long)daddr->sin_addr.s_addr);
248
249         /*
250          * Adjust for header
251          */
252         m->m_data -= sizeof(struct udpiphdr);
253         m->m_len += sizeof(struct udpiphdr);
254
255         /*
256          * Fill in mbuf with extended UDP header
257          * and addresses and length put into network format.
258          */
259         ui = mtod(m, struct udpiphdr *);
260     memset(&ui->ui_i.ih_mbuf, 0 , sizeof(struct mbuf_ptr));
261         ui->ui_x1 = 0;
262         ui->ui_pr = IPPROTO_UDP;
263         ui->ui_len = htons(m->m_len - sizeof(struct ip));
264         /* XXXXX Check for from-one-location sockets, or from-any-location sockets */
265         ui->ui_src = saddr->sin_addr;
266         ui->ui_dst = daddr->sin_addr;
267         ui->ui_sport = saddr->sin_port;
268         ui->ui_dport = daddr->sin_port;
269         ui->ui_ulen = ui->ui_len;
270
271         /*
272          * Stuff checksum and output datagram.
273          */
274         ui->ui_sum = 0;
275         if ((ui->ui_sum = cksum(m, m->m_len)) == 0)
276                 ui->ui_sum = 0xffff;
277         ((struct ip *)ui)->ip_len = m->m_len;
278
279         ((struct ip *)ui)->ip_ttl = IPDEFTTL;
280         ((struct ip *)ui)->ip_tos = iptos;
281
282         STAT(udpstat.udps_opackets++);
283
284         error = ip_output(so, m);
285
286         return (error);
287 }
288
289 int udp_output(struct socket *so, struct mbuf *m,
290                struct sockaddr_in *addr)
291
292 {
293     struct sockaddr_in saddr, daddr;
294
295     saddr = *addr;
296     if ((so->so_faddr.s_addr & vnetwork_mask.s_addr) == vnetwork_addr.s_addr) {
297         if ((so->so_faddr.s_addr & ~vnetwork_mask.s_addr) ==
298             ~vnetwork_mask.s_addr) {
299             saddr.sin_addr = vhost_addr;
300         } else if (addr->sin_addr.s_addr == loopback_addr.s_addr ||
301                    so->so_faddr.s_addr != vhost_addr.s_addr) {
302             saddr.sin_addr = so->so_faddr;
303         }
304     }
305     daddr.sin_addr = so->so_laddr;
306     daddr.sin_port = so->so_lport;
307
308     return udp_output2(so, m, &saddr, &daddr, so->so_iptos);
309 }
310
311 int
312 udp_attach(struct socket *so)
313 {
314   struct sockaddr_in addr;
315
316   if((so->s = socket(AF_INET,SOCK_DGRAM,0)) != -1) {
317     /*
318      * Here, we bind() the socket.  Although not really needed
319      * (sendto() on an unbound socket will bind it), it's done
320      * here so that emulation of ytalk etc. don't have to do it
321      */
322     addr.sin_family = AF_INET;
323     addr.sin_port = 0;
324     addr.sin_addr.s_addr = INADDR_ANY;
325     if(bind(so->s, (struct sockaddr *)&addr, sizeof(addr))<0) {
326       int lasterrno=errno;
327       closesocket(so->s);
328       so->s=-1;
329 #ifdef _WIN32
330       WSASetLastError(lasterrno);
331 #else
332       errno=lasterrno;
333 #endif
334     } else {
335       /* success, insert in queue */
336       so->so_expire = curtime + SO_EXPIRE;
337       insque(so,&udb);
338     }
339   }
340   return(so->s);
341 }
342
343 void
344 udp_detach(struct socket *so)
345 {
346         closesocket(so->s);
347         sofree(so);
348 }
349
350 static const struct tos_t udptos[] = {
351         {0, 53, IPTOS_LOWDELAY, 0},                     /* DNS */
352         {517, 517, IPTOS_LOWDELAY, EMU_TALK},   /* talk */
353         {518, 518, IPTOS_LOWDELAY, EMU_NTALK},  /* ntalk */
354         {0, 7648, IPTOS_LOWDELAY, EMU_CUSEEME}, /* Cu-Seeme */
355         {0, 0, 0, 0}
356 };
357
358 static u_int8_t
359 udp_tos(struct socket *so)
360 {
361         int i = 0;
362
363         while(udptos[i].tos) {
364                 if ((udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport) ||
365                     (udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport)) {
366                         so->so_emu = udptos[i].emu;
367                         return udptos[i].tos;
368                 }
369                 i++;
370         }
371
372         return 0;
373 }
374
375 #ifdef EMULATE_TALK
376 #include "talkd.h"
377 #endif
378
379 /*
380  * Here, talk/ytalk/ntalk requests must be emulated
381  */
382 static void
383 udp_emu(struct socket *so, struct mbuf *m)
384 {
385         struct sockaddr_in addr;
386         socklen_t addrlen = sizeof(addr);
387 #ifdef EMULATE_TALK
388         CTL_MSG_OLD *omsg;
389         CTL_MSG *nmsg;
390         char buff[sizeof(CTL_MSG)];
391         u_char type;
392
393 struct talk_request {
394         struct talk_request *next;
395         struct socket *udp_so;
396         struct socket *tcp_so;
397 } *req;
398
399         static struct talk_request *req_tbl = 0;
400
401 #endif
402
403 struct cu_header {
404         uint16_t        d_family;               // destination family
405         uint16_t        d_port;                 // destination port
406         uint32_t        d_addr;                 // destination address
407         uint16_t        s_family;               // source family
408         uint16_t        s_port;                 // source port
409         uint32_t        so_addr;                // source address
410         uint32_t        seqn;                   // sequence number
411         uint16_t        message;                // message
412         uint16_t        data_type;              // data type
413         uint16_t        pkt_len;                // packet length
414 } *cu_head;
415
416         switch(so->so_emu) {
417
418 #ifdef EMULATE_TALK
419          case EMU_TALK:
420          case EMU_NTALK:
421                 /*
422                  * Talk emulation. We always change the ctl_addr to get
423                  * some answers from the daemon. When an ANNOUNCE comes,
424                  * we send LEAVE_INVITE to the local daemons. Also when a
425                  * DELETE comes, we send copies to the local daemons.
426                  */
427                 if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0)
428                         return;
429
430 #define IS_OLD  (so->so_emu == EMU_TALK)
431
432 #define COPY_MSG(dest, src) { dest->type = src->type; \
433                               dest->id_num = src->id_num; \
434                               dest->pid = src->pid; \
435                               dest->addr = src->addr; \
436                               dest->ctl_addr = src->ctl_addr; \
437                               memcpy(&dest->l_name, &src->l_name, NAME_SIZE_OLD); \
438                               memcpy(&dest->r_name, &src->r_name, NAME_SIZE_OLD); \
439                               memcpy(&dest->r_tty, &src->r_tty, TTY_SIZE); }
440
441 #define OTOSIN(ptr, field) ((struct sockaddr_in *)&ptr->field)
442 /* old_sockaddr to sockaddr_in */
443
444
445                 if (IS_OLD) {           /* old talk */
446                         omsg = mtod(m, CTL_MSG_OLD*);
447                         nmsg = (CTL_MSG *) buff;
448                         type = omsg->type;
449                         OTOSIN(omsg, ctl_addr)->sin_port = addr.sin_port;
450                         OTOSIN(omsg, ctl_addr)->sin_addr = our_addr;
451                         pstrcpy(omsg->l_name, NAME_SIZE_OLD, getlogin());
452                 } else {                /* new talk */
453                         omsg = (CTL_MSG_OLD *) buff;
454                         nmsg = mtod(m, CTL_MSG *);
455                         type = nmsg->type;
456                         OTOSIN(nmsg, ctl_addr)->sin_port = addr.sin_port;
457                         OTOSIN(nmsg, ctl_addr)->sin_addr = our_addr;
458                         pstrcpy(nmsg->l_name, NAME_SIZE_OLD, getlogin());
459                 }
460
461                 if (type == LOOK_UP)
462                         return;         /* for LOOK_UP this is enough */
463
464                 if (IS_OLD) {           /* make a copy of the message */
465                         COPY_MSG(nmsg, omsg);
466                         nmsg->vers = 1;
467                         nmsg->answer = 0;
468                 } else
469                         COPY_MSG(omsg, nmsg);
470
471                 /*
472                  * If if is an ANNOUNCE message, we go through the
473                  * request table to see if a tcp port has already
474                  * been redirected for this socket. If not, we solisten()
475                  * a new socket and add this entry to the table.
476                  * The port number of the tcp socket and our IP
477                  * are put to the addr field of the message structures.
478                  * Then a LEAVE_INVITE is sent to both local daemon
479                  * ports, 517 and 518. This is why we have two copies
480                  * of the message, one in old talk and one in new talk
481                  * format.
482                  */
483
484                 if (type == ANNOUNCE) {
485                         int s;
486                         u_short temp_port;
487
488                         for(req = req_tbl; req; req = req->next)
489                                 if (so == req->udp_so)
490                                         break;          /* found it */
491
492                         if (!req) {     /* no entry for so, create new */
493                                 req = (struct talk_request *)
494                                         malloc(sizeof(struct talk_request));
495                                 req->udp_so = so;
496                                 req->tcp_so = solisten(0,
497                                         OTOSIN(omsg, addr)->sin_addr.s_addr,
498                                         OTOSIN(omsg, addr)->sin_port,
499                                         SS_FACCEPTONCE);
500                                 req->next = req_tbl;
501                                 req_tbl = req;
502                         }
503
504                         /* replace port number in addr field */
505                         addrlen = sizeof(addr);
506                         getsockname(req->tcp_so->s,
507                                         (struct sockaddr *) &addr,
508                                         &addrlen);
509                         OTOSIN(omsg, addr)->sin_port = addr.sin_port;
510                         OTOSIN(omsg, addr)->sin_addr = our_addr;
511                         OTOSIN(nmsg, addr)->sin_port = addr.sin_port;
512                         OTOSIN(nmsg, addr)->sin_addr = our_addr;
513
514                         /* send LEAVE_INVITEs */
515                         temp_port = OTOSIN(omsg, ctl_addr)->sin_port;
516                         OTOSIN(omsg, ctl_addr)->sin_port = 0;
517                         OTOSIN(nmsg, ctl_addr)->sin_port = 0;
518                         omsg->type = nmsg->type = LEAVE_INVITE;
519
520                         s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
521                         addr.sin_addr = our_addr;
522                         addr.sin_family = AF_INET;
523                         addr.sin_port = htons(517);
524                         sendto(s, (char *)omsg, sizeof(*omsg), 0,
525                                 (struct sockaddr *)&addr, sizeof(addr));
526                         addr.sin_port = htons(518);
527                         sendto(s, (char *)nmsg, sizeof(*nmsg), 0,
528                                 (struct sockaddr *) &addr, sizeof(addr));
529                         closesocket(s) ;
530
531                         omsg->type = nmsg->type = ANNOUNCE;
532                         OTOSIN(omsg, ctl_addr)->sin_port = temp_port;
533                         OTOSIN(nmsg, ctl_addr)->sin_port = temp_port;
534                 }
535
536                 /*
537                  * If it is a DELETE message, we send a copy to the
538                  * local daemons. Then we delete the entry corresponding
539                  * to our socket from the request table.
540                  */
541
542                 if (type == DELETE) {
543                         struct talk_request *temp_req, *req_next;
544                         int s;
545                         u_short temp_port;
546
547                         temp_port = OTOSIN(omsg, ctl_addr)->sin_port;
548                         OTOSIN(omsg, ctl_addr)->sin_port = 0;
549                         OTOSIN(nmsg, ctl_addr)->sin_port = 0;
550
551                         s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
552                         addr.sin_addr = our_addr;
553                         addr.sin_family = AF_INET;
554                         addr.sin_port = htons(517);
555                         sendto(s, (char *)omsg, sizeof(*omsg), 0,
556                                 (struct sockaddr *)&addr, sizeof(addr));
557                         addr.sin_port = htons(518);
558                         sendto(s, (char *)nmsg, sizeof(*nmsg), 0,
559                                 (struct sockaddr *)&addr, sizeof(addr));
560                         closesocket(s);
561
562                         OTOSIN(omsg, ctl_addr)->sin_port = temp_port;
563                         OTOSIN(nmsg, ctl_addr)->sin_port = temp_port;
564
565                         /* delete table entry */
566                         if (so == req_tbl->udp_so) {
567                                 temp_req = req_tbl;
568                                 req_tbl = req_tbl->next;
569                                 free(temp_req);
570                         } else {
571                                 temp_req = req_tbl;
572                                 for(req = req_tbl->next; req; req = req_next) {
573                                         req_next = req->next;
574                                         if (so == req->udp_so) {
575                                                 temp_req->next = req_next;
576                                                 free(req);
577                                                 break;
578                                         } else {
579                                                 temp_req = req;
580                                         }
581                                 }
582                         }
583                 }
584
585                 return;
586 #endif
587
588         case EMU_CUSEEME:
589
590                 /*
591                  * Cu-SeeMe emulation.
592                  * Hopefully the packet is more that 16 bytes long. We don't
593                  * do any other tests, just replace the address and port
594                  * fields.
595                  */
596                 if (m->m_len >= sizeof (*cu_head)) {
597                         if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0)
598                                 return;
599                         cu_head = mtod(m, struct cu_header *);
600                         cu_head->s_port = addr.sin_port;
601                         cu_head->so_addr = our_addr.s_addr;
602                 }
603
604                 return;
605         }
606 }
607
608 struct socket *
609 udp_listen(u_int32_t haddr, u_int hport, u_int32_t laddr, u_int lport,
610            int flags)
611 {
612         struct sockaddr_in addr;
613         struct socket *so;
614         socklen_t addrlen = sizeof(struct sockaddr_in), opt = 1;
615
616         if ((so = socreate()) == NULL) {
617                 free(so);
618                 return NULL;
619         }
620         so->s = socket(AF_INET,SOCK_DGRAM,0);
621         so->so_expire = curtime + SO_EXPIRE;
622         insque(so,&udb);
623
624         addr.sin_family = AF_INET;
625         addr.sin_addr.s_addr = haddr;
626         addr.sin_port = hport;
627
628         if (bind(so->s,(struct sockaddr *)&addr, addrlen) < 0) {
629                 udp_detach(so);
630                 return NULL;
631         }
632         setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
633
634         getsockname(so->s,(struct sockaddr *)&addr,&addrlen);
635         so->so_fport = addr.sin_port;
636         if (addr.sin_addr.s_addr == 0 ||
637             addr.sin_addr.s_addr == loopback_addr.s_addr) {
638            so->so_faddr = vhost_addr;
639         } else {
640            so->so_faddr = addr.sin_addr;
641         }
642         so->so_lport = lport;
643         so->so_laddr.s_addr = laddr;
644         if (flags != SS_FACCEPTONCE)
645            so->so_expire = 0;
646
647         so->so_state &= SS_PERSISTENT_MASK;
648         so->so_state |= SS_ISFCONNECTED | flags;
649
650         return so;
651 }
This page took 0.063751 seconds and 4 git commands to generate.