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

  1. /*
  2.  * Copyright (c) 1982, 1986, 1991 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.  *    @(#)in_pcb.c    7.14 (Berkeley) 4/20/91
  34.  */
  35.  
  36. #include "param.h"
  37. #include "systm.h"
  38. #include "malloc.h"
  39. #include "mbuf.h"
  40. #include "protosw.h"
  41. #include "socket.h"
  42. #include "socketvar.h"
  43. #include "ioctl.h"
  44.  
  45. #include "../net/if.h"
  46. #include "../net/route.h"
  47.  
  48. #include "in.h"
  49. #include "in_systm.h"
  50. #include "ip.h"
  51. #include "in_pcb.h"
  52. #include "in_var.h"
  53.  
  54. struct    in_addr zeroin_addr;
  55.  
  56. in_pcballoc(so, head)
  57.     struct socket *so;
  58.     struct inpcb *head;
  59. {
  60.     struct mbuf *m;
  61.     register struct inpcb *inp;
  62.  
  63.     m = m_getclr(M_DONTWAIT, MT_PCB);
  64.     if (m == NULL)
  65.         return (ENOBUFS);
  66.     inp = mtod(m, struct inpcb *);
  67.     inp->inp_head = head;
  68.     inp->inp_socket = so;
  69.     insque(inp, head);
  70.     so->so_pcb = (caddr_t)inp;
  71.     return (0);
  72. }
  73.     
  74. in_pcbbind(inp, nam)
  75.     register struct inpcb *inp;
  76.     struct mbuf *nam;
  77. {
  78.     register struct socket *so = inp->inp_socket;
  79.     register struct inpcb *head = inp->inp_head;
  80.     register struct sockaddr_in *sin;
  81.     u_short lport = 0;
  82.  
  83.     if (in_ifaddr == 0)
  84.         return (EADDRNOTAVAIL);
  85.     if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY)
  86.         return (EINVAL);
  87.     if (nam == 0)
  88.         goto noname;
  89.     sin = mtod(nam, struct sockaddr_in *);
  90.     if (nam->m_len != sizeof (*sin))
  91.         return (EINVAL);
  92.     if (sin->sin_addr.s_addr != INADDR_ANY) {
  93.         int tport = sin->sin_port;
  94.  
  95.         sin->sin_port = 0;        /* yech... */
  96.         if (ifa_ifwithaddr((struct sockaddr *)sin) == 0)
  97.             return (EADDRNOTAVAIL);
  98.         sin->sin_port = tport;
  99.     }
  100.     lport = sin->sin_port;
  101.     if (lport) {
  102.         u_short aport = ntohs(lport);
  103.         int wild = 0;
  104.  
  105.         /* GROSS */
  106.         if (aport < IPPORT_RESERVED && (so->so_state & SS_PRIV) == 0)
  107.             return (EACCES);
  108.         /* even GROSSER, but this is the Internet */
  109.         if ((so->so_options & SO_REUSEADDR) == 0 &&
  110.             ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
  111.              (so->so_options & SO_ACCEPTCONN) == 0))
  112.             wild = INPLOOKUP_WILDCARD;
  113.         if (in_pcblookup(head,
  114.             zeroin_addr, 0, sin->sin_addr, lport, wild))
  115.             return (EADDRINUSE);
  116.     }
  117.     inp->inp_laddr = sin->sin_addr;
  118. noname:
  119.     if (lport == 0)
  120.         do {
  121.             if (head->inp_lport++ < IPPORT_RESERVED ||
  122.                 head->inp_lport > IPPORT_USERRESERVED)
  123.                 head->inp_lport = IPPORT_RESERVED;
  124.             lport = htons(head->inp_lport);
  125.         } while (in_pcblookup(head,
  126.                 zeroin_addr, 0, inp->inp_laddr, lport, 0));
  127.     inp->inp_lport = lport;
  128.     return (0);
  129. }
  130.  
  131. /*
  132.  * Connect from a socket to a specified address.
  133.  * Both address and port must be specified in argument sin.
  134.  * If don't have a local address for this socket yet,
  135.  * then pick one.
  136.  */
  137. in_pcbconnect(inp, nam)
  138.     register struct inpcb *inp;
  139.     struct mbuf *nam;
  140. {
  141.     struct in_ifaddr *ia;
  142.     struct sockaddr_in *ifaddr;
  143.     register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
  144.  
  145.     if (nam->m_len != sizeof (*sin))
  146.         return (EINVAL);
  147.     if (sin->sin_family != AF_INET)
  148.         return (EAFNOSUPPORT);
  149.     if (sin->sin_port == 0)
  150.         return (EADDRNOTAVAIL);
  151.     if (in_ifaddr) {
  152.         /*
  153.          * If the destination address is INADDR_ANY,
  154.          * use the primary local address.
  155.          * If the supplied address is INADDR_BROADCAST,
  156.          * and the primary interface supports broadcast,
  157.          * choose the broadcast address for that interface.
  158.          */
  159. #define    satosin(sa)    ((struct sockaddr_in *)(sa))
  160.         if (sin->sin_addr.s_addr == INADDR_ANY)
  161.             sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr;
  162.         else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST &&
  163.           (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST))
  164.             sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr;
  165.     }
  166.     if (inp->inp_laddr.s_addr == INADDR_ANY) {
  167.         register struct route *ro;
  168.         struct ifnet *ifp;
  169.  
  170.         ia = (struct in_ifaddr *)0;
  171.         /* 
  172.          * If route is known or can be allocated now,
  173.          * our src addr is taken from the i/f, else punt.
  174.          */
  175.         ro = &inp->inp_route;
  176.         if (ro->ro_rt &&
  177.             (satosin(&ro->ro_dst)->sin_addr.s_addr !=
  178.             sin->sin_addr.s_addr || 
  179.             inp->inp_socket->so_options & SO_DONTROUTE)) {
  180.             RTFREE(ro->ro_rt);
  181.             ro->ro_rt = (struct rtentry *)0;
  182.         }
  183.         if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
  184.             (ro->ro_rt == (struct rtentry *)0 ||
  185.             ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
  186.             /* No route yet, so try to acquire one */
  187.             ro->ro_dst.sa_family = AF_INET;
  188.             ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
  189.             ((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
  190.                 sin->sin_addr;
  191.             rtalloc(ro);
  192.         }
  193.         /*
  194.          * If we found a route, use the address
  195.          * corresponding to the outgoing interface
  196.          * unless it is the loopback (in case a route
  197.          * to our address on another net goes to loopback).
  198.          */
  199.         if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp) &&
  200.             (ifp->if_flags & IFF_LOOPBACK) == 0)
  201.             for (ia = in_ifaddr; ia; ia = ia->ia_next)
  202.                 if (ia->ia_ifp == ifp)
  203.                     break;
  204.         if (ia == 0) {
  205.             int fport = sin->sin_port;
  206.  
  207.             sin->sin_port = 0;
  208.             ia = (struct in_ifaddr *)
  209.                 ifa_ifwithdstaddr((struct sockaddr *)sin);
  210.             sin->sin_port = fport;
  211.             if (ia == 0)
  212.                 ia = in_iaonnetof(in_netof(sin->sin_addr));
  213.             if (ia == 0)
  214.                 ia = in_ifaddr;
  215.             if (ia == 0)
  216.                 return (EADDRNOTAVAIL);
  217.         }
  218.         ifaddr = (struct sockaddr_in *)&ia->ia_addr;
  219.     }
  220.     if (in_pcblookup(inp->inp_head,
  221.         sin->sin_addr,
  222.         sin->sin_port,
  223.         inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
  224.         inp->inp_lport,
  225.         0))
  226.         return (EADDRINUSE);
  227.     if (inp->inp_laddr.s_addr == INADDR_ANY) {
  228.         if (inp->inp_lport == 0)
  229.             (void)in_pcbbind(inp, (struct mbuf *)0);
  230.         inp->inp_laddr = ifaddr->sin_addr;
  231.     }
  232.     inp->inp_faddr = sin->sin_addr;
  233.     inp->inp_fport = sin->sin_port;
  234.     return (0);
  235. }
  236.  
  237. in_pcbdisconnect(inp)
  238.     struct inpcb *inp;
  239. {
  240.  
  241.     inp->inp_faddr.s_addr = INADDR_ANY;
  242.     inp->inp_fport = 0;
  243.     if (inp->inp_socket->so_state & SS_NOFDREF)
  244.         in_pcbdetach(inp);
  245. }
  246.  
  247. in_pcbdetach(inp)
  248.     struct inpcb *inp;
  249. {
  250.     struct socket *so = inp->inp_socket;
  251.  
  252.     so->so_pcb = 0;
  253.     sofree(so);
  254.     if (inp->inp_options)
  255.         (void)m_free(inp->inp_options);
  256.     if (inp->inp_route.ro_rt)
  257.         rtfree(inp->inp_route.ro_rt);
  258.     remque(inp);
  259.     (void) m_free(dtom(inp));
  260. }
  261.  
  262. in_setsockaddr(inp, nam)
  263.     register struct inpcb *inp;
  264.     struct mbuf *nam;
  265. {
  266.     register struct sockaddr_in *sin;
  267.     
  268.     nam->m_len = sizeof (*sin);
  269.     sin = mtod(nam, struct sockaddr_in *);
  270.     bzero((caddr_t)sin, sizeof (*sin));
  271.     sin->sin_family = AF_INET;
  272.     sin->sin_len = sizeof(*sin);
  273.     sin->sin_port = inp->inp_lport;
  274.     sin->sin_addr = inp->inp_laddr;
  275. }
  276.  
  277. in_setpeeraddr(inp, nam)
  278.     struct inpcb *inp;
  279.     struct mbuf *nam;
  280. {
  281.     register struct sockaddr_in *sin;
  282.     
  283.     nam->m_len = sizeof (*sin);
  284.     sin = mtod(nam, struct sockaddr_in *);
  285.     bzero((caddr_t)sin, sizeof (*sin));
  286.     sin->sin_family = AF_INET;
  287.     sin->sin_len = sizeof(*sin);
  288.     sin->sin_port = inp->inp_fport;
  289.     sin->sin_addr = inp->inp_faddr;
  290. }
  291.  
  292. /*
  293.  * Pass some notification to all connections of a protocol
  294.  * associated with address dst.  The local address and/or port numbers
  295.  * may be specified to limit the search.  The "usual action" will be
  296.  * taken, depending on the ctlinput cmd.  The caller must filter any
  297.  * cmds that are uninteresting (e.g., no error in the map).
  298.  * Call the protocol specific routine (if any) to report
  299.  * any errors for each matching socket.
  300.  *
  301.  * Must be called at splnet.
  302.  */
  303. in_pcbnotify(head, dst, fport, laddr, lport, cmd, notify)
  304.     struct inpcb *head;
  305.     struct sockaddr *dst;
  306.     u_short fport, lport;
  307.     struct in_addr laddr;
  308.     int cmd, (*notify)();
  309. {
  310.     register struct inpcb *inp, *oinp;
  311.     struct in_addr faddr;
  312.     int errno;
  313.     int in_rtchange();
  314.     extern u_char inetctlerrmap[];
  315.  
  316.     if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET)
  317.         return;
  318.     faddr = ((struct sockaddr_in *)dst)->sin_addr;
  319.     if (faddr.s_addr == INADDR_ANY)
  320.         return;
  321.  
  322.     /*
  323.      * Redirects go to all references to the destination,
  324.      * and use in_rtchange to invalidate the route cache.
  325.      * Dead host indications: notify all references to the destination.
  326.      * Otherwise, if we have knowledge of the local port and address,
  327.      * deliver only to that socket.
  328.      */
  329.     if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
  330.         fport = 0;
  331.         lport = 0;
  332.         laddr.s_addr = 0;
  333.         if (cmd != PRC_HOSTDEAD)
  334.             notify = in_rtchange;
  335.     }
  336.     errno = inetctlerrmap[cmd];
  337.     for (inp = head->inp_next; inp != head;) {
  338.         if (inp->inp_faddr.s_addr != faddr.s_addr ||
  339.             inp->inp_socket == 0 ||
  340.             (lport && inp->inp_lport != lport) ||
  341.             (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) ||
  342.             (fport && inp->inp_fport != fport)) {
  343.             inp = inp->inp_next;
  344.             continue;
  345.         }
  346.         oinp = inp;
  347.         inp = inp->inp_next;
  348.         if (notify)
  349.             (*notify)(oinp, errno);
  350.     }
  351. }
  352.  
  353. /*
  354.  * Check for alternatives when higher level complains
  355.  * about service problems.  For now, invalidate cached
  356.  * routing information.  If the route was created dynamically
  357.  * (by a redirect), time to try a default gateway again.
  358.  */
  359. in_losing(inp)
  360.     struct inpcb *inp;
  361. {
  362.     register struct rtentry *rt;
  363.  
  364.     if ((rt = inp->inp_route.ro_rt)) {
  365.         rt_missmsg(RTM_LOSING, &inp->inp_route.ro_dst,
  366.                 rt->rt_gateway, (struct sockaddr *)rt_mask(rt),
  367.                 (struct sockaddr *)0, rt->rt_flags, 0);
  368.         if (rt->rt_flags & RTF_DYNAMIC)
  369.             (void) rtrequest(RTM_DELETE, rt_key(rt),
  370.                 rt->rt_gateway, rt_mask(rt), rt->rt_flags, 
  371.                 (struct rtentry **)0);
  372.         inp->inp_route.ro_rt = 0;
  373.         rtfree(rt);
  374.         /*
  375.          * A new route can be allocated
  376.          * the next time output is attempted.
  377.          */
  378.     }
  379. }
  380.  
  381. /*
  382.  * After a routing change, flush old routing
  383.  * and allocate a (hopefully) better one.
  384.  */
  385. in_rtchange(inp)
  386.     register struct inpcb *inp;
  387. {
  388.     if (inp->inp_route.ro_rt) {
  389.         rtfree(inp->inp_route.ro_rt);
  390.         inp->inp_route.ro_rt = 0;
  391.         /*
  392.          * A new route can be allocated the next time
  393.          * output is attempted.
  394.          */
  395.     }
  396. }
  397.  
  398. struct inpcb *
  399. in_pcblookup(head, faddr, fport, laddr, lport, flags)
  400.     struct inpcb *head;
  401.     struct in_addr faddr, laddr;
  402.     u_short fport, lport;
  403.     int flags;
  404. {
  405.     register struct inpcb *inp, *match = 0;
  406.     int matchwild = 3, wildcard;
  407.  
  408.     for (inp = head->inp_next; inp != head; inp = inp->inp_next) {
  409.         if (inp->inp_lport != lport)
  410.             continue;
  411.         wildcard = 0;
  412.         if (inp->inp_laddr.s_addr != INADDR_ANY) {
  413.             if (laddr.s_addr == INADDR_ANY)
  414.                 wildcard++;
  415.             else if (inp->inp_laddr.s_addr != laddr.s_addr)
  416.                 continue;
  417.         } else {
  418.             if (laddr.s_addr != INADDR_ANY)
  419.                 wildcard++;
  420.         }
  421.         if (inp->inp_faddr.s_addr != INADDR_ANY) {
  422.             if (faddr.s_addr == INADDR_ANY)
  423.                 wildcard++;
  424.             else if (inp->inp_faddr.s_addr != faddr.s_addr ||
  425.                 inp->inp_fport != fport)
  426.                 continue;
  427.         } else {
  428.             if (faddr.s_addr != INADDR_ANY)
  429.                 wildcard++;
  430.         }
  431.         if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0)
  432.             continue;
  433.         if (wildcard < matchwild) {
  434.             match = inp;
  435.             matchwild = wildcard;
  436.             if (matchwild == 0)
  437.                 break;
  438.         }
  439.     }
  440.     return (match);
  441. }
  442.