1 /* $FreeBSD: src/sys/netinet6/udp6_usrreq.c,v 1.6.2.6 2001/07/29 19:32:40 ume Exp $ */
2 /* $KAME: udp6_usrreq.c,v 1.27 2001/05/21 05:45:10 jinmei Exp $ */
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * Copyright (c) 1982, 1986, 1989, 1993
35 * The Regents of the University of California. All rights reserved.
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
45 * 3. All advertising materials mentioning features or use of this software
46 * must display the following acknowledgement:
47 * This product includes software developed by the University of
48 * California, Berkeley and its contributors.
49 * 4. Neither the name of the University nor the names of its contributors
50 * may be used to endorse or promote products derived from this software
51 * without specific prior written permission.
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65 * @(#)udp_var.h 8.1 (Berkeley) 6/10/93
68 #include <sys/param.h>
69 #include <sys/kernel.h>
70 #include <sys/malloc.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>
78 #include <sys/systm.h>
79 #include <sys/syslog.h>
81 #include <sys/kauth.h>
84 #include <net/route.h>
85 #include <net/if_types.h>
87 #include <netinet/in.h>
88 #include <netinet/in_systm.h>
89 #include <netinet/ip.h>
90 #include <netinet/in_pcb.h>
91 #include <netinet/in_var.h>
92 #include <netinet/ip_var.h>
93 #include <netinet/udp.h>
94 #include <netinet/udp_var.h>
95 #include <netinet/ip6.h>
96 #include <netinet6/ip6_var.h>
97 #include <netinet6/in6_pcb.h>
98 #include <netinet/icmp6.h>
99 #include <netinet6/udp6_var.h>
100 #include <netinet6/ip6protosw.h>
103 #include <netinet6/ipsec.h>
104 #include <netinet6/ipsec6.h>
105 extern int ipsec_bypass
;
106 extern lck_mtx_t
*sadb_mutex
;
107 extern lck_mtx_t
*nd6_mutex
;
111 #if defined(NFAITH) && NFAITH > 0
112 #include <net/if_faith.h>
116 * UDP protocol inplementation.
117 * Per RFC 768, August, 1980.
120 extern struct protosw inetsw
[];
121 static int in6_mcmatch(struct inpcb
*, struct in6_addr
*, struct ifnet
*);
122 static int udp6_detach(struct socket
*so
);
125 extern void ipfwsyslog( int level
, char *format
,...);
126 extern int fw_verbose
;
128 #define log_in_vain_log( a ) { \
129 if ( (log_in_vain == 3 ) && (fw_verbose == 2)) { /* Apple logging, log to ipfw.log */ \
139 register struct in6_addr
*ia6
,
142 struct ip6_moptions
*im6o
= in6p
->in6p_moptions
;
143 struct in6_multi_mship
*imm
;
148 lck_mtx_lock(nd6_mutex
);
149 for (imm
= im6o
->im6o_memberships
.lh_first
; imm
!= NULL
;
150 imm
= imm
->i6mm_chain
.le_next
) {
152 imm
->i6mm_maddr
->in6m_ifp
== ifp
) &&
153 IN6_ARE_ADDR_EQUAL(&imm
->i6mm_maddr
->in6m_addr
,
155 lck_mtx_unlock(nd6_mutex
);
159 lck_mtx_unlock(nd6_mutex
);
168 struct mbuf
*m
= *mp
;
169 register struct ip6_hdr
*ip6
;
170 register struct udphdr
*uh
;
171 register struct inpcb
*in6p
;
172 struct mbuf
*opts
= NULL
;
175 struct sockaddr_in6 udp_in6
;
176 struct inpcbinfo
*pcbinfo
= &udbinfo
;
178 IP6_EXTHDR_CHECK(m
, off
, sizeof(struct udphdr
), return IPPROTO_DONE
);
180 ip6
= mtod(m
, struct ip6_hdr
*);
182 #if defined(NFAITH) && 0 < NFAITH
183 if (faithprefix(&ip6
->ip6_dst
)) {
184 /* XXX send icmp6 host/port unreach? */
190 udpstat
.udps_ipackets
++;
192 plen
= ntohs(ip6
->ip6_plen
) - off
+ sizeof(*ip6
);
193 uh
= (struct udphdr
*)((caddr_t
)ip6
+ off
);
194 ulen
= ntohs((u_short
)uh
->uh_ulen
);
197 udpstat
.udps_badlen
++;
202 * Checksum extended UDP header and data.
206 udpstat
.udps_nosum
++;
208 else if (in6_cksum(m
, IPPROTO_UDP
, off
, ulen
) != 0) {
209 udpstat
.udps_badsum
++;
213 if (IN6_IS_ADDR_MULTICAST(&ip6
->ip6_dst
)) {
217 * Deliver a multicast datagram to all sockets
218 * for which the local and remote addresses and ports match
219 * those of the incoming datagram. This allows more than
220 * one process to receive multicasts on the same port.
221 * (This really ought to be done for unicast datagrams as
222 * well, but that would cause problems with existing
223 * applications that open both address-specific sockets and
224 * a wildcard socket listening to the same port -- they would
225 * end up receiving duplicates of every unicast datagram.
226 * Those applications open the multiple sockets to overcome an
227 * inadequacy of the UDP socket interface, but for backwards
228 * compatibility we avoid the problem here rather than
229 * fixing the interface. Maybe 4.5BSD will remedy this?)
233 * In a case that laddr should be set to the link-local
234 * address (this happens in RIPng), the multicast address
235 * specified in the received packet does not match with
236 * laddr. To cure this situation, the matching is relaxed
237 * if the receiving interface is the same as one specified
238 * in the socket and if the destination multicast address
239 * matches one of the multicast groups specified in the socket.
243 * Construct sockaddr format source address.
245 init_sin6(&udp_in6
, m
); /* general init */
246 udp_in6
.sin6_port
= uh
->uh_sport
;
248 * KAME note: usually we drop udphdr from mbuf here.
249 * We need udphdr for IPsec processing so we do that later.
253 * Locate pcb(s) for datagram.
254 * (Algorithm copied from raw_intr().)
257 lck_rw_lock_shared(pcbinfo
->mtx
);
259 LIST_FOREACH(in6p
, &udb
, inp_list
) {
261 if ((in6p
->inp_vflag
& INP_IPV6
) == 0)
264 if (in_pcb_checkstate(in6p
, WNT_ACQUIRE
, 0) == WNT_STOPUSING
)
267 udp_lock(in6p
->in6p_socket
, 1, 0);
269 if (in_pcb_checkstate(in6p
, WNT_RELEASE
, 1) == WNT_STOPUSING
) {
270 udp_unlock(in6p
->in6p_socket
, 1, 0);
273 if (in6p
->in6p_lport
!= uh
->uh_dport
) {
274 udp_unlock(in6p
->in6p_socket
, 1, 0);
277 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p
->in6p_laddr
)) {
278 if (!IN6_ARE_ADDR_EQUAL(&in6p
->in6p_laddr
,
280 !in6_mcmatch(in6p
, &ip6
->ip6_dst
,
281 m
->m_pkthdr
.rcvif
)) {
282 udp_unlock(in6p
->in6p_socket
, 1, 0);
286 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p
->in6p_faddr
)) {
287 if (!IN6_ARE_ADDR_EQUAL(&in6p
->in6p_faddr
,
289 in6p
->in6p_fport
!= uh
->uh_sport
) {
290 udp_unlock(in6p
->in6p_socket
, 1, 0);
300 * Check AH/ESP integrity.
302 if (ipsec_bypass
== 0) {
303 lck_mtx_lock(sadb_mutex
);
304 if (ipsec6_in_reject_so(m
, last
->inp_socket
))
305 ipsec6stat
.in_polvio
++;
306 /* do not inject data into pcb */
307 lck_mtx_unlock(sadb_mutex
);
311 if ((n
= m_copy(m
, 0, M_COPYALL
)) != NULL
) {
314 * m_copy(m, offset, ...) above.
315 * sbappendaddr() expects M_PKTHDR,
316 * and m_copy() will copy M_PKTHDR
317 * only if offset is 0.
319 if (last
->in6p_flags
& IN6P_CONTROLOPTS
320 || last
->in6p_socket
->so_options
& SO_TIMESTAMP
)
321 ip6_savecontrol(last
, &opts
,
324 m_adj(n
, off
+ sizeof(struct udphdr
));
325 if (sbappendaddr(&last
->in6p_socket
->so_rcv
,
326 (struct sockaddr
*)&udp_in6
,
327 n
, opts
, NULL
) == 0) {
328 udpstat
.udps_fullsock
++;
330 sorwakeup(last
->in6p_socket
);
333 udp_unlock(last
->in6p_socket
, 1, 0);
337 * Don't look for additional matches if this one does
338 * not have either the SO_REUSEPORT or SO_REUSEADDR
339 * socket options set. This heuristic avoids searching
340 * through all pcbs in the common case of a non-shared
341 * port. It assumes that an application will never
342 * clear these options after setting them.
344 if ((last
->in6p_socket
->so_options
&
345 (SO_REUSEPORT
|SO_REUSEADDR
)) == 0)
348 lck_rw_done(pcbinfo
->mtx
);
352 * No matching pcb found; discard datagram.
353 * (No need to send an ICMP Port Unreachable
354 * for a broadcast or multicast datgram.)
356 udpstat
.udps_noport
++;
358 udpstat
.udps_noportmcast
++;
364 * Check AH/ESP integrity.
366 if (ipsec_bypass
== 0) {
367 lck_mtx_lock(sadb_mutex
);
368 if (ipsec6_in_reject_so(m
, last
->inp_socket
)) {
369 ipsec6stat
.in_polvio
++;
370 lck_mtx_unlock(sadb_mutex
);
371 udp_unlock(last
->in6p_socket
, 1, 0);
374 lck_mtx_unlock(sadb_mutex
);
377 if (last
->in6p_flags
& IN6P_CONTROLOPTS
378 || last
->in6p_socket
->so_options
& SO_TIMESTAMP
)
379 ip6_savecontrol(last
, &opts
, ip6
, m
);
381 m_adj(m
, off
+ sizeof(struct udphdr
));
382 if (sbappendaddr(&last
->in6p_socket
->so_rcv
,
383 (struct sockaddr
*)&udp_in6
,
384 m
, opts
, NULL
) == 0) {
385 udpstat
.udps_fullsock
++;
388 udp_unlock(last
->in6p_socket
, 1, 0);
391 sorwakeup(last
->in6p_socket
);
392 udp_unlock(last
->in6p_socket
, 1, 0);
396 * Locate pcb for datagram.
398 in6p
= in6_pcblookup_hash(&udbinfo
, &ip6
->ip6_src
, uh
->uh_sport
,
399 &ip6
->ip6_dst
, uh
->uh_dport
, 1,
403 char buf
[INET6_ADDRSTRLEN
];
405 strcpy(buf
, ip6_sprintf(&ip6
->ip6_dst
));
406 if (log_in_vain
!= 3)
408 "Connection attempt to UDP %s:%d from %s:%d\n",
409 buf
, ntohs(uh
->uh_dport
),
410 ip6_sprintf(&ip6
->ip6_src
), ntohs(uh
->uh_sport
));
411 else if (!(m
->m_flags
& (M_BCAST
| M_MCAST
)) &&
412 !IN6_ARE_ADDR_EQUAL(&ip6
->ip6_dst
, &ip6
->ip6_src
))
413 log_in_vain_log((LOG_INFO
,
414 "Connection attempt to UDP %s:%d from %s:%d\n",
415 buf
, ntohs(uh
->uh_dport
),
416 ip6_sprintf(&ip6
->ip6_src
), ntohs(uh
->uh_sport
)));
418 udpstat
.udps_noport
++;
419 if (m
->m_flags
& M_MCAST
) {
420 printf("UDP6: M_MCAST is set in a unicast packet.\n");
422 udpstat
.udps_noportmcast
++;
426 icmp6_error(m
, ICMP6_DST_UNREACH
, ICMP6_DST_UNREACH_NOPORT
, 0);
431 * Check AH/ESP integrity.
433 if (ipsec_bypass
== 0) {
434 lck_mtx_lock(sadb_mutex
);
435 if (ipsec6_in_reject_so(m
, in6p
->in6p_socket
)) {
436 ipsec6stat
.in_polvio
++;
437 lck_mtx_unlock(sadb_mutex
);
438 in_pcb_checkstate(in6p
, WNT_RELEASE
, 0);
441 lck_mtx_unlock(sadb_mutex
);
446 * Construct sockaddr format source address.
447 * Stuff source address and datagram in user buffer.
449 udp_lock(in6p
->in6p_socket
, 1, 0);
451 if (in_pcb_checkstate(in6p
, WNT_RELEASE
, 1) == WNT_STOPUSING
) {
452 udp_unlock(in6p
->in6p_socket
, 1, 0);
456 init_sin6(&udp_in6
, m
); /* general init */
457 udp_in6
.sin6_port
= uh
->uh_sport
;
458 if (in6p
->in6p_flags
& IN6P_CONTROLOPTS
459 || in6p
->in6p_socket
->so_options
& SO_TIMESTAMP
)
460 ip6_savecontrol(in6p
, &opts
, ip6
, m
);
461 m_adj(m
, off
+ sizeof(struct udphdr
));
462 if (sbappendaddr(&in6p
->in6p_socket
->so_rcv
,
463 (struct sockaddr
*)&udp_in6
,
464 m
, opts
, NULL
) == 0) {
467 udpstat
.udps_fullsock
++;
468 udp_unlock(in6p
->in6p_socket
, 1, 0);
471 sorwakeup(in6p
->in6p_socket
);
472 udp_unlock(in6p
->in6p_socket
, 1, 0);
492 struct ip6ctlparam
*ip6cp
= NULL
;
493 const struct sockaddr_in6
*sa6_src
= NULL
;
494 void (*notify
)(struct inpcb
*, int) = udp_notify
;
495 struct udp_portonly
{
500 if (sa
->sa_family
!= AF_INET6
||
501 sa
->sa_len
!= sizeof(struct sockaddr_in6
))
504 if ((unsigned)cmd
>= PRC_NCMDS
)
506 if (PRC_IS_REDIRECT(cmd
))
507 notify
= in6_rtchange
, d
= NULL
;
508 else if (cmd
== PRC_HOSTDEAD
)
510 else if (inet6ctlerrmap
[cmd
] == 0)
513 /* if the parameter is from icmp6, decode it. */
515 ip6cp
= (struct ip6ctlparam
*)d
;
517 ip6
= ip6cp
->ip6c_ip6
;
518 off
= ip6cp
->ip6c_off
;
519 sa6_src
= ip6cp
->ip6c_src
;
528 * XXX: We assume that when IPV6 is non NULL,
529 * M and OFF are valid.
532 /* check if we can safely examine src and dst ports */
533 if (m
->m_pkthdr
.len
< off
+ sizeof(*uhp
))
536 bzero(&uh
, sizeof(uh
));
537 m_copydata(m
, off
, sizeof(*uhp
), (caddr_t
)&uh
);
539 (void) in6_pcbnotify(&udbinfo
, sa
, uh
.uh_dport
,
540 (struct sockaddr
*)ip6cp
->ip6c_src
,
541 uh
.uh_sport
, cmd
, notify
);
543 (void) in6_pcbnotify(&udbinfo
, sa
, 0, (struct sockaddr
*)&sa6_src
,
549 udp6_getcred SYSCTL_HANDLER_ARGS
551 struct sockaddr_in6 addrs
[2];
555 error
= suser(req
->p
->p_ucred
, &req
->p
->p_acflag
);
559 if (req
->newlen
!= sizeof(addrs
))
561 if (req
->oldlen
!= sizeof(*(kauth_cred_t
)0))
563 error
= SYSCTL_IN(req
, addrs
, sizeof(addrs
));
567 inp
= in6_pcblookup_hash(&udbinfo
, &addrs
[1].sin6_addr
,
569 &addrs
[0].sin6_addr
, addrs
[0].sin6_port
,
571 if (!inp
|| !inp
->inp_socket
|| !inp
->inp_socket
->so_cred
) {
575 error
= SYSCTL_OUT(req
, inp
->inp_socket
->so_cred
->pc_ucred
,
576 sizeof(*(kauth_cred_t
)0));
583 SYSCTL_PROC(_net_inet6_udp6
, OID_AUTO
, getcred
, CTLTYPE_OPAQUE
|CTLFLAG_RW
,
585 udp6_getcred
, "S,ucred", "Get the ucred of a UDP6 connection");
589 udp6_abort(struct socket
*so
)
595 return EINVAL
; /* ??? possible? panic instead? */
596 soisdisconnected(so
);
602 udp6_attach(struct socket
*so
, int proto
, struct proc
*p
)
611 error
= in_pcballoc(so
, &udbinfo
, p
);
615 if (so
->so_snd
.sb_hiwat
== 0 || so
->so_rcv
.sb_hiwat
== 0) {
616 error
= soreserve(so
, udp_sendspace
, udp_recvspace
);
620 inp
= (struct inpcb
*)so
->so_pcb
;
621 inp
->inp_vflag
|= INP_IPV6
;
622 if (ip6_mapped_addr_on
)
623 inp
->inp_vflag
|= INP_IPV4
;
624 inp
->in6p_hops
= -1; /* use kernel default */
625 inp
->in6p_cksum
= -1; /* just to be sure */
628 * IPv4 TTL initialization is necessary for an IPv6 socket as well,
629 * because the socket may be bound to an IPv6 wildcard address,
630 * which may match an IPv4-mapped IPv6 address.
632 inp
->inp_ip_ttl
= ip_defttl
;
637 udp6_bind(struct socket
*so
, struct sockaddr
*nam
, struct proc
*p
)
646 inp
->inp_vflag
&= ~INP_IPV4
;
647 inp
->inp_vflag
|= INP_IPV6
;
648 if ((inp
->inp_flags
& IN6P_IPV6_V6ONLY
) == 0) {
649 struct sockaddr_in6
*sin6_p
;
651 sin6_p
= (struct sockaddr_in6
*)nam
;
653 if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p
->sin6_addr
))
654 inp
->inp_vflag
|= INP_IPV4
;
655 else if (IN6_IS_ADDR_V4MAPPED(&sin6_p
->sin6_addr
)) {
656 struct sockaddr_in sin
;
658 in6_sin6_2_sin(&sin
, sin6_p
);
659 inp
->inp_vflag
|= INP_IPV4
;
660 inp
->inp_vflag
&= ~INP_IPV6
;
661 error
= in_pcbbind(inp
, (struct sockaddr
*)&sin
, p
);
666 error
= in6_pcbbind(inp
, nam
, p
);
671 udp6_connect(struct socket
*so
, struct sockaddr
*nam
, struct proc
*p
)
680 if ((inp
->inp_flags
& IN6P_IPV6_V6ONLY
) == 0) {
681 struct sockaddr_in6
*sin6_p
;
683 sin6_p
= (struct sockaddr_in6
*)nam
;
684 if (IN6_IS_ADDR_V4MAPPED(&sin6_p
->sin6_addr
)) {
685 struct sockaddr_in sin
;
687 if (inp
->inp_faddr
.s_addr
!= INADDR_ANY
)
689 in6_sin6_2_sin(&sin
, sin6_p
);
690 error
= in_pcbconnect(inp
, (struct sockaddr
*)&sin
, p
);
692 inp
->inp_vflag
|= INP_IPV4
;
693 inp
->inp_vflag
&= ~INP_IPV6
;
700 if (!IN6_IS_ADDR_UNSPECIFIED(&inp
->in6p_faddr
))
702 error
= in6_pcbconnect(inp
, nam
, p
);
704 if (ip6_mapped_addr_on
|| (inp
->inp_flags
& IN6P_IPV6_V6ONLY
) == 0) { /* should be non mapped addr */
705 inp
->inp_vflag
&= ~INP_IPV4
;
706 inp
->inp_vflag
|= INP_IPV6
;
714 udp6_detach(struct socket
*so
)
726 udp6_disconnect(struct socket
*so
)
734 if (inp
->inp_vflag
& INP_IPV4
) {
735 struct pr_usrreqs
*pru
;
737 pru
= ip_protox
[IPPROTO_UDP
]->pr_usrreqs
;
738 return ((*pru
->pru_disconnect
)(so
));
741 if (IN6_IS_ADDR_UNSPECIFIED(&inp
->in6p_faddr
))
744 in6_pcbdisconnect(inp
);
745 inp
->in6p_laddr
= in6addr_any
;
746 so
->so_state
&= ~SS_ISCONNECTED
; /* XXX */
751 udp6_send(struct socket
*so
, int flags
, struct mbuf
*m
, struct sockaddr
*addr
,
752 struct mbuf
*control
, struct proc
*p
)
764 if (addr
->sa_len
!= sizeof(struct sockaddr_in6
)) {
768 if (addr
->sa_family
!= AF_INET6
) {
769 error
= EAFNOSUPPORT
;
774 if (ip6_mapped_addr_on
|| (inp
->inp_flags
& IN6P_IPV6_V6ONLY
) == 0) {
776 struct sockaddr_in6
*sin6
= 0;
779 hasv4addr
= (inp
->inp_vflag
& INP_IPV4
);
781 sin6
= (struct sockaddr_in6
*)addr
;
782 hasv4addr
= IN6_IS_ADDR_V4MAPPED(&sin6
->sin6_addr
)
786 struct pr_usrreqs
*pru
;
789 in6_sin6_2_sin_in_sock(addr
);
790 pru
= ip_protox
[IPPROTO_UDP
]->pr_usrreqs
;
791 error
= ((*pru
->pru_send
)(so
, flags
, m
, addr
, control
,
793 /* addr will just be freed in sendit(). */
798 return udp6_output(inp
, m
, addr
, control
, p
);
805 struct pr_usrreqs udp6_usrreqs
= {
806 udp6_abort
, pru_accept_notsupp
, udp6_attach
, udp6_bind
, udp6_connect
,
807 pru_connect2_notsupp
, in6_control
, udp6_detach
, udp6_disconnect
,
808 pru_listen_notsupp
, in6_mapped_peeraddr
, pru_rcvd_notsupp
,
809 pru_rcvoob_notsupp
, udp6_send
, pru_sense_null
, udp_shutdown
,
810 in6_mapped_sockaddr
, sosend
, soreceive
, pru_sopoll_notsupp