The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet/udp_usrreq.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 6797dbb61287613c0cb5f6d41476b4fa


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.