ddp_usrreq.c revision 83366
1/* 2 * Copyright (c) 1990,1994 Regents of The University of Michigan. 3 * All Rights Reserved. See COPYRIGHT. 4 * 5 * $FreeBSD: head/sys/netatalk/ddp_usrreq.c 83366 2001-09-12 08:38:13Z julian $ 6 */ 7 8#include <sys/param.h> 9#include <sys/systm.h> 10#include <sys/malloc.h> 11#include <sys/mbuf.h> 12#include <sys/socket.h> 13#include <sys/socketvar.h> 14#include <sys/protosw.h> 15#include <net/if.h> 16#include <net/route.h> 17 18#include <netatalk/at.h> 19#include <netatalk/at_var.h> 20#include <netatalk/ddp_var.h> 21#include <netatalk/at_extern.h> 22 23static void at_pcbdisconnect( struct ddpcb *ddp ); 24static void at_sockaddr(struct ddpcb *ddp, struct sockaddr **addr); 25static int at_pcbsetaddr(struct ddpcb *ddp, struct sockaddr *addr, 26 struct thread *td); 27static int at_pcbconnect(struct ddpcb *ddp, struct sockaddr *addr, 28 struct thread *td); 29static void at_pcbdetach(struct socket *so, struct ddpcb *ddp); 30static int at_pcballoc(struct socket *so); 31 32struct ddpcb *ddp_ports[ ATPORT_LAST ]; 33struct ddpcb *ddpcb = NULL; 34static u_long ddp_sendspace = DDP_MAXSZ; /* Max ddp size + 1 (ddp_type) */ 35static u_long ddp_recvspace = 10 * ( 587 + sizeof( struct sockaddr_at )); 36 37 38static int 39ddp_attach(struct socket *so, int proto, struct thread *td) 40{ 41 struct ddpcb *ddp; 42 int error = 0; 43 int s; 44 45 46 ddp = sotoddpcb( so ); 47 if ( ddp != NULL ) { 48 return( EINVAL); 49 } 50 51 s = splnet(); 52 error = at_pcballoc( so ); 53 splx(s); 54 if (error) { 55 return (error); 56 } 57 return (soreserve( so, ddp_sendspace, ddp_recvspace )); 58} 59 60static int 61ddp_detach(struct socket *so) 62{ 63 struct ddpcb *ddp; 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 thread *td) 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, td); 89 splx(s); 90 return (error); 91} 92 93static int 94ddp_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 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, td ); 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 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 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 sockaddr *addr, 155 struct mbuf *control, struct thread *td) 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, td); 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 sockaddr **addr) 216{ 217 *addr = dup_sockaddr((struct sockaddr *)&ddp->ddp_lsat, 0); 218} 219 220static int 221at_pcbsetaddr(struct ddpcb *ddp, struct sockaddr *addr, struct thread *td) 222{ 223 struct sockaddr_at lsat, *sat; 224 struct at_ifaddr *aa; 225 struct ddpcb *ddpp; 226 227 if ( ddp->ddp_lsat.sat_port != ATADDR_ANYPORT ) { /* shouldn't be bound */ 228 return( EINVAL ); 229 } 230 231 if (addr != 0) { /* validate passed address */ 232 sat = (struct sockaddr_at *)addr; 233 if (sat->sat_family != AF_APPLETALK) { 234 return(EAFNOSUPPORT); 235 } 236 237 if ( sat->sat_addr.s_node != ATADDR_ANYNODE || 238 sat->sat_addr.s_net != ATADDR_ANYNET ) { 239 for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { 240 if (( sat->sat_addr.s_net == AA_SAT( aa )->sat_addr.s_net ) && 241 ( sat->sat_addr.s_node == AA_SAT( aa )->sat_addr.s_node )) { 242 break; 243 } 244 } 245 if ( !aa ) { 246 return( EADDRNOTAVAIL ); 247 } 248 } 249 250 if ( sat->sat_port != ATADDR_ANYPORT ) { 251 if ( sat->sat_port < ATPORT_FIRST || 252 sat->sat_port >= ATPORT_LAST ) { 253 return( EINVAL ); 254 } 255 if ( sat->sat_port < ATPORT_RESERVED && 256 suser_td(td) ) { 257 return( EACCES ); 258 } 259 } 260 } else { 261 bzero( (caddr_t)&lsat, sizeof( struct sockaddr_at )); 262 lsat.sat_len = sizeof(struct sockaddr_at); 263 lsat.sat_addr.s_node = ATADDR_ANYNODE; 264 lsat.sat_addr.s_net = ATADDR_ANYNET; 265 lsat.sat_family = AF_APPLETALK; 266 sat = &lsat; 267 } 268 269 if ( sat->sat_addr.s_node == ATADDR_ANYNODE && 270 sat->sat_addr.s_net == ATADDR_ANYNET ) { 271 if ( at_ifaddr == NULL ) { 272 return( EADDRNOTAVAIL ); 273 } 274 sat->sat_addr = AA_SAT( at_ifaddr )->sat_addr; 275 } 276 ddp->ddp_lsat = *sat; 277 278 /* 279 * Choose port. 280 */ 281 if ( sat->sat_port == ATADDR_ANYPORT ) { 282 for ( sat->sat_port = ATPORT_RESERVED; 283 sat->sat_port < ATPORT_LAST; sat->sat_port++ ) { 284 if ( ddp_ports[ sat->sat_port - 1 ] == 0 ) { 285 break; 286 } 287 } 288 if ( sat->sat_port == ATPORT_LAST ) { 289 return( EADDRNOTAVAIL ); 290 } 291 ddp->ddp_lsat.sat_port = sat->sat_port; 292 ddp_ports[ sat->sat_port - 1 ] = ddp; 293 } else { 294 for ( ddpp = ddp_ports[ sat->sat_port - 1 ]; ddpp; 295 ddpp = ddpp->ddp_pnext ) { 296 if ( ddpp->ddp_lsat.sat_addr.s_net == sat->sat_addr.s_net && 297 ddpp->ddp_lsat.sat_addr.s_node == sat->sat_addr.s_node ) { 298 break; 299 } 300 } 301 if ( ddpp != NULL ) { 302 return( EADDRINUSE ); 303 } 304 ddp->ddp_pnext = ddp_ports[ sat->sat_port - 1 ]; 305 ddp_ports[ sat->sat_port - 1 ] = ddp; 306 if ( ddp->ddp_pnext ) { 307 ddp->ddp_pnext->ddp_pprev = ddp; 308 } 309 } 310 311 return( 0 ); 312} 313 314static int 315at_pcbconnect(struct ddpcb *ddp, struct sockaddr *addr, struct thread *td) 316{ 317 struct sockaddr_at *sat = (struct sockaddr_at *)addr; 318 struct route *ro; 319 struct at_ifaddr *aa = 0; 320 struct ifnet *ifp; 321 u_short hintnet = 0, net; 322 323 if (sat->sat_family != AF_APPLETALK) { 324 return(EAFNOSUPPORT); 325 } 326 327 /* 328 * Under phase 2, network 0 means "the network". We take "the 329 * network" to mean the network the control block is bound to. 330 * If the control block is not bound, there is an error. 331 */ 332 if ( sat->sat_addr.s_net == ATADDR_ANYNET 333 && sat->sat_addr.s_node != ATADDR_ANYNODE ) { 334 if ( ddp->ddp_lsat.sat_port == ATADDR_ANYPORT ) { 335 return( EADDRNOTAVAIL ); 336 } 337 hintnet = ddp->ddp_lsat.sat_addr.s_net; 338 } 339 340 ro = &ddp->ddp_route; 341 /* 342 * If we've got an old route for this pcb, check that it is valid. 343 * If we've changed our address, we may have an old "good looking" 344 * route here. Attempt to detect it. 345 */ 346 if ( ro->ro_rt ) { 347 if ( hintnet ) { 348 net = hintnet; 349 } else { 350 net = sat->sat_addr.s_net; 351 } 352 aa = 0; 353 if ((ifp = ro->ro_rt->rt_ifp) != NULL) { 354 for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { 355 if ( aa->aa_ifp == ifp && 356 ntohs( net ) >= ntohs( aa->aa_firstnet ) && 357 ntohs( net ) <= ntohs( aa->aa_lastnet )) { 358 break; 359 } 360 } 361 } 362 if ( aa == NULL || ( satosat( &ro->ro_dst )->sat_addr.s_net != 363 ( hintnet ? hintnet : sat->sat_addr.s_net ) || 364 satosat( &ro->ro_dst )->sat_addr.s_node != 365 sat->sat_addr.s_node )) { 366 RTFREE( ro->ro_rt ); 367 ro->ro_rt = (struct rtentry *)0; 368 } 369 } 370 371 /* 372 * If we've got no route for this interface, try to find one. 373 */ 374 if ( ro->ro_rt == (struct rtentry *)0 || 375 ro->ro_rt->rt_ifp == (struct ifnet *)0 ) { 376 ro->ro_dst.sa_len = sizeof( struct sockaddr_at ); 377 ro->ro_dst.sa_family = AF_APPLETALK; 378 if ( hintnet ) { 379 satosat( &ro->ro_dst )->sat_addr.s_net = hintnet; 380 } else { 381 satosat( &ro->ro_dst )->sat_addr.s_net = sat->sat_addr.s_net; 382 } 383 satosat( &ro->ro_dst )->sat_addr.s_node = sat->sat_addr.s_node; 384 rtalloc( ro ); 385 } 386 387 /* 388 * Make sure any route that we have has a valid interface. 389 */ 390 aa = 0; 391 if ( ro->ro_rt && ( ifp = ro->ro_rt->rt_ifp )) { 392 for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { 393 if ( aa->aa_ifp == ifp ) { 394 break; 395 } 396 } 397 } 398 if ( aa == 0 ) { 399 return( ENETUNREACH ); 400 } 401 402 ddp->ddp_fsat = *sat; 403 if ( ddp->ddp_lsat.sat_port == ATADDR_ANYPORT ) { 404 return(at_pcbsetaddr(ddp, (struct sockaddr *)0, td)); 405 } 406 return( 0 ); 407} 408 409static void 410at_pcbdisconnect( struct ddpcb *ddp ) 411{ 412 ddp->ddp_fsat.sat_addr.s_net = ATADDR_ANYNET; 413 ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE; 414 ddp->ddp_fsat.sat_port = ATADDR_ANYPORT; 415} 416 417static int 418at_pcballoc( struct socket *so ) 419{ 420 struct ddpcb *ddp; 421 422 MALLOC(ddp, struct ddpcb *, sizeof *ddp, M_PCB, M_WAITOK | M_ZERO); 423 ddp->ddp_lsat.sat_port = ATADDR_ANYPORT; 424 425 ddp->ddp_next = ddpcb; 426 ddp->ddp_prev = NULL; 427 ddp->ddp_pprev = NULL; 428 ddp->ddp_pnext = NULL; 429 if (ddpcb) { 430 ddpcb->ddp_prev = ddp; 431 } 432 ddpcb = ddp; 433 434 ddp->ddp_socket = so; 435 so->so_pcb = (caddr_t)ddp; 436 return(0); 437} 438 439static void 440at_pcbdetach( struct socket *so, struct ddpcb *ddp) 441{ 442 soisdisconnected( so ); 443 so->so_pcb = 0; 444 sofree( so ); 445 446 /* remove ddp from ddp_ports list */ 447 if ( ddp->ddp_lsat.sat_port != ATADDR_ANYPORT && 448 ddp_ports[ ddp->ddp_lsat.sat_port - 1 ] != NULL ) { 449 if ( ddp->ddp_pprev != NULL ) { 450 ddp->ddp_pprev->ddp_pnext = ddp->ddp_pnext; 451 } else { 452 ddp_ports[ ddp->ddp_lsat.sat_port - 1 ] = ddp->ddp_pnext; 453 } 454 if ( ddp->ddp_pnext != NULL ) { 455 ddp->ddp_pnext->ddp_pprev = ddp->ddp_pprev; 456 } 457 } 458 459 if ( ddp->ddp_route.ro_rt ) { 460 rtfree( ddp->ddp_route.ro_rt ); 461 } 462 463 if ( ddp->ddp_prev ) { 464 ddp->ddp_prev->ddp_next = ddp->ddp_next; 465 } else { 466 ddpcb = ddp->ddp_next; 467 } 468 if ( ddp->ddp_next ) { 469 ddp->ddp_next->ddp_prev = ddp->ddp_prev; 470 } 471 FREE(ddp, M_PCB); 472} 473 474/* 475 * For the moment, this just find the pcb with the correct local address. 476 * In the future, this will actually do some real searching, so we can use 477 * the sender's address to do de-multiplexing on a single port to many 478 * sockets (pcbs). 479 */ 480struct ddpcb * 481ddp_search( struct sockaddr_at *from, struct sockaddr_at *to, 482 struct at_ifaddr *aa) 483{ 484 struct ddpcb *ddp; 485 486 /* 487 * Check for bad ports. 488 */ 489 if ( to->sat_port < ATPORT_FIRST || to->sat_port >= ATPORT_LAST ) { 490 return( NULL ); 491 } 492 493 /* 494 * Make sure the local address matches the sent address. What about 495 * the interface? 496 */ 497 for ( ddp = ddp_ports[ to->sat_port - 1 ]; ddp; ddp = ddp->ddp_pnext ) { 498 /* XXX should we handle 0.YY? */ 499 500 /* XXXX.YY to socket on destination interface */ 501 if ( to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net && 502 to->sat_addr.s_node == ddp->ddp_lsat.sat_addr.s_node ) { 503 break; 504 } 505 506 /* 0.255 to socket on receiving interface */ 507 if ( to->sat_addr.s_node == ATADDR_BCAST && ( to->sat_addr.s_net == 0 || 508 to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net ) && 509 ddp->ddp_lsat.sat_addr.s_net == AA_SAT( aa )->sat_addr.s_net ) { 510 break; 511 } 512 513 /* XXXX.0 to socket on destination interface */ 514 if ( to->sat_addr.s_net == aa->aa_firstnet && 515 to->sat_addr.s_node == 0 && 516 ntohs( ddp->ddp_lsat.sat_addr.s_net ) >= 517 ntohs( aa->aa_firstnet ) && 518 ntohs( ddp->ddp_lsat.sat_addr.s_net ) <= 519 ntohs( aa->aa_lastnet )) { 520 break; 521 } 522 } 523 return( ddp ); 524} 525static int 526at_setpeeraddr(struct socket *so, struct sockaddr **nam) 527{ 528 return(EOPNOTSUPP); 529} 530 531static int 532at_setsockaddr(struct socket *so, struct sockaddr **nam) 533{ 534 struct ddpcb *ddp; 535 536 ddp = sotoddpcb( so ); 537 if ( ddp == NULL ) { 538 return( EINVAL); 539 } 540 at_sockaddr( ddp, nam ); 541 return(0); 542} 543 544 545void 546ddp_init(void ) 547{ 548 atintrq1.ifq_maxlen = IFQ_MAXLEN; 549 atintrq2.ifq_maxlen = IFQ_MAXLEN; 550 mtx_init(&atintrq1.ifq_mtx, "at1_inq", MTX_DEF); 551 mtx_init(&atintrq2.ifq_mtx, "at2_inq", MTX_DEF); 552} 553 554#if 0 555static void 556ddp_clean(void ) 557{ 558 struct ddpcb *ddp; 559 560 for ( ddp = ddpcb; ddp; ddp = ddp->ddp_next ) { 561 at_pcbdetach( ddp->ddp_socket, ddp ); 562 } 563} 564#endif 565 566struct pr_usrreqs ddp_usrreqs = { 567 ddp_abort, 568 pru_accept_notsupp, 569 ddp_attach, 570 ddp_bind, 571 ddp_connect, 572 pru_connect2_notsupp, 573 at_control, 574 ddp_detach, 575 ddp_disconnect, 576 pru_listen_notsupp, 577 at_setpeeraddr, 578 pru_rcvd_notsupp, 579 pru_rcvoob_notsupp, 580 ddp_send, 581 pru_sense_null, 582 ddp_shutdown, 583 at_setsockaddr, 584 sosend, 585 soreceive, 586 sopoll 587}; 588