home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sys / netinet / udp_usrreq.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-08  |  11.6 KB  |  515 lines

  1. /*
  2.  * Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California.
  3.  * 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    7.20 (Berkeley) 4/20/91
  34.  */
  35.  
  36. #include "param.h"
  37. #include "malloc.h"
  38. #include "mbuf.h"
  39. #include "protosw.h"
  40. #include "socket.h"
  41. #include "socketvar.h"
  42. #include "stat.h"
  43.  
  44. #include "../net/if.h"
  45. #include "../net/route.h"
  46.  
  47. #include "in.h"
  48. #include "in_systm.h"
  49. #include "ip.h"
  50. #include "in_pcb.h"
  51. #include "ip_var.h"
  52. #include "ip_icmp.h"
  53. #include "udp.h"
  54. #include "udp_var.h"
  55.  
  56. struct    inpcb *udp_last_inpcb = &udb;
  57.  
  58. /*
  59.  * UDP protocol implementation.
  60.  * Per RFC 768, August, 1980.
  61.  */
  62. udp_init()
  63. {
  64.  
  65.     udb.inp_next = udb.inp_prev = &udb;
  66. }
  67.  
  68. #ifndef    COMPAT_42
  69. int    udpcksum = 1;
  70. #else
  71. int    udpcksum = 0;        /* XXX */
  72. #endif
  73. int    udp_ttl = UDP_TTL;
  74.  
  75. struct    sockaddr_in udp_in = { sizeof(udp_in), AF_INET };
  76.  
  77. udp_input(m, iphlen)
  78.     register struct mbuf *m;
  79.     int iphlen;
  80. {
  81.     register struct ip *ip;
  82.     register struct udphdr *uh;
  83.     register struct inpcb *inp;
  84.     struct mbuf *opts = 0;
  85.     int len;
  86.     struct ip save_ip;
  87.  
  88.     udpstat.udps_ipackets++;
  89.  
  90.     /*
  91.      * Strip IP options, if any; should skip this,
  92.      * make available to user, and use on returned packets,
  93.      * but we don't yet have a way to check the checksum
  94.      * with options still present.
  95.      */
  96.     if (iphlen > sizeof (struct ip)) {
  97.         ip_stripoptions(m, (struct mbuf *)0);
  98.         iphlen = sizeof(struct ip);
  99.     }
  100.  
  101.     /*
  102.      * Get IP and UDP header together in first mbuf.
  103.      */
  104.     ip = mtod(m, struct ip *);
  105.     if (m->m_len < iphlen + sizeof(struct udphdr)) {
  106.         if ((m = m_pullup(m, iphlen + sizeof(struct udphdr))) == 0) {
  107.             udpstat.udps_hdrops++;
  108.             return;
  109.         }
  110.         ip = mtod(m, struct ip *);
  111.     }
  112.     uh = (struct udphdr *)((caddr_t)ip + iphlen);
  113.  
  114.     /*
  115.      * Make mbuf data length reflect UDP length.
  116.      * If not enough data to reflect UDP length, drop.
  117.      */
  118.     len = ntohs((u_short)uh->uh_ulen);
  119.     if (ip->ip_len != len) {
  120.         if (len > ip->ip_len) {
  121.             udpstat.udps_badlen++;
  122.             goto bad;
  123.         }
  124.         m_adj(m, len - ip->ip_len);
  125.         /* ip->ip_len = len; */
  126.     }
  127.     /*
  128.      * Save a copy of the IP header in case we want restore it
  129.      * for sending an ICMP error message in response.
  130.      */
  131.     save_ip = *ip;
  132.  
  133.     /*
  134.      * Checksum extended UDP header and data.
  135.      */
  136.     if (udpcksum && uh->uh_sum) {
  137.         ((struct ipovly *)ip)->ih_next = 0;
  138.         ((struct ipovly *)ip)->ih_prev = 0;
  139.         ((struct ipovly *)ip)->ih_x1 = 0;
  140.         ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
  141.         if (uh->uh_sum = in_cksum(m, len + sizeof (struct ip))) {
  142.             udpstat.udps_badsum++;
  143.             m_freem(m);
  144.             return;
  145.         }
  146.     }
  147.  
  148.     /*
  149.      * Locate pcb for datagram.
  150.      */
  151.     inp = udp_last_inpcb;
  152.     if (inp->inp_lport != uh->uh_dport ||
  153.         inp->inp_fport != uh->uh_sport ||
  154.         inp->inp_faddr.s_addr != ip->ip_src.s_addr ||
  155.         inp->inp_laddr.s_addr != ip->ip_dst.s_addr) {
  156.         inp = in_pcblookup(&udb, ip->ip_src, uh->uh_sport,
  157.             ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD);
  158.         if (inp)
  159.             udp_last_inpcb = inp;
  160.         udpstat.udpps_pcbcachemiss++;
  161.     }
  162.     if (inp == 0) {
  163.         /* don't send ICMP response for broadcast packet */
  164.         udpstat.udps_noport++;
  165.         if (m->m_flags & M_BCAST) {
  166.             udpstat.udps_noportbcast++;
  167.             goto bad;
  168.         }
  169.         *ip = save_ip;
  170.         ip->ip_len += iphlen;
  171.         icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT);
  172.         return;
  173.     }
  174.  
  175.     /*
  176.      * Construct sockaddr format source address.
  177.      * Stuff source address and datagram in user buffer.
  178.      */
  179.     udp_in.sin_port = uh->uh_sport;
  180.     udp_in.sin_addr = ip->ip_src;
  181.     if (inp->inp_flags & INP_CONTROLOPTS) {
  182.         struct mbuf **mp = &opts;
  183.         struct mbuf *udp_saveopt();
  184.  
  185.         if (inp->inp_flags & INP_RECVDSTADDR) {
  186.             *mp = udp_saveopt((caddr_t) &ip->ip_dst,
  187.                 sizeof(struct in_addr), IP_RECVDSTADDR);
  188.             if (*mp)
  189.                 mp = &(*mp)->m_next;
  190.         }
  191. #ifdef notyet
  192.         /* options were tossed above */
  193.         if (inp->inp_flags & INP_RECVOPTS) {
  194.             *mp = udp_saveopt((caddr_t) opts_deleted_above,
  195.                 sizeof(struct in_addr), IP_RECVOPTS);
  196.             if (*mp)
  197.                 mp = &(*mp)->m_next;
  198.         }
  199.         /* ip_srcroute doesn't do what we want here, need to fix */
  200.         if (inp->inp_flags & INP_RECVRETOPTS) {
  201.             *mp = udp_saveopt((caddr_t) ip_srcroute(),
  202.                 sizeof(struct in_addr), IP_RECVRETOPTS);
  203.             if (*mp)
  204.                 mp = &(*mp)->m_next;
  205.         }
  206. #endif
  207.     }
  208.     iphlen += sizeof(struct udphdr);
  209.     m->m_len -= iphlen;
  210.     m->m_pkthdr.len -= iphlen;
  211.     m->m_data += iphlen;
  212.     if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in,
  213.         m, opts) == 0) {
  214.         udpstat.udps_fullsock++;
  215.         goto bad;
  216.     }
  217.     sorwakeup(inp->inp_socket);
  218.     return;
  219. bad:
  220.     m_freem(m);
  221.     if (opts)
  222.         m_freem(opts);
  223. }
  224.  
  225. /*
  226.  * Create a "control" mbuf containing the specified data
  227.  * with the specified type for presentation with a datagram.
  228.  */
  229. struct mbuf *
  230. udp_saveopt(p, size, type)
  231.     caddr_t p;
  232.     register int size;
  233.     int type;
  234. {
  235.     register struct cmsghdr *cp;
  236.     struct mbuf *m;
  237.  
  238.     if ((m = m_get(M_DONTWAIT, MT_CONTROL)) == NULL)
  239.         return ((struct mbuf *) NULL);
  240.     cp = (struct cmsghdr *) mtod(m, struct cmsghdr *);
  241.     bcopy(p, (caddr_t)(cp + 1), size);
  242.     size += sizeof(*cp);
  243.     m->m_len = size;
  244.     cp->cmsg_len = size;
  245.     cp->cmsg_level = IPPROTO_IP;
  246.     cp->cmsg_type = type;
  247.     return (m);
  248. }
  249.  
  250. /*
  251.  * Notify a udp user of an asynchronous error;
  252.  * just wake up so that he can collect error status.
  253.  */
  254. udp_notify(inp, errno)
  255.     register struct inpcb *inp;
  256. {
  257.  
  258.     inp->inp_socket->so_error = errno;
  259.     sorwakeup(inp->inp_socket);
  260.     sowwakeup(inp->inp_socket);
  261. }
  262.  
  263. udp_ctlinput(cmd, sa, ip)
  264.     int cmd;
  265.     struct sockaddr *sa;
  266.     register struct ip *ip;
  267. {
  268.     register struct udphdr *uh;
  269.     extern struct in_addr zeroin_addr;
  270.     extern u_char inetctlerrmap[];
  271.  
  272.     if ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0)
  273.         return;
  274.     if (ip) {
  275.         uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
  276.         in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport,
  277.             cmd, udp_notify);
  278.     } else
  279.         in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify);
  280. }
  281.  
  282. udp_output(inp, m, addr, control)
  283.     register struct inpcb *inp;
  284.     register struct mbuf *m;
  285.     struct mbuf *addr, *control;
  286. {
  287.     register struct udpiphdr *ui;
  288.     register int len = m->m_pkthdr.len;
  289.     struct in_addr laddr;
  290.     int s, error = 0;
  291.  
  292.     if (control)
  293.         m_freem(control);        /* XXX */
  294.  
  295.     if (addr) {
  296.         laddr = inp->inp_laddr;
  297.         if (inp->inp_faddr.s_addr != INADDR_ANY) {
  298.             error = EISCONN;
  299.             goto release;
  300.         }
  301.         /*
  302.          * Must block input while temporarily connected.
  303.          */
  304.         s = splnet();
  305.         error = in_pcbconnect(inp, addr);
  306.         if (error) {
  307.             splx(s);
  308.             goto release;
  309.         }
  310.     } else {
  311.         if (inp->inp_faddr.s_addr == INADDR_ANY) {
  312.             error = ENOTCONN;
  313.             goto release;
  314.         }
  315.     }
  316.     /*
  317.      * Calculate data length and get a mbuf
  318.      * for UDP and IP headers.
  319.      */
  320.     M_PREPEND(m, sizeof(struct udpiphdr), M_WAIT);
  321.  
  322.     /*
  323.      * Fill in mbuf with extended UDP header
  324.      * and addresses and length put into network format.
  325.      */
  326.     ui = mtod(m, struct udpiphdr *);
  327.     ui->ui_next = ui->ui_prev = 0;
  328.     ui->ui_x1 = 0;
  329.     ui->ui_pr = IPPROTO_UDP;
  330.     ui->ui_len = htons((u_short)len + sizeof (struct udphdr));
  331.     ui->ui_src = inp->inp_laddr;
  332.     ui->ui_dst = inp->inp_faddr;
  333.     ui->ui_sport = inp->inp_lport;
  334.     ui->ui_dport = inp->inp_fport;
  335.     ui->ui_ulen = ui->ui_len;
  336.  
  337.     /*
  338.      * Stuff checksum and output datagram.
  339.      */
  340.     ui->ui_sum = 0;
  341.     if (udpcksum) {
  342.         if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0)
  343.         ui->ui_sum = 0xffff;
  344.     }
  345.     ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len;
  346.     ((struct ip *)ui)->ip_ttl = inp->inp_ip.ip_ttl;    /* XXX */
  347.     ((struct ip *)ui)->ip_tos = inp->inp_ip.ip_tos;    /* XXX */
  348.     udpstat.udps_opackets++;
  349.     error = ip_output(m, inp->inp_options, &inp->inp_route,
  350.         inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST));
  351.  
  352.     if (addr) {
  353.         in_pcbdisconnect(inp);
  354.         inp->inp_laddr = laddr;
  355.         splx(s);
  356.     }
  357.     return (error);
  358.  
  359. release:
  360.     m_freem(m);
  361.     return (error);
  362. }
  363.  
  364. u_long    udp_sendspace = 9216;        /* really max datagram size */
  365. u_long    udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
  366.                     /* 40 1K datagrams */
  367.  
  368. /*ARGSUSED*/
  369. udp_usrreq(so, req, m, addr, control)
  370.     struct socket *so;
  371.     int req;
  372.     struct mbuf *m, *addr, *control;
  373. {
  374.     struct inpcb *inp = sotoinpcb(so);
  375.     int error = 0;
  376.     int s;
  377.  
  378.     if (req == PRU_CONTROL)
  379.         return (in_control(so, (int)m, (caddr_t)addr,
  380.             (struct ifnet *)control));
  381.     if (inp == NULL && req != PRU_ATTACH) {
  382.         error = EINVAL;
  383.         goto release;
  384.     }
  385.     /*
  386.      * Note: need to block udp_input while changing
  387.      * the udp pcb queue and/or pcb addresses.
  388.      */
  389.     switch (req) {
  390.  
  391.     case PRU_ATTACH:
  392.         if (inp != NULL) {
  393.             error = EINVAL;
  394.             break;
  395.         }
  396.         s = splnet();
  397.         error = in_pcballoc(so, &udb);
  398.         splx(s);
  399.         if (error)
  400.             break;
  401.         error = soreserve(so, udp_sendspace, udp_recvspace);
  402.         if (error)
  403.             break;
  404.         ((struct inpcb *) so->so_pcb)->inp_ip.ip_ttl = udp_ttl;
  405.         break;
  406.  
  407.     case PRU_DETACH:
  408.         udp_detach(inp);
  409.         break;
  410.  
  411.     case PRU_BIND:
  412.         s = splnet();
  413.         error = in_pcbbind(inp, addr);
  414.         splx(s);
  415.         break;
  416.  
  417.     case PRU_LISTEN:
  418.         error = EOPNOTSUPP;
  419.         break;
  420.  
  421.     case PRU_CONNECT:
  422.         if (inp->inp_faddr.s_addr != INADDR_ANY) {
  423.             error = EISCONN;
  424.             break;
  425.         }
  426.         s = splnet();
  427.         error = in_pcbconnect(inp, addr);
  428.         splx(s);
  429.         if (error == 0)
  430.             soisconnected(so);
  431.         break;
  432.  
  433.     case PRU_CONNECT2:
  434.         error = EOPNOTSUPP;
  435.         break;
  436.  
  437.     case PRU_ACCEPT:
  438.         error = EOPNOTSUPP;
  439.         break;
  440.  
  441.     case PRU_DISCONNECT:
  442.         if (inp->inp_faddr.s_addr == INADDR_ANY) {
  443.             error = ENOTCONN;
  444.             break;
  445.         }
  446.         s = splnet();
  447.         in_pcbdisconnect(inp);
  448.         inp->inp_laddr.s_addr = INADDR_ANY;
  449.         splx(s);
  450.         so->so_state &= ~SS_ISCONNECTED;        /* XXX */
  451.         break;
  452.  
  453.     case PRU_SHUTDOWN:
  454.         socantsendmore(so);
  455.         break;
  456.  
  457.     case PRU_SEND:
  458.         return (udp_output(inp, m, addr, control));
  459.  
  460.     case PRU_ABORT:
  461.         soisdisconnected(so);
  462.         udp_detach(inp);
  463.         break;
  464.  
  465.     case PRU_SOCKADDR:
  466.         in_setsockaddr(inp, addr);
  467.         break;
  468.  
  469.     case PRU_PEERADDR:
  470.         in_setpeeraddr(inp, addr);
  471.         break;
  472.  
  473.     case PRU_SENSE:
  474.         /*
  475.          * stat: don't bother with a blocksize.
  476.          */
  477.         return (0);
  478.  
  479.     case PRU_SENDOOB:
  480.     case PRU_FASTTIMO:
  481.     case PRU_SLOWTIMO:
  482.     case PRU_PROTORCV:
  483.     case PRU_PROTOSEND:
  484.         error =  EOPNOTSUPP;
  485.         break;
  486.  
  487.     case PRU_RCVD:
  488.     case PRU_RCVOOB:
  489.         return (EOPNOTSUPP);    /* do not free mbuf's */
  490.  
  491.     default:
  492.         panic("udp_usrreq");
  493.     }
  494.  
  495. release:
  496.     if (control) {
  497.         printf("udp control data unexpectedly retained\n");
  498.         m_freem(control);
  499.     }
  500.     if (m)
  501.         m_freem(m);
  502.     return (error);
  503. }
  504.  
  505. udp_detach(inp)
  506.     struct inpcb *inp;
  507. {
  508.     int s = splnet();
  509.  
  510.     if (inp == udp_last_inpcb)
  511.         udp_last_inpcb = &udb;
  512.     in_pcbdetach(inp);
  513.     splx(s);
  514. }
  515.