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