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