1/* 2 * $Id: ddp_usrreq.c,v 1.2 2001-06-29 14:14:47 rufustfirefly Exp $ 3 * 4 * Copyright (c) 1990,1994 Regents of The University of Michigan. 5 * All Rights Reserved. See COPYRIGHT. 6 */ 7 8#ifdef HAVE_CONFIG_H 9#include "config.h" 10#endif /* HAVE_CONFIG_H */ 11 12#include <sys/errno.h> 13#include <sys/types.h> 14#include <sys/param.h> 15#include <sys/systm.h> 16#ifdef ibm032 17#include <sys/dir.h> 18#endif /* ibm032 */ 19#include <sys/user.h> 20#include <sys/mbuf.h> 21#include <sys/ioctl.h> 22#include <sys/socket.h> 23#include <sys/socketvar.h> 24#include <sys/protosw.h> 25#include <net/if.h> 26#include <net/route.h> 27#ifdef _IBMR2 28#include <net/spl.h> 29#endif /* _IBMR2 */ 30 31#include "at.h" 32#include "at_var.h" 33#include "ddp_var.h" 34#include "endian.h" 35 36struct ddpcb *ddpcb = NULL; 37u_int32_t ddp_sendspace = DDP_MAXSZ; /* Max ddp size + 1 (ddp_type) */ 38u_int32_t ddp_recvspace = 10 * ( 587 + sizeof( struct sockaddr_at )); 39 40/*ARGSUSED*/ 41ddp_usrreq( so, req, m, addr, rights ) 42 struct socket *so; 43 int req; 44 struct mbuf *m, *addr, *rights; 45{ 46 struct ddpcb *ddp; 47 int error = 0; 48 49 ddp = sotoddpcb( so ); 50 51 if ( req == PRU_CONTROL ) { 52 return( at_control( (int) m, (caddr_t) addr, 53 (struct ifnet *) rights )); 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 ); 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 ); 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; 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 ); 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 186at_sockaddr( ddp, addr ) 187 struct ddpcb *ddp; 188 struct mbuf *addr; 189{ 190 struct sockaddr_at *sat; 191 192 addr->m_len = sizeof( struct sockaddr_at ); 193 sat = mtod( addr, struct sockaddr_at *); 194 *sat = ddp->ddp_lsat; 195} 196 197at_pcbsetaddr( ddp, addr ) 198 struct ddpcb *ddp; 199 struct mbuf *addr; 200{ 201 struct sockaddr_at lsat, *sat; 202 struct at_ifaddr *aa; 203 struct ddpcb *ddpp; 204 205 if ( ddp->ddp_lsat.sat_port != ATADDR_ANYPORT ) { /* shouldn't be bound */ 206 return( EINVAL ); 207 } 208 209 if ( addr != 0 ) { /* validate passed address */ 210 sat = mtod( addr, struct sockaddr_at *); 211 if ( addr->m_len != sizeof( *sat )) { 212 return( EINVAL ); 213 } 214 if ( sat->sat_family != AF_APPLETALK ) { 215 return( EAFNOSUPPORT ); 216 } 217 218 if ( sat->sat_addr.s_node != ATADDR_ANYNODE || 219 sat->sat_addr.s_net != ATADDR_ANYNET ) { 220 for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { 221 if (( sat->sat_addr.s_net == AA_SAT( aa )->sat_addr.s_net ) && 222 ( sat->sat_addr.s_node == AA_SAT( aa )->sat_addr.s_node )) { 223 break; 224 } 225 } 226 if ( !aa ) { 227 return( EADDRNOTAVAIL ); 228 } 229 } 230 231 if ( sat->sat_port != ATADDR_ANYPORT ) { 232 if ( sat->sat_port < ATPORT_FIRST || 233 sat->sat_port >= ATPORT_LAST ) { 234 return( EINVAL ); 235 } 236#ifdef BSD4_4 237 if ( sat->sat_port < ATPORT_RESERVED && 238 suser( u.u_cred, &u.u_acflag )) { 239 return( EACCES ); 240 } 241#else /* BSD4_4 */ 242 if ( sat->sat_port < ATPORT_RESERVED && ( !suser())) { 243 return( EACCES ); 244 } 245#endif /* BSD4_4 */ 246 } 247 } else { 248 bzero( (caddr_t)&lsat, sizeof( struct sockaddr_at )); 249 lsat.sat_family = AF_APPLETALK; 250 sat = &lsat; 251 } 252 253 if ( sat->sat_addr.s_node == ATADDR_ANYNODE && 254 sat->sat_addr.s_net == ATADDR_ANYNET ) { 255 if ( at_ifaddr == NULL ) { 256 return( EADDRNOTAVAIL ); 257 } 258 sat->sat_addr = AA_SAT( at_ifaddr )->sat_addr; 259 } 260 ddp->ddp_lsat = *sat; 261 262 /* 263 * Choose port. 264 */ 265 if ( sat->sat_port == ATADDR_ANYPORT ) { 266 for ( sat->sat_port = ATPORT_RESERVED; 267 sat->sat_port < ATPORT_LAST; sat->sat_port++ ) { 268 if ( ddp_ports[ sat->sat_port - 1 ] == 0 ) { 269 break; 270 } 271 } 272 if ( sat->sat_port == ATPORT_LAST ) { 273 return( EADDRNOTAVAIL ); 274 } 275 ddp->ddp_lsat.sat_port = sat->sat_port; 276 ddp_ports[ sat->sat_port - 1 ] = ddp; 277 } else { 278 for ( ddpp = ddp_ports[ sat->sat_port - 1 ]; ddpp; 279 ddpp = ddpp->ddp_pnext ) { 280 if ( ddpp->ddp_lsat.sat_addr.s_net == sat->sat_addr.s_net && 281 ddpp->ddp_lsat.sat_addr.s_node == sat->sat_addr.s_node ) { 282 break; 283 } 284 } 285 if ( ddpp != NULL ) { 286 return( EADDRINUSE ); 287 } 288 ddp->ddp_pnext = ddp_ports[ sat->sat_port - 1 ]; 289 ddp_ports[ sat->sat_port - 1 ] = ddp; 290 if ( ddp->ddp_pnext ) { 291 ddp->ddp_pnext->ddp_pprev = ddp; 292 } 293 } 294 295 return( 0 ); 296} 297 298at_pcbconnect( ddp, addr ) 299 struct ddpcb *ddp; 300 struct mbuf *addr; 301{ 302 struct sockaddr_at *sat = mtod( addr, struct sockaddr_at *); 303 struct route *ro; 304 struct at_ifaddr *aa = 0; 305 struct ifnet *ifp; 306 u_short hintnet = 0, net; 307 308 if ( addr->m_len != sizeof( *sat )) 309 return( EINVAL ); 310 if ( sat->sat_family != AF_APPLETALK ) { 311 return( EAFNOSUPPORT ); 312 } 313 314 /* 315 * Under phase 2, network 0 means "the network". We take "the 316 * network" to mean the network the control block is bound to. 317 * If the control block is not bound, there is an error. 318 */ 319 if ( sat->sat_addr.s_net == 0 && sat->sat_addr.s_node != ATADDR_ANYNODE ) { 320 if ( ddp->ddp_lsat.sat_port == ATADDR_ANYPORT ) { 321 return( EADDRNOTAVAIL ); 322 } 323 hintnet = ddp->ddp_lsat.sat_addr.s_net; 324 } 325 326 ro = &ddp->ddp_route; 327 /* 328 * If we've got an old route for this pcb, check that it is valid. 329 * If we've changed our address, we may have an old "good looking" 330 * route here. Attempt to detect it. 331 */ 332 if ( ro->ro_rt ) { 333 if ( hintnet ) { 334 net = hintnet; 335 } else { 336 net = sat->sat_addr.s_net; 337 } 338 aa = 0; 339 if ( ifp = ro->ro_rt->rt_ifp ) { 340 for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { 341 if ( aa->aa_ifp == ifp && 342 ntohs( net ) >= ntohs( aa->aa_firstnet ) && 343 ntohs( net ) <= ntohs( aa->aa_lastnet )) { 344 break; 345 } 346 } 347 } 348 if ( aa == NULL || ( satosat( &ro->ro_dst )->sat_addr.s_net != 349 ( hintnet ? hintnet : sat->sat_addr.s_net ) || 350 satosat( &ro->ro_dst )->sat_addr.s_node != 351 sat->sat_addr.s_node )) { 352#ifdef ultrix 353 rtfree( ro->ro_rt ); 354#else /* ultrix */ 355 RTFREE( ro->ro_rt ); 356#endif /* ultrix */ 357 ro->ro_rt = (struct rtentry *)0; 358 } 359 } 360 361 /* 362 * If we've got no route for this interface, try to find one. 363 */ 364 if ( ro->ro_rt == (struct rtentry *)0 || 365 ro->ro_rt->rt_ifp == (struct ifnet *)0 ) { 366#ifdef BSD4_4 367 ro->ro_dst.sa_len = sizeof( struct sockaddr_at ); 368#endif /* BSD4_4 */ 369 ro->ro_dst.sa_family = AF_APPLETALK; 370 if ( hintnet != 0 ) { 371 satosat( &ro->ro_dst )->sat_addr.s_net = hintnet; 372 } else { 373 satosat( &ro->ro_dst )->sat_addr.s_net = sat->sat_addr.s_net; 374 } 375 satosat( &ro->ro_dst )->sat_addr.s_node = sat->sat_addr.s_node; 376 rtalloc( ro ); 377 } 378 379 /* 380 * Make sure any route that we have has a valid interface. 381 */ 382 aa = 0; 383 if ( ro->ro_rt && ( ifp = ro->ro_rt->rt_ifp )) { 384 for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { 385 if ( aa->aa_ifp == ifp ) { 386 break; 387 } 388 } 389 } 390 if ( aa == 0 ) { 391 return( ENETUNREACH ); 392 } 393 394 ddp->ddp_fsat = *sat; 395 if ( ddp->ddp_lsat.sat_port == ATADDR_ANYPORT ) { 396 return( at_pcbsetaddr( ddp, (struct mbuf *)0 )); 397 } 398 return( 0 ); 399} 400 401at_pcbdisconnect( ddp ) 402 struct ddpcb *ddp; 403{ 404 ddp->ddp_fsat.sat_addr.s_net = ATADDR_ANYNET; 405 ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE; 406 ddp->ddp_fsat.sat_port = ATADDR_ANYPORT; 407} 408 409at_pcballoc( so ) 410 struct socket *so; 411{ 412 struct ddpcb *ddp; 413 struct mbuf *m; 414 415 m = m_getclr( M_WAIT, MT_PCB ); 416 ddp = mtod( m, struct ddpcb * ); 417 ddp->ddp_lsat.sat_port = ATADDR_ANYPORT; 418 419 ddp->ddp_next = ddpcb; 420 ddp->ddp_prev = NULL; 421 ddp->ddp_pprev = NULL; 422 ddp->ddp_pnext = NULL; 423 if ( ddpcb ) { 424 ddpcb->ddp_prev = ddp; 425 } 426 ddpcb = ddp; 427 428 ddp->ddp_socket = so; 429 so->so_pcb = (caddr_t)ddp; 430 return( 0 ); 431} 432 433at_pcbdetach( so, ddp ) 434 struct socket *so; 435 struct ddpcb *ddp; 436{ 437 soisdisconnected( so ); 438 so->so_pcb = 0; 439 sofree( so ); 440 441 /* remove ddp from ddp_ports list */ 442 if ( ddp->ddp_lsat.sat_port != ATADDR_ANYPORT && 443 ddp_ports[ ddp->ddp_lsat.sat_port - 1 ] != NULL ) { 444 if ( ddp->ddp_pprev != NULL ) { 445 ddp->ddp_pprev->ddp_pnext = ddp->ddp_pnext; 446 } else { 447 ddp_ports[ ddp->ddp_lsat.sat_port - 1 ] = ddp->ddp_pnext; 448 } 449 if ( ddp->ddp_pnext != NULL ) { 450 ddp->ddp_pnext->ddp_pprev = ddp->ddp_pprev; 451 } 452 } 453 454 if ( ddp->ddp_route.ro_rt ) { 455 rtfree( ddp->ddp_route.ro_rt ); 456 } 457 458 if ( ddp->ddp_prev ) { 459 ddp->ddp_prev->ddp_next = ddp->ddp_next; 460 } else { 461 ddpcb = ddp->ddp_next; 462 } 463 if ( ddp->ddp_next ) { 464 ddp->ddp_next->ddp_prev = ddp->ddp_prev; 465 } 466 467 (void) m_free( dtom( ddp )); 468} 469 470/* 471 * For the moment, this just find the pcb with the correct local address. 472 * In the future, this will actually do some real searching, so we can use 473 * the sender's address to do de-multiplexing on a single port to many 474 * sockets (pcbs). 475 */ 476 struct ddpcb * 477ddp_search( from, to, aa ) 478 struct sockaddr_at *from, *to; 479 struct at_ifaddr *aa; 480{ 481 struct ddpcb *ddp; 482 483 /* 484 * Check for bad ports. 485 */ 486 if ( to->sat_port < ATPORT_FIRST || to->sat_port >= ATPORT_LAST ) { 487 return( NULL ); 488 } 489 490 /* 491 * Make sure the local address matches the sent address. What about 492 * the interface? 493 */ 494 for ( ddp = ddp_ports[ to->sat_port - 1 ]; ddp; ddp = ddp->ddp_pnext ) { 495 /* XXX should we handle 0.YY? */ 496 497 /* XXXX.YY to socket on destination interface */ 498 if ( to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net && 499 to->sat_addr.s_node == ddp->ddp_lsat.sat_addr.s_node ) { 500 break; 501 } 502 503 /* 0.255 to socket on receiving interface */ 504 if ( to->sat_addr.s_node == ATADDR_BCAST && ( to->sat_addr.s_net == 0 || 505 to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net ) && 506 ddp->ddp_lsat.sat_addr.s_net == AA_SAT( aa )->sat_addr.s_net ) { 507 break; 508 } 509 510 /* XXXX.0 to socket on destination interface */ 511 if ( to->sat_addr.s_net == aa->aa_firstnet && 512 to->sat_addr.s_node == 0 && 513 ntohs( ddp->ddp_lsat.sat_addr.s_net ) >= 514 ntohs( aa->aa_firstnet ) && 515 ntohs( ddp->ddp_lsat.sat_addr.s_net ) <= 516 ntohs( aa->aa_lastnet )) { 517 break; 518 } 519 } 520 return( ddp ); 521} 522 523ddp_init() 524{ 525 atintrq1.ifq_maxlen = IFQ_MAXLEN; 526 atintrq2.ifq_maxlen = IFQ_MAXLEN; 527} 528 529ddp_clean() 530{ 531 struct ddpcb *ddp; 532 533 for ( ddp = ddpcb; ddp; ddp = ddp->ddp_next ) { 534 at_pcbdetach( ddp->ddp_socket, ddp ); 535 } 536} 537