]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netinet6/udp6_usrreq.c
This commit was generated by cvs2svn to compensate for changes in r56893,
[FreeBSD/FreeBSD.git] / sys / netinet6 / udp6_usrreq.c
1 /*
2  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3  * 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 project 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 PROJECT 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 PROJECT 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
30 /*
31  * Copyright (c) 1982, 1986, 1989, 1993
32  *      The Regents of the University of California.  All rights reserved.
33  *
34  * Redistribution and use in source and binary forms, with or without
35  * modification, are permitted provided that the following conditions
36  * are met:
37  * 1. Redistributions of source code must retain the above copyright
38  *    notice, this list of conditions and the following disclaimer.
39  * 2. Redistributions in binary form must reproduce the above copyright
40  *    notice, this list of conditions and the following disclaimer in the
41  *    documentation and/or other materials provided with the distribution.
42  * 3. All advertising materials mentioning features or use of this software
43  *    must display the following acknowledgement:
44  *      This product includes software developed by the University of
45  *      California, Berkeley and its contributors.
46  * 4. Neither the name of the University nor the names of its contributors
47  *    may be used to endorse or promote products derived from this software
48  *    without specific prior written permission.
49  *
50  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60  * SUCH DAMAGE.
61  *
62  *      @(#)udp_var.h   8.1 (Berkeley) 6/10/93
63  * $FreeBSD$
64  */
65
66 #include "opt_ipsec.h"
67
68 #include <sys/param.h>
69 #include <sys/kernel.h>
70 #include <sys/malloc.h>
71 #include <sys/mbuf.h>
72 #include <sys/protosw.h>
73 #include <sys/socket.h>
74 #include <sys/socketvar.h>
75 #include <sys/sysctl.h>
76 #include <sys/errno.h>
77 #include <sys/stat.h>
78 #include <sys/systm.h>
79 #include <sys/syslog.h>
80 #include <sys/proc.h>
81
82 #include <net/if.h>
83 #include <net/route.h>
84 #include <net/if_types.h>
85
86 #include <netinet/in.h>
87 #include <netinet/in_systm.h>
88 #include <netinet/ip.h>
89 #include <netinet/in_pcb.h>
90 #include <netinet/in_var.h>
91 #include <netinet/ip_var.h>
92 #include <netinet/udp.h>
93 #include <netinet/udp_var.h>
94 #include <netinet6/ip6.h>
95 #include <netinet6/ip6_var.h>
96 #include <netinet6/in6_pcb.h>
97 #include <netinet6/icmp6.h>
98 #include <netinet6/udp6_var.h>
99 #include <netinet6/ip6protosw.h>
100
101 #ifdef IPSEC
102 #include <netinet6/ipsec.h>
103 #include <netinet6/ipsec6.h>
104 #endif /*IPSEC*/
105
106 #include "faith.h"
107
108 /*
109  * UDP protocol inplementation.
110  * Per RFC 768, August, 1980.
111  */
112
113 extern  struct protosw inetsw[];
114 static  int in6_mcmatch __P((struct inpcb *, struct in6_addr *, struct ifnet *));
115 static  int udp6_detach __P((struct socket *so));
116
117 static int
118 in6_mcmatch(in6p, ia6, ifp)
119         struct inpcb *in6p;
120         register struct in6_addr *ia6;
121         struct ifnet *ifp;
122 {
123         struct ip6_moptions *im6o = in6p->in6p_moptions;
124         struct in6_multi_mship *imm;
125
126         if (im6o == NULL)
127                 return 0;
128
129         for (imm = im6o->im6o_memberships.lh_first; imm != NULL;
130              imm = imm->i6mm_chain.le_next) {
131                 if ((ifp == NULL ||
132                      imm->i6mm_maddr->in6m_ifp == ifp) &&
133                     IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr,
134                                        ia6))
135                         return 1;
136         }
137         return 0;
138 }
139
140 int
141 udp6_input(mp, offp, proto)
142         struct mbuf **mp;
143         int *offp, proto;
144 {
145         struct mbuf *m = *mp;
146         register struct ip6_hdr *ip6;
147         register struct udphdr *uh;
148         register struct inpcb *in6p;
149         struct  mbuf *opts = 0;
150         int off = *offp;
151         int plen, ulen;
152         struct sockaddr_in6 udp_in6;
153
154 #if defined(NFAITH) && 0 < NFAITH
155         if (m->m_pkthdr.rcvif) {
156                 if (m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
157                         /* XXX send icmp6 host/port unreach? */
158                         m_freem(m);
159                         return IPPROTO_DONE;
160                 }
161         }
162 #endif
163         udpstat.udps_ipackets++;
164
165         IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE);
166
167         ip6 = mtod(m, struct ip6_hdr *);
168         plen = ntohs(ip6->ip6_plen) - off + sizeof(*ip6);
169         uh = (struct udphdr *)((caddr_t)ip6 + off);
170         ulen = ntohs((u_short)uh->uh_ulen);
171
172         if (plen != ulen) {
173                 udpstat.udps_badlen++;
174                 goto bad;
175         }
176
177         /*
178          * Checksum extended UDP header and data.
179          */
180         if (uh->uh_sum == 0)
181                 udpstat.udps_nosum++;
182         else if (in6_cksum(m, IPPROTO_UDP, off, ulen) != 0) {
183                 udpstat.udps_badsum++;
184                 goto bad;
185         }
186
187         if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
188                 struct  inpcb *last;
189
190                 /*
191                  * Deliver a multicast datagram to all sockets
192                  * for which the local and remote addresses and ports match
193                  * those of the incoming datagram.  This allows more than
194                  * one process to receive multicasts on the same port.
195                  * (This really ought to be done for unicast datagrams as
196                  * well, but that would cause problems with existing
197                  * applications that open both address-specific sockets and
198                  * a wildcard socket listening to the same port -- they would
199                  * end up receiving duplicates of every unicast datagram.
200                  * Those applications open the multiple sockets to overcome an
201                  * inadequacy of the UDP socket interface, but for backwards
202                  * compatibility we avoid the problem here rather than
203                  * fixing the interface.  Maybe 4.5BSD will remedy this?)
204                  */
205
206                 /*
207                  * In a case that laddr should be set to the link-local
208                  * address (this happens in RIPng), the multicast address
209                  * specified in the received packet does not match with
210                  * laddr. To cure this situation, the matching is relaxed
211                  * if the receiving interface is the same as one specified
212                  * in the socket and if the destination multicast address
213                  * matches one of the multicast groups specified in the socket.
214                  */
215
216                 /*
217                  * Construct sockaddr format source address.
218                  */
219                 init_sin6(&udp_in6, m); /* general init */
220                 udp_in6.sin6_port = uh->uh_sport;
221                 /*
222                  * KAME note: usually we drop udphdr from mbuf here.
223                  * We need udphdr for IPsec processing so we do that later.
224                  */
225
226                 /*
227                  * Locate pcb(s) for datagram.
228                  * (Algorithm copied from raw_intr().)
229                  */
230                 last = NULL;
231                 LIST_FOREACH(in6p, &udb, inp_list) {
232                         if ((in6p->inp_vflag & INP_IPV6) == 0)
233                                 continue;
234                         if (in6p->in6p_lport != uh->uh_dport)
235                                 continue;
236                         if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) {
237                                 if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr,
238                                                         &ip6->ip6_dst) &&
239                                     !in6_mcmatch(in6p, &ip6->ip6_dst,
240                                                  m->m_pkthdr.rcvif))
241                                         continue;
242                         }
243                         if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
244                                 if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr,
245                                                         &ip6->ip6_src) ||
246                                    in6p->in6p_fport != uh->uh_sport)
247                                         continue;
248                         }
249
250                         if (last != NULL) {
251                                 struct  mbuf *n;
252
253 #ifdef IPSEC
254                                 /*
255                                  * Check AH/ESP integrity.
256                                  */
257                                 if (ipsec6_in_reject_so(m, last->inp_socket))
258                                         ipsec6stat.in_polvio++;
259                                         /* do not inject data into pcb */
260                                 else
261 #endif /*IPSEC*/
262                                 if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
263                                         /*
264                                          * KAME NOTE: do not
265                                          * m_copy(m, offset, ...) above.
266                                          * sbappendaddr() expects M_PKTHDR,
267                                          * and m_copy() will copy M_PKTHDR
268                                          * only if offset is 0.
269                                          */
270                                         if (last->in6p_flags & IN6P_CONTROLOPTS
271                                             || last->in6p_socket->so_options & SO_TIMESTAMP)
272                                                 ip6_savecontrol(last, &opts,
273                                                                 ip6, n);
274                                         m_adj(n, off + sizeof(struct udphdr));
275                                         if (sbappendaddr(&last->in6p_socket->so_rcv,
276                                                         (struct sockaddr *)&udp_in6,
277                                                         n, opts) == 0) {
278                                                 m_freem(n);
279                                                 if (opts)
280                                                         m_freem(opts);
281                                                 udpstat.udps_fullsock++;
282                                         } else
283                                                 sorwakeup(last->in6p_socket);
284                                         opts = 0;
285                                 }
286                         }
287                         last = in6p;
288                         /*
289                          * Don't look for additional matches if this one does
290                          * not have either the SO_REUSEPORT or SO_REUSEADDR
291                          * socket options set.  This heuristic avoids searching
292                          * through all pcbs in the common case of a non-shared
293                          * port.  It assumes that an application will never
294                          * clear these options after setting them.
295                          */
296                         if ((last->in6p_socket->so_options &
297                              (SO_REUSEPORT|SO_REUSEADDR)) == 0)
298                                 break;
299                 }
300
301                 if (last == NULL) {
302                         /*
303                          * No matching pcb found; discard datagram.
304                          * (No need to send an ICMP Port Unreachable
305                          * for a broadcast or multicast datgram.)
306                          */
307                         udpstat.udps_noport++;
308                         udpstat.udps_noportmcast++;
309                         goto bad;
310                 }
311 #ifdef IPSEC
312                 /*
313                  * Check AH/ESP integrity.
314                  */
315                 if (ipsec6_in_reject_so(m, last->inp_socket)) {
316                         ipsec6stat.in_polvio++;
317                         goto bad;
318                 }
319 #endif /*IPSEC*/
320                 if (last->in6p_flags & IN6P_CONTROLOPTS
321                     || last->in6p_socket->so_options & SO_TIMESTAMP)
322                         ip6_savecontrol(last, &opts, ip6, m);
323
324                 m_adj(m, off + sizeof(struct udphdr));
325                 if (sbappendaddr(&last->in6p_socket->so_rcv,
326                                 (struct sockaddr *)&udp_in6,
327                                 m, opts) == 0) {
328                         udpstat.udps_fullsock++;
329                         goto bad;
330                 }
331                 sorwakeup(last->in6p_socket);
332                 return IPPROTO_DONE;
333         }
334         /*
335          * Locate pcb for datagram.
336          */
337         in6p = in6_pcblookup_hash(&udbinfo, &ip6->ip6_src, uh->uh_sport,
338                                   &ip6->ip6_dst, uh->uh_dport, 1,
339                                   m->m_pkthdr.rcvif);
340         if (in6p == 0) {
341                 if (log_in_vain) {
342                         char buf[INET6_ADDRSTRLEN];
343
344                         strcpy(buf, ip6_sprintf(&ip6->ip6_dst));
345                         log(LOG_INFO,
346                             "Connection attempt to UDP %s:%d from %s:%d\n",
347                             buf, ntohs(uh->uh_dport),
348                             ip6_sprintf(&ip6->ip6_src), ntohs(uh->uh_sport));
349                 }
350                 udpstat.udps_noport++;
351                 if (m->m_flags & M_MCAST) {
352                         printf("UDP6: M_MCAST is set in a unicast packet.\n");
353                         udpstat.udps_noportmcast++;
354                         goto bad;
355                 }
356                 icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0);
357                 return IPPROTO_DONE;
358         }
359 #ifdef IPSEC
360         /*
361          * Check AH/ESP integrity.
362          */
363         if (ipsec6_in_reject_so(m, in6p->in6p_socket)) {
364                 ipsec6stat.in_polvio++;
365                 goto bad;
366         }
367 #endif /*IPSEC*/
368
369         /*
370          * Construct sockaddr format source address.
371          * Stuff source address and datagram in user buffer.
372          */
373         init_sin6(&udp_in6, m); /* general init */
374         udp_in6.sin6_port = uh->uh_sport;
375         if (in6p->in6p_flags & IN6P_CONTROLOPTS
376             || in6p->in6p_socket->so_options & SO_TIMESTAMP)
377                 ip6_savecontrol(in6p, &opts, ip6, m);
378         m_adj(m, off + sizeof(struct udphdr));
379         if (sbappendaddr(&in6p->in6p_socket->so_rcv,
380                         (struct sockaddr *)&udp_in6,
381                         m, opts) == 0) {
382                 udpstat.udps_fullsock++;
383                 goto bad;
384         }
385         sorwakeup(in6p->in6p_socket);
386         return IPPROTO_DONE;
387 bad:
388         if (m)
389                 m_freem(m);
390         if (opts)
391                 m_freem(opts);
392         return IPPROTO_DONE;
393 }
394
395 void
396 udp6_ctlinput(cmd, sa, d)
397         int cmd;
398         struct sockaddr *sa;
399         void *d;
400 {
401         register struct udphdr *uhp;
402         struct udphdr uh;
403         struct sockaddr_in6 sa6;
404         struct ip6_hdr *ip6;
405         struct mbuf *m;
406         int off;
407
408         if (sa->sa_family != AF_INET6 ||
409             sa->sa_len != sizeof(struct sockaddr_in6))
410                 return;
411
412         off = 0;
413         if (!PRC_IS_REDIRECT(cmd) &&
414             ((unsigned)cmd >= PRC_NCMDS || inet6ctlerrmap[cmd] == 0))
415                 return;
416
417         /* if the parameter is from icmp6, decode it. */
418         if (d != NULL) {
419                 struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d;
420                 m = ip6cp->ip6c_m;
421                 ip6 = ip6cp->ip6c_ip6;
422                 off = ip6cp->ip6c_off;
423         } else {
424                 m = NULL;
425                 ip6 = NULL;
426         }
427
428         /* translate addresses into internal form */
429         sa6 = *(struct sockaddr_in6 *)sa;
430         if (m != NULL && IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr))
431                 sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
432
433         if (ip6) {
434                 /*
435                  * XXX: We assume that when IPV6 is non NULL,
436                  * M and OFF are valid.
437                  */
438                 struct in6_addr s;
439
440                 /* translate addresses into internal form */
441                 memcpy(&s, &ip6->ip6_src, sizeof(s));
442                 if (IN6_IS_ADDR_LINKLOCAL(&s))
443                         s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
444
445                 if (m->m_len < off + sizeof(uh)) {
446                         /*
447                          * this should be rare case,
448                          * so we compromise on this copy...
449                          */
450                         m_copydata(m, off, sizeof(uh), (caddr_t)&uh);
451                         uhp = &uh;
452                 } else
453                         uhp = (struct udphdr *)(mtod(m, caddr_t) + off);
454                 (void) in6_pcbnotify(&udb, (struct sockaddr *)&sa6,
455                                      uhp->uh_dport, &s,
456                                      uhp->uh_sport, cmd, udp_notify);
457         } else
458                 (void) in6_pcbnotify(&udb, (struct sockaddr *)&sa6, 0,
459                                      &zeroin6_addr, 0, cmd, udp_notify);
460 }
461
462 static int
463 udp6_getcred SYSCTL_HANDLER_ARGS
464 {
465         struct sockaddr_in6 addrs[2];
466         struct inpcb *inp;
467         int error, s;
468
469         error = suser(req->p);
470         if (error)
471                 return (error);
472         error = SYSCTL_IN(req, addrs, sizeof(addrs));
473         if (error)
474                 return (error);
475         s = splnet();
476         inp = in6_pcblookup_hash(&udbinfo, &addrs[1].sin6_addr,
477                                  addrs[1].sin6_port,
478                                  &addrs[0].sin6_addr, addrs[0].sin6_port,
479                                  1, NULL);
480         if (!inp || !inp->inp_socket) {
481                 error = ENOENT;
482                 goto out;
483         }
484         error = SYSCTL_OUT(req, inp->inp_socket->so_cred,
485                            sizeof(struct ucred));
486
487 out:
488         splx(s);
489         return (error);
490 }
491
492 SYSCTL_PROC(_net_inet6_udp6, OID_AUTO, getcred, CTLTYPE_OPAQUE|CTLFLAG_RW,
493             0, 0,
494             udp6_getcred, "S,ucred", "Get the ucred of a UDP6 connection");
495
496 int
497 udp6_output(in6p, m, addr6, control, p)
498         register struct inpcb *in6p;
499         struct mbuf *m;
500         struct sockaddr *addr6;
501         struct mbuf *control;
502         struct proc *p;
503 {
504         register int ulen = m->m_pkthdr.len;
505         int plen = sizeof(struct udphdr) + ulen;
506         struct ip6_hdr *ip6;
507         struct udphdr *udp6;
508         struct  in6_addr laddr6;
509         int s = 0, error = 0;
510         struct ip6_pktopts opt, *stickyopt = in6p->in6p_outputopts;
511
512         if (control) {
513                 if ((error = ip6_setpktoptions(control, &opt, suser(p))) != 0)
514                         goto release;
515                 in6p->in6p_outputopts = &opt;
516         }
517
518         if (addr6) {
519                 laddr6 = in6p->in6p_laddr;
520                 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
521                         error = EISCONN;
522                         goto release;
523                 }
524                 /*
525                  * Must block input while temporarily connected.
526                  */
527                 s = splnet();
528                 /*
529                  * XXX: the user might want to overwrite the local address
530                  * via an ancillary data.
531                  */
532                 bzero(&in6p->in6p_laddr, sizeof(struct in6_addr));
533                 error = in6_pcbconnect(in6p, addr6, p);
534                 if (error) {
535                         splx(s);
536                         goto release;
537                 }
538         } else {
539                 if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
540                         error = ENOTCONN;
541                         goto release;
542                 }
543         }
544         /*
545          * Calculate data length and get a mbuf
546          * for UDP and IP6 headers.
547          */
548         M_PREPEND(m, sizeof(struct ip6_hdr) + sizeof(struct udphdr),
549                   M_DONTWAIT);
550         if (m == 0) {
551                 error = ENOBUFS;
552                 if (addr6)
553                         splx(s);
554                 goto release;
555         }
556
557         /*
558          * Stuff checksum and output datagram.
559          */
560         ip6 = mtod(m, struct ip6_hdr *);
561         ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) |
562                 (in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK);
563         ip6->ip6_vfc = (ip6->ip6_vfc & ~IPV6_VERSION_MASK) |
564                 (IPV6_VERSION & IPV6_VERSION_MASK);
565         /* ip6_plen will be filled in ip6_output. */
566         ip6->ip6_nxt    = IPPROTO_UDP;
567         ip6->ip6_hlim   = in6_selecthlim(in6p,
568                                          in6p->in6p_route.ro_rt ?
569                                          in6p->in6p_route.ro_rt->rt_ifp :
570                                          NULL);
571         ip6->ip6_src    = in6p->in6p_laddr;
572         ip6->ip6_dst    = in6p->in6p_faddr;
573
574         udp6 = (struct udphdr *)(ip6 + 1);
575         udp6->uh_sport = in6p->in6p_lport;
576         udp6->uh_dport = in6p->in6p_fport;
577         udp6->uh_ulen  = htons((u_short)plen);
578         udp6->uh_sum   = 0;
579
580         if ((udp6->uh_sum = in6_cksum(m, IPPROTO_UDP,
581                                         sizeof(struct ip6_hdr), plen)) == 0) {
582                 udp6->uh_sum = 0xffff;
583         }
584
585         udpstat.udps_opackets++;
586
587 #ifdef IPSEC
588         m->m_pkthdr.rcvif = (struct ifnet *)in6p->in6p_socket;
589 #endif /*IPSEC*/
590         error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route,
591                             IPV6_SOCKINMRCVIF, in6p->in6p_moptions, NULL);
592
593         if (addr6) {
594                 in6_pcbdisconnect(in6p);
595                 in6p->in6p_laddr = laddr6;
596                 splx(s);
597         }
598         goto releaseopt;
599
600 release:
601         m_freem(m);
602
603 releaseopt:
604         if (control) {
605                 in6p->in6p_outputopts = stickyopt;
606                 m_freem(control);
607         }
608         return(error);
609 }
610
611 static int
612 udp6_abort(struct socket *so)
613 {
614         struct inpcb *inp;
615         int s;
616
617         inp = sotoinpcb(so);
618         if (inp == 0)
619                 return EINVAL;  /* ??? possible? panic instead? */
620         soisdisconnected(so);
621         s = splnet();
622         in6_pcbdetach(inp);
623         splx(s);
624         return 0;
625 }
626
627 static int
628 udp6_attach(struct socket *so, int proto, struct proc *p)
629 {
630         struct inpcb *inp;
631         int s, error;
632
633         inp = sotoinpcb(so);
634         if (inp != 0)
635                 return EINVAL;
636
637         if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
638                 error = soreserve(so, udp_sendspace, udp_recvspace);
639                 if (error)
640                         return error;
641         }
642         s = splnet();
643         error = in_pcballoc(so, &udbinfo, p);
644         splx(s);
645         if (error)
646                 return error;
647         inp = (struct inpcb *)so->so_pcb;
648         inp->inp_vflag |= INP_IPV6;
649         inp->in6p_hops = -1;    /* use kernel default */
650         inp->in6p_cksum = -1;   /* just to be sure */
651 #ifdef IPSEC
652         error = ipsec_init_policy(so, &inp->in6p_sp);
653         if (error != 0) {
654                 in6_pcbdetach(inp);
655                 return (error);
656         }
657 #endif /*IPSEC*/
658         return 0;
659 }
660
661 static int
662 udp6_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
663 {
664         struct inpcb *inp;
665         int s, error;
666
667         inp = sotoinpcb(so);
668         if (inp == 0)
669                 return EINVAL;
670
671         inp->inp_vflag &= ~INP_IPV4;
672         inp->inp_vflag |= INP_IPV6;
673         if (ip6_mapped_addr_on && (inp->inp_flags & IN6P_BINDV6ONLY) == 0) {
674                 struct sockaddr_in6 *sin6_p;
675
676                 sin6_p = (struct sockaddr_in6 *)nam;
677
678                 if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr))
679                         inp->inp_vflag |= INP_IPV4;
680                 else if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
681                         struct sockaddr_in sin;
682
683                         in6_sin6_2_sin(&sin, sin6_p);
684                         inp->inp_vflag |= INP_IPV4;
685                         inp->inp_vflag &= ~INP_IPV6;
686                         s = splnet();
687                         error = in_pcbbind(inp, (struct sockaddr *)&sin, p);
688                         splx(s);
689                         return error;
690                 }
691         }
692
693         s = splnet();
694         error = in6_pcbbind(inp, nam, p);
695         splx(s);
696         return error;
697 }
698
699 static int
700 udp6_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
701 {
702         struct inpcb *inp;
703         int s, error;
704
705         inp = sotoinpcb(so);
706         if (inp == 0)
707                 return EINVAL;
708         if (ip6_mapped_addr_on) {
709                 struct sockaddr_in6 *sin6_p;
710
711                 sin6_p = (struct sockaddr_in6 *)nam;
712                 if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
713                         struct sockaddr_in sin;
714
715                         if (inp->inp_faddr.s_addr != INADDR_ANY)
716                                 return EISCONN;
717                         in6_sin6_2_sin(&sin, sin6_p);
718                         s = splnet();
719                         error = in_pcbconnect(inp, (struct sockaddr *)&sin, p);
720                         splx(s);
721                         if (error == 0) {
722                                 inp->inp_vflag |= INP_IPV4;
723                                 inp->inp_vflag &= ~INP_IPV6;
724                                 soisconnected(so);
725                         }
726                         return error;
727                 }
728         }
729         if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr))
730                 return EISCONN;
731         s = splnet();
732         error = in6_pcbconnect(inp, nam, p);
733         splx(s);
734         if (error == 0) {
735                 inp->inp_vflag &= ~INP_IPV4;
736                 inp->inp_vflag |= INP_IPV6;
737                 soisconnected(so);
738         }
739         return error;
740 }
741
742 static int
743 udp6_detach(struct socket *so)
744 {
745         struct inpcb *inp;
746         int s;
747
748         inp = sotoinpcb(so);
749         if (inp == 0)
750                 return EINVAL;
751         s = splnet();
752         in6_pcbdetach(inp);
753         splx(s);
754         return 0;
755 }
756
757 static int
758 udp6_disconnect(struct socket *so)
759 {
760         struct inpcb *inp;
761         int s;
762
763         inp = sotoinpcb(so);
764         if (inp == 0)
765                 return EINVAL;
766
767         if (inp->inp_vflag & INP_IPV4) {
768                 struct pr_usrreqs *pru;
769
770                 pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs;
771                 return ((*pru->pru_disconnect)(so));
772         }
773
774         if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr))
775                 return ENOTCONN;
776
777         s = splnet();
778         in6_pcbdisconnect(inp);
779         inp->in6p_laddr = in6addr_any;
780         splx(s);
781         so->so_state &= ~SS_ISCONNECTED;                /* XXX */
782         return 0;
783 }
784
785 static int
786 udp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
787           struct mbuf *control, struct proc *p)
788 {
789         struct inpcb *inp;
790
791         inp = sotoinpcb(so);
792         if (inp == 0) {
793                 m_freem(m);
794                 return EINVAL;
795         }
796
797         if (ip6_mapped_addr_on) {
798                 int hasv4addr;
799                 struct sockaddr_in6 *sin6 = 0;
800
801                 if (addr == 0)
802                         hasv4addr = (inp->inp_vflag & INP_IPV4);
803                 else {
804                         sin6 = (struct sockaddr_in6 *)addr;
805                         hasv4addr = IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)
806                                 ? 1 : 0;
807                 }
808                 if (hasv4addr) {
809                         struct pr_usrreqs *pru;
810                         int error;
811
812                         if (sin6)
813                                 in6_sin6_2_sin_in_sock(addr);
814                         pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs;
815                         error = ((*pru->pru_send)(so, flags, m, addr, control,
816                                                   p));
817                         /* addr will just be freed in sendit(). */
818                         return error;
819                 }
820         }
821
822         return udp6_output(inp, m, addr, control, p);
823 }
824
825 struct pr_usrreqs udp6_usrreqs = {
826         udp6_abort, pru_accept_notsupp, udp6_attach, udp6_bind, udp6_connect,
827         pru_connect2_notsupp, in6_control, udp6_detach, udp6_disconnect,
828         pru_listen_notsupp, in6_mapped_peeraddr, pru_rcvd_notsupp,
829         pru_rcvoob_notsupp, udp6_send, pru_sense_null, udp_shutdown,
830         in6_mapped_sockaddr, sosend, soreceive, sopoll
831 };