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