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

Cache object: f13682f37ea40616a06c6a319b533fb3


[ 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.