arch/cpu.resource: remove dead code
[AROS.git] / workbench / network / stacks / AROSTCP / bsdsocket / netinet / udp_usrreq.c
blobe58dfbe10a800c99fc5f6ae2f05646e1de7df4ad
1 /*
2 * Copyright (c) 1982, 1986, 1988, 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 * Copyright (c) 2006
5 * Pavel Fedin
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
35 * @(#)udp_usrreq.c 8.4 (Berkeley) 1/21/94
36 * $Id$
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/malloc.h>
42 #include <sys/mbuf.h>
43 #include <sys/socket.h>
44 #include <sys/socketvar.h>
45 #include <sys/protosw.h>
46 #include <sys/errno.h>
47 #include <sys/stat.h>
48 #include <sys/queue.h>
49 #include <sys/synch.h>
50 #ifdef ENABLE_SYSCTL
51 #include <sys/sysctl.h>
52 #endif
54 #include <net/route.h>
55 #include <net/if.h>
57 #include <netinet/in.h>
58 #include <netinet/in_systm.h>
59 #include <netinet/ip.h>
60 #include <netinet/in_pcb.h>
61 #include <netinet/in_var.h>
62 #include <netinet/ip_var.h>
63 #include <netinet/ip_icmp.h>
64 #include <netinet/udp.h>
65 #include <netinet/udp_var.h>
67 #include <kern/kern_subr_protos.h>
70 * UDP protocol implementation.
71 * Per RFC 768, August, 1980.
73 #ifndef COMPAT_42
74 int udpcksum = 1;
75 #else
76 int udpcksum = 0; /* XXX */
77 #endif
79 struct inpcbhead udb; /* from udp_var.h */
80 struct inpcbinfo udbinfo;
82 #ifndef UDBHASHSIZE
83 #define UDBHASHSIZE 64
84 #endif
86 struct udpstat udpstat; /* from udp_var.h */
88 struct sockaddr_in udp_in = { sizeof(udp_in), AF_INET };
90 extern struct in_addr zeroin_addr;
91 extern u_char inetctlerrmap[];
92 extern int ip_defttl;
94 static void udp_detach __P((struct inpcb *));
95 static void udp_notify __P((struct inpcb *, int));
96 static struct mbuf *udp_saveopt __P((caddr_t, int, int));
98 void
99 udp_init()
101 LIST_INIT(&udb);
102 udbinfo.listhead = &udb;
103 udbinfo.hashbase = phashinit(UDBHASHSIZE, M_PCB, &udbinfo.hashsize);
106 void udp_input(void *args, ...)
108 register struct ip *ip;
109 register struct udphdr *uh;
110 register struct inpcb *inp;
111 struct mbuf *opts = 0;
112 int len;
113 struct ip save_ip;
114 register struct mbuf *m = args;
115 int iphlen;
116 va_list va;
118 va_start(va, args);
119 iphlen = va_arg(va, int);
120 va_end(va);
122 udpstat.udps_ipackets++;
125 * Strip IP options, if any; should skip this,
126 * make available to user, and use on returned packets,
127 * but we don't yet have a way to check the checksum
128 * with options still present.
130 if (iphlen > sizeof (struct ip)) {
131 ip_stripoptions(m, (struct mbuf *)0);
132 iphlen = sizeof(struct ip);
136 * Get IP and UDP header together in first mbuf.
138 ip = mtod(m, struct ip *);
139 if (m->m_len < iphlen + sizeof(struct udphdr)) {
140 if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) {
141 udpstat.udps_hdrops++;
142 return;
144 ip = mtod(m, struct ip *);
146 uh = (struct udphdr *)((caddr_t)ip + iphlen);
149 * Make mbuf data length reflect UDP length.
150 * If not enough data to reflect UDP length, drop.
152 len = ntohs((u_short)uh->uh_ulen);
153 if (ip->ip_len != len) {
154 if (len > ip->ip_len) {
155 udpstat.udps_badlen++;
156 goto bad;
158 m_adj(m, len - ip->ip_len);
159 /* ip->ip_len = len; */
162 * Save a copy of the IP header in case we want restore it
163 * for sending an ICMP error message in response.
165 save_ip = *ip;
168 * Checksum extended UDP header and data.
170 if (udpcksum && uh->uh_sum) {
171 bzero(((struct ipovly *)ip)->ih_x1, 9);
172 ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
173 uh->uh_sum = in_cksum(m, len + sizeof (struct ip));
174 if (uh->uh_sum) {
175 udpstat.udps_badsum++;
176 m_freem(m);
177 return;
181 if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) ||
182 in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) {
183 struct socket *last;
185 * Deliver a multicast or broadcast datagram to *all* sockets
186 * for which the local and remote addresses and ports match
187 * those of the incoming datagram. This allows more than
188 * one process to receive multi/broadcasts on the same port.
189 * (This really ought to be done for unicast datagrams as
190 * well, but that would cause problems with existing
191 * applications that open both address-specific sockets and
192 * a wildcard socket listening to the same port -- they would
193 * end up receiving duplicates of every unicast datagram.
194 * Those applications open the multiple sockets to overcome an
195 * inadequacy of the UDP socket interface, but for backwards
196 * compatibility we avoid the problem here rather than
197 * fixing the interface. Maybe 4.5BSD will remedy this?)
201 * Construct sockaddr format source address.
203 udp_in.sin_port = uh->uh_sport;
204 udp_in.sin_addr = ip->ip_src;
205 m->m_len -= sizeof (struct udpiphdr);
206 m->m_data += sizeof (struct udpiphdr);
208 * Locate pcb(s) for datagram.
209 * (Algorithm copied from raw_intr().)
211 last = NULL;
212 for (inp = udb.lh_first; inp != NULL; inp = inp->inp_list.le_next) {
213 if (inp->inp_lport != uh->uh_dport)
214 continue;
215 if (inp->inp_laddr.s_addr != INADDR_ANY) {
216 if (inp->inp_laddr.s_addr !=
217 ip->ip_dst.s_addr)
218 continue;
220 if (inp->inp_faddr.s_addr != INADDR_ANY) {
221 if (inp->inp_faddr.s_addr !=
222 ip->ip_src.s_addr ||
223 inp->inp_fport != uh->uh_sport)
224 continue;
227 if (last != NULL) {
228 struct mbuf *n;
230 if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
231 if (sbappendaddr(&last->so_rcv,
232 (struct sockaddr *)&udp_in,
233 n, (struct mbuf *)0) == 0) {
234 m_freem(n);
235 udpstat.udps_fullsock++;
236 } else
237 sorwakeup(last);
240 last = inp->inp_socket;
242 * Don't look for additional matches if this one does
243 * not have either the SO_REUSEPORT or SO_REUSEADDR
244 * socket options set. This heuristic avoids searching
245 * through all pcbs in the common case of a non-shared
246 * port. It * assumes that an application will never
247 * clear these options after setting them.
249 if ((last->so_options&(SO_REUSEPORT|SO_REUSEADDR) == 0))
250 break;
253 if (last == NULL) {
255 * No matching pcb found; discard datagram.
256 * (No need to send an ICMP Port Unreachable
257 * for a broadcast or multicast datgram.)
259 udpstat.udps_noportbcast++;
260 goto bad;
262 if (sbappendaddr(&last->so_rcv, (struct sockaddr *)&udp_in,
263 m, (struct mbuf *)0) == 0) {
264 udpstat.udps_fullsock++;
265 goto bad;
267 sorwakeup(last);
268 return;
271 * Locate pcb for datagram. First look for an exact match.
273 inp = in_pcblookuphash(&udbinfo, ip->ip_src, uh->uh_sport,
274 ip->ip_dst, uh->uh_dport);
276 * ...and if that fails, do a wildcard search.
278 if (inp == NULL) {
279 inp = in_pcblookup(&udb, ip->ip_src, uh->uh_sport, ip->ip_dst,
280 uh->uh_dport, INPLOOKUP_WILDCARD);
282 if (inp == NULL) {
283 udpstat.udps_noport++;
284 if (m->m_flags & (M_BCAST | M_MCAST)) {
285 udpstat.udps_noportbcast++;
286 goto bad;
288 *ip = save_ip;
289 icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0);
290 return;
294 * Construct sockaddr format source address.
295 * Stuff source address and datagram in user buffer.
297 udp_in.sin_port = uh->uh_sport;
298 udp_in.sin_addr = ip->ip_src;
299 if (inp->inp_flags & INP_CONTROLOPTS) {
300 struct mbuf **mp = &opts;
302 if (inp->inp_flags & INP_RECVDSTADDR) {
303 *mp = udp_saveopt((caddr_t) &ip->ip_dst,
304 sizeof(struct in_addr), IP_RECVDSTADDR);
305 if (*mp)
306 mp = &(*mp)->m_next;
308 #ifdef notyet
309 /* options were tossed above */
310 if (inp->inp_flags & INP_RECVOPTS) {
311 *mp = udp_saveopt((caddr_t) opts_deleted_above,
312 sizeof(struct in_addr), IP_RECVOPTS);
313 if (*mp)
314 mp = &(*mp)->m_next;
316 /* ip_srcroute doesn't do what we want here, need to fix */
317 if (inp->inp_flags & INP_RECVRETOPTS) {
318 *mp = udp_saveopt((caddr_t) ip_srcroute(),
319 sizeof(struct in_addr), IP_RECVRETOPTS);
320 if (*mp)
321 mp = &(*mp)->m_next;
323 #endif
325 iphlen += sizeof(struct udphdr);
326 m->m_len -= iphlen;
327 m->m_pkthdr.len -= iphlen;
328 m->m_data += iphlen;
329 if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in,
330 m, opts) == 0) {
331 udpstat.udps_fullsock++;
332 goto bad;
334 sorwakeup(inp->inp_socket);
335 return;
336 bad:
337 m_freem(m);
338 if (opts)
339 m_freem(opts);
343 * Create a "control" mbuf containing the specified data
344 * with the specified type for presentation with a datagram.
346 struct mbuf *
347 udp_saveopt(p, size, type)
348 caddr_t p;
349 register int size;
350 int type;
352 register struct cmsghdr *cp;
353 struct mbuf *m;
355 if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL)
356 return ((struct mbuf *) NULL);
357 cp = (struct cmsghdr *) mtod(m, struct cmsghdr *);
358 (void)memcpy(CMSG_DATA(cp), p, size);
359 size += sizeof(*cp);
360 m->m_len = size;
361 cp->cmsg_len = size;
362 cp->cmsg_level = IPPROTO_IP;
363 cp->cmsg_type = type;
364 return (m);
368 * Notify a udp user of an asynchronous error;
369 * just wake up so that he can collect error status.
371 static void
372 udp_notify(inp, _errno)
373 register struct inpcb *inp;
374 int _errno;
376 inp->inp_socket->so_error = _errno;
377 sorwakeup(inp->inp_socket);
378 sowwakeup(inp->inp_socket);
381 void
382 udp_ctlinput(cmd, sa, arg)
383 int cmd;
384 struct sockaddr *sa;
385 void *arg;
387 register struct ip *ip = arg;
388 register struct udphdr *uh;
390 if (!PRC_IS_REDIRECT(cmd) &&
391 ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0))
392 return;
393 if (ip) {
394 uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
395 in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport,
396 cmd, udp_notify);
397 } else
398 in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify);
402 udp_output(void *arg, ...)
404 register struct inpcb *inp = arg;
405 register struct mbuf *m;
406 struct mbuf *addr, *control;
407 register struct udpiphdr *ui;
408 register int len;
409 struct in_addr laddr;
410 int s = 0, error = 0;
411 va_list va;
413 va_start(va, arg);
414 m = va_arg(va, struct mbuf *);
415 addr = va_arg(va, struct mbuf *);
416 control = va_arg(va, struct mbuf *);
417 va_end(va);
419 len = m->m_pkthdr.len;
421 if (control)
422 m_freem(control); /* XXX */
424 if (addr) {
425 laddr = inp->inp_laddr;
426 if (inp->inp_faddr.s_addr != INADDR_ANY) {
427 error = EISCONN;
428 goto release;
431 * Must block input while temporarily connected.
433 s = splnet();
434 error = in_pcbconnect(inp, addr);
435 if (error) {
436 splx(s);
437 goto release;
439 } else {
440 if (inp->inp_faddr.s_addr == INADDR_ANY) {
441 error = ENOTCONN;
442 goto release;
446 * Calculate data length and get a mbuf
447 * for UDP and IP headers.
449 M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
450 if (m == 0) {
451 error = ENOBUFS;
452 if (addr)
453 splx(s);
454 goto release;
458 * Fill in mbuf with extended UDP header
459 * and addresses and length put into network format.
461 ui = mtod(m, struct udpiphdr *);
462 bzero(ui->ui_x1, sizeof(ui->ui_x1));
463 ui->ui_pr = IPPROTO_UDP;
464 ui->ui_len = htons((u_short)len + sizeof (struct udphdr));
465 ui->ui_src = inp->inp_laddr;
466 ui->ui_dst = inp->inp_faddr;
467 ui->ui_sport = inp->inp_lport;
468 ui->ui_dport = inp->inp_fport;
469 ui->ui_ulen = ui->ui_len;
472 * Stuff checksum and output datagram.
474 ui->ui_sum = 0;
475 if (udpcksum) {
476 if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
477 ui->ui_sum = 0xffff;
479 ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
480 ((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl; /* XXX */
481 ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; /* XXX */
482 udpstat.udps_opackets++;
483 error = ip_output(m, inp->inp_options, &inp->inp_route,
484 inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST),
485 inp->inp_moptions);
487 if (addr) {
488 in_pcbdisconnect(inp);
489 inp->inp_laddr = laddr;
490 splx(s);
492 return (error);
494 release:
495 m_freem(m);
496 return (error);
499 u_long udp_sendspace = 9216; /* really max datagram size */
500 u_long udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
501 /* 40 1K datagrams */
503 /*ARGSUSED*/
505 udp_usrreq(so, req, m, addr, control)
506 struct socket *so;
507 int req;
508 struct mbuf *m, *addr, *control;
510 struct inpcb *inp = sotoinpcb(so);
511 int error = 0;
512 int s;
514 if (req == PRU_CONTROL)
515 return (in_control(so, (long)m, (caddr_t)addr,
516 (struct ifnet *)control));
517 if (inp == NULL && req != PRU_ATTACH) {
518 error = EINVAL;
519 goto release;
522 * Note: need to block udp_input while changing
523 * the udp pcb queue and/or pcb addresses.
525 switch (req) {
527 case PRU_ATTACH:
528 if (inp != NULL) {
529 error = EINVAL;
530 break;
532 s = splnet();
533 error = in_pcballoc(so, &udbinfo);
534 splx(s);
535 if (error)
536 break;
537 error = soreserve(so, udp_sendspace, udp_recvspace);
538 if (error)
539 break;
540 ((struct inpcb *) so->so_pcb)->inp_ip.ip_ttl = ip_defttl;
541 break;
543 case PRU_DETACH:
544 udp_detach(inp);
545 break;
547 case PRU_BIND:
548 s = splnet();
549 error = in_pcbbind(inp, addr);
550 splx(s);
551 break;
553 case PRU_LISTEN:
554 error = EOPNOTSUPP;
555 break;
557 case PRU_CONNECT:
558 if (inp->inp_faddr.s_addr != INADDR_ANY) {
559 error = EISCONN;
560 break;
562 s = splnet();
563 error = in_pcbconnect(inp, addr);
564 splx(s);
565 if (error == 0)
566 soisconnected(so);
567 break;
569 case PRU_CONNECT2:
570 error = EOPNOTSUPP;
571 break;
573 case PRU_ACCEPT:
574 error = EOPNOTSUPP;
575 break;
577 case PRU_DISCONNECT:
578 if (inp->inp_faddr.s_addr == INADDR_ANY) {
579 error = ENOTCONN;
580 break;
582 s = splnet();
583 in_pcbdisconnect(inp);
584 inp->inp_laddr.s_addr = INADDR_ANY;
585 splx(s);
586 so->so_state &= ~SS_ISCONNECTED; /* XXX */
587 break;
589 case PRU_SHUTDOWN:
590 socantsendmore(so);
591 break;
593 case PRU_SEND:
594 return (udp_output(inp, m, addr, control));
596 case PRU_ABORT:
597 soisdisconnected(so);
598 udp_detach(inp);
599 break;
601 case PRU_SOCKADDR:
602 in_setsockaddr(inp, addr);
603 break;
605 case PRU_PEERADDR:
606 in_setpeeraddr(inp, addr);
607 break;
609 case PRU_SENSE:
611 * stat: don't bother with a blocksize.
613 return (0);
615 case PRU_SENDOOB:
616 case PRU_FASTTIMO:
617 case PRU_SLOWTIMO:
618 case PRU_PROTORCV:
619 case PRU_PROTOSEND:
620 error = EOPNOTSUPP;
621 break;
623 case PRU_RCVD:
624 case PRU_RCVOOB:
625 return (EOPNOTSUPP); /* do not free mbuf's */
627 default:
628 panic("udp_usrreq");
631 release:
632 if (control) {
633 printf("udp control data unexpectedly retained\n");
634 m_freem(control);
636 if (m)
637 m_freem(m);
638 return (error);
641 static void
642 udp_detach(inp)
643 struct inpcb *inp;
645 int s = splnet();
647 in_pcbdetach(inp);
648 splx(s);
651 #ifdef ENABLE_SYSCTL
653 * Sysctl for udp variables.
656 udp_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
657 int *name;
658 u_int namelen;
659 void *oldp;
660 size_t *oldlenp;
661 void *newp;
662 size_t newlen;
664 /* All sysctl names at this level are terminal. */
665 if (namelen != 1)
666 return (ENOTDIR);
668 switch (name[0]) {
669 case UDPCTL_CHECKSUM:
670 return (sysctl_int(oldp, oldlenp, newp, newlen, &udpcksum));
671 case UDPCTL_STATS:
672 return (sysctl_rdstruct(oldp, oldlenp, newp, &udpstat,
673 sizeof udpstat));
674 case UDPCTL_MAXDGRAM:
675 return (sysctl_int(oldp, oldlenp, newp, newlen,
676 (int *)&udp_sendspace)); /* XXX */
677 case UDPCTL_RECVSPACE:
678 return (sysctl_int(oldp, oldlenp, newp, newlen,
679 (int *)&udp_recvspace)); /* XXX */
680 default:
681 return (ENOPROTOOPT);
683 /* NOTREACHED */
685 #endif