[BACK]Return to udp6_usrreq.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / netinet6

Annotation of src/sys/netinet6/udp6_usrreq.c, Revision 1.30

1.30    ! itojun      1: /*     $NetBSD: udp6_usrreq.c,v 1.29 2000/06/05 06:38:23 itojun Exp $  */
1.29      itojun      2: /*     $KAME: udp6_usrreq.c,v 1.52 2000/06/05 00:41:58 itojun Exp $    */
1.3       thorpej     3:
1.2       itojun      4: /*
                      5:  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
                      6:  * All rights reserved.
1.27      itojun      7:  *
1.2       itojun      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     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.
1.27      itojun     19:  *
1.2       itojun     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
                     30:  * SUCH DAMAGE.
                     31:  */
                     32:
                     33: /*
                     34:  * Copyright (c) 1982, 1986, 1989, 1993
                     35:  *     The Regents of the University of California.  All rights reserved.
                     36:  *
                     37:  * Redistribution and use in source and binary forms, with or without
                     38:  * modification, are permitted provided that the following conditions
                     39:  * are met:
                     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.
                     52:  *
                     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
                     63:  * SUCH DAMAGE.
                     64:  *
                     65:  *     @(#)udp_var.h   8.1 (Berkeley) 6/10/93
                     66:  */
1.5       thorpej    67:
                     68: #include "opt_ipsec.h"
1.2       itojun     69:
                     70: #include <sys/param.h>
                     71: #include <sys/malloc.h>
                     72: #include <sys/mbuf.h>
                     73: #include <sys/protosw.h>
                     74: #include <sys/socket.h>
                     75: #include <sys/socketvar.h>
                     76: #include <sys/errno.h>
                     77: #include <sys/stat.h>
                     78: #include <sys/systm.h>
                     79: #include <sys/proc.h>
1.8       itojun     80: #include <sys/syslog.h>
1.2       itojun     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_var.h>
1.14      itojun     88: #include <netinet/in_systm.h>
                     89: #include <netinet/ip.h>
                     90: #include <netinet/ip_var.h>
                     91: #include <netinet/in_pcb.h>
                     92: #include <netinet/udp.h>
                     93: #include <netinet/udp_var.h>
1.23      itojun     94: #include <netinet/ip6.h>
1.27      itojun     95: #include <netinet6/ip6_var.h>
1.2       itojun     96: #include <netinet6/in6_pcb.h>
1.23      itojun     97: #include <netinet/icmp6.h>
1.2       itojun     98: #include <netinet6/udp6_var.h>
1.14      itojun     99: #include <netinet6/ip6protosw.h>
1.2       itojun    100:
                    101: #ifdef IPSEC
                    102: #include <netinet6/ipsec.h>
                    103: #endif /*IPSEC*/
                    104:
                    105: #include "faith.h"
                    106:
                    107: /*
                    108:  * UDP protocol inplementation.
                    109:  * Per RFC 768, August, 1980.
                    110:  */
                    111:
                    112: struct in6pcb *udp6_last_in6pcb = &udb6;
                    113:
1.17      itojun    114: #ifdef UDP6
1.2       itojun    115: static int in6_mcmatch __P((struct in6pcb *, struct in6_addr *, struct ifnet *));
1.14      itojun    116: #endif
1.2       itojun    117: static void udp6_detach __P((struct in6pcb *));
                    118: static void udp6_notify __P((struct in6pcb *, int));
                    119:
                    120: void
                    121: udp6_init()
                    122: {
                    123:        udb6.in6p_next = udb6.in6p_prev = &udb6;
                    124: }
                    125:
1.17      itojun    126: #ifdef UDP6
1.2       itojun    127: static int
                    128: in6_mcmatch(in6p, ia6, ifp)
                    129:        struct in6pcb *in6p;
                    130:        register struct in6_addr *ia6;
                    131:        struct ifnet *ifp;
                    132: {
                    133:        struct ip6_moptions *im6o = in6p->in6p_moptions;
                    134:        struct in6_multi_mship *imm;
                    135:
                    136:        if (im6o == NULL)
                    137:                return 0;
                    138:
                    139:        for (imm = im6o->im6o_memberships.lh_first; imm != NULL;
                    140:             imm = imm->i6mm_chain.le_next) {
                    141:                if ((ifp == NULL ||
                    142:                     imm->i6mm_maddr->in6m_ifp == ifp) &&
                    143:                    IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr,
                    144:                                       ia6))
                    145:                        return 1;
                    146:        }
                    147:        return 0;
                    148: }
                    149:
                    150: int
                    151: udp6_input(mp, offp, proto)
                    152:        struct mbuf **mp;
                    153:        int *offp, proto;
                    154: {
                    155:        struct mbuf *m = *mp;
                    156:        register struct ip6_hdr *ip6;
                    157:        register struct udphdr *uh;
                    158:        register struct in6pcb *in6p;
                    159:        struct  mbuf *opts = 0;
                    160:        int off = *offp;
1.14      itojun    161:        u_int32_t plen, ulen;
1.2       itojun    162:        struct sockaddr_in6 udp_in6;
                    163:
                    164: #if defined(NFAITH) && 0 < NFAITH
                    165:        if (m->m_pkthdr.rcvif) {
                    166:                if (m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
                    167:                        /* send icmp6 host unreach? */
                    168:                        m_freem(m);
                    169:                        return IPPROTO_DONE;
                    170:                }
                    171:        }
                    172: #endif
                    173:        udp6stat.udp6s_ipackets++;
                    174:
1.14      itojun    175:        ip6 = mtod(m, struct ip6_hdr *);
                    176:        /* check for jumbogram is done in ip6_input.  we can trust pkthdr.len */
                    177:        plen = m->m_pkthdr.len - off;
                    178: #ifndef PULLDOWN_TEST
1.2       itojun    179:        IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE);
                    180:        uh = (struct udphdr *)((caddr_t)ip6 + off);
1.14      itojun    181: #else
1.24      itojun    182:        IP6_EXTHDR_GET(uh, struct udphdr *, m, off, sizeof(struct udphdr));
1.14      itojun    183:        if (uh == NULL) {
                    184:                udp6stat.udp6s_hdrops++;
                    185:                return IPPROTO_DONE;
                    186:        }
                    187: #endif
1.2       itojun    188:        ulen = ntohs((u_short)uh->uh_ulen);
1.27      itojun    189:        /*
                    190:         * RFC2675 section 4: jumbograms will have 0 in the UDP header field,
                    191:         * iff payload length > 0xffff.
                    192:         */
                    193:        if (ulen == 0 && plen > 0xffff)
1.14      itojun    194:                ulen = plen;
1.2       itojun    195:
                    196:        if (plen != ulen) {
                    197:                udp6stat.udp6s_badlen++;
1.16      itojun    198:                goto bad;
                    199:        }
1.18      itojun    200:
                    201:        /* destination port of 0 is illegal, based on RFC768. */
                    202:        if (uh->uh_dport == 0)
                    203:                goto bad;
1.16      itojun    204:
                    205:        /* Be proactive about malicious use of IPv4 mapped address */
                    206:        if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) ||
                    207:            IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) {
                    208:                /* XXX stat */
1.2       itojun    209:                goto bad;
                    210:        }
                    211:
                    212:        /*
                    213:         * Checksum extended UDP header and data.
                    214:         */
                    215:        if (uh->uh_sum == 0)
                    216:                udp6stat.udp6s_nosum++;
                    217:        else if (in6_cksum(m, IPPROTO_UDP, off, ulen) != 0) {
                    218:                udp6stat.udp6s_badsum++;
                    219:                goto bad;
                    220:        }
                    221:
                    222:        if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
                    223:                struct  in6pcb *last;
                    224:
                    225:                /*
                    226:                 * Deliver a multicast datagram to all sockets
                    227:                 * for which the local and remote addresses and ports match
                    228:                 * those of the incoming datagram.  This allows more than
                    229:                 * one process to receive multicasts on the same port.
                    230:                 * (This really ought to be done for unicast datagrams as
                    231:                 * well, but that would cause problems with existing
                    232:                 * applications that open both address-specific sockets and
                    233:                 * a wildcard socket listening to the same port -- they would
                    234:                 * end up receiving duplicates of every unicast datagram.
                    235:                 * Those applications open the multiple sockets to overcome an
                    236:                 * inadequacy of the UDP socket interface, but for backwards
                    237:                 * compatibility we avoid the problem here rather than
                    238:                 * fixing the interface.  Maybe 4.5BSD will remedy this?)
                    239:                 */
                    240:
                    241:                /*
                    242:                 * In a case that laddr should be set to the link-local
                    243:                 * address (this happens in RIPng), the multicast address
                    244:                 * specified in the received packet does not match with
                    245:                 * laddr. To cure this situation, the matching is relaxed
                    246:                 * if the receiving interface is the same as one specified
                    247:                 * in the socket and if the destination multicast address
                    248:                 * matches one of the multicast groups specified in the socket.
                    249:                 */
                    250:
1.27      itojun    251:                /*
1.2       itojun    252:                 * Construct sockaddr format source address.
                    253:                 */
                    254:                bzero(&udp_in6, sizeof(udp_in6));
                    255:                udp_in6.sin6_len = sizeof(struct sockaddr_in6);
                    256:                udp_in6.sin6_family = AF_INET6;
                    257:                udp_in6.sin6_port = uh->uh_sport;
                    258:                udp_in6.sin6_addr = ip6->ip6_src;
                    259:                if (IN6_IS_SCOPE_LINKLOCAL(&udp_in6.sin6_addr))
                    260:                        udp_in6.sin6_addr.s6_addr16[1] = 0;
                    261:                if (m->m_pkthdr.rcvif) {
                    262:                        if (IN6_IS_SCOPE_LINKLOCAL(&udp_in6.sin6_addr)) {
                    263:                                udp_in6.sin6_scope_id =
                    264:                                        m->m_pkthdr.rcvif->if_index;
                    265:                        } else
                    266:                                udp_in6.sin6_scope_id = 0;
                    267:                } else
                    268:                        udp_in6.sin6_scope_id = 0;
                    269:                /*
                    270:                 * KAME note: usually we drop udphdr from mbuf here.
                    271:                 * We need udphdr for IPsec processing so we do that later.
                    272:                 */
                    273:
                    274:                /*
                    275:                 * Locate pcb(s) for datagram.
                    276:                 * (Algorithm copied from raw_intr().)
                    277:                 */
                    278:                last = NULL;
                    279:                for (in6p = udb6.in6p_next;
                    280:                     in6p != &udb6;
                    281:                     in6p = in6p->in6p_next) {
                    282:                        if (in6p->in6p_lport != uh->uh_dport)
                    283:                                continue;
1.14      itojun    284:                        if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) {
1.2       itojun    285:                                if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr,
                    286:                                                        &ip6->ip6_dst) &&
                    287:                                    !in6_mcmatch(in6p, &ip6->ip6_dst,
                    288:                                                 m->m_pkthdr.rcvif))
                    289:                                        continue;
                    290:                        }
1.14      itojun    291:                        if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
1.2       itojun    292:                                if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr,
                    293:                                                        &ip6->ip6_src) ||
                    294:                                   in6p->in6p_fport != uh->uh_sport)
                    295:                                        continue;
                    296:                        }
                    297:
                    298:                        if (last != NULL) {
                    299:                                struct  mbuf *n;
                    300:
                    301: #ifdef IPSEC
                    302:                                /*
                    303:                                 * Check AH/ESP integrity.
                    304:                                 */
1.24      itojun    305:                                if (ipsec6_in_reject(m, last)) {
1.2       itojun    306:                                        ipsec6stat.in_polvio++;
                    307:                                        /* do not inject data into pcb */
                    308:                                } else
                    309: #endif /*IPSEC*/
                    310:                                if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
                    311:                                        /*
                    312:                                         * KAME NOTE: do not
                    313:                                         * m_copy(m, offset, ...) above.
                    314:                                         * sbappendaddr() expects M_PKTHDR,
                    315:                                         * and m_copy() will copy M_PKTHDR
                    316:                                         * only if offset is 0.
                    317:                                         */
1.8       itojun    318:                                        if (last->in6p_flags & IN6P_CONTROLOPTS
                    319:                                         || last->in6p_socket->so_options & SO_TIMESTAMP) {
1.2       itojun    320:                                                ip6_savecontrol(last, &opts,
                    321:                                                                ip6, n);
                    322:                                        }
                    323:
1.11      itojun    324:                                        m_adj(n, off + sizeof(struct udphdr));
1.2       itojun    325:                                        if (sbappendaddr(&last->in6p_socket->so_rcv,
                    326:                                                        (struct sockaddr *)&udp_in6,
                    327:                                                        n, opts) == 0) {
                    328:                                                m_freem(n);
                    329:                                                if (opts)
                    330:                                                        m_freem(opts);
                    331:                                                udp6stat.udp6s_fullsock++;
                    332:                                        } else
                    333:                                                sorwakeup(last->in6p_socket);
                    334:                                        opts = 0;
                    335:                                }
                    336:                        }
                    337:                        last = in6p;
                    338:                        /*
                    339:                         * Don't look for additional matches if this one does
                    340:                         * not have either the SO_REUSEPORT or SO_REUSEADDR
                    341:                         * socket options set.  This heuristic avoids searching
                    342:                         * through all pcbs in the common case of a non-shared
                    343:                         * port.  It assumes that an application will never
                    344:                         * clear these options after setting them.
                    345:                         */
                    346:                        if ((last->in6p_socket->so_options &
                    347:                             (SO_REUSEPORT|SO_REUSEADDR)) == 0)
                    348:                                break;
                    349:                }
                    350:
                    351:                if (last == NULL) {
                    352:                        /*
                    353:                         * No matching pcb found; discard datagram.
                    354:                         * (No need to send an ICMP Port Unreachable
                    355:                         * for a broadcast or multicast datgram.)
                    356:                         */
                    357:                        udp6stat.udp6s_noport++;
                    358:                        udp6stat.udp6s_noportmcast++;
                    359:                        goto bad;
                    360:                }
                    361: #ifdef IPSEC
                    362:                /*
                    363:                 * Check AH/ESP integrity.
                    364:                 */
                    365:                if (last != NULL && ipsec6_in_reject(m, last)) {
                    366:                        ipsec6stat.in_polvio++;
                    367:                        goto bad;
                    368:                }
                    369: #endif /*IPSEC*/
1.8       itojun    370:                if (last->in6p_flags & IN6P_CONTROLOPTS
                    371:                 || last->in6p_socket->so_options & SO_TIMESTAMP) {
1.2       itojun    372:                        ip6_savecontrol(last, &opts, ip6, m);
1.8       itojun    373:                }
1.2       itojun    374:
                    375:                m_adj(m, off + sizeof(struct udphdr));
                    376:                if (sbappendaddr(&last->in6p_socket->so_rcv,
                    377:                                (struct sockaddr *)&udp_in6,
                    378:                                m, opts) == 0) {
                    379:                        udp6stat.udp6s_fullsock++;
                    380:                        goto bad;
                    381:                }
                    382:                sorwakeup(last->in6p_socket);
                    383:                return IPPROTO_DONE;
                    384:        }
                    385:        /*
                    386:         * Locate pcb for datagram.
                    387:         */
                    388:        in6p = udp6_last_in6pcb;
                    389:        if (in6p->in6p_lport != uh->uh_dport ||
                    390:           in6p->in6p_fport != uh->uh_sport ||
                    391:           !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src) ||
                    392:           !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst)) {
                    393:                in6p = in6_pcblookup(&udb6,
                    394:                                     &ip6->ip6_src, uh->uh_sport,
                    395:                                     &ip6->ip6_dst, uh->uh_dport,
                    396:                                     IN6PLOOKUP_WILDCARD);
                    397:                if (in6p)
                    398:                        udp6_last_in6pcb = in6p;
                    399:                udp6stat.udp6ps_pcbcachemiss++;
                    400:        }
                    401:        if (in6p == 0) {
                    402:                udp6stat.udp6s_noport++;
                    403:                if (m->m_flags & M_MCAST) {
                    404:                        printf("UDP6: M_MCAST is set in a unicast packet.\n");
                    405:                        udp6stat.udp6s_noportmcast++;
                    406:                        goto bad;
                    407:                }
                    408:                icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0);
                    409:                return IPPROTO_DONE;
                    410:        }
                    411: #ifdef IPSEC
                    412:        /*
                    413:         * Check AH/ESP integrity.
                    414:         */
                    415:        if (in6p != NULL && ipsec6_in_reject(m, in6p)) {
                    416:                ipsec6stat.in_polvio++;
                    417:                goto bad;
                    418:        }
                    419: #endif /*IPSEC*/
                    420:
                    421:        /*
                    422:         * Construct sockaddr format source address.
                    423:         * Stuff source address and datagram in user buffer.
                    424:         */
                    425:        bzero(&udp_in6, sizeof(udp_in6));
                    426:        udp_in6.sin6_len = sizeof(struct sockaddr_in6);
                    427:        udp_in6.sin6_family = AF_INET6;
                    428:        udp_in6.sin6_port = uh->uh_sport;
                    429:        udp_in6.sin6_addr = ip6->ip6_src;
                    430:        if (IN6_IS_SCOPE_LINKLOCAL(&udp_in6.sin6_addr))
                    431:                udp_in6.sin6_addr.s6_addr16[1] = 0;
                    432:        if (m->m_pkthdr.rcvif) {
                    433:                if (IN6_IS_SCOPE_LINKLOCAL(&udp_in6.sin6_addr))
                    434:                        udp_in6.sin6_scope_id = m->m_pkthdr.rcvif->if_index;
                    435:                else
                    436:                        udp_in6.sin6_scope_id = 0;
                    437:        } else
                    438:                udp_in6.sin6_scope_id = 0;
1.8       itojun    439:        if (in6p->in6p_flags & IN6P_CONTROLOPTS
                    440:         || in6p->in6p_socket->so_options & SO_TIMESTAMP) {
1.2       itojun    441:                ip6_savecontrol(in6p, &opts, ip6, m);
1.8       itojun    442:        }
1.2       itojun    443:
                    444:        m_adj(m, off + sizeof(struct udphdr));
                    445:        if (sbappendaddr(&in6p->in6p_socket->so_rcv,
                    446:                        (struct sockaddr *)&udp_in6,
                    447:                        m, opts) == 0) {
                    448:                udp6stat.udp6s_fullsock++;
                    449:                goto bad;
                    450:        }
                    451:        sorwakeup(in6p->in6p_socket);
                    452:        return IPPROTO_DONE;
                    453: bad:
                    454:        if (m)
                    455:                m_freem(m);
                    456:        if (opts)
                    457:                m_freem(opts);
                    458:        return IPPROTO_DONE;
                    459: }
1.14      itojun    460: #endif
1.2       itojun    461:
                    462: /*
                    463:  * Notify a udp user of an asynchronous error;
1.27      itojun    464:  * just wake up so that he can collect error status.
1.2       itojun    465:  */
                    466: static void
                    467: udp6_notify(in6p, errno)
                    468:        register struct in6pcb *in6p;
                    469:        int errno;
                    470: {
                    471:        in6p->in6p_socket->so_error = errno;
                    472:        sorwakeup(in6p->in6p_socket);
                    473:        sowwakeup(in6p->in6p_socket);
                    474: }
                    475:
                    476: void
1.14      itojun    477: udp6_ctlinput(cmd, sa, d)
1.2       itojun    478:        int cmd;
                    479:        struct sockaddr *sa;
1.14      itojun    480:        void *d;
1.2       itojun    481: {
                    482:        register struct udphdr *uhp;
                    483:        struct udphdr uh;
1.7       itojun    484:        struct sockaddr_in6 sa6;
1.14      itojun    485:        register struct ip6_hdr *ip6;
                    486:        struct mbuf *m;
                    487:        int off;
1.25      itojun    488:        void (*notify) __P((struct in6pcb *, int)) = udp6_notify;
1.2       itojun    489:
1.10      itojun    490:        if (sa->sa_family != AF_INET6 ||
                    491:            sa->sa_len != sizeof(struct sockaddr_in6))
                    492:                return;
1.14      itojun    493:
1.25      itojun    494:        if ((unsigned)cmd >= PRC_NCMDS)
                    495:                return;
                    496:        if (PRC_IS_REDIRECT(cmd))
                    497:                notify = in6_rtchange, d = NULL;
                    498:        else if (cmd == PRC_HOSTDEAD)
                    499:                d = NULL;
                    500:        else if (inet6ctlerrmap[cmd] == 0)
1.2       itojun    501:                return;
1.7       itojun    502:
1.14      itojun    503:        /* if the parameter is from icmp6, decode it. */
                    504:        if (d != NULL) {
                    505:                struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d;
                    506:                m = ip6cp->ip6c_m;
                    507:                ip6 = ip6cp->ip6c_ip6;
                    508:                off = ip6cp->ip6c_off;
                    509:        } else {
                    510:                m = NULL;
                    511:                ip6 = NULL;
                    512:        }
                    513:
1.7       itojun    514:        /* translate addresses into internal form */
                    515:        sa6 = *(struct sockaddr_in6 *)sa;
1.22      itojun    516:        if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr) && m && m->m_pkthdr.rcvif)
1.7       itojun    517:                sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
                    518:
1.2       itojun    519:        if (ip6) {
                    520:                /*
                    521:                 * XXX: We assume that when IPV6 is non NULL,
                    522:                 * M and OFF are valid.
                    523:                 */
1.7       itojun    524:                struct in6_addr s;
                    525:
                    526:                /* translate addresses into internal form */
1.12      itojun    527:                memcpy(&s, &ip6->ip6_src, sizeof(s));
1.7       itojun    528:                if (IN6_IS_ADDR_LINKLOCAL(&s))
                    529:                        s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
                    530:
1.2       itojun    531:                if (m->m_len < off + sizeof(uh)) {
                    532:                        /*
                    533:                         * this should be rare case,
                    534:                         * so we compromise on this copy...
                    535:                         */
                    536:                        m_copydata(m, off, sizeof(uh), (caddr_t)&uh);
                    537:                        uhp = &uh;
                    538:                } else
                    539:                        uhp = (struct udphdr *)(mtod(m, caddr_t) + off);
1.7       itojun    540:                (void) in6_pcbnotify(&udb6, (struct sockaddr *)&sa6,
                    541:                                        uhp->uh_dport, &s,
1.25      itojun    542:                                        uhp->uh_sport, cmd, notify);
1.2       itojun    543:        } else {
1.7       itojun    544:                (void) in6_pcbnotify(&udb6, (struct sockaddr *)&sa6, 0,
1.25      itojun    545:                                        &zeroin6_addr, 0, cmd, notify);
1.2       itojun    546:        }
                    547: }
                    548:
                    549: int
1.29      itojun    550: udp6_output(in6p, m, addr6, control, p)
1.2       itojun    551:        register struct in6pcb *in6p;
                    552:        register struct mbuf *m;
                    553:        struct mbuf *addr6, *control;
1.29      itojun    554:        struct proc *p;
1.2       itojun    555: {
1.14      itojun    556:        register u_int32_t ulen = m->m_pkthdr.len;
                    557:        u_int32_t plen = sizeof(struct udphdr) + ulen;
1.2       itojun    558:        struct ip6_hdr *ip6;
                    559:        struct udphdr *udp6;
1.14      itojun    560:        struct  in6_addr *laddr, *faddr;
                    561:        u_short fport;
                    562:        int error = 0;
1.2       itojun    563:        struct ip6_pktopts opt, *stickyopt = in6p->in6p_outputopts;
1.14      itojun    564:        int priv;
                    565:        int af, hlen;
                    566: #ifdef INET
                    567:        struct ip *ip;
                    568: #endif
1.30    ! itojun    569:        struct sockaddr_in6 tmp;
1.2       itojun    570:
1.14      itojun    571:        priv = 0;
1.2       itojun    572:        if (p && !suser(p->p_ucred, &p->p_acflag))
                    573:                priv = 1;
                    574:        if (control) {
                    575:                if ((error = ip6_setpktoptions(control, &opt, priv)) != 0)
                    576:                        goto release;
                    577:                in6p->in6p_outputopts = &opt;
                    578:        }
                    579:
                    580:        if (addr6) {
1.14      itojun    581:                /*
                    582:                 * IPv4 version of udp_output calls in_pcbconnect in this case,
                    583:                 * which needs splnet and affects performance.
                    584:                 * Since we saw no essential reason for calling in_pcbconnect,
                    585:                 * we get rid of such kind of logic, and call in6_selectsrc
                    586:                 * and In6_pcbsetport in order to fill in the local address
                    587:                 * and the local port.
                    588:                 */
                    589:                struct sockaddr_in6 *sin6 = mtod(addr6, struct sockaddr_in6 *);
                    590:
                    591:                if (addr6->m_len != sizeof(*sin6)) {
                    592:                        error = EINVAL;
                    593:                        goto release;
                    594:                }
                    595:                if (sin6->sin6_family != AF_INET6) {
                    596:                        error = EAFNOSUPPORT;
                    597:                        goto release;
                    598:                }
                    599:                if (sin6->sin6_port == 0) {
                    600:                        error = EADDRNOTAVAIL;
                    601:                        goto release;
                    602:                }
                    603:
                    604:                if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
1.2       itojun    605:                        error = EISCONN;
                    606:                        goto release;
                    607:                }
1.30    ! itojun    608:
        !           609:                /* protect *sin6 from overwrites */
        !           610:                tmp = *sin6;
        !           611:                sin6 = &tmp;
1.14      itojun    612:
                    613:                faddr = &sin6->sin6_addr;
                    614:                fport = sin6->sin6_port; /* allow 0 port */
1.2       itojun    615:                /*
1.14      itojun    616:                 * If the scope of the destination is link-local,
1.27      itojun    617:                 * embed the interface index in the address.
1.14      itojun    618:                 *
1.27      itojun    619:                 * XXX advanced-api value overrides sin6_scope_id
1.2       itojun    620:                 */
1.14      itojun    621:                if (IN6_IS_ADDR_LINKLOCAL(faddr) ||
                    622:                    IN6_IS_ADDR_MC_LINKLOCAL(faddr)) {
                    623:                        struct ip6_pktopts *optp = in6p->in6p_outputopts;
                    624:                        struct in6_pktinfo *pi = NULL;
                    625:                        struct ifnet *oifp = NULL;
                    626:                        struct ip6_moptions *mopt = NULL;
                    627:
                    628:                        /*
                    629:                         * XXX Boundary check is assumed to be already done in
                    630:                         * ip6_setpktoptions().
                    631:                         */
                    632:                        if (optp && (pi = optp->ip6po_pktinfo) &&
                    633:                            pi->ipi6_ifindex) {
                    634:                                faddr->s6_addr16[1] = htons(pi->ipi6_ifindex);
                    635:                                oifp = ifindex2ifnet[pi->ipi6_ifindex];
1.27      itojun    636:                        } else if (IN6_IS_ADDR_MULTICAST(faddr) &&
1.14      itojun    637:                                 (mopt = in6p->in6p_moptions) &&
                    638:                                 mopt->im6o_multicast_ifp) {
                    639:                                oifp = mopt->im6o_multicast_ifp;
1.27      itojun    640:                                faddr->s6_addr16[1] = htons(oifp->if_index);
1.14      itojun    641:                        } else if (sin6->sin6_scope_id) {
                    642:                                /* boundary check */
1.27      itojun    643:                                if (sin6->sin6_scope_id < 0
1.14      itojun    644:                                    || if_index < sin6->sin6_scope_id) {
                    645:                                        error = ENXIO;  /* XXX EINVAL? */
                    646:                                        goto release;
                    647:                                }
                    648:                                /* XXX */
                    649:                                faddr->s6_addr16[1] =
                    650:                                        htons(sin6->sin6_scope_id & 0xffff);
                    651:                        }
                    652:                }
                    653:
                    654:                if (!IN6_IS_ADDR_V4MAPPED(faddr)) {
                    655:                        laddr = in6_selectsrc(sin6, in6p->in6p_outputopts,
                    656:                                              in6p->in6p_moptions,
                    657:                                              &in6p->in6p_route,
                    658:                                              &in6p->in6p_laddr, &error);
                    659:                } else
                    660:                        laddr = &in6p->in6p_laddr;      /*XXX*/
                    661:                if (laddr == NULL) {
                    662:                        if (error == 0)
                    663:                                error = EADDRNOTAVAIL;
1.2       itojun    664:                        goto release;
                    665:                }
1.14      itojun    666:                if (in6p->in6p_lport == 0 &&
                    667:                    (error = in6_pcbsetport(laddr, in6p)) != 0)
                    668:                        goto release;
1.2       itojun    669:        } else {
1.14      itojun    670:                if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
1.2       itojun    671:                        error = ENOTCONN;
                    672:                        goto release;
                    673:                }
1.14      itojun    674:                laddr = &in6p->in6p_laddr;
                    675:                faddr = &in6p->in6p_faddr;
                    676:                fport = in6p->in6p_fport;
1.2       itojun    677:        }
1.14      itojun    678:
                    679:        if (!IN6_IS_ADDR_V4MAPPED(faddr)) {
                    680:                af = AF_INET6;
                    681:                hlen = sizeof(struct ip6_hdr);
                    682:        } else {
                    683:                af = AF_INET;
                    684:                hlen = sizeof(struct ip);
                    685:        }
                    686:
1.2       itojun    687:        /*
                    688:         * Calculate data length and get a mbuf
                    689:         * for UDP and IP6 headers.
                    690:         */
1.14      itojun    691:        M_PREPEND(m, hlen + sizeof(struct udphdr), M_DONTWAIT);
1.2       itojun    692:        if (m == 0) {
                    693:                error = ENOBUFS;
                    694:                goto release;
                    695:        }
                    696:
                    697:        /*
                    698:         * Stuff checksum and output datagram.
                    699:         */
1.14      itojun    700:        udp6 = (struct udphdr *)(mtod(m, caddr_t) + hlen);
                    701:        udp6->uh_sport = in6p->in6p_lport; /* lport is always set in the PCB */
                    702:        udp6->uh_dport = fport;
                    703:        if (plen <= 0xffff)
                    704:                udp6->uh_ulen = htons((u_short)plen);
                    705:        else
                    706:                udp6->uh_ulen = 0;
                    707:        udp6->uh_sum = 0;
                    708:
                    709:        switch (af) {
                    710:        case AF_INET6:
                    711:                ip6 = mtod(m, struct ip6_hdr *);
                    712:                ip6->ip6_flow   = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK;
1.15      itojun    713:                ip6->ip6_vfc    &= ~IPV6_VERSION_MASK;
                    714:                ip6->ip6_vfc    |= IPV6_VERSION;
1.2       itojun    715: #if 0                          /* ip6_plen will be filled in ip6_output. */
1.14      itojun    716:                ip6->ip6_plen   = htons((u_short)plen);
1.2       itojun    717: #endif
1.14      itojun    718:                ip6->ip6_nxt    = IPPROTO_UDP;
                    719:                ip6->ip6_hlim   = in6_selecthlim(in6p,
                    720:                                                 in6p->in6p_route.ro_rt ?
                    721:                                                 in6p->in6p_route.ro_rt->rt_ifp : NULL);
                    722:                ip6->ip6_src    = *laddr;
                    723:                ip6->ip6_dst    = *faddr;
                    724:
                    725:                if ((udp6->uh_sum = in6_cksum(m, IPPROTO_UDP,
                    726:                                sizeof(struct ip6_hdr), plen)) == 0) {
                    727:                        udp6->uh_sum = 0xffff;
                    728:                }
                    729:
                    730:                udp6stat.udp6s_opackets++;
                    731: #ifdef IPSEC
1.26      itojun    732:                ipsec_setsocket(m, in6p->in6p_socket);
1.14      itojun    733: #endif /*IPSEC*/
                    734:                error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route,
                    735:                            0, in6p->in6p_moptions, NULL);
                    736:                break;
                    737:        case AF_INET:
                    738: #ifdef INET
                    739:                /* can't transmit jumbogram over IPv4 */
                    740:                if (plen > 0xffff) {
                    741:                        error = EMSGSIZE;
                    742:                        goto release;
                    743:                }
                    744:
                    745:                ip = mtod(m, struct ip *);
1.2       itojun    746:
1.14      itojun    747:                ip->ip_len = plen;
                    748:                ip->ip_p = IPPROTO_UDP;
                    749:                ip->ip_ttl = in6p->in6p_hops;   /*XXX*/
                    750:                ip->ip_tos = 0;                 /*XXX*/
                    751:                bcopy(&laddr->s6_addr[12], &ip->ip_src, sizeof(ip->ip_src));
                    752:                bcopy(&faddr->s6_addr[12], &ip->ip_dst, sizeof(ip->ip_dst));
                    753:
                    754:                udp6->uh_sum = 0;
                    755:                if ((udp6->uh_sum = in_cksum(m, ulen)) == 0)
                    756:                        udp6->uh_sum = 0xffff;
1.2       itojun    757:
1.14      itojun    758:                udpstat.udps_opackets++;
1.2       itojun    759: #ifdef IPSEC
1.26      itojun    760:                ipsec_setsocket(m, NULL);       /*XXX*/
1.2       itojun    761: #endif /*IPSEC*/
1.14      itojun    762:                error = ip_output(m, NULL, &in6p->in6p_route, 0 /*XXX*/);
                    763:                break;
                    764: #else
                    765:                error = EAFNOSUPPORT;
                    766:                goto release;
                    767: #endif
1.2       itojun    768:        }
                    769:        goto releaseopt;
                    770:
                    771: release:
                    772:        m_freem(m);
                    773:
                    774: releaseopt:
                    775:        if (control) {
                    776:                in6p->in6p_outputopts = stickyopt;
                    777:                m_freem(control);
                    778:        }
                    779:        return(error);
                    780: }
                    781:
                    782: extern int udp6_sendspace;
                    783: extern int udp6_recvspace;
                    784:
                    785: int
                    786: udp6_usrreq(so, req, m, addr6, control, p)
                    787:        struct socket *so;
                    788:        int req;
                    789:        struct mbuf *m, *addr6, *control;
                    790:        struct proc *p;
                    791: {
                    792:        struct  in6pcb *in6p = sotoin6pcb(so);
                    793:        int     error = 0;
                    794:        int     s;
                    795:
1.27      itojun    796:        /*
1.2       itojun    797:         * MAPPED_ADDR implementation info:
                    798:         *  Mapped addr support for PRU_CONTROL is not necessary.
                    799:         *  Because typical user of PRU_CONTROL is such as ifconfig,
                    800:         *  and they don't associate any addr to their socket.  Then
                    801:         *  socket family is only hint about the PRU_CONTROL'ed address
                    802:         *  family, especially when getting addrs from kernel.
                    803:         *  So AF_INET socket need to be used to control AF_INET addrs,
                    804:         *  and AF_INET6 socket for AF_INET6 addrs.
                    805:         */
                    806:        if (req == PRU_CONTROL)
                    807:                return(in6_control(so, (u_long)m, (caddr_t)addr6,
                    808:                                   (struct ifnet *)control, p));
1.20      thorpej   809:
1.21      thorpej   810:        if (req == PRU_PURGEIF) {
                    811:                in6_purgeif((struct ifnet *)control);
                    812:                in6_pcbpurgeif(&udb6, (struct ifnet *)control);
1.20      thorpej   813:                return (0);
                    814:        }
1.2       itojun    815:
                    816:        if (in6p == NULL && req != PRU_ATTACH) {
                    817:                error = EINVAL;
                    818:                goto release;
                    819:        }
                    820:
                    821:        switch (req) {
                    822:        case PRU_ATTACH:
                    823:                /*
                    824:                 * MAPPED_ADDR implementation spec:
1.27      itojun    825:                 *  Always attach for IPv6,
1.2       itojun    826:                 *  and only when necessary for IPv4.
                    827:                 */
                    828:                if (in6p != NULL) {
                    829:                        error = EINVAL;
                    830:                        break;
                    831:                }
1.4       itojun    832:                s = splsoftnet();
1.2       itojun    833:                error = in6_pcballoc(so, &udb6);
                    834:                splx(s);
                    835:                if (error)
                    836:                        break;
                    837:                error = soreserve(so, udp6_sendspace, udp6_recvspace);
                    838:                if (error)
                    839:                        break;
                    840:                in6p = sotoin6pcb(so);
                    841:                in6p->in6p_cksum = -1;  /* just to be sure */
                    842: #ifdef IPSEC
1.19      itojun    843:                error = ipsec_init_policy(so, &in6p->in6p_sp);
1.14      itojun    844:                if (error != 0) {
1.13      itojun    845:                        in6_pcbdetach(in6p);
1.14      itojun    846:                        break;
                    847:                }
1.2       itojun    848: #endif /*IPSEC*/
                    849:                break;
                    850:
                    851:        case PRU_DETACH:
                    852:                udp6_detach(in6p);
                    853:                break;
                    854:
                    855:        case PRU_BIND:
1.4       itojun    856:                s = splsoftnet();
1.29      itojun    857:                error = in6_pcbbind(in6p, addr6, p);
1.2       itojun    858:                splx(s);
                    859:                break;
                    860:
                    861:        case PRU_LISTEN:
                    862:                error = EOPNOTSUPP;
                    863:                break;
                    864:
                    865:        case PRU_CONNECT:
1.14      itojun    866:                if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
1.2       itojun    867:                        error = EISCONN;
                    868:                        break;
                    869:                }
1.4       itojun    870:                s = splsoftnet();
1.2       itojun    871:                error = in6_pcbconnect(in6p, addr6);
                    872:                if (ip6_auto_flowlabel) {
                    873:                        in6p->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK;
1.27      itojun    874:                        in6p->in6p_flowinfo |=
1.2       itojun    875:                                (htonl(ip6_flow_seq++) & IPV6_FLOWLABEL_MASK);
                    876:                }
                    877:                splx(s);
                    878:                if (error == 0)
                    879:                        soisconnected(so);
                    880:                break;
                    881:
                    882:        case PRU_CONNECT2:
                    883:                error = EOPNOTSUPP;
                    884:                break;
                    885:
                    886:        case PRU_ACCEPT:
                    887:                error = EOPNOTSUPP;
                    888:                break;
                    889:
                    890:        case PRU_DISCONNECT:
                    891:                if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
                    892:                        error = ENOTCONN;
                    893:                        break;
                    894:                }
1.4       itojun    895:                s = splsoftnet();
1.2       itojun    896:                in6_pcbdisconnect(in6p);
                    897:                bzero((caddr_t)&in6p->in6p_laddr, sizeof(in6p->in6p_laddr));
                    898:                splx(s);
                    899:                so->so_state &= ~SS_ISCONNECTED;                /* XXX */
                    900:                break;
                    901:
                    902:        case PRU_SHUTDOWN:
                    903:                socantsendmore(so);
                    904:                break;
                    905:
                    906:        case PRU_SEND:
1.29      itojun    907:                return(udp6_output(in6p, m, addr6, control, p));
1.2       itojun    908:
                    909:        case PRU_ABORT:
                    910:                soisdisconnected(so);
                    911:                udp6_detach(in6p);
                    912:                break;
                    913:
                    914:        case PRU_SOCKADDR:
                    915:                in6_setsockaddr(in6p, addr6);
                    916:                break;
                    917:
                    918:        case PRU_PEERADDR:
                    919:                in6_setpeeraddr(in6p, addr6);
                    920:                break;
                    921:
                    922:        case PRU_SENSE:
                    923:                /*
                    924:                 * stat: don't bother with a blocksize
                    925:                 */
                    926:                return(0);
                    927:
                    928:        case PRU_SENDOOB:
                    929:        case PRU_FASTTIMO:
                    930:        case PRU_SLOWTIMO:
                    931:        case PRU_PROTORCV:
                    932:        case PRU_PROTOSEND:
                    933:                error = EOPNOTSUPP;
                    934:                break;
                    935:
                    936:        case PRU_RCVD:
                    937:        case PRU_RCVOOB:
                    938:                return(EOPNOTSUPP);     /* do not free mbuf's */
                    939:
                    940:        default:
                    941:                panic("udp6_usrreq");
                    942:        }
                    943:
                    944: release:
                    945:        if (control) {
                    946:                printf("udp control data unexpectedly retained\n");
                    947:                m_freem(control);
                    948:        }
                    949:        if (m)
                    950:                m_freem(m);
                    951:        return(error);
                    952: }
                    953:
                    954: static void
                    955: udp6_detach(in6p)
                    956:        struct in6pcb *in6p;
                    957: {
1.27      itojun    958:        int s = splsoftnet();
1.2       itojun    959:
                    960:        if (in6p == udp6_last_in6pcb)
                    961:                udp6_last_in6pcb = &udb6;
                    962:        in6_pcbdetach(in6p);
                    963:        splx(s);
                    964: }
                    965:
                    966: #include <vm/vm.h>
                    967: #include <sys/sysctl.h>
                    968:
                    969: int
                    970: udp6_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
                    971:        int *name;
                    972:        u_int namelen;
                    973:        void *oldp;
                    974:        size_t *oldlenp;
                    975:        void *newp;
                    976:        size_t newlen;
                    977: {
                    978:        /* All sysctl names at this level are terminal. */
                    979:        if (namelen != 1)
                    980:                return ENOTDIR;
                    981:
                    982:        switch (name[0]) {
                    983:
1.28      itojun    984:        case UDP6CTL_SENDSPACE:
1.2       itojun    985:                return sysctl_int(oldp, oldlenp, newp, newlen,
                    986:                    &udp6_sendspace);
                    987:        case UDP6CTL_RECVSPACE:
1.27      itojun    988:                return sysctl_int(oldp, oldlenp, newp, newlen,
1.2       itojun    989:                    &udp6_recvspace);
                    990:        default:
                    991:                return ENOPROTOOPT;
                    992:        }
                    993:        /* NOTREACHED */
                    994: }

CVSweb <webmaster@jp.NetBSD.org>