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

Cache object: 9e42660148243a9284aba175e192a2c0


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