root/netatalk/ddp_usrreq.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ddp_usrreq
  2. at_sockaddr
  3. at_pcbsetaddr
  4. at_pcbconnect
  5. at_pcbdisconnect
  6. at_pcballoc
  7. at_pcbdetach
  8. ddp_search
  9. ddp_init

    1 /*      $OpenBSD: ddp_usrreq.c,v 1.8 2007/05/26 12:09:40 claudio Exp $  */
    2 
    3 /*
    4  * Copyright (c) 1990,1994 Regents of The University of Michigan.
    5  * All Rights Reserved.  See COPYRIGHT.
    6  */
    7 
    8 /*
    9  * The following is the contents of the COPYRIGHT file from the
   10  * netatalk-1.4a2 distribution, from which this file is derived.
   11  */
   12 /*
   13  * Copyright (c) 1990,1996 Regents of The University of Michigan.
   14  *
   15  * All Rights Reserved.
   16  *
   17  *    Permission to use, copy, modify, and distribute this software and
   18  *    its documentation for any purpose and without fee is hereby granted,
   19  *    provided that the above copyright notice appears in all copies and
   20  *    that both that copyright notice and this permission notice appear
   21  *    in supporting documentation, and that the name of The University
   22  *    of Michigan not be used in advertising or publicity pertaining to
   23  *    distribution of the software without specific, written prior
   24  *    permission. This software is supplied as is without expressed or
   25  *    implied warranties of any kind.
   26  *
   27  * This product includes software developed by the University of
   28  * California, Berkeley and its contributors.
   29  *
   30  * Solaris code is encumbered by the following:
   31  *
   32  *     Copyright (C) 1996 by Sun Microsystems Computer Co.
   33  *
   34  *     Permission to use, copy, modify, and distribute this software and
   35  *     its documentation for any purpose and without fee is hereby
   36  *     granted, provided that the above copyright notice appear in all
   37  *     copies and that both that copyright notice and this permission
   38  *     notice appear in supporting documentation.  This software is
   39  *     provided "as is" without express or implied warranty.
   40  *
   41  * Research Systems Unix Group
   42  * The University of Michigan
   43  * c/o Wesley Craig
   44  * 535 W. William Street
   45  * Ann Arbor, Michigan
   46  * +1-313-764-2278
   47  * netatalk@umich.edu
   48  */
   49 /*
   50  * None of the Solaris code mentioned is included in OpenBSD.
   51  * This code also relies heavily on previous effort in FreeBSD and NetBSD.
   52  */
   53 
   54 #include <sys/errno.h>
   55 #include <sys/types.h>
   56 #include <sys/param.h>
   57 #include <sys/systm.h>
   58 #include <sys/proc.h>
   59 #include <sys/user.h>
   60 #include <sys/mbuf.h>
   61 #include <sys/ioctl.h>
   62 #include <sys/socket.h>
   63 #include <sys/socketvar.h>
   64 #include <sys/protosw.h>
   65 #include <net/if.h>
   66 #include <net/route.h>
   67 
   68 #include <machine/endian.h>
   69 
   70 #include <netatalk/at.h>
   71 #include <netatalk/at_var.h>
   72 #include <netatalk/ddp_var.h>
   73 #include <netatalk/at_extern.h>
   74 
   75 int ddp_usrreq(struct socket *, int, struct mbuf *,
   76                         struct mbuf *, struct mbuf * );
   77 static void at_sockaddr( struct ddpcb *, struct mbuf * );
   78 static int at_pcbsetaddr( struct ddpcb *, struct mbuf *,
   79                         struct proc * );
   80 static int at_pcbconnect( struct ddpcb *, struct mbuf *,
   81                         struct proc *);
   82 static void at_pcbdisconnect( struct ddpcb * );
   83 static int at_pcballoc( struct socket * );
   84 static void at_pcbdetach( struct socket *, struct ddpcb * );
   85 struct ddpcb *ddp_search( struct sockaddr_at *,
   86                         struct sockaddr_at *, struct at_ifaddr * );
   87 void ddp_init(void);
   88 
   89 struct at_ifaddr        *at_ifaddr;
   90 struct ifqueue          atintrq1, atintrq2;
   91 int                     atdebug;
   92 
   93 struct ddpcb            *ddp_ports[ ATPORT_LAST ];
   94 struct ddpstat          ddpstat;
   95 
   96 struct ddpcb    *ddpcb = NULL;
   97 u_long          ddp_sendspace = DDP_MAXSZ; /* Max ddp size + 1 (ddp_type) */
   98 u_long          ddp_recvspace = 10 * ( 587 + sizeof( struct sockaddr_at ));
   99 
  100 /*ARGSUSED*/
  101 int
  102 ddp_usrreq( so, req, m, addr, rights )
  103     struct socket       *so;
  104     int                 req;
  105     struct mbuf         *m, *addr, *rights;
  106 {
  107     /* XXX Need to pass p into this routine */
  108     struct proc *p = curproc;
  109     struct ddpcb        *ddp;
  110     int                 error = 0;
  111 
  112     ddp = sotoddpcb( so );
  113 
  114     if ( req == PRU_CONTROL ) {
  115         return( at_control( (u_long) m, (caddr_t) addr,
  116                 (struct ifnet *) rights, p ));
  117     }
  118 
  119     if ( rights && rights->m_len ) {
  120         error = EINVAL;
  121         goto release;
  122     }
  123 
  124     if ( ddp == NULL && req != PRU_ATTACH ) {
  125         error = EINVAL;
  126         goto release;
  127     }
  128 
  129     switch ( req ) {
  130     case PRU_ATTACH :
  131         if ( ddp != NULL ) {
  132             error = EINVAL;
  133             break;
  134         }
  135         if (( error = at_pcballoc( so )) != 0 ) {
  136             break;
  137         }
  138         error = soreserve( so, ddp_sendspace, ddp_recvspace );
  139         break;
  140 
  141     case PRU_DETACH :
  142         at_pcbdetach( so, ddp );
  143         break;
  144 
  145     case PRU_BIND :
  146         error = at_pcbsetaddr( ddp, addr, p );
  147         break;
  148     
  149     case PRU_SOCKADDR :
  150         at_sockaddr( ddp, addr );
  151         break;
  152 
  153     case PRU_CONNECT:
  154         if ( ddp->ddp_fsat.sat_port != ATADDR_ANYPORT ) {
  155             error = EISCONN;
  156             break;
  157         }
  158 
  159         error = at_pcbconnect( ddp, addr, p );
  160         if ( error == 0 )
  161             soisconnected( so );
  162         break;
  163 
  164     case PRU_DISCONNECT:
  165         if ( ddp->ddp_fsat.sat_addr.s_node == ATADDR_ANYNODE ) {
  166             error = ENOTCONN;
  167             break;
  168         }
  169         at_pcbdisconnect( ddp );
  170         soisdisconnected( so );
  171         break;
  172 
  173     case PRU_SHUTDOWN:
  174         socantsendmore( so );
  175         break;
  176 
  177     case PRU_SEND: {
  178         int     s;
  179 
  180         if ( addr ) {
  181             if ( ddp->ddp_fsat.sat_port != ATADDR_ANYPORT ) {
  182                 error = EISCONN;
  183                 break;
  184             }
  185 
  186             s = splnet();
  187             error = at_pcbconnect( ddp, addr, p );
  188             if ( error ) {
  189                 splx( s );
  190                 break;
  191             }
  192         } else {
  193             if ( ddp->ddp_fsat.sat_port == ATADDR_ANYPORT ) {
  194                 error = ENOTCONN;
  195                 break;
  196             }
  197         }
  198 
  199         error = ddp_output( m, ddp );
  200         m = NULL;
  201         if ( addr ) {
  202             at_pcbdisconnect( ddp );
  203             splx( s );
  204         }
  205         }
  206         break;
  207 
  208     case PRU_ABORT:
  209         soisdisconnected( so );
  210         at_pcbdetach( so, ddp );
  211         break;
  212 
  213     case PRU_LISTEN:
  214     case PRU_CONNECT2:
  215     case PRU_ACCEPT:
  216     case PRU_SENDOOB:
  217     case PRU_FASTTIMO:
  218     case PRU_SLOWTIMO:
  219     case PRU_PROTORCV:
  220     case PRU_PROTOSEND:
  221         error = EOPNOTSUPP;
  222         break;
  223 
  224     case PRU_RCVD:
  225     case PRU_RCVOOB:
  226         /*
  227          * Don't mfree. Good architecture...
  228          */
  229         return( EOPNOTSUPP );
  230 
  231     case PRU_SENSE:
  232         /*
  233          * 1. Don't return block size.
  234          * 2. Don't mfree.
  235          */
  236         return( 0 );
  237 
  238     default:
  239         error = EOPNOTSUPP;
  240     }
  241 
  242 release:
  243     if ( m != NULL ) {
  244         m_freem( m );
  245     }
  246     return( error );
  247 }
  248 
  249 static void
  250 at_sockaddr( ddp, addr )
  251     struct ddpcb        *ddp;
  252     struct mbuf         *addr;
  253 {
  254     struct sockaddr_at  *sat;
  255 
  256     addr->m_len = sizeof( struct sockaddr_at );
  257     sat = mtod( addr, struct sockaddr_at *);
  258     *sat = ddp->ddp_lsat;
  259 }
  260 
  261 static int
  262 at_pcbsetaddr( ddp, addr, p )
  263     struct ddpcb        *ddp;
  264     struct mbuf         *addr;
  265     struct proc         *p;
  266 {
  267     struct sockaddr_at  lsat, *sat;
  268     struct at_ifaddr    *aa;
  269     struct ddpcb        *ddpp;
  270 
  271     if ( ddp->ddp_lsat.sat_port != ATADDR_ANYPORT ) { /* shouldn't be bound */
  272         return( EINVAL );
  273     }
  274 
  275     if ( addr != 0 ) {                  /* validate passed address */
  276         sat = mtod( addr, struct sockaddr_at *);
  277         if ( addr->m_len != sizeof( *sat )) {
  278             return( EINVAL );
  279         }
  280         if ( sat->sat_family != AF_APPLETALK ) {
  281             return( EAFNOSUPPORT );
  282         }
  283 
  284         if ( sat->sat_addr.s_node != ATADDR_ANYNODE ||
  285                 sat->sat_addr.s_net != ATADDR_ANYNET ) {
  286             for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
  287                 if (( sat->sat_addr.s_net == AA_SAT( aa )->sat_addr.s_net ) &&
  288                  ( sat->sat_addr.s_node == AA_SAT( aa )->sat_addr.s_node )) {
  289                     break;
  290                 }
  291             }
  292             if ( !aa ) {
  293                 return( EADDRNOTAVAIL );
  294             }
  295         }
  296 
  297         if ( sat->sat_port != ATADDR_ANYPORT ) {
  298             if ( sat->sat_port < ATPORT_FIRST ||
  299                     sat->sat_port >= ATPORT_LAST ) {
  300                 return( EINVAL );
  301             }
  302             if ( sat->sat_port < ATPORT_RESERVED &&
  303                     suser( p, 0 )) {
  304                 return( EACCES );
  305             }
  306         }
  307     } else {
  308         bzero( (caddr_t)&lsat, sizeof( struct sockaddr_at ));
  309         lsat.sat_family = AF_APPLETALK;
  310         sat = &lsat;
  311     }
  312 
  313     if ( sat->sat_addr.s_node == ATADDR_ANYNODE &&
  314             sat->sat_addr.s_net == ATADDR_ANYNET ) {
  315         if ( at_ifaddr == NULL ) {
  316             return( EADDRNOTAVAIL );
  317         }
  318         sat->sat_addr = AA_SAT( at_ifaddr )->sat_addr;
  319     }
  320     ddp->ddp_lsat = *sat;
  321 
  322     /*
  323      * Choose port.
  324      */
  325     if ( sat->sat_port == ATADDR_ANYPORT ) {
  326         for ( sat->sat_port = ATPORT_RESERVED;
  327                 sat->sat_port < ATPORT_LAST; sat->sat_port++ ) {
  328             if ( ddp_ports[ sat->sat_port - 1 ] == 0 ) {
  329                 break;
  330             }
  331         }
  332         if ( sat->sat_port == ATPORT_LAST ) {
  333             return( EADDRNOTAVAIL );
  334         }
  335         ddp->ddp_lsat.sat_port = sat->sat_port;
  336         ddp_ports[ sat->sat_port - 1 ] = ddp;
  337     } else {
  338         for ( ddpp = ddp_ports[ sat->sat_port - 1 ]; ddpp;
  339                 ddpp = ddpp->ddp_pnext ) {
  340             if ( ddpp->ddp_lsat.sat_addr.s_net == sat->sat_addr.s_net &&
  341                     ddpp->ddp_lsat.sat_addr.s_node == sat->sat_addr.s_node ) {
  342                 break;
  343             }
  344         }
  345         if ( ddpp != NULL ) {
  346             return( EADDRINUSE );
  347         }
  348         ddp->ddp_pnext = ddp_ports[ sat->sat_port - 1 ];
  349         ddp_ports[ sat->sat_port - 1 ] = ddp;
  350         if ( ddp->ddp_pnext ) {
  351             ddp->ddp_pnext->ddp_pprev = ddp;
  352         }
  353     }
  354 
  355     return( 0 );
  356 }
  357 
  358 static int
  359 at_pcbconnect( ddp, addr, p )
  360     struct ddpcb        *ddp;
  361     struct mbuf         *addr;
  362     struct proc         *p;
  363 {
  364     struct sockaddr_at  *sat = mtod( addr, struct sockaddr_at *);
  365     struct route        *ro;
  366     struct at_ifaddr    *aa = 0;
  367     struct ifnet        *ifp;
  368     u_int16_t           hintnet = 0, net;
  369 
  370     if ( addr->m_len != sizeof( *sat ))
  371         return( EINVAL );
  372     if ( sat->sat_family != AF_APPLETALK ) {
  373         return( EAFNOSUPPORT );
  374     }
  375 
  376     /*
  377      * Under phase 2, network 0 means "the network".  We take "the
  378      * network" to mean the network the control block is bound to.
  379      * If the control block is not bound, there is an error.
  380      */
  381     if ( sat->sat_addr.s_net == 0 && sat->sat_addr.s_node != ATADDR_ANYNODE ) {
  382         if ( ddp->ddp_lsat.sat_port == ATADDR_ANYPORT ) {
  383             return( EADDRNOTAVAIL );
  384         }
  385         hintnet = ddp->ddp_lsat.sat_addr.s_net;
  386     }
  387 
  388     ro = &ddp->ddp_route;
  389     /*
  390      * If we've got an old route for this pcb, check that it is valid.
  391      * If we've changed our address, we may have an old "good looking"
  392      * route here.  Attempt to detect it.
  393      */
  394     if ( ro->ro_rt ) {
  395         if ( hintnet ) {
  396             net = hintnet;
  397         } else {
  398             net = sat->sat_addr.s_net;
  399         }
  400         aa = 0;
  401         if ( (ifp = ro->ro_rt->rt_ifp) != NULL ) {
  402             for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
  403                 if ( aa->aa_ifp == ifp &&
  404                         ntohs( net ) >= ntohs( aa->aa_firstnet ) &&
  405                         ntohs( net ) <= ntohs( aa->aa_lastnet )) {
  406                     break;
  407                 }
  408             }
  409         }
  410         if ( aa == NULL || ( satosat( &ro->ro_dst )->sat_addr.s_net !=
  411                 ( hintnet ? hintnet : sat->sat_addr.s_net ) ||
  412                 satosat( &ro->ro_dst )->sat_addr.s_node !=
  413                 sat->sat_addr.s_node )) {
  414             RTFREE( ro->ro_rt );
  415             ro->ro_rt = (struct rtentry *)0;
  416         }
  417     }
  418 
  419     /*
  420      * If we've got no route for this interface, try to find one.
  421      */
  422     if ( ro->ro_rt == (struct rtentry *)0 ||
  423          ro->ro_rt->rt_ifp == (struct ifnet *)0 ) {
  424         ro->ro_dst.sa_len = sizeof( struct sockaddr_at );
  425         ro->ro_dst.sa_family = AF_APPLETALK;
  426         if ( hintnet != 0 ) {
  427             satosat( &ro->ro_dst )->sat_addr.s_net = hintnet;
  428         } else {
  429             satosat( &ro->ro_dst )->sat_addr.s_net = sat->sat_addr.s_net;
  430         }
  431         satosat( &ro->ro_dst )->sat_addr.s_node = sat->sat_addr.s_node;
  432         rtalloc( ro );
  433     }
  434 
  435     /*
  436      * Make sure any route that we have has a valid interface.
  437      */
  438     aa = 0;
  439     if ( ro->ro_rt && ( ifp = ro->ro_rt->rt_ifp )) {
  440         for ( aa = at_ifaddr; aa; aa = aa->aa_next ) {
  441             if ( aa->aa_ifp == ifp ) {
  442                 break;
  443             }
  444         }
  445     }
  446     if ( aa == 0 ) {
  447         return( ENETUNREACH );
  448     }
  449 
  450     ddp->ddp_fsat = *sat;
  451     if ( ddp->ddp_lsat.sat_port == ATADDR_ANYPORT ) {
  452         return( at_pcbsetaddr( ddp, (struct mbuf *)0, p ));
  453     }
  454     return( 0 );
  455 }
  456 
  457 static void
  458 at_pcbdisconnect( ddp )
  459     struct ddpcb        *ddp;
  460 {
  461     ddp->ddp_fsat.sat_addr.s_net = ATADDR_ANYNET;
  462     ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE;
  463     ddp->ddp_fsat.sat_port = ATADDR_ANYPORT;
  464 }
  465 
  466 static int
  467 at_pcballoc( so )
  468     struct socket       *so;
  469 {
  470     struct ddpcb        *ddp;
  471 
  472     MALLOC( ddp, struct ddpcb *, sizeof( *ddp ), M_PCB, M_NOWAIT );
  473     if ( ddp == NULL ) {
  474         return (ENOBUFS);
  475     }
  476     bzero( ddp, sizeof( *ddp ));
  477 
  478     ddp->ddp_lsat.sat_port = ATADDR_ANYPORT;
  479 
  480     ddp->ddp_next = ddpcb;
  481     ddp->ddp_prev = NULL;
  482     ddp->ddp_pprev = NULL;
  483     ddp->ddp_pnext = NULL;
  484     if ( ddpcb ) {
  485         ddpcb->ddp_prev = ddp;
  486     }
  487     ddpcb = ddp;
  488 
  489     ddp->ddp_socket = so;
  490     so->so_pcb = (caddr_t)ddp;
  491     return( 0 );
  492 }
  493 
  494 static void
  495 at_pcbdetach( so, ddp )
  496     struct socket       *so;
  497     struct ddpcb        *ddp;
  498 {
  499     soisdisconnected( so );
  500     so->so_pcb = 0;
  501     sofree( so );
  502 
  503     /* remove ddp from ddp_ports list */
  504     if ( ddp->ddp_lsat.sat_port != ATADDR_ANYPORT &&
  505             ddp_ports[ ddp->ddp_lsat.sat_port - 1 ] != NULL ) {
  506         if ( ddp->ddp_pprev != NULL ) {
  507             ddp->ddp_pprev->ddp_pnext = ddp->ddp_pnext;
  508         } else {
  509             ddp_ports[ ddp->ddp_lsat.sat_port - 1 ] = ddp->ddp_pnext;
  510         }
  511         if ( ddp->ddp_pnext != NULL ) {
  512             ddp->ddp_pnext->ddp_pprev = ddp->ddp_pprev;
  513         }
  514     }
  515 
  516     if ( ddp->ddp_route.ro_rt ) {
  517         rtfree( ddp->ddp_route.ro_rt );
  518     }
  519 
  520     if ( ddp->ddp_prev ) {
  521         ddp->ddp_prev->ddp_next = ddp->ddp_next;
  522     } else {
  523         ddpcb = ddp->ddp_next;
  524     }
  525     if ( ddp->ddp_next ) {
  526         ddp->ddp_next->ddp_prev = ddp->ddp_prev;
  527     }
  528 
  529     FREE( ddp, M_PCB );
  530 }
  531 
  532 /*
  533  * For the moment, this just find the pcb with the correct local address.
  534  * In the future, this will actually do some real searching, so we can use
  535  * the sender's address to do de-multiplexing on a single port to many
  536  * sockets (pcbs).
  537  */
  538 struct ddpcb *
  539 ddp_search( from, to, aa )
  540     struct sockaddr_at  *from, *to;
  541     struct at_ifaddr    *aa;
  542 {
  543     struct ddpcb        *ddp;
  544 
  545     /*
  546      * Check for bad ports.
  547      */
  548     if ( to->sat_port < ATPORT_FIRST || to->sat_port >= ATPORT_LAST ) {
  549         return( NULL );
  550     }
  551 
  552     /*
  553      * Make sure the local address matches the sent address.  What about
  554      * the interface?
  555      */
  556     for ( ddp = ddp_ports[ to->sat_port - 1 ]; ddp; ddp = ddp->ddp_pnext ) {
  557         /* XXX should we handle 0.YY? */
  558 
  559         /* XXXX.YY to socket on destination interface */
  560         if ( to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net &&
  561                 to->sat_addr.s_node == ddp->ddp_lsat.sat_addr.s_node ) {
  562             break;
  563         }
  564 
  565         /* 0.255 to socket on receiving interface */
  566         if ( to->sat_addr.s_node == ATADDR_BCAST && ( to->sat_addr.s_net == 0 ||
  567                 to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net ) &&
  568                 ddp->ddp_lsat.sat_addr.s_net == AA_SAT( aa )->sat_addr.s_net ) {
  569             break;
  570         }
  571 
  572         /* XXXX.0 to socket on destination interface */
  573         if ( to->sat_addr.s_net == aa->aa_firstnet &&
  574                 to->sat_addr.s_node == 0 &&
  575                 ntohs( ddp->ddp_lsat.sat_addr.s_net ) >=
  576                 ntohs( aa->aa_firstnet ) &&
  577                 ntohs( ddp->ddp_lsat.sat_addr.s_net ) <=
  578                 ntohs( aa->aa_lastnet )) {
  579             break;
  580         }
  581     }
  582     return( ddp );
  583 }
  584 
  585 void
  586 ddp_init()
  587 {
  588     atintrq1.ifq_maxlen = IFQ_MAXLEN;
  589     atintrq2.ifq_maxlen = IFQ_MAXLEN;
  590 }

/* [<][>][^][v][top][bottom][index][help] */