Annotation of XNU/bsd/netinet/udp_usrreq.c, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.