1 /*
2 * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995
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. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)udp_usrreq.c 8.6 (Berkeley) 5/23/95
34 * $FreeBSD$
35 */
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/malloc.h>
41 #include <sys/mbuf.h>
42 #include <sys/proc.h>
43 #include <sys/protosw.h>
44 #include <sys/socket.h>
45 #include <sys/socketvar.h>
46 #include <sys/sysctl.h>
47 #include <sys/syslog.h>
48
49 #include <vm/vm_zone.h>
50
51 #include <net/if.h>
52 #include <net/route.h>
53
54 #include <netinet/in.h>
55 #include <netinet/in_systm.h>
56 #include <netinet/ip.h>
57 #include <netinet/in_pcb.h>
58 #include <netinet/in_var.h>
59 #include <netinet/ip_var.h>
60 #include <netinet/ip_icmp.h>
61 #include <netinet/icmp_var.h>
62 #include <netinet/udp.h>
63 #include <netinet/udp_var.h>
64
65 /*
66 * UDP protocol implementation.
67 * Per RFC 768, August, 1980.
68 */
69 #ifndef COMPAT_42
70 static int udpcksum = 1;
71 #else
72 static int udpcksum = 0; /* XXX */
73 #endif
74 SYSCTL_INT(_net_inet_udp, UDPCTL_CHECKSUM, checksum, CTLFLAG_RW,
75 &udpcksum, 0, "");
76
77 static int log_in_vain = 0;
78 SYSCTL_INT(_net_inet_udp, OID_AUTO, log_in_vain, CTLFLAG_RW,
79 &log_in_vain, 0, "");
80
81 static struct inpcbhead udb; /* from udp_var.h */
82 struct inpcbinfo udbinfo;
83
84 #ifndef UDBHASHSIZE
85 #define UDBHASHSIZE 16
86 #endif
87
88 static struct udpstat udpstat; /* from udp_var.h */
89 SYSCTL_STRUCT(_net_inet_udp, UDPCTL_STATS, stats, CTLFLAG_RD,
90 &udpstat, udpstat, "");
91
92 static struct sockaddr_in udp_in = { sizeof(udp_in), AF_INET };
93
94 static int udp_output __P((struct inpcb *, struct mbuf *, struct sockaddr *,
95 struct mbuf *, struct proc *));
96 static void udp_notify __P((struct inpcb *, int));
97
98 void
99 udp_init()
100 {
101 LIST_INIT(&udb);
102 udbinfo.listhead = &udb;
103 udbinfo.hashbase = hashinit(UDBHASHSIZE, M_PCB, &udbinfo.hashmask);
104 udbinfo.porthashbase = hashinit(UDBHASHSIZE, M_PCB,
105 &udbinfo.porthashmask);
106 udbinfo.ipi_zone = zinit("udpcb", sizeof(struct inpcb), maxsockets,
107 ZONE_INTERRUPT, 0);
108 }
109
110 void
111 udp_input(m, iphlen)
112 register struct mbuf *m;
113 int iphlen;
114 {
115 register struct ip *ip;
116 register struct udphdr *uh;
117 register struct inpcb *inp;
118 struct mbuf *opts = 0;
119 int len;
120 struct ip save_ip;
121
122 udpstat.udps_ipackets++;
123
124 /*
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.
129 */
130 if (iphlen > sizeof (struct ip)) {
131 ip_stripoptions(m, (struct mbuf *)0);
132 iphlen = sizeof(struct ip);
133 }
134
135 /*
136 * Get IP and UDP header together in first mbuf.
137 */
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;
143 }
144 ip = mtod(m, struct ip *);
145 }
146 uh = (struct udphdr *)((caddr_t)ip + iphlen);
147
148 /*
149 * Make mbuf data length reflect UDP length.
150 * If not enough data to reflect UDP length, drop.
151 */
152 len = ntohs((u_short)uh->uh_ulen);
153 if (ip->ip_len != len) {
154 if (len > ip->ip_len || len < sizeof(struct udphdr)) {
155 udpstat.udps_badlen++;
156 goto bad;
157 }
158 m_adj(m, len - ip->ip_len);
159 /* ip->ip_len = len; */
160 }
161 /*
162 * Save a copy of the IP header in case we want restore it
163 * for sending an ICMP error message in response.
164 */
165 save_ip = *ip;
166
167 /*
168 * Checksum extended UDP header and data.
169 */
170 if (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;
178 }
179 }
180
181 if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) ||
182 in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) {
183 struct inpcb *last;
184 /*
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?)
198 */
199
200 /*
201 * Construct sockaddr format source address.
202 */
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);
207 /*
208 * Locate pcb(s) for datagram.
209 * (Algorithm copied from raw_intr().)
210 */
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;
219 }
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;
225 }
226
227 if (last != NULL) {
228 struct mbuf *n;
229
230 if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
231 if (last->inp_flags & INP_CONTROLOPTS
232 || last->inp_socket->so_options & SO_TIMESTAMP)
233 ip_savecontrol(last, &opts, ip, n);
234 if (sbappendaddr(&last->inp_socket->so_rcv,
235 (struct sockaddr *)&udp_in,
236 n, opts) == 0) {
237 m_freem(n);
238 if (opts)
239 m_freem(opts);
240 udpstat.udps_fullsock++;
241 } else
242 sorwakeup(last->inp_socket);
243 opts = 0;
244 }
245 }
246 last = inp;
247 /*
248 * Don't look for additional matches if this one does
249 * not have either the SO_REUSEPORT or SO_REUSEADDR
250 * socket options set. This heuristic avoids searching
251 * through all pcbs in the common case of a non-shared
252 * port. It * assumes that an application will never
253 * clear these options after setting them.
254 */
255 if ((last->inp_socket->so_options&(SO_REUSEPORT|SO_REUSEADDR)) == 0)
256 break;
257 }
258
259 if (last == NULL) {
260 /*
261 * No matching pcb found; discard datagram.
262 * (No need to send an ICMP Port Unreachable
263 * for a broadcast or multicast datgram.)
264 */
265 udpstat.udps_noportbcast++;
266 goto bad;
267 }
268 if (last->inp_flags & INP_CONTROLOPTS
269 || last->inp_socket->so_options & SO_TIMESTAMP)
270 ip_savecontrol(last, &opts, ip, m);
271 if (sbappendaddr(&last->inp_socket->so_rcv,
272 (struct sockaddr *)&udp_in,
273 m, opts) == 0) {
274 udpstat.udps_fullsock++;
275 goto bad;
276 }
277 sorwakeup(last->inp_socket);
278 return;
279 }
280 /*
281 * Locate pcb for datagram.
282 */
283 inp = in_pcblookup_hash(&udbinfo, ip->ip_src, uh->uh_sport,
284 ip->ip_dst, uh->uh_dport, 1);
285 if (inp == NULL) {
286 if (log_in_vain) {
287 char buf[4*sizeof "123"];
288
289 strcpy(buf, inet_ntoa(ip->ip_dst));
290 log(LOG_INFO,
291 "Connection attempt to UDP %s:%d from %s:%d\n",
292 buf, ntohs(uh->uh_dport), inet_ntoa(ip->ip_src),
293 ntohs(uh->uh_sport));
294 }
295 udpstat.udps_noport++;
296 if (m->m_flags & (M_BCAST | M_MCAST)) {
297 udpstat.udps_noportbcast++;
298 goto bad;
299 }
300 *ip = save_ip;
301 #ifdef ICMP_BANDLIM
302 if (badport_bandlim(0) < 0)
303 goto bad;
304 #endif
305 icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0);
306 return;
307 }
308
309 /*
310 * Construct sockaddr format source address.
311 * Stuff source address and datagram in user buffer.
312 */
313 udp_in.sin_port = uh->uh_sport;
314 udp_in.sin_addr = ip->ip_src;
315 if (inp->inp_flags & INP_CONTROLOPTS
316 || inp->inp_socket->so_options & SO_TIMESTAMP)
317 ip_savecontrol(inp, &opts, ip, m);
318 iphlen += sizeof(struct udphdr);
319 m->m_len -= iphlen;
320 m->m_pkthdr.len -= iphlen;
321 m->m_data += iphlen;
322 if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in,
323 m, opts) == 0) {
324 udpstat.udps_fullsock++;
325 goto bad;
326 }
327 sorwakeup(inp->inp_socket);
328 return;
329 bad:
330 m_freem(m);
331 if (opts)
332 m_freem(opts);
333 }
334
335 /*
336 * Notify a udp user of an asynchronous error;
337 * just wake up so that he can collect error status.
338 */
339 static void
340 udp_notify(inp, errno)
341 register struct inpcb *inp;
342 int errno;
343 {
344 inp->inp_socket->so_error = errno;
345 sorwakeup(inp->inp_socket);
346 sowwakeup(inp->inp_socket);
347 }
348
349 void
350 udp_ctlinput(cmd, sa, vip)
351 int cmd;
352 struct sockaddr *sa;
353 void *vip;
354 {
355 register struct ip *ip = vip;
356 register struct udphdr *uh;
357 void (*notify) __P((struct inpcb *, int)) = udp_notify;
358
359 if (PRC_IS_REDIRECT(cmd)) {
360 /*
361 * Redirects go to all references to the destination,
362 * and use in_rtchange to invalidate the route cache.
363 */
364 ip = 0;
365 notify = in_rtchange;
366 } else if (cmd == PRC_HOSTDEAD)
367 /*
368 * Dead host indications: notify all references to the destination.
369 */
370 ip = 0;
371 else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0)
372 return;
373 if (ip) {
374 uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
375 in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport,
376 cmd, notify);
377 } else
378 in_pcbnotifyall(&udb, sa, cmd, notify);
379 }
380
381 static int
382 udp_pcblist SYSCTL_HANDLER_ARGS
383 {
384 int error, i, n, s;
385 struct inpcb *inp, **inp_list;
386 inp_gen_t gencnt;
387 struct xinpgen xig;
388
389 /*
390 * The process of preparing the TCB list is too time-consuming and
391 * resource-intensive to repeat twice on every request.
392 */
393 if (req->oldptr == 0) {
394 n = udbinfo.ipi_count;
395 req->oldidx = 2 * (sizeof xig)
396 + (n + n/8) * sizeof(struct xinpcb);
397 return 0;
398 }
399
400 if (req->newptr != 0)
401 return EPERM;
402
403 /*
404 * OK, now we're committed to doing something.
405 */
406 s = splnet();
407 gencnt = udbinfo.ipi_gencnt;
408 n = udbinfo.ipi_count;
409 splx(s);
410
411 xig.xig_len = sizeof xig;
412 xig.xig_count = n;
413 xig.xig_gen = gencnt;
414 xig.xig_sogen = so_gencnt;
415 error = SYSCTL_OUT(req, &xig, sizeof xig);
416 if (error)
417 return error;
418
419 inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK);
420 if (inp_list == 0)
421 return ENOMEM;
422
423 s = splnet();
424 for (inp = udbinfo.listhead->lh_first, i = 0; inp && i < n;
425 inp = inp->inp_list.le_next) {
426 if (inp->inp_gencnt <= gencnt)
427 inp_list[i++] = inp;
428 }
429 splx(s);
430 n = i;
431
432 error = 0;
433 for (i = 0; i < n; i++) {
434 inp = inp_list[i];
435 if (inp->inp_gencnt <= gencnt) {
436 struct xinpcb xi;
437 xi.xi_len = sizeof xi;
438 /* XXX should avoid extra copy */
439 bcopy(inp, &xi.xi_inp, sizeof *inp);
440 if (inp->inp_socket)
441 sotoxsocket(inp->inp_socket, &xi.xi_socket);
442 error = SYSCTL_OUT(req, &xi, sizeof xi);
443 }
444 }
445 if (!error) {
446 /*
447 * Give the user an updated idea of our state.
448 * If the generation differs from what we told
449 * her before, she knows that something happened
450 * while we were processing this request, and it
451 * might be necessary to retry.
452 */
453 s = splnet();
454 xig.xig_gen = udbinfo.ipi_gencnt;
455 xig.xig_sogen = so_gencnt;
456 xig.xig_count = udbinfo.ipi_count;
457 splx(s);
458 error = SYSCTL_OUT(req, &xig, sizeof xig);
459 }
460 free(inp_list, M_TEMP);
461 return error;
462 }
463
464 SYSCTL_PROC(_net_inet_udp, UDPCTL_PCBLIST, pcblist, CTLFLAG_RD, 0, 0,
465 udp_pcblist, "S,xinpcb", "List of active UDP sockets");
466
467 static int
468 udp_getcred SYSCTL_HANDLER_ARGS
469 {
470 struct sockaddr_in addrs[2];
471 struct inpcb *inp;
472 int error, s;
473
474 error = suser(req->p->p_ucred, &req->p->p_acflag);
475 if (error)
476 return (error);
477
478 if (req->newlen != sizeof(addrs))
479 return (EINVAL);
480 if (req->oldlen != sizeof(struct ucred))
481 return (EINVAL);
482 error = SYSCTL_IN(req, addrs, sizeof(addrs));
483 if (error)
484 return (error);
485 s = splnet();
486 inp = in_pcblookup_hash(&udbinfo, addrs[1].sin_addr, addrs[1].sin_port,
487 addrs[0].sin_addr, addrs[0].sin_port, 1);
488 if (!inp || !inp->inp_socket || !inp->inp_socket->so_cred) {
489 error = ENOENT;
490 goto out;
491 }
492 error = SYSCTL_OUT(req, inp->inp_socket->so_cred->pc_ucred,
493 sizeof(struct ucred));
494
495 out:
496 splx(s);
497 return (error);
498 }
499
500 SYSCTL_PROC(_net_inet_udp, OID_AUTO, getcred, CTLTYPE_OPAQUE|CTLFLAG_RW, 0, 0,
501 udp_getcred, "S,ucred", "Get the ucred of a UDP connection");
502
503
504 static int
505 udp_output(inp, m, addr, control, p)
506 register struct inpcb *inp;
507 register struct mbuf *m;
508 struct sockaddr *addr;
509 struct mbuf *control;
510 struct proc *p;
511 {
512 register struct udpiphdr *ui;
513 register int len = m->m_pkthdr.len;
514 struct in_addr laddr;
515 int s = 0, error = 0;
516
517 if (control)
518 m_freem(control); /* XXX */
519
520 if (len + sizeof(struct udpiphdr) > IP_MAXPACKET) {
521 error = EMSGSIZE;
522 goto release;
523 }
524
525 if (addr) {
526 laddr = inp->inp_laddr;
527 if (inp->inp_faddr.s_addr != INADDR_ANY) {
528 error = EISCONN;
529 goto release;
530 }
531 /*
532 * Must block input while temporarily connected.
533 */
534 s = splnet();
535 error = in_pcbconnect(inp, addr, p);
536 if (error) {
537 splx(s);
538 goto release;
539 }
540 } else {
541 if (inp->inp_faddr.s_addr == INADDR_ANY) {
542 error = ENOTCONN;
543 goto release;
544 }
545 }
546 /*
547 * Calculate data length and get a mbuf
548 * for UDP and IP headers.
549 */
550 M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
551 if (m == 0) {
552 error = ENOBUFS;
553 if (addr)
554 splx(s);
555 goto release;
556 }
557
558 /*
559 * Fill in mbuf with extended UDP header
560 * and addresses and length put into network format.
561 */
562 ui = mtod(m, struct udpiphdr *);
563 bzero(ui->ui_x1, sizeof(ui->ui_x1));
564 ui->ui_pr = IPPROTO_UDP;
565 ui->ui_len = htons((u_short)len + sizeof (struct udphdr));
566 ui->ui_src = inp->inp_laddr;
567 ui->ui_dst = inp->inp_faddr;
568 ui->ui_sport = inp->inp_lport;
569 ui->ui_dport = inp->inp_fport;
570 ui->ui_ulen = ui->ui_len;
571
572 /*
573 * Stuff checksum and output datagram.
574 */
575 ui->ui_sum = 0;
576 if (udpcksum) {
577 if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
578 ui->ui_sum = 0xffff;
579 }
580 ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
581 ((struct ip *)ui)->ip_ttl = inp->inp_ip_ttl; /* XXX */
582 ((struct ip *)ui)->ip_tos = inp->inp_ip_tos; /* XXX */
583 udpstat.udps_opackets++;
584 error = ip_output(m, inp->inp_options, &inp->inp_route,
585 inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST),
586 inp->inp_moptions);
587
588 if (addr) {
589 in_pcbdisconnect(inp);
590 inp->inp_laddr = laddr; /* XXX rehash? */
591 splx(s);
592 }
593 return (error);
594
595 release:
596 m_freem(m);
597 return (error);
598 }
599
600 static u_long udp_sendspace = 9216; /* really max datagram size */
601 /* 40 1K datagrams */
602 SYSCTL_INT(_net_inet_udp, UDPCTL_MAXDGRAM, maxdgram, CTLFLAG_RW,
603 &udp_sendspace, 0, "");
604
605 static u_long udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
606 SYSCTL_INT(_net_inet_udp, UDPCTL_RECVSPACE, recvspace, CTLFLAG_RW,
607 &udp_recvspace, 0, "");
608
609 static int
610 udp_abort(struct socket *so)
611 {
612 struct inpcb *inp;
613 int s;
614
615 inp = sotoinpcb(so);
616 if (inp == 0)
617 return EINVAL; /* ??? possible? panic instead? */
618 soisdisconnected(so);
619 s = splnet();
620 in_pcbdetach(inp);
621 splx(s);
622 return 0;
623 }
624
625 static int
626 udp_attach(struct socket *so, int proto, struct proc *p)
627 {
628 struct inpcb *inp;
629 int s, error;
630
631 inp = sotoinpcb(so);
632 if (inp != 0)
633 return EINVAL;
634
635 s = splnet();
636 error = in_pcballoc(so, &udbinfo, p);
637 splx(s);
638 if (error)
639 return error;
640 error = soreserve(so, udp_sendspace, udp_recvspace);
641 if (error)
642 return error;
643 ((struct inpcb *) so->so_pcb)->inp_ip_ttl = ip_defttl;
644 return 0;
645 }
646
647 static int
648 udp_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
649 {
650 struct inpcb *inp;
651 int s, error;
652
653 inp = sotoinpcb(so);
654 if (inp == 0)
655 return EINVAL;
656 s = splnet();
657 error = in_pcbbind(inp, nam, p);
658 splx(s);
659 return error;
660 }
661
662 static int
663 udp_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
664 {
665 struct inpcb *inp;
666 int s, error;
667
668 inp = sotoinpcb(so);
669 if (inp == 0)
670 return EINVAL;
671 if (inp->inp_faddr.s_addr != INADDR_ANY)
672 return EISCONN;
673 s = splnet();
674 error = in_pcbconnect(inp, nam, p);
675 splx(s);
676 if (error == 0)
677 soisconnected(so);
678 return error;
679 }
680
681 static int
682 udp_detach(struct socket *so)
683 {
684 struct inpcb *inp;
685 int s;
686
687 inp = sotoinpcb(so);
688 if (inp == 0)
689 return EINVAL;
690 s = splnet();
691 in_pcbdetach(inp);
692 splx(s);
693 return 0;
694 }
695
696 static int
697 udp_disconnect(struct socket *so)
698 {
699 struct inpcb *inp;
700 int s;
701
702 inp = sotoinpcb(so);
703 if (inp == 0)
704 return EINVAL;
705 if (inp->inp_faddr.s_addr == INADDR_ANY)
706 return ENOTCONN;
707
708 s = splnet();
709 in_pcbdisconnect(inp);
710 inp->inp_laddr.s_addr = INADDR_ANY;
711 splx(s);
712 so->so_state &= ~SS_ISCONNECTED; /* XXX */
713 return 0;
714 }
715
716 static int
717 udp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
718 struct mbuf *control, struct proc *p)
719 {
720 struct inpcb *inp;
721
722 inp = sotoinpcb(so);
723 if (inp == 0) {
724 m_freem(m);
725 return EINVAL;
726 }
727 return udp_output(inp, m, addr, control, p);
728 }
729
730 static int
731 udp_shutdown(struct socket *so)
732 {
733 struct inpcb *inp;
734
735 inp = sotoinpcb(so);
736 if (inp == 0)
737 return EINVAL;
738 socantsendmore(so);
739 return 0;
740 }
741
742 struct pr_usrreqs udp_usrreqs = {
743 udp_abort, pru_accept_notsupp, udp_attach, udp_bind, udp_connect,
744 pru_connect2_notsupp, in_control, udp_detach, udp_disconnect,
745 pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp,
746 pru_rcvoob_notsupp, udp_send, pru_sense_null, udp_shutdown,
747 in_setsockaddr, sosend, soreceive, sopoll
748 };
749
Cache object: 6797dbb61287613c0cb5f6d41476b4fa
|