Annotation of sys/netatalk/ddp_usrreq.c, Revision 1.1
1.1 ! nbrk 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: }
CVSweb