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