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