Annotation of XNU/bsd/netinet/udp_usrreq.c, revision 1.1.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.