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