1 /*
2 * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 *
7 * @(#)udp_usrreq.c 8.6 (Berkeley) 05/23/95
8 */
9
10 #include <sys/param.h>
11 #include <sys/malloc.h>
12 #include <sys/mbuf.h>
13 #include <sys/protosw.h>
14 #include <sys/socket.h>
15 #include <sys/socketvar.h>
16 #include <sys/errno.h>
17 #include <sys/stat.h>
18
19 #include <net/if.h>
20 #include <net/route.h>
21
22 #include <netinet/in.h>
23 #include <netinet/in_systm.h>
24 #include <netinet/ip.h>
25 #include <netinet/in_pcb.h>
26 #include <netinet/ip_var.h>
27 #include <netinet/ip_icmp.h>
28 #include <netinet/udp.h>
29 #include <netinet/udp_var.h>
30
31 /*
32 * UDP protocol implementation.
33 * Per RFC 768, August, 1980.
34 */
35 #ifndef COMPAT_42
36 int udpcksum = 1;
37 #else
38 int udpcksum = 0; /* XXX */
39 #endif
40
41 struct sockaddr_in udp_in = { sizeof(udp_in), AF_INET };
42 struct inpcb *udp_last_inpcb = &udb;
43
44 static void udp_detach __P((struct inpcb *));
45 static void udp_notify __P((struct inpcb *, int));
46 static struct mbuf *udp_saveopt __P((caddr_t, int, int));
47
48 void
udp_init()49 udp_init()
50 {
51 udb.inp_next = udb.inp_prev = &udb;
52 }
53
54 void
udp_input(m,iphlen)55 udp_input(m, iphlen)
56 register struct mbuf *m;
57 int iphlen;
58 {
59 register struct ip *ip;
60 register struct udphdr *uh;
61 register struct inpcb *inp;
62 struct mbuf *opts = 0;
63 int len;
64 struct ip save_ip;
65
66 udpstat.udps_ipackets++;
67
68 /*
69 * Strip IP options, if any; should skip this,
70 * make available to user, and use on returned packets,
71 * but we don't yet have a way to check the checksum
72 * with options still present.
73 */
74 if (iphlen > sizeof (struct ip)) {
75 ip_stripoptions(m, (struct mbuf *)0);
76 iphlen = sizeof(struct ip);
77 }
78
79 /*
80 * Get IP and UDP header together in first mbuf.
81 */
82 ip = mtod(m, struct ip *);
83 if (m->m_len < iphlen + sizeof(struct udphdr)) {
84 if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) {
85 udpstat.udps_hdrops++;
86 return;
87 }
88 ip = mtod(m, struct ip *);
89 }
90 uh = (struct udphdr *)((caddr_t)ip + iphlen);
91
92 /*
93 * Make mbuf data length reflect UDP length.
94 * If not enough data to reflect UDP length, drop.
95 */
96 len = ntohs((u_short)uh->uh_ulen);
97 if (ip->ip_len != len) {
98 if (len > ip->ip_len) {
99 udpstat.udps_badlen++;
100 goto bad;
101 }
102 m_adj(m, len - ip->ip_len);
103 /* ip->ip_len = len; */
104 }
105 /*
106 * Save a copy of the IP header in case we want restore it
107 * for sending an ICMP error message in response.
108 */
109 save_ip = *ip;
110
111 /*
112 * Checksum extended UDP header and data.
113 */
114 if (uh->uh_sum) {
115 ((struct ipovly *)ip)->ih_next = 0;
116 ((struct ipovly *)ip)->ih_prev = 0;
117 ((struct ipovly *)ip)->ih_x1 = 0;
118 ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
119 if (uh->uh_sum = in_cksum(m, len + sizeof (struct ip))) {
120 udpstat.udps_badsum++;
121 m_freem(m);
122 return;
123 }
124 }
125
126 if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) ||
127 in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) {
128 struct socket *last;
129 /*
130 * Deliver a multicast or broadcast datagram to *all* sockets
131 * for which the local and remote addresses and ports match
132 * those of the incoming datagram. This allows more than
133 * one process to receive multi/broadcasts on the same port.
134 * (This really ought to be done for unicast datagrams as
135 * well, but that would cause problems with existing
136 * applications that open both address-specific sockets and
137 * a wildcard socket listening to the same port -- they would
138 * end up receiving duplicates of every unicast datagram.
139 * Those applications open the multiple sockets to overcome an
140 * inadequacy of the UDP socket interface, but for backwards
141 * compatibility we avoid the problem here rather than
142 * fixing the interface. Maybe 4.5BSD will remedy this?)
143 */
144
145 /*
146 * Construct sockaddr format source address.
147 */
148 udp_in.sin_port = uh->uh_sport;
149 udp_in.sin_addr = ip->ip_src;
150 m->m_len -= sizeof (struct udpiphdr);
151 m->m_data += sizeof (struct udpiphdr);
152 /*
153 * Locate pcb(s) for datagram.
154 * (Algorithm copied from raw_intr().)
155 */
156 last = NULL;
157 for (inp = udb.inp_next; inp != &udb; inp = inp->inp_next) {
158 if (inp->inp_lport != uh->uh_dport)
159 continue;
160 if (inp->inp_laddr.s_addr != INADDR_ANY) {
161 if (inp->inp_laddr.s_addr !=
162 ip->ip_dst.s_addr)
163 continue;
164 }
165 if (inp->inp_faddr.s_addr != INADDR_ANY) {
166 if (inp->inp_faddr.s_addr !=
167 ip->ip_src.s_addr ||
168 inp->inp_fport != uh->uh_sport)
169 continue;
170 }
171
172 if (last != NULL) {
173 struct mbuf *n;
174
175 if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
176 if (sbappendaddr(&last->so_rcv,
177 (struct sockaddr *)&udp_in,
178 n, (struct mbuf *)0) == 0) {
179 m_freem(n);
180 udpstat.udps_fullsock++;
181 } else
182 sorwakeup(last);
183 }
184 }
185 last = inp->inp_socket;
186 /*
187 * Don't look for additional matches if this one does
188 * not have either the SO_REUSEPORT or SO_REUSEADDR
189 * socket options set. This heuristic avoids searching
190 * through all pcbs in the common case of a non-shared
191 * port. It * assumes that an application will never
192 * clear these options after setting them.
193 */
194 if ((last->so_options&(SO_REUSEPORT|SO_REUSEADDR) == 0))
195 break;
196 }
197
198 if (last == NULL) {
199 /*
200 * No matching pcb found; discard datagram.
201 * (No need to send an ICMP Port Unreachable
202 * for a broadcast or multicast datgram.)
203 */
204 udpstat.udps_noportbcast++;
205 goto bad;
206 }
207 if (sbappendaddr(&last->so_rcv, (struct sockaddr *)&udp_in,
208 m, (struct mbuf *)0) == 0) {
209 udpstat.udps_fullsock++;
210 goto bad;
211 }
212 sorwakeup(last);
213 return;
214 }
215 /*
216 * Locate pcb for datagram.
217 */
218 inp = udp_last_inpcb;
219 if (inp->inp_lport != uh->uh_dport ||
220 inp->inp_fport != uh->uh_sport ||
221 inp->inp_faddr.s_addr != ip->ip_src.s_addr ||
222 inp->inp_laddr.s_addr != ip->ip_dst.s_addr) {
223 inp = in_pcblookup(&udb, ip->ip_src, uh->uh_sport,
224 ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD);
225 if (inp)
226 udp_last_inpcb = inp;
227 udpstat.udpps_pcbcachemiss++;
228 }
229 if (inp == 0) {
230 udpstat.udps_noport++;
231 if (m->m_flags & (M_BCAST | M_MCAST)) {
232 udpstat.udps_noportbcast++;
233 goto bad;
234 }
235 *ip = save_ip;
236 ip->ip_len += iphlen;
237 icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0);
238 return;
239 }
240
241 /*
242 * Construct sockaddr format source address.
243 * Stuff source address and datagram in user buffer.
244 */
245 udp_in.sin_port = uh->uh_sport;
246 udp_in.sin_addr = ip->ip_src;
247 if (inp->inp_flags & INP_CONTROLOPTS) {
248 struct mbuf **mp = &opts;
249
250 if (inp->inp_flags & INP_RECVDSTADDR) {
251 *mp = udp_saveopt((caddr_t) &ip->ip_dst,
252 sizeof(struct in_addr), IP_RECVDSTADDR);
253 if (*mp)
254 mp = &(*mp)->m_next;
255 }
256 #ifdef notyet
257 /* options were tossed above */
258 if (inp->inp_flags & INP_RECVOPTS) {
259 *mp = udp_saveopt((caddr_t) opts_deleted_above,
260 sizeof(struct in_addr), IP_RECVOPTS);
261 if (*mp)
262 mp = &(*mp)->m_next;
263 }
264 /* ip_srcroute doesn't do what we want here, need to fix */
265 if (inp->inp_flags & INP_RECVRETOPTS) {
266 *mp = udp_saveopt((caddr_t) ip_srcroute(),
267 sizeof(struct in_addr), IP_RECVRETOPTS);
268 if (*mp)
269 mp = &(*mp)->m_next;
270 }
271 #endif
272 }
273 iphlen += sizeof(struct udphdr);
274 m->m_len -= iphlen;
275 m->m_pkthdr.len -= iphlen;
276 m->m_data += iphlen;
277 if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in,
278 m, opts) == 0) {
279 udpstat.udps_fullsock++;
280 goto bad;
281 }
282 sorwakeup(inp->inp_socket);
283 return;
284 bad:
285 m_freem(m);
286 if (opts)
287 m_freem(opts);
288 }
289
290 /*
291 * Create a "control" mbuf containing the specified data
292 * with the specified type for presentation with a datagram.
293 */
294 struct mbuf *
udp_saveopt(p,size,type)295 udp_saveopt(p, size, type)
296 caddr_t p;
297 register int size;
298 int type;
299 {
300 register struct cmsghdr *cp;
301 struct mbuf *m;
302
303 if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL)
304 return ((struct mbuf *) NULL);
305 cp = (struct cmsghdr *) mtod(m, struct cmsghdr *);
306 bcopy(p, CMSG_DATA(cp), size);
307 size += sizeof(*cp);
308 m->m_len = size;
309 cp->cmsg_len = size;
310 cp->cmsg_level = IPPROTO_IP;
311 cp->cmsg_type = type;
312 return (m);
313 }
314
315 /*
316 * Notify a udp user of an asynchronous error;
317 * just wake up so that he can collect error status.
318 */
319 static void
udp_notify(inp,errno)320 udp_notify(inp, errno)
321 register struct inpcb *inp;
322 int errno;
323 {
324 inp->inp_socket->so_error = errno;
325 sorwakeup(inp->inp_socket);
326 sowwakeup(inp->inp_socket);
327 }
328
329 void
udp_ctlinput(cmd,sa,ip)330 udp_ctlinput(cmd, sa, ip)
331 int cmd;
332 struct sockaddr *sa;
333 register struct ip *ip;
334 {
335 register struct udphdr *uh;
336 extern struct in_addr zeroin_addr;
337 extern u_char inetctlerrmap[];
338
339 if (!PRC_IS_REDIRECT(cmd) &&
340 ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0))
341 return;
342 if (ip) {
343 uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
344 in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport,
345 cmd, udp_notify);
346 } else
347 in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify);
348 }
349
350 int
udp_output(inp,m,addr,control)351 udp_output(inp, m, addr, control)
352 register struct inpcb *inp;
353 register struct mbuf *m;
354 struct mbuf *addr, *control;
355 {
356 register struct udpiphdr *ui;
357 register int len = m->m_pkthdr.len;
358 struct in_addr laddr;
359 int s, error = 0;
360
361 if (control)
362 m_freem(control); /* XXX */
363
364 if (addr) {
365 laddr = inp->inp_laddr;
366 if (inp->inp_faddr.s_addr != INADDR_ANY) {
367 error = EISCONN;
368 goto release;
369 }
370 /*
371 * Must block input while temporarily connected.
372 */
373 s = splnet();
374 error = in_pcbconnect(inp, addr);
375 if (error) {
376 splx(s);
377 goto release;
378 }
379 } else {
380 if (inp->inp_faddr.s_addr == INADDR_ANY) {
381 error = ENOTCONN;
382 goto release;
383 }
384 }
385 /*
386 * Calculate data length and get a mbuf
387 * for UDP and IP headers.
388 */
389 M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
390 if (m == 0) {
391 error = ENOBUFS;
392 goto release;
393 }
394
395 /*
396 * Fill in mbuf with extended UDP header
397 * and addresses and length put into network format.
398 */
399 ui = mtod(m, struct udpiphdr *);
400 ui->ui_next = ui->ui_prev = 0;
401 ui->ui_x1 = 0;
402 ui->ui_pr = IPPROTO_UDP;
403 ui->ui_len = htons((u_short)len + sizeof (struct udphdr));
404 ui->ui_src = inp->inp_laddr;
405 ui->ui_dst = inp->inp_faddr;
406 ui->ui_sport = inp->inp_lport;
407 ui->ui_dport = inp->inp_fport;
408 ui->ui_ulen = ui->ui_len;
409
410 /*
411 * Stuff checksum and output datagram.
412 */
413 ui->ui_sum = 0;
414 if (udpcksum) {
415 if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
416 ui->ui_sum = 0xffff;
417 }
418 ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
419 ((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl; /* XXX */
420 ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos; /* XXX */
421 udpstat.udps_opackets++;
422 error = ip_output(m, inp->inp_options, &inp->inp_route,
423 inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST),
424 inp->inp_moptions);
425
426 if (addr) {
427 in_pcbdisconnect(inp);
428 inp->inp_laddr = laddr;
429 splx(s);
430 }
431 return (error);
432
433 release:
434 m_freem(m);
435 return (error);
436 }
437
438 u_long udp_sendspace = 9216; /* really max datagram size */
439 u_long udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
440 /* 40 1K datagrams */
441
442 /*ARGSUSED*/
443 int
udp_usrreq(so,req,m,addr,control)444 udp_usrreq(so, req, m, addr, control)
445 struct socket *so;
446 int req;
447 struct mbuf *m, *addr, *control;
448 {
449 struct inpcb *inp = sotoinpcb(so);
450 int error = 0;
451 int s;
452
453 if (req == PRU_CONTROL)
454 return (in_control(so, (u_long)m, (caddr_t)addr,
455 (struct ifnet *)control));
456 if (inp == NULL && req != PRU_ATTACH) {
457 error = EINVAL;
458 goto release;
459 }
460 /*
461 * Note: need to block udp_input while changing
462 * the udp pcb queue and/or pcb addresses.
463 */
464 switch (req) {
465
466 case PRU_ATTACH:
467 if (inp != NULL) {
468 error = EINVAL;
469 break;
470 }
471 s = splnet();
472 error = in_pcballoc(so, &udb);
473 splx(s);
474 if (error)
475 break;
476 error = soreserve(so, udp_sendspace, udp_recvspace);
477 if (error)
478 break;
479 ((struct inpcb *) so->so_pcb)->inp_ip.ip_ttl = ip_defttl;
480 break;
481
482 case PRU_DETACH:
483 udp_detach(inp);
484 break;
485
486 case PRU_BIND:
487 s = splnet();
488 error = in_pcbbind(inp, addr);
489 splx(s);
490 break;
491
492 case PRU_LISTEN:
493 error = EOPNOTSUPP;
494 break;
495
496 case PRU_CONNECT:
497 if (inp->inp_faddr.s_addr != INADDR_ANY) {
498 error = EISCONN;
499 break;
500 }
501 s = splnet();
502 error = in_pcbconnect(inp, addr);
503 splx(s);
504 if (error == 0)
505 soisconnected(so);
506 break;
507
508 case PRU_CONNECT2:
509 error = EOPNOTSUPP;
510 break;
511
512 case PRU_ACCEPT:
513 error = EOPNOTSUPP;
514 break;
515
516 case PRU_DISCONNECT:
517 if (inp->inp_faddr.s_addr == INADDR_ANY) {
518 error = ENOTCONN;
519 break;
520 }
521 s = splnet();
522 in_pcbdisconnect(inp);
523 inp->inp_laddr.s_addr = INADDR_ANY;
524 splx(s);
525 so->so_state &= ~SS_ISCONNECTED; /* XXX */
526 break;
527
528 case PRU_SHUTDOWN:
529 socantsendmore(so);
530 break;
531
532 case PRU_SEND:
533 return (udp_output(inp, m, addr, control));
534
535 case PRU_ABORT:
536 soisdisconnected(so);
537 udp_detach(inp);
538 break;
539
540 case PRU_SOCKADDR:
541 in_setsockaddr(inp, addr);
542 break;
543
544 case PRU_PEERADDR:
545 in_setpeeraddr(inp, addr);
546 break;
547
548 case PRU_SENSE:
549 /*
550 * stat: don't bother with a blocksize.
551 */
552 return (0);
553
554 case PRU_SENDOOB:
555 case PRU_FASTTIMO:
556 case PRU_SLOWTIMO:
557 case PRU_PROTORCV:
558 case PRU_PROTOSEND:
559 error = EOPNOTSUPP;
560 break;
561
562 case PRU_RCVD:
563 case PRU_RCVOOB:
564 return (EOPNOTSUPP); /* do not free mbuf's */
565
566 default:
567 panic("udp_usrreq");
568 }
569
570 release:
571 if (control) {
572 printf("udp control data unexpectedly retained\n");
573 m_freem(control);
574 }
575 if (m)
576 m_freem(m);
577 return (error);
578 }
579
580 static void
udp_detach(inp)581 udp_detach(inp)
582 struct inpcb *inp;
583 {
584 int s = splnet();
585
586 if (inp == udp_last_inpcb)
587 udp_last_inpcb = &udb;
588 in_pcbdetach(inp);
589 splx(s);
590 }
591
592 /*
593 * Sysctl for udp variables.
594 */
udp_sysctl(name,namelen,oldp,oldlenp,newp,newlen)595 udp_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
596 int *name;
597 u_int namelen;
598 void *oldp;
599 size_t *oldlenp;
600 void *newp;
601 size_t newlen;
602 {
603 /* All sysctl names at this level are terminal. */
604 if (namelen != 1)
605 return (ENOTDIR);
606
607 switch (name[0]) {
608 case UDPCTL_CHECKSUM:
609 return (sysctl_int(oldp, oldlenp, newp, newlen, &udpcksum));
610 default:
611 return (ENOPROTOOPT);
612 }
613 /* NOTREACHED */
614 }
615