1/* 2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* 29 * Copyright (c) 1995-1998 Apple Computer, Inc. 30 * All Rights Reserved. 31 */ 32 33/* 34 * 09/07/95 - Modified for performance (Tuyen Nguyen) 35 * Modified for MP, 1996 by Tuyen Nguyen 36 * Modified, April 9, 1997 by Tuyen Nguyen for MacOSX. 37 */ 38#include <sys/errno.h> 39#include <sys/types.h> 40#include <sys/param.h> 41#include <machine/spl.h> 42#include <sys/systm.h> 43#include <sys/kernel.h> 44#include <sys/proc.h> 45#include <sys/filedesc.h> 46#include <sys/fcntl.h> 47#include <sys/mbuf.h> 48#include <sys/socket.h> 49#include <sys/socketvar.h> 50#include <sys/time.h> 51#include <sys/ioctl.h> 52#include <sys/malloc.h> 53 54#include <net/if.h> 55 56#include <netat/sysglue.h> 57#include <netat/appletalk.h> 58#include <netat/ddp.h> 59#include <netat/at_snmp.h> 60#include <netat/at_pcb.h> 61#include <netat/debug.h> 62#include <netat/at_var.h> 63#include <netat/adsp.h> 64#include <netat/adsp_internal.h> 65 66void adsp_rput(gref_t *, gbuf_t *); 67static void adsp_iocack(gref_t *, gbuf_t *); 68static void adsp_iocnak(gref_t *, gbuf_t *, int err); 69void adsp_dequeue_ccb(CCB *); 70int adspInited = 0; 71 72GLOBAL adspGlobal; 73 74/**********/ 75 76int adsp_pidM[256]; 77char adsp_inputC[256]; 78CCB *adsp_inputQ[256]; 79 80extern at_ifaddr_t *ifID_home; 81 82CCB *ccb_used_list; 83 84void adsp_input(mp) 85 gbuf_t *mp; 86{ 87 gref_t *gref; 88 CCBPtr sp; 89 at_ddp_t *p; 90 gbuf_t *mb; 91 92 switch (gbuf_type(mp)) { 93 case MSG_DATA: 94 p = (at_ddp_t *)gbuf_rptr(mp); 95 sp = adsp_inputQ[p->dst_socket]; 96 if ((sp == 0) || (sp->gref==0) || (sp->state==sClosed)) 97 { 98 gbuf_freem(mp); 99 return; 100 } 101 else if (sp->otccbLink != 0) { 102 do { 103 if ((sp->remoteAddress.a.node == p->src_node) 104 && (sp->remoteAddress.a.socket == p->src_socket) 105 && (sp->remoteAddress.a.net == NET_VALUE(p->src_net))) 106 break; 107 } while ((sp = sp->otccbLink) != 0); 108 if (sp == 0) 109 { 110 gbuf_freem(mp); 111 return; 112 } 113 } 114 if (sp->lockFlag) { 115 gbuf_next(mp) = 0; 116 if (sp->deferred_mb) { 117 for (mb=sp->deferred_mb; gbuf_next(mb); mb=gbuf_next(mb)) ; 118 gbuf_next(mb) = mp; 119 } else 120 sp->deferred_mb = mp; 121 return; 122 } 123 sp->lockFlag = 1; 124 while (mp) { 125 adsp_rput(sp->gref, mp); 126 if ((mp = sp->deferred_mb) != 0) { 127 sp->deferred_mb = gbuf_next(mp); 128 gbuf_next(mp) = 0; 129 } 130 } 131 sp->lockFlag = 0; 132 return; 133 134 case MSG_IOCACK: 135 case MSG_IOCNAK: 136 gref = (gref_t *)((ioc_t *)gbuf_rptr(mp))->ioc_private; 137 break; 138 139 case MSG_IOCTL: 140#ifdef APPLETALK_DEBUG 141 kprintf("unexpected MSG_IOCTL in adsp_input()"); 142#endif 143 /* fall through */ 144 145 default: 146 gbuf_freem(mp); 147 return; 148 } 149 150 adsp_rput(gref, mp); 151} 152 153/**********/ 154int adsp_readable(gref_t *); 155 156int adsp_readable(gref) 157 gref_t *gref; 158{ 159 int rc; 160 CCBPtr sp; 161 162 if (gref->info == 0) 163 /* 164 * we don't have the structure we need to determine 165 * if there's data available... we return readable in 166 * this case to keep from hanging up in the select 167 * a subsequent read will run into the same missing data 168 * structure and return an error... the ATselect code does 169 * this if it can't retrieve the 'gref' structure from the 170 * file table for the fd specified 171 */ 172 return(1); 173 174 sp = (CCBPtr)gbuf_rptr(((gbuf_t *)gref->info)); 175 rc = sp->rData; 176 177 return rc; 178} 179 180int adsp_writeable(gref_t *); 181int adsp_writeable(gref) 182 gref_t *gref; 183{ 184 int rc; 185 CCBPtr sp; 186 187 if (gref->info == 0) 188 /* 189 * we don't have the structure we need to determine 190 * if there's room available... we return writeable in 191 * this case to keep from hanging up in the select 192 * a subsequent write will run into the same missing data 193 * structure and return an error... the ATselect code does 194 * this if it can't retrieve the 'gref' structure from the 195 * file table for the fd specified 196 */ 197 return(1); 198 199 sp = (CCBPtr)gbuf_rptr(((gbuf_t *)gref->info)); 200 rc = CalcSendQFree(sp); 201 202 return rc; 203} 204 205static void adsp_init(void); 206 207static void adsp_init(void) 208{ 209 adspInited++; 210 InitGlobals(); 211 ccb_used_list = 0; 212 bzero(adsp_pidM, sizeof(adsp_pidM)); 213 bzero(adsp_inputC, sizeof(adsp_inputC)); 214 bzero(adsp_inputQ, sizeof(adsp_inputQ)); 215} 216 217/* 218 * Description: 219 * ADSP open and close routines. These routines 220 * initalize and release the ADSP structures. They do not 221 * have anything to do with "connections" 222 */ 223 224int adsp_open(gref) 225 gref_t *gref; 226{ 227 register CCBPtr sp; 228 229 if (!adspInited) 230 adsp_init(); 231 232 if (!adspAllocateCCB(gref)) 233 return(ENOBUFS); /* can't get buffers */ 234 235 sp = (CCBPtr)gbuf_rptr(((gbuf_t *)gref->info)); 236 gref->readable = adsp_readable; 237 gref->writeable = adsp_writeable; 238 if ((sp->otccbLink = ccb_used_list) != 0) 239 sp->otccbLink->ccbLink = sp; 240 ccb_used_list = sp; 241 return 0; 242} 243 244int adsp_close(gref) 245 gref_t *gref; 246{ 247 unsigned char localSocket; 248 249 /* make sure we've not yet removed the CCB (e.g., due to TrashSession) */ 250 if (gref->info) { 251 CCBPtr sp = (CCBPtr)gbuf_rptr(((gbuf_t *)gref->info)); 252 localSocket = sp->localSocket; 253 if (localSocket) 254 adspRelease(gref); 255 else 256 { 257 adsp_dequeue_ccb(sp); 258 gbuf_freeb((gbuf_t *)gref->info); 259 } 260 } 261 return 0; 262} 263 264 265/* 266 * Name: 267 * adsp_rput 268 * 269 * Description: 270 * ADSP streams read put and service routines. 271 */ 272 273void adsp_rput(gref, mp) 274 gref_t *gref; /* READ queue */ 275 gbuf_t *mp; 276{ 277 switch (gbuf_type(mp)) { 278 case MSG_HANGUP: 279 case MSG_IOCACK: 280 case MSG_IOCNAK: 281 switch (adspReadHandler(gref, mp)) { 282 case STR_PUTNEXT: 283 atalk_putnext(gref, mp); 284 break; 285 case STR_IGNORE: 286 break; 287 } 288 break; 289 case MSG_ERROR: 290#ifdef APPLETALK_DEBUG 291 kprintf("adsp_rput received MSG_ERROR"); 292#endif 293 /* fall through */ 294 default: 295 CheckReadQueue((CCBPtr)gbuf_rptr(((gbuf_t *)gref->info))); 296 CheckSend((CCBPtr)gbuf_rptr(((gbuf_t *)gref->info))); 297 298 switch (gbuf_type(mp)) { 299 case MSG_IOCTL: 300 case MSG_DATA: 301 case MSG_PROTO: 302 if (adspReadHandler(gref, mp) == STR_PUTNEXT) 303 atalk_putnext(gref, mp); 304 break; 305 default: 306 atalk_putnext(gref, mp); 307 break; 308 } 309 } 310} 311 312/* 313 * Name: 314 * adsp_wput 315 * 316 * Description: 317 * ADSP streams write put and service routines. 318 * 319 */ 320 321int adsp_wput(gref, mp) 322 gref_t *gref; /* WRITE queue */ 323 gbuf_t *mp; 324{ 325 int rc; 326 gbuf_t *xm; 327 ioc_t *iocbp; 328 CCBPtr sp; 329 330 if (gref->info) 331 sp = (CCBPtr)gbuf_rptr(((gbuf_t *)gref->info)); 332 else 333 sp = 0; 334 335 if (gbuf_type(mp) == MSG_IOCTL) { 336 iocbp = (ioc_t *)gbuf_rptr(mp); 337 switch (iocbp->ioc_cmd) { 338 case ADSPBINDREQ: 339 { 340 unsigned char v; 341 342 if (gbuf_cont(mp) == NULL) { 343 iocbp->ioc_rval = -1; 344 adsp_iocnak(gref, mp, EINVAL); 345 } 346 v = *(unsigned char *)gbuf_rptr(gbuf_cont(mp)); 347 if ( (v != 0) 348 && ((v > DDP_SOCKET_LAST) || (v < 2) 349 || ddp_socket_inuse(v, DDP_ADSP))) { 350 iocbp->ioc_rval = -1; 351 adsp_iocnak(gref, mp, EINVAL); 352 } 353 else { 354 if (v == 0) { 355 if ((v = adspAssignSocket(gref, 0)) == 0) { 356 iocbp->ioc_rval = -1; 357 adsp_iocnak(gref, mp, EINVAL); 358 return 0; 359 } 360 } else { 361 adsp_inputC[v] = 1; 362 adsp_inputQ[v] = sp; 363 adsp_pidM[v] = sp->pid; 364 adsp_dequeue_ccb(sp); 365 } 366 *(unsigned char *)gbuf_rptr(gbuf_cont(mp)) = v; 367 sp->localSocket = v; 368 iocbp->ioc_rval = 0; 369 adsp_iocack(gref, mp); 370 } 371 return 0; 372 } 373 374 case ADSPGETSOCK: 375 case ADSPGETPEER: 376 { 377 at_inet_t *addr; 378 379 if (((xm = gbuf_cont(mp)) == NULL) 380 && ((xm = gbuf_alloc(sizeof(at_inet_t), PRI_MED)) == NULL)) { 381 iocbp->ioc_rval = -1; 382 adsp_iocnak(gref, mp, ENOBUFS); 383 return 0; 384 } 385 gbuf_cont(mp) = xm; 386 gbuf_wset(xm,sizeof(at_inet_t)); 387 addr = (at_inet_t *)gbuf_rptr(xm); 388 if (iocbp->ioc_cmd == ADSPGETSOCK) { 389 /* Obtain Network and Node Id's from DDP */ 390 /* *** was ddp_get_cfg() *** */ 391 addr->net = ifID_home->ifThisNode.s_net; 392 addr->node = ifID_home->ifThisNode.s_node; 393 addr->socket = (sp)? sp->localSocket: 0; 394 } else 395 if (sp) 396 *addr = sp->remoteAddress.a; 397 else { 398 addr->net = 0; 399 addr->node = 0; 400 addr->socket = 0; 401 } 402 iocbp->ioc_rval = 0; 403 adsp_iocack(gref, mp); 404 return 0; 405 } 406 case DDP_IOC_GET_CFG: 407 /* respond to an DDP_IOC_GET_CFG sent on an adsp fd */ 408 if (((xm = gbuf_cont(mp)) == NULL) && 409 (xm = gbuf_alloc(sizeof(ddp_addr_t), PRI_MED)) == NULL) { 410 iocbp->ioc_rval = -1; 411 adsp_iocnak(gref, mp, ENOBUFS); 412 return 0; 413 } 414 gbuf_cont(mp) = xm; 415 gbuf_wset(xm, sizeof(ddp_addr_t)); 416 /* Obtain Network and Node Id's from DDP */ 417 { 418 /* *** was ddp_get_cfg() *** */ 419 ddp_addr_t *cfgp = 420 (ddp_addr_t *)gbuf_rptr(gbuf_cont(mp)); 421 cfgp->inet.net = ifID_home->ifThisNode.s_net; 422 cfgp->inet.node = ifID_home->ifThisNode.s_node; 423 cfgp->inet.socket = (sp)? sp->localSocket: 0; 424 cfgp->ddptype = DDP_ADSP; 425 } 426 iocbp->ioc_rval = 0; 427 adsp_iocack(gref, mp); 428 return 0; 429 } /* switch */ 430 } 431 432 if (!gref->info) 433 gbuf_freem(mp); 434 else { 435 rc = adspWriteHandler(gref, mp); 436 437 switch (rc) { 438 case STR_PUTNEXT: 439 if (gbuf_type(mp) == MSG_IOCTL) { 440 iocbp = (ioc_t *)gbuf_rptr(mp); 441 iocbp->ioc_private = (void *)gref; 442 } 443 DDP_OUTPUT(mp); 444 break; 445 case STR_IGNORE: 446 case STR_IGNORE+99: 447 break; 448 default: 449 gbuf_freem(mp); 450 break; 451 } 452 } 453 454 return 0; 455} /* adsp_wput */ 456 457void adspioc_ack(errno, m, gref) 458 int errno; 459 gbuf_t *m; 460 gref_t *gref; 461{ 462 ioc_t *iocbp; 463 464 if (m == NULL) 465 return; 466 iocbp = (ioc_t *) gbuf_rptr(m); 467 468 iocbp->ioc_error = errno; /* set the errno */ 469 iocbp->ioc_count = gbuf_msgsize(gbuf_cont(m)); 470 if (gbuf_type(m) == MSG_IOCTL) /* if an ioctl, this is an ack */ 471 gbuf_set_type(m, MSG_IOCACK); /* and ALWAYS update the user */ 472 /* ioctl structure */ 473 trace_mbufs(D_M_ADSP,"A ", m); 474 SndMsgUp(gref, m); 475} 476 477static void adsp_iocack(gref, m) 478 gref_t *gref; 479 register gbuf_t *m; 480{ 481 if (gbuf_type(m) == MSG_IOCTL) 482 gbuf_set_type(m, MSG_IOCACK); 483 484 if (gbuf_cont(m)) 485 ((ioc_t *)gbuf_rptr(m))->ioc_count = gbuf_msgsize(gbuf_cont(m)); 486 else 487 ((ioc_t *)gbuf_rptr(m))->ioc_count = 0; 488 489 SndMsgUp(gref, m); 490} 491 492 493static void adsp_iocnak(gref, m, err) 494 gref_t *gref; 495 register gbuf_t *m; 496 register int err; 497{ 498 if (gbuf_type(m) == MSG_IOCTL) 499 gbuf_set_type(m, MSG_IOCNAK); 500 ((ioc_t *)gbuf_rptr(m))->ioc_count = 0; 501 502 if (err == 0) 503 err = ENXIO; 504 ((ioc_t *)gbuf_rptr(m))->ioc_error = err; 505 506 if (gbuf_cont(m)) { 507 gbuf_freem(gbuf_cont(m)); 508 gbuf_cont(m) = NULL; 509 } 510 SndMsgUp(gref, m); 511} 512 513unsigned char 514adspAssignSocket(gref, flag) 515 gref_t *gref; 516 int flag; 517{ 518 unsigned char sVal, sMax, sMin, sSav = 0, inputC; 519 CCBPtr sp; 520 521 sMax = flag ? DDP_SOCKET_LAST-46 : DDP_SOCKET_LAST-6; 522 sMin = DDP_SOCKET_1st_DYNAMIC; 523 524 for (inputC=255, sVal=sMax; sVal >= sMin; sVal--) { 525 if (!ddp_socket_inuse(sVal, DDP_ADSP)) 526 break; 527 else if (flag) { 528 if (adsp_inputC[sVal] && 529 /* meaning that raw DDP doesn't have it */ 530 (adsp_inputC[sVal] < inputC) 531 && (adsp_inputQ[sVal]->state == sOpen)) { 532 inputC = adsp_inputC[sVal]; 533 sSav = sVal; 534 } 535 } 536 } 537 if (sVal < sMin) { 538 if (!flag || (inputC == 255)) 539 return 0; 540 sVal = sSav; 541 } 542 sp = (CCBPtr)gbuf_rptr(((gbuf_t *)gref->info)); 543 adsp_dequeue_ccb(sp); 544 adsp_inputC[sVal]++; 545 sp->otccbLink = adsp_inputQ[sVal]; 546 adsp_inputQ[sVal] = sp; 547 if (!flag) 548 adsp_pidM[sVal] = sp->pid; 549 return sVal; 550} 551 552int 553adspDeassignSocket(sp) 554 CCBPtr sp; 555{ 556 unsigned char sVal; 557 CCBPtr curr_sp; 558 CCBPtr prev_sp; 559 int pid = 0; 560 561 dPrintf(D_M_ADSP, D_L_TRACE, ("adspDeassignSocket: pid=%d,s=%d\n", 562 sp->pid, sp->localSocket)); 563 sVal = sp->localSocket; 564 if ((curr_sp = adsp_inputQ[sVal]) != 0) { 565 prev_sp = 0; 566 while (curr_sp != sp) { 567 prev_sp = curr_sp; 568 curr_sp = curr_sp->otccbLink; 569 } 570 if (curr_sp) { 571 if (prev_sp) 572 prev_sp->otccbLink = sp->otccbLink; 573 else 574 adsp_inputQ[sVal] = sp->otccbLink; 575 if (adsp_inputQ[sVal]) 576 adsp_inputC[sVal]--; 577 else { 578 pid = adsp_pidM[sVal]; 579 adsp_inputC[sVal] = 0; 580 adsp_pidM[sVal] = 0; 581 } 582 sp->ccbLink = 0; 583 sp->otccbLink = 0; 584 sp->localSocket = 0; 585 return pid ? 0 : 1; 586 } 587 } 588 589 dPrintf(D_M_ADSP, D_L_ERROR, 590 ("adspDeassignSocket: closing, no CCB block, trouble ahead\n")); 591 return -1; 592} /* adspDeassignSocket */ 593 594/* 595 * remove CCB from the use list 596 */ 597void 598adsp_dequeue_ccb(sp) 599 CCB *sp; 600{ 601 602 if (sp == ccb_used_list) { 603 if ((ccb_used_list = sp->otccbLink) != 0) 604 sp->otccbLink->ccbLink = 0; 605 } else if (sp->ccbLink) { 606 if ((sp->ccbLink->otccbLink = sp->otccbLink) != 0) 607 sp->otccbLink->ccbLink = sp->ccbLink; 608 } 609 610 sp->otccbLink = 0; 611 sp->ccbLink = 0; 612} 613 614void SndMsgUp(gref, mp) 615 gref_t *gref; /* WRITE queue */ 616 gbuf_t *mp; 617{ 618/* 619 dPrintf(D_M_ADSP, D_L_TRACE, 620 ("SndMsgUp: gref=0x%x, mbuf=0x%x\n", (unsigned)gref, (unsigned)mp)); 621 trace_mbufs(D_M_ADSP, " m", mp); 622*/ 623 atalk_putnext(gref, mp); 624} 625