1/* 2 * Copyright (c) 1995-2007 Apple 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 * Change Log: 30 * Created February 20, 1995 by Tuyen Nguyen 31 * Modified for MP, 1996 by Tuyen Nguyen 32 * Modified, March 17, 1997 by Tuyen Nguyen for MacOSX. 33 */ 34 35#include <sys/errno.h> 36#include <sys/types.h> 37#include <sys/param.h> 38#include <machine/spl.h> 39#include <sys/systm.h> 40#include <sys/kernel.h> 41#include <sys/proc.h> 42#include <sys/filedesc.h> 43#include <sys/fcntl.h> 44#include <sys/mbuf.h> 45#include <sys/ioctl.h> 46#include <sys/malloc.h> 47#include <kern/locks.h> 48#include <sys/socket.h> 49#include <sys/socketvar.h> 50 51#include <net/if.h> 52 53#include <netat/sysglue.h> 54#include <netat/appletalk.h> 55#include <netat/at_pcb.h> 56#include <netat/atp.h> 57#include <netat/ddp.h> 58#include <netat/asp.h> 59#include <netat/at_var.h> 60#include <netat/debug.h> 61 62 63#define atpBDSsize (sizeof(struct atpBDS)*ATP_TRESP_MAX) 64#define aspCMDsize (atpBDSsize+sizeof(struct atp_set_default)+TOTAL_ATP_HDR_SIZE) 65#define SCBS_PER_BLK 16 66#define TICKS_PER_SEC HZ 67#define SESS_TMO_RES 2 68#define DEF_SESS_TMO 120 69#define NEXT_SEQ_NUM(x) (x = (x == 65535) ? 0 : (x + 1)) 70#define MAX_RCV_CNT 5 71#define BAD_REMADDR(addr) \ 72 ( (*(long *)&scb->rem_addr != *(long *)&addr) \ 73 && ((scb->rem_addr.net != addr.net) \ 74 || (scb->rem_addr.node != addr.node)) ) 75 76StaticProc asp_scb_t *asp_find_scb(unsigned char, at_inet_t *); 77StaticProc asp_scb_t *asp_scb_alloc(void); 78 79StaticProc void asp_putnext(gref_t *, gbuf_t *); 80StaticProc void asp_iocack(gref_t *, gbuf_t *); 81StaticProc void asp_iocnak(gref_t *, gbuf_t *, int); 82StaticProc void asp_dequeue_scb(asp_scb_t *); 83StaticProc void asp_scb_free(asp_scb_t *); 84StaticProc void asp_timout(asp_tmo_func, asp_scb_t *, int); 85StaticProc void asp_untimout(asp_tmo_func, asp_scb_t *); 86StaticProc void asp_hangup(asp_scb_t *); 87StaticProc void asp_send_tickle(asp_scb_t *); 88StaticProc void asp_send_tickle_locked(void *); 89StaticProc void asp_accept(asp_scb_t *scb, asp_scb_t *sess_scb, gbuf_t *m); 90StaticProc int asp_send_req(gref_t *, gbuf_t *, at_inet_t *, at_retry_t *, asp_word_t *, 91 unsigned char , unsigned char, unsigned char); 92 93extern at_ifaddr_t *ifID_home; 94extern int atp_pidM[]; 95extern gref_t *atp_inputQ[]; 96extern lck_mtx_t *atalk_mutex; 97gbuf_t *scb_resource_m = 0; 98unsigned char asp_inpC[256]; 99asp_scb_t *asp_scbQ[256]; 100 101static at_retry_t asp_def_retry = {2, -1, 1}; 102static unsigned char scb_tmo_cnt; 103asp_scb_t *scb_used_list; 104static asp_scb_t *scb_tmo_list; 105asp_scb_t *scb_free_list; 106 107int asp_readable(gref_t *); 108 109int 110asp_readable(gref) 111 gref_t *gref; 112{ 113 return (((asp_scb_t *)gref->info)->sess_ioc ? 1 : 0); 114} 115 116void 117asp_init() 118{ 119 scb_tmo_cnt = 1; 120 scb_tmo_list = 0; 121 scb_used_list = 0; 122 scb_free_list = 0; 123 bzero(asp_inpC, sizeof(asp_inpC)); 124 bzero(asp_scbQ, sizeof(asp_scbQ)); 125} 126 127/* 128 * the open routine allocates a state structure 129 */ 130int asp_open(gref) 131 gref_t *gref; 132{ 133 asp_scb_t *scb; 134 135 /* 136 * if no asp structure available, return failure 137 */ 138 if ((scb = asp_scb_alloc()) == 0) 139 return ENOBUFS; 140 141 /* 142 * initialize the gref data structure 143 */ 144 gref->info = (void *)scb; 145 gref->readable = asp_readable; 146 147 /* 148 * initialize the scb data structure 149 */ 150 scb->dflag = 1; 151 scb->magic_num = 222; 152 scb->state = ASPSTATE_Idle; 153 scb->pid = gref->pid; 154 scb->gref = gref; 155 scb->session_timer = DEF_SESS_TMO; 156 scb->cmd_retry = asp_def_retry; 157 if ((scb->next_scb = scb_used_list) != 0) 158 scb->next_scb->prev_scb = scb; 159 scb_used_list = scb; 160 161 /* 162 * return success 163 */ 164 dPrintf(D_M_ASP, D_L_INFO, ("asp_open: pid=%d\n", scb->pid)); 165 return 0; 166} /* asp_open */ 167 168/* 169 * the close routine frees all the data structures 170 */ 171int 172asp_close(gref) 173 gref_t *gref; 174{ 175 unsigned char sock_num; 176 asp_scb_t *scb, *new_scb; 177 gbuf_t *m; 178 179 scb = (asp_scb_t *)gref->info; 180 dPrintf(D_M_ASP, D_L_INFO, ("asp_close: loc=%d\n", 181 scb->loc_addr.socket)); 182 183 if (scb->pid && scb->sess_ioc && (scb->dflag != 1)) { 184 /* 185 * send the CloseSess response to peer 186 */ 187 if (gbuf_type(scb->sess_ioc) != MSG_PROTO) { 188 m = scb->sess_ioc; 189 scb->sess_ioc = gbuf_next(m); 190 atp_send_rsp(scb->gref, m, TRUE); 191 } 192 } 193 194 if (scb->atp_state) { 195 sock_num = scb->loc_addr.socket; 196 if ((scb->dflag != 1) && scb->stat_msg) { 197 untimeout(atp_retry_req, scb->stat_msg); 198 gbuf_freem(scb->stat_msg); 199 scb->stat_msg = 0; 200 } 201 if (asp_scbQ[sock_num]->next_scb == 0) { 202 asp_scbQ[sock_num] = 0; 203 asp_inpC[sock_num] = 0; 204 dPrintf(D_M_ASP, D_L_INFO, 205 (" : atp_close(), loc=%d\n", scb->loc_addr.socket)); 206 atp_close(gref, 0); 207 } else { 208 asp_inpC[sock_num]--; 209 if (scb == asp_scbQ[sock_num]) { 210 new_scb = scb->next_scb; 211 new_scb->prev_scb = 0; 212 asp_scbQ[sock_num] = new_scb; 213 new_scb->atp_state->atp_gref = new_scb->gref; 214 new_scb->atp_state->pid = new_scb->pid; 215 atp_inputQ[sock_num] = new_scb->gref; 216 } else { 217 if ((scb->prev_scb->next_scb = scb->next_scb) != 0) 218 scb->next_scb->prev_scb = scb->prev_scb; 219 } 220 scb->next_scb = 0; 221 } 222 } else 223 asp_dequeue_scb(scb); 224 225 /* 226 * free all allocated blocks if any 227 */ 228 if (scb->stat_msg) { 229 gbuf_freem(scb->stat_msg); 230 scb->stat_msg = 0; 231 } 232 if (scb->sess_ioc) { 233 gbuf_freel(scb->sess_ioc); 234 scb->sess_ioc = 0; 235 } 236 if (scb->req_msgq) { 237 gbuf_freel(scb->req_msgq); 238 scb->req_msgq = 0; 239 } 240 241 scb->rem_addr.node = 0; 242 243 /* 244 * stop all timers 245 */ 246 scb->tmo_cnt = 0; 247 asp_untimout(asp_hangup, scb); 248 untimeout(asp_send_tickle_locked, (void *)scb); /* added for 2225395 */ 249 250 /* 251 * free the asp session control block 252 */ 253 scb->state = ASPSTATE_Close; 254 asp_scb_free(scb); 255 return 0; 256} /* asp_close */ 257 258#if DEBUG 259 260static const char *aspStateStr(int); 261 262static const char *aspStateStr(state) 263 int state; 264{ 265 return ((state==ASPSTATE_Close)? "Close": 266 (state==ASPSTATE_Idle)? "Idle": 267 (state==ASPSTATE_WaitingForGetStatusRsp)? "GetStatusRsp": 268 (state==ASPSTATE_WaitingForOpenSessRsp)? "OpenSessRsp": 269 (state==ASPSTATE_WaitingForCommandRsp)? "CmdRsp": 270 (state==ASPSTATE_WaitingForWriteContinue)? "WriteCont": 271 (state==ASPSTATE_WaitingForWriteRsp)? "WriteRsp": 272 (state==ASPSTATE_WaitingForWriteContinueRsp)? "WriteContRsp": 273 (state==ASPSTATE_WaitingForCloseSessRsp)? "CloseSessRsp": 274 "unknown"); 275} 276 277static const char *aspCmdStr(int); 278 279static const char *aspCmdStr(aspCmd) 280 int aspCmd; 281{ 282return ((aspCmd==ASPFUNC_CloseSess)? "CloseSess": 283 (aspCmd==ASPFUNC_Command)? "Command": 284 (aspCmd==ASPFUNC_GetStatus)? "GetStatus": 285 (aspCmd==ASPFUNC_OpenSess)? "OpenSess": 286 (aspCmd==ASPFUNC_Tickle)? "Tickle": 287 (aspCmd==ASPFUNC_Write)? "Write": 288 (aspCmd==ASPFUNC_WriteContinue)? "WriteContinue": 289 (aspCmd==ASPFUNC_Attention)? "Attention": 290 (aspCmd==ASPFUNC_CmdReply)? "CmdReply": "unknown"); 291} 292 293static const char *aspIOCStr(int); 294 295static const char *aspIOCStr(aspIOC) 296 int aspIOC; 297{ 298return ( 299 (aspIOC==ASPIOC_ClientBind)? "ClientBind": 300 (aspIOC==ASPIOC_CloseSession)? "CloseSession": 301 (aspIOC==ASPIOC_GetLocEntity)? "GetLocEntity": 302 (aspIOC==ASPIOC_GetRemEntity)? "GetRemEntity": 303 (aspIOC==ASPIOC_GetSession)? "GetSession": 304 (aspIOC==ASPIOC_GetStatus)? "GetStatus": 305 (aspIOC==ASPIOC_ListenerBind)? "ListenerBind": 306 (aspIOC==ASPIOC_OpenSession)? "OpenSession": 307 (aspIOC==ASPIOC_StatusBlock)? "StatusBlock": 308 (aspIOC==ASPIOC_SetPid)? "SetPid": 309 (aspIOC==ASPIOC_GetSessId)? "GetSessId": 310 (aspIOC==ASPIOC_EnableSelect)? "EnableSelect": 311 (aspIOC==ASPIOC_Look)? "Look": 312 "unknown" 313 ); 314} 315#endif /* DEBUG */ 316 317#ifdef AT_MBUF_TRACE 318 319static char mbuf_str[100]; 320char *mbuf_totals() 321{ 322 snprintf(mbuf_str, sizeof(mbuf_str), 323 /* 324 "dat = %d, prot = %d, ioc = %d, err = %d, hu = %d, ack = %d, nak = %d, ctl = %d", 325 */ 326 "dat = %d, prot = %d, ioc = %d, ctl = %d", 327 mbstat.m_mtypes[MSG_DATA], mbstat.m_mtypes[MSG_PROTO], mbstat.m_mtypes[MSG_IOCTL], 328 /* 329 mbstat.m_mtypes[MSG_ERROR], mbstat.m_mtypes[MSG_HANGUP], mbstat.m_mtypes[MSG_IOCACK], 330 mbstat.m_mtypes[MSG_IOCNAK], 331 */ 332 mbstat.m_mtypes[MSG_CTL]); 333 return(&mbuf_str[0]); 334} 335 336void trace_beg(str, m) 337 char *str; 338 gbuf_t *m; 339{ 340 int i = 0, j = 0; 341 gbuf_t *mdata, *mchain; 342 343 if (m) 344 for (i = 0, j = 0, mdata = m, mchain = m; mdata; i++) { 345 mdata = gbuf_cont(mdata); 346 if (!mdata && mchain) { 347 mdata = gbuf_next(mchain); 348 mchain = mdata; 349 j++; 350 } 351 } 352 dPrintf(D_M_ASP, D_L_TRACE, 353 ("%s: %s, m# = %d, c# = %d\n", str, mbuf_totals(), i, j)); 354} 355 356void trace_end(str) 357 char *str; 358{ 359 dPrintf(D_M_ASP, D_L_TRACE, 360 (" %s: %s\n", str, mbuf_totals())); 361} 362#endif /* AT_MBUF_TRACE */ 363 364/* 365 * the write routine 366 */ 367int asp_wput(gref, m) 368 gref_t *gref; 369 gbuf_t *m; 370{ 371 int err; 372 unsigned char sockSav, sock_num; 373 gbuf_t *mioc, *mdata; 374 ioc_t *iocbp; 375 asp_scb_t *scb, *server_scb, *curr_scb; 376 at_inet_t *addr; 377 asp_word_t aw; 378 union asp_primitives *primitives; 379 asp_status_cmd_t *status_cmd; 380 asp_open_cmd_t *open_cmd; 381 at_retry_t Retry; 382 383 scb = (asp_scb_t *)gref->info; 384 if (scb->dflag == 0) { 385 atp_wput(gref, m); 386 return 0; 387 } 388 389 if (gbuf_type(m) != MSG_IOCTL) { 390 dPrintf(D_M_ASP, D_L_WARNING, 391 ("asp_wput: UNKNOWN message, type=%d\n", 392 gbuf_type(m))); 393 gbuf_freem(m); 394 return 0; 395 } 396 397 mioc = m; 398 iocbp = (ioc_t *)gbuf_rptr(mioc); 399 400 dPrintf(D_M_ASP_LOW, D_L_INFO, 401 ("asp_wput: %s, loc=%d, state=%s\n", 402 aspIOCStr(iocbp->ioc_cmd), scb->loc_addr.socket, 403 aspStateStr(scb->state))); 404 405 switch (iocbp->ioc_cmd) { 406 case ASPIOC_CloseSession: 407 if ((scb->state == ASPSTATE_Close) || (scb->rem_addr.node == 0)) 408 break; 409 410 Retry.retries = 3; 411 Retry.interval = 1; 412 aw.func = ASPFUNC_CloseSess; 413 aw.param1 = scb->sess_id; 414 aw.param2 = 0; 415 iocbp->ioc_private = (void *)scb; 416 scb->ioc_wait = (unsigned char)(iocbp->ioc_cmd & 0xff); 417 iocbp->ioc_cmd = AT_ATP_ISSUE_REQUEST; 418 asp_send_req(gref, mioc, &scb->rem_addr, &Retry, &aw, 419 0, ASPSTATE_WaitingForCloseSessRsp, 0x01); 420 return 0; 421 422 case ASPIOC_ClientBind: 423 /* 424 * open an ATP channel 425 */ 426 if ((err = atp_open(gref, 0)) != 0) { 427 asp_iocnak(gref, mioc, err); 428 return 0; 429 } 430 scb->atp_state = (atp_state_t *)gref->info; 431 scb->atp_state->pid = scb->pid; 432 /* 433 * bind to any available socket 434 */ 435 scb->dflag = 2; 436 sockSav = scb->dflag; 437 if ((sock_num = (at_socket)atp_bind(gref, 0, &sockSav)) == 0) { 438 scb->atp_state = (atp_state_t *)0; 439 atp_close(gref, 0); 440 gref->info = (void *)scb; 441 asp_iocnak(gref, mioc, EINVAL); 442 return 0; 443 } 444 gref->info = (void *)scb; 445 asp_dequeue_scb(scb); 446 scb->atp_state->dflag = scb->dflag; 447 scb->loc_addr.socket = sock_num; 448 asp_scbQ[sock_num] = scb; 449 asp_inpC[sock_num]++; 450 atp_pidM[sock_num] = 0; 451 break; 452 453 case ASPIOC_ListenerBind: 454 /* 455 * open an ATP channel 456 */ 457 if ((err = atp_open(gref, 0)) != 0) { 458 asp_iocnak(gref, mioc, err); 459 return 0; 460 } 461 scb->atp_state = (atp_state_t *)gref->info; 462 scb->atp_state->pid = scb->pid; 463 /* 464 * bind to any available socket 465 */ 466 if ((sock_num = (at_socket)atp_bind(gref, 0, 0)) == 0) { 467 scb->atp_state = (atp_state_t *)0; 468 atp_close(gref, 0); 469 gref->info = (void *)scb; 470 asp_iocnak(gref, mioc, EINVAL); 471 return 0; 472 } 473 gref->info = (void *)scb; 474 asp_dequeue_scb(scb); 475 scb->atp_state->dflag = scb->dflag; 476 scb->loc_addr.socket = sock_num; 477 asp_scbQ[sock_num] = scb; 478 asp_inpC[sock_num]++; 479 if (gbuf_cont(mioc)) 480 *(at_inet_t *)gbuf_rptr(gbuf_cont(mioc)) = scb->loc_addr; 481 break; 482 483 case ASPIOC_GetLocEntity: 484 if ((gbuf_cont(mioc) == 0) || (scb->atp_state == 0)) { 485 asp_iocnak(gref, mioc, EPROTOTYPE); 486 return 0; 487 } 488 *(at_inet_t *)gbuf_rptr(gbuf_cont(mioc)) = scb->loc_addr; 489 break; 490 491 case ASPIOC_GetRemEntity: 492 if ((gbuf_cont(mioc) == 0) || (scb->atp_state == 0)) { 493 asp_iocnak(gref, mioc, EPROTOTYPE); 494 return 0; 495 } 496 *(at_inet_t *)gbuf_rptr(gbuf_cont(mioc)) = scb->rem_addr; 497 break; 498 499 case ASPIOC_GetSession: 500 if ((mdata = gbuf_cont(mioc)) == 0) { 501 asp_iocnak(gref, mioc, EPROTOTYPE); 502 return 0; 503 } 504 addr = (at_inet_t *)gbuf_rptr(mdata); 505 scb->tickle_interval = (unsigned short)addr->node; 506 scb->session_timer = addr->net; 507 server_scb = asp_scbQ[addr->socket]; 508/*### LD 10/28/97: changed to make sure we're not accessing a null server_scb */ 509 if (server_scb == 0) { 510 asp_iocnak(gref, mioc, EPROTOTYPE); 511 return 0; 512 } 513 if (server_scb->sess_ioc == 0) { 514 asp_iocnak(gref, mioc, EPROTOTYPE); 515 return 0; 516 } 517 518 /* 519 * open an ATP channel 520 */ 521 if ((err = atp_open(gref, 0)) != 0) { 522 gref->info = (void *)scb; 523 asp_iocnak(gref, mioc, err); 524 return 0; 525 } 526 scb->atp_state = (atp_state_t *)gref->info; 527 scb->atp_state->pid = scb->pid; 528 /* 529 * bind to any available socket 530 */ 531 scb->dflag = 3; 532 sockSav = scb->dflag; 533 if ((sock_num = (at_socket)atp_bind(gref, 0, &sockSav)) == 0) { 534 atp_close(gref, 0); 535 asp_dequeue_scb(scb); 536 sock_num = sockSav; 537 scb->loc_addr.socket = sock_num; 538 for (curr_scb = asp_scbQ[sock_num]; 539 curr_scb->next_scb; curr_scb = curr_scb->next_scb) ; 540 scb->prev_scb = curr_scb; 541 curr_scb->next_scb = scb; 542 scb->atp_state = curr_scb->atp_state; 543 } else { 544 asp_dequeue_scb(scb); 545 scb->loc_addr.socket = sock_num; 546 asp_scbQ[sock_num] = scb; 547 scb->atp_state->dflag = scb->dflag; 548 } 549 gref->info = (void *)scb; 550 asp_inpC[sock_num]++; 551 gbuf_cont(mioc) = 0; 552 asp_accept(server_scb, scb, mdata); 553 break; 554 555 case ASPIOC_GetStatus: 556 if ((mdata = gbuf_cont(mioc)) == 0) { 557 asp_iocnak(gref, mioc, EINVAL); 558 return 0; 559 } 560 gbuf_cont(mioc) = 0; 561 status_cmd = (asp_status_cmd_t *)gbuf_rptr(mdata); 562 aw.func = ASPFUNC_GetStatus; 563 aw.param1 = 0; 564 aw.param2 = 0; 565 scb->ioc_wait = (unsigned char)(iocbp->ioc_cmd & 0xff); 566 iocbp->ioc_cmd = AT_ATP_ISSUE_REQUEST_DEF; 567 /* bms: make sure this is an ALO request */ 568 asp_send_req(gref, mioc, &status_cmd->SLSEntityIdentifier, 569 &status_cmd->Retry, &aw, 0, ASPSTATE_WaitingForGetStatusRsp, 0xff); 570 gbuf_freeb(mdata); 571 return 0; 572 573 case ASPIOC_OpenSession: 574 if ((mdata = gbuf_cont(mioc)) == 0) { 575 asp_iocnak(gref, mioc, EINVAL); 576 return 0; 577 } 578 gbuf_cont(mioc) = 0; 579 open_cmd = (asp_open_cmd_t *)gbuf_rptr(mdata); 580 scb->svc_addr = open_cmd->SLSEntityIdentifier; 581 scb->rem_addr = scb->svc_addr; 582 scb->rem_node = scb->rem_addr.node; 583 scb->rem_addr.node = 0; 584 scb->tickle_interval = open_cmd->TickleInterval; 585 scb->session_timer = open_cmd->SessionTimer; 586 aw.func = ASPFUNC_OpenSess; 587 aw.param1 = scb->loc_addr.socket; 588 aw.param2 = htons(ASP_Version); 589 scb->ioc_wait = (unsigned char)(iocbp->ioc_cmd & 0xff); 590 iocbp->ioc_cmd = AT_ATP_ISSUE_REQUEST_DEF; 591 asp_send_req(gref, mioc, &open_cmd->SLSEntityIdentifier, 592 &open_cmd->Retry, &aw, 1, ASPSTATE_WaitingForOpenSessRsp, 0x01); 593 gbuf_freeb(mdata); 594 return 0; 595 596 case ASPIOC_StatusBlock: 597 /* 598 * save the server status block 599 */ 600 if (scb->stat_msg) 601 gbuf_freem(scb->stat_msg); 602 scb->stat_msg = gbuf_cont(mioc); 603 gbuf_cont(mioc) = 0; 604 break; 605 606 /* *** Does scb->pid get used in a packet header, 607 and if so is it in ASP, or in ATP? 608 If not, do we need this call for anything? 609 (cap does currently use it in _ANS code.) 610 *** */ 611 case ASPIOC_SetPid: 612 if (gbuf_cont(mioc) == 0) { 613 asp_iocnak(gref, mioc, EINVAL); 614 return 0; 615 } 616 scb->pid = *(int *)gbuf_rptr(gbuf_cont(mioc)); 617 break; 618 619 case ASPIOC_GetSessId: 620 if (gbuf_cont(mioc) == 0) { 621 asp_iocnak(gref, mioc, EINVAL); 622 return 0; 623 } 624 *(gref_t **)gbuf_rptr(gbuf_cont(mioc)) = gref; 625 break; 626 627 case ASPIOC_Look: 628 if (gbuf_cont(mioc) == 0) { 629 asp_iocnak(gref, mioc, EINVAL); 630 return 0; 631 } 632 if (scb->sess_ioc) { 633 primitives = (union asp_primitives *)gbuf_rptr(scb->sess_ioc); 634 if (primitives->Primitive == ASPFUNC_CmdReply) 635 *(int *)gbuf_rptr(gbuf_cont(mioc)) = 0; 636 else 637 *(int *)gbuf_rptr(gbuf_cont(mioc)) = 1; 638 } else 639 *(int *)gbuf_rptr(gbuf_cont(mioc)) = -1; 640 break; 641 642 case DDP_IOC_GET_CFG: 643 { 644 struct atp_state *atp = (struct atp_state *)gref->info; 645 if (atp->dflag) 646 atp = (struct atp_state *)atp->atp_msgq; 647 648 if (gbuf_cont(mioc) == 0) { 649 asp_iocnak(gref, mioc, EINVAL); 650 return 0; 651 } 652 /* *** borrowed from ddp_proto.c to handle DDP_IOC_GET_CFG 653 on atp fd *** */ 654 scb->state = ASPSTATE_Idle; 655 { 656 /* *** was ddp_get_cfg() *** */ 657 ddp_addr_t *cfgp = 658 (ddp_addr_t *)gbuf_rptr(gbuf_cont(mioc)); 659 cfgp->inet.net = ifID_home->ifThisNode.s_net; 660 cfgp->inet.node = ifID_home->ifThisNode.s_node; 661 cfgp->inet.socket = atp->atp_socket_no; 662 cfgp->ddptype = DDP_ATP; 663 } 664 gbuf_wset(gbuf_cont(mioc), sizeof(at_inet_t)); 665 } 666 break; 667 668 default: 669 asp_iocnak(gref, mioc, EINVAL); 670 return 0; 671 } 672 673 asp_iocack(gref, mioc); 674 return 0; 675} /* asp_wput */ 676 677/* 678 * send request routine 679 */ 680StaticProc int 681asp_send_req(gref, mioc, dest, retry, awp, xo, state, bitmap) 682 gref_t *gref; 683 gbuf_t *mioc; 684 at_inet_t *dest; 685 at_retry_t *retry; 686 asp_word_t *awp; 687 unsigned char xo; 688 unsigned char state; 689 unsigned char bitmap; 690{ 691 int i; 692 gbuf_t *mdata; 693 ioc_t *iocbp; 694 struct atp_set_default *sd; 695 at_ddp_t *ddp; 696 at_atp_t *atp; 697 struct atpBDS *atpBDS; 698 asp_scb_t *scb = (asp_scb_t *)gref->info; 699 700 /* 701 * allocate an ATP buffer for the request 702 */ 703 if ((gbuf_cont(mioc) = gbuf_alloc(aspCMDsize, PRI_MED)) == 0) { 704 if (awp->func == ASPFUNC_Tickle) 705 gbuf_freem(mioc); 706 else 707 asp_iocnak(gref, mioc, ENOBUFS); 708 dPrintf(D_M_ASP, D_L_WARNING, 709 ("asp_send_req: ENOBUFS, loc=%d\n", scb->loc_addr.socket)); 710 711 return -1; 712 } 713 mdata = gbuf_cont(mioc); 714 iocbp = (ioc_t *)gbuf_rptr(mioc); 715 716 /* 717 * build the request 718 */ 719 atpBDS = (struct atpBDS *)gbuf_rptr(mdata); 720 gbuf_wset(mdata,atpBDSsize); 721 for (i=0; i < ATP_TRESP_MAX; i++) { 722 *(unsigned long *)atpBDS[i].bdsBuffAddr = 1; 723 *(unsigned short *)atpBDS[i].bdsBuffSz = ATP_DATA_SIZE; 724 } 725 sd = (struct atp_set_default *)gbuf_wptr(mdata); 726 gbuf_winc(mdata,sizeof(struct atp_set_default)); 727 sd->def_retries = (retry->retries == -1) ? 728 ATP_INFINITE_RETRIES : retry->retries; 729 sd->def_rate = retry->interval*TICKS_PER_SEC; 730 sd->def_BDSlen = atpBDSsize; 731 ddp = (at_ddp_t *)gbuf_wptr(mdata); 732 NET_ASSIGN(ddp->src_net, scb->loc_addr.net); 733 ddp->src_node = scb->loc_addr.node; 734 NET_ASSIGN(ddp->dst_net, dest->net); 735 ddp->dst_node = dest->node; 736 ddp->dst_socket = dest->socket; 737 UAS_ASSIGN(ddp->checksum, 0); 738 atp = ATP_ATP_HDR(gbuf_wptr(mdata)); 739 atp->xo = xo; 740 atp->xo_relt = xo; 741 atp->bitmap = bitmap; 742 gbuf_winc(mdata,TOTAL_ATP_HDR_SIZE); 743 *(asp_word_t *)atp->user_bytes = *awp; 744 iocbp->ioc_count = gbuf_len(mdata); 745 iocbp->ioc_rval = 0; 746 747 /* 748 * send the request 749 */ 750 scb->state = state; 751 dPrintf(D_M_ASP, D_L_INFO, 752 ("asp_send_req: %s, loc=%d, rem= %d, len=%d, state=%s\n", 753 aspCmdStr(awp->func), 754 scb->loc_addr.socket, ddp->dst_socket, iocbp->ioc_count, 755 aspStateStr(scb->state))); 756 757 atp_send_req(gref, mioc); 758 return 0; 759} 760 761/* 762 * send tickle routine - locked version 763 */ 764StaticProc void 765asp_send_tickle_locked(scb) 766 void *scb; 767{ 768 atalk_lock(); 769 asp_send_tickle((asp_scb_t *)scb); 770 atalk_unlock(); 771} 772 773 774/* 775 * send tickle routine 776 */ 777StaticProc void 778asp_send_tickle(scb) 779 asp_scb_t *scb; 780{ 781 gbuf_t *mioc; 782 at_retry_t retry; 783 asp_word_t aw; 784 at_inet_t *dest; 785 786 787 /* 788 * make sure the connection is still there 789 */ 790 if (scb->rem_addr.node == 0) { 791 return; 792 } 793 794 if ((mioc = gbuf_alloc(sizeof(ioc_t), PRI_HI)) == 0) { 795 dPrintf(D_M_ASP, D_L_WARNING, 796 ("asp_send_tickle: ENOBUFS 0, loc=%d, rem=%d\n", 797 scb->loc_addr.socket,scb->rem_addr.socket)); 798 timeout(asp_send_tickle_locked, (void *)scb, 10); 799 return; 800 } 801 gbuf_wset(mioc,sizeof(ioc_t)); 802 gbuf_set_type(mioc, MSG_IOCTL); 803 804 dest = scb->svc_addr.node ? 805 (at_inet_t *)&scb->svc_addr : (at_inet_t *)&scb->rem_addr; 806 retry.interval = scb->tickle_interval; 807 retry.retries = -1; 808 retry.backoff = 1; 809 aw.func = ASPFUNC_Tickle; 810 aw.param1 = scb->sess_id; 811 aw.param2 = 0; 812 ((ioc_t *)gbuf_rptr(mioc))->ioc_cr = (void *)scb; 813 ((ioc_t *)gbuf_rptr(mioc))->ioc_cmd = AT_ATP_ISSUE_REQUEST_TICKLE; 814 815 if (asp_send_req(scb->gref, mioc, dest, &retry, &aw, 0, scb->state, 0)) { 816 dPrintf(D_M_ASP, D_L_WARNING, 817 ("asp_send_tickle: ENOBUFS 1, loc=%d, rem=%d\n", 818 scb->loc_addr.socket,scb->rem_addr.socket)); 819 820 timeout(asp_send_tickle_locked, (void *)scb, 10); 821 return; 822 } 823} 824 825/* 826 * accept connection routine 827 */ 828StaticProc void 829asp_accept(scb, sess_scb, m) 830 asp_scb_t *scb; 831 asp_scb_t *sess_scb; 832 gbuf_t *m; 833{ 834 gbuf_t *mdata; 835 at_ddp_t *ddp; 836 at_atp_t *atp; 837 asp_word_t *awp; 838 at_inet_t rem_addr; 839 840 mdata = scb->sess_ioc; 841 ddp = (at_ddp_t *)gbuf_rptr(mdata); 842 atp = (at_atp_t *)(gbuf_rptr(mdata) + DDP_X_HDR_SIZE); 843 rem_addr.net = NET_VALUE(ddp->src_net); 844 rem_addr.node = ddp->src_node; 845 rem_addr.socket = ddp->src_socket; 846 awp = (asp_word_t *)atp->user_bytes; 847 848 sess_scb->loc_addr.net = NET_VALUE(ddp->dst_net); 849 sess_scb->loc_addr.node = ddp->dst_node; 850 NET_ASSIGN(ddp->src_net, sess_scb->loc_addr.net); 851 ddp->src_node = sess_scb->loc_addr.node; 852 NET_ASSIGN(ddp->dst_net, rem_addr.net); 853 ddp->dst_node = rem_addr.node; 854 ddp->dst_socket = rem_addr.socket; 855 856 sess_scb->sess_id = sess_scb->loc_addr.socket; 857 sess_scb->rem_socket = rem_addr.socket; 858 sess_scb->rem_addr = rem_addr; 859 sess_scb->rem_addr.socket = awp->param1; 860 sess_scb->reply_socket = sess_scb->rem_addr.socket; 861 awp->func = sess_scb->loc_addr.socket; 862 awp->param1 = sess_scb->sess_id; 863 awp->param2 = 0; 864 gbuf_freeb(m); 865 scb->sess_ioc = gbuf_next(mdata); 866 gbuf_next(mdata) = 0; 867 asp_timout(asp_hangup, sess_scb, sess_scb->session_timer); 868 atp_send_rsp(scb->gref, mdata, TRUE); 869 asp_send_tickle(sess_scb); 870 dPrintf(D_M_ASP, D_L_INFO, 871 ("asp_accept: ACCEPT connect request, loc=%d, rem=%x.%x.%d\n", 872 sess_scb->loc_addr.socket, 873 sess_scb->rem_addr.net, 874 sess_scb->rem_addr.node,sess_scb->rem_addr.socket)); 875} /* asp_accept */ 876 877/* 878 * timer routine - locked version 879 */ 880void asp_clock_locked(arg) 881 void *arg; 882{ 883 atalk_lock(); 884 asp_clock(arg); 885 atalk_unlock(); 886} 887 888/* 889 * timer routine 890 */ 891void asp_clock(arg) 892 void *arg; 893{ 894 asp_scb_t *scb; 895 asp_tmo_func tmo_func; 896 897 if (scb_tmo_list) 898 scb_tmo_list->tmo_delta--; 899 while (((scb = scb_tmo_list) != 0) && (scb_tmo_list->tmo_delta == 0)) { 900 if ((scb_tmo_list = scb->next_tmo) != 0) 901 scb_tmo_list->prev_tmo = 0; 902 if ((tmo_func = scb->tmo_func) != 0) { 903 scb->tmo_func = 0; 904 (*tmo_func)(scb); 905 } 906 } 907 908 if (++scb_tmo_cnt == 0) scb_tmo_cnt++; 909 timeout(asp_clock_locked, (void *)arg, (1<<SESS_TMO_RES)*TICKS_PER_SEC); 910 911} 912 913/* 914 * ACK reply routine 915 */ 916void 917asp_ack_reply(gref, mioc) 918 register gref_t *gref; 919 register gbuf_t *mioc; 920{ 921 int len, msize, nbds; 922 register gbuf_t *mdata, *m, *mx; 923 struct atpBDS *atpBDS; 924 at_ddp_t *ddp; 925 at_atp_t *atp; 926 register asp_scb_t *scb, *sess_scb; 927 register ioc_t *iocbp; 928 register asp_word_t *awp; 929 register asp_command_ind_t *command_ind; 930 register asp_cmdreply_ind_t *cmdreply_ind; 931 at_inet_t rem_addr; 932 933 iocbp = (ioc_t *)gbuf_rptr(mioc); 934 935 if (iocbp->ioc_cmd == AT_ATP_ISSUE_REQUEST_TICKLE) { 936 /* 937 * ignore the ack for the tickle request 938 */ 939 scb = (asp_scb_t *)iocbp->ioc_cr; 940 scb->tickle_tid = (unsigned short)iocbp->ioc_rval; 941 gbuf_freem(mioc); 942 return; 943 } 944 945 scb = (asp_scb_t *)gref->info; 946 if (scb == 0) { 947 gbuf_freem(mioc); 948 return; 949 } 950 951 if (iocbp->ioc_cmd == AT_ATP_GET_POLL) { 952 /* 953 * if no data, just drop the request 954 */ 955 if ((mdata = gbuf_cont(mioc)) == 0) { 956 gbuf_freeb(mioc); 957 return; 958 } 959 960 gbuf_set_type(mioc, MSG_IOCTL); 961 ddp = (at_ddp_t *)gbuf_rptr(mdata); 962 gbuf_rinc(mdata,DDP_X_HDR_SIZE); 963 atp = (at_atp_t *)gbuf_rptr(mdata); 964 gbuf_rinc(mdata,ATP_HDR_SIZE); 965 rem_addr.net = NET_VALUE(ddp->src_net); 966 rem_addr.node = ddp->src_node; 967 rem_addr.socket = ddp->src_socket; 968 awp = (asp_word_t *)atp->user_bytes; 969 970 if (scb->next_scb) { 971 /* 972 * find the responsible scb 973 */ 974 if ((scb = asp_find_scb(scb->loc_addr.socket, &rem_addr)) == 0) { 975 gbuf_freem(mioc); 976 return; 977 } 978 } 979 dPrintf(D_M_ASP, D_L_INFO, 980 ("asp_ack_reply: %s, loc=%d, rem=%x.%x.%d\n", 981 aspCmdStr(awp->func),scb->loc_addr.socket, 982 NET_VALUE(ddp->src_net) ,ddp->src_node,ddp->src_socket)); 983 984 if (scb->rem_addr.node) 985 asp_untimout(asp_hangup, scb); 986 987 switch (awp->func) { 988 case ASPFUNC_GetStatus: 989 /* 990 * ignore if this is not a server socket 991 */ 992 mx = 0; 993 if ((scb->dflag != 1) || (scb->stat_msg 994 && ((mx = gbuf_dupb(scb->stat_msg)) == 0))) 995 break; 996 gbuf_freeb(mioc); 997 998 /* 999 * send the status block 1000 */ 1001 if (gbuf_cont(mdata)) { 1002 gbuf_freem(gbuf_cont(mdata)); 1003 gbuf_cont(mdata) = 0; 1004 } 1005 gbuf_rdec(mdata,TOTAL_ATP_HDR_SIZE); 1006 if ((m = gbuf_alloc( (TOTAL_ATP_HDR_SIZE+atpBDSsize), PRI_MED)) == 0) { 1007 gbuf_freem(mdata); 1008 gbuf_freeb(mx); 1009 goto l_done; 1010 } 1011 bcopy(gbuf_rptr(mdata), gbuf_rptr(m), TOTAL_ATP_HDR_SIZE); 1012 gbuf_freeb(mdata); 1013 mdata = m; 1014 ddp = (at_ddp_t *)gbuf_rptr(mdata); 1015 gbuf_wset(mdata,DDP_X_HDR_SIZE); 1016 atp = (at_atp_t *)gbuf_wptr(mdata); 1017 gbuf_winc(mdata,ATP_HDR_SIZE); 1018 awp = (asp_word_t *)atp->user_bytes; 1019 NET_NET(ddp->src_net, ddp->dst_net); 1020 ddp->src_node = ddp->dst_node; 1021 NET_ASSIGN(ddp->dst_net, rem_addr.net); 1022 ddp->dst_node = rem_addr.node; 1023 ddp->dst_socket = rem_addr.socket; 1024 UAS_ASSIGN(ddp->checksum, 0); 1025 atpBDS = (struct atpBDS *)gbuf_wptr(mdata); 1026 msize = mx ? gbuf_msgsize(mx) : 0; 1027 for (nbds=0; (nbds < ATP_TRESP_MAX) && (msize > 0); nbds++) { 1028 len = msize < ATP_DATA_SIZE ? msize : ATP_DATA_SIZE; 1029 msize -= ATP_DATA_SIZE; 1030 *(long *)atpBDS[nbds].bdsUserData = 0; 1031 UAL_ASSIGN(atpBDS[nbds].bdsBuffAddr, 1); 1032 UAS_ASSIGN(atpBDS[nbds].bdsBuffSz, len); 1033 } 1034 UAS_ASSIGN(atpBDS[0].bdsDataSz, nbds); 1035 gbuf_winc(mdata,atpBDSsize); 1036 gbuf_cont(mdata) = mx; 1037 atp_send_rsp(gref, mdata, FALSE); 1038 goto l_done; 1039 1040 case ASPFUNC_OpenSess: 1041 /* 1042 * ignore if server is not ready 1043 */ 1044 if ((scb->dflag != 1) || (scb->stat_msg == 0)) 1045 break; 1046 gbuf_freeb(mioc); 1047 1048 if (gbuf_cont(mdata)) { 1049 gbuf_freem(gbuf_cont(mdata)); 1050 gbuf_cont(mdata) = 0; 1051 } 1052 gbuf_rdec(mdata,TOTAL_ATP_HDR_SIZE); 1053 gbuf_wset(mdata,TOTAL_ATP_HDR_SIZE); 1054 if (awp->param2 != ASP_Version) { 1055 /* 1056 * bad version number, send the OpenSession response 1057 */ 1058 awp->func = 0; 1059 awp->param1 = 0; 1060 awp->param2 = htons((unsigned short)ASPERR_BadVersNum); 1061 dPrintf(D_M_ASP, D_L_INFO, 1062 (" : version=%d\n", 1063 ASPERR_BadVersNum)); 1064 1065 NET_NET(ddp->src_net, ddp->dst_net); 1066 ddp->src_node = ddp->dst_node; 1067 NET_ASSIGN(ddp->dst_net, rem_addr.net); 1068 ddp->dst_node = rem_addr.node; 1069 ddp->dst_socket = rem_addr.socket; 1070 atp_send_rsp(gref, mdata, FALSE); 1071 return; 1072 } 1073 1074 /* 1075 * queue the connection request 1076 */ 1077 gbuf_next(mdata) = 0; 1078 if ((m = scb->sess_ioc) == 0) { 1079 scb->sess_ioc = mdata; 1080 if (scb->get_wait) 1081 wakeup(&scb->event); 1082 else 1083 atalk_notify_sel(gref); 1084 } else { 1085 while (gbuf_next(m)) 1086 m = gbuf_next(m); 1087 gbuf_next(m) = mdata; 1088 } 1089 dPrintf(D_M_ASP, D_L_INFO, 1090 (" : QUEUE connect request\n")); 1091 1092 return; 1093 1094 case ASPFUNC_Command: 1095 case ASPFUNC_Write: 1096 if ( (scb->sess_id != awp->param1) 1097 || (scb->rcv_seq_num != ntohs(awp->param2)) 1098 || BAD_REMADDR(rem_addr) ) { 1099 char era[8], ra[8]; 1100 snprintf(era, sizeof(era), "%d.%d", scb->rem_addr.node,scb->rem_addr.socket); 1101 snprintf(ra, sizeof(ra), "%d.%d", rem_addr.node,rem_addr.socket); 1102 dPrintf(D_M_ASP, D_L_WARNING, 1103 (" : DROP, id=%d,esn=%d,sn=%d,erem=%s,rem=%s\n", 1104 scb->sess_id,scb->rcv_seq_num,awp->param2,era,ra)); 1105 gbuf_cont(mioc) = 0; 1106 gbuf_rdec(mdata,TOTAL_ATP_HDR_SIZE); 1107 atp_drop_req(gref, mdata); 1108 break; 1109 } 1110 scb->reply_socket = rem_addr.socket; 1111 if (awp->func == ASPFUNC_Write) 1112 scb->wrt_seq_num = scb->rcv_seq_num; 1113 NEXT_SEQ_NUM(scb->rcv_seq_num); 1114 gbuf_set_type(mioc, MSG_PROTO); 1115 gbuf_wset(mioc,sizeof(asp_command_ind_t)); 1116 command_ind = (asp_command_ind_t *)gbuf_rptr(mioc); 1117 command_ind->Primitive = (int)awp->func; 1118 command_ind->ReqRefNum = 1119 ntohs(*(unsigned short *)atp->tid); 1120 command_ind->ReqType = awp->func; 1121 1122 mdata = gbuf_strip(mdata); 1123 gbuf_cont(mioc) = mdata; 1124 if (scb->req_flag) { 1125 if ((mx = scb->req_msgq) != 0) { 1126 while (gbuf_next(mx)) 1127 mx = gbuf_next(mx); 1128 gbuf_next(mx) = mioc; 1129 } else 1130 scb->req_msgq = mioc; 1131 } else { 1132 scb->req_flag = 1; 1133 asp_putnext(scb->gref, mioc); 1134 } 1135 goto l_done; 1136 1137 case ASPFUNC_WriteContinue: 1138 if ( (scb->sess_id != awp->param1) 1139 || (scb->snd_seq_num != awp->param2) 1140 || BAD_REMADDR(rem_addr) ) { 1141 break; 1142 } 1143 scb->reply_socket = rem_addr.socket; 1144 gbuf_set_type(mioc, MSG_PROTO); 1145 gbuf_wset(mioc,sizeof(asp_command_ind_t)); 1146 command_ind = (asp_command_ind_t *)gbuf_rptr(mioc); 1147 command_ind->Primitive = (int)awp->func; 1148 command_ind->ReqRefNum = 1149 ntohs(*(unsigned short *)atp->tid); 1150 command_ind->ReqType = awp->func; 1151 1152 mdata = gbuf_strip(mdata); 1153 gbuf_cont(mioc) = mdata; 1154 asp_putnext(scb->gref, mioc); 1155 goto l_done; 1156 1157 case ASPFUNC_Tickle: 1158 if (scb->stat_msg) { 1159 sess_scb = asp_scbQ[awp->param1]; 1160 if (sess_scb && sess_scb->next_scb) 1161 sess_scb = asp_find_scb( 1162 sess_scb->loc_addr.socket, &rem_addr); 1163 if (sess_scb) { 1164 if (sess_scb->rem_addr.node) 1165 asp_untimout(asp_hangup, sess_scb); 1166 if (sess_scb->rem_addr.node) 1167 asp_timout(asp_hangup, sess_scb, sess_scb->session_timer); 1168 } 1169 } 1170 dPrintf(D_M_ASP, D_L_INFO, 1171 (" : Tickle, %d -> %d, id=%d\n", 1172 ddp->src_socket,ddp->dst_socket,awp->param1)); 1173 break; 1174 1175 case ASPFUNC_CloseSess: 1176 if ( (scb->sess_id != awp->param1) 1177 || (scb->state == ASPSTATE_Close) 1178 || (scb->state == ASPSTATE_WaitingForCloseSessRsp) 1179 || (scb->rem_addr.net != rem_addr.net) 1180 || (scb->rem_addr.node != rem_addr.node) ) { 1181 dPrintf(D_M_ASP, D_L_INFO, 1182 (" : CLOSE retry, loc=%d, rem=%x.%x.%d\n", 1183 scb->loc_addr.socket, 1184 scb->rem_addr.net, 1185 scb->rem_addr.node, 1186 scb->rem_addr.socket)); 1187 1188 break; 1189 } 1190 gbuf_freeb(mioc); 1191 1192 /* 1193 * build the CloseSess response to be sent to peer 1194 * when the session is closed by the user. 1195 */ 1196 if (gbuf_cont(mdata)) { 1197 gbuf_freem(gbuf_cont(mdata)); 1198 gbuf_cont(mdata) = 0; 1199 } 1200 gbuf_rdec(mdata,TOTAL_ATP_HDR_SIZE); 1201 gbuf_wset(mdata,TOTAL_ATP_HDR_SIZE); 1202 NET_NET(ddp->src_net, ddp->dst_net); 1203 ddp->src_node = ddp->dst_node; 1204 NET_ASSIGN(ddp->dst_net, rem_addr.net); 1205 ddp->dst_node = rem_addr.node; 1206 ddp->dst_socket = rem_addr.socket; 1207 awp->func = 0; 1208 awp->param1 = 0; 1209 awp->param2 = 0; 1210 dPrintf(D_M_ASP,D_L_INFO, 1211 (" : CLOSE, loc=%d, rem=%x.%x.%d\n", 1212 scb->loc_addr.socket, 1213 scb->rem_addr.net, 1214 scb->rem_addr.node, 1215 scb->rem_addr.socket)); 1216 1217 gbuf_next(mdata) = 0; 1218 if (scb->sess_ioc) 1219 gbuf_freel(scb->sess_ioc); 1220 scb->sess_ioc = mdata; 1221 scb->state = ASPSTATE_Close; 1222 1223 /* 1224 * notify upstream of the CloseSess from peer 1225 */ 1226 asp_hangup(scb); 1227 return; 1228 1229 case ASPFUNC_Attention: 1230 if ( (scb->sess_id != awp->param1) 1231 || (scb->rem_addr.net != rem_addr.net) 1232 || (scb->rem_addr.node != rem_addr.node) ) { 1233 break; 1234 } 1235 gbuf_set_type(mioc, MSG_PROTO); 1236 gbuf_wset(mioc,sizeof(asp_command_ind_t)); 1237 command_ind = (asp_command_ind_t *)gbuf_rptr(mioc); 1238 command_ind->Primitive = (int)awp->func; 1239 command_ind->ReqRefNum = 1240 ntohs(*(unsigned short *)atp->tid); 1241 command_ind->ReqType = awp->func; 1242 scb->attn_tid = *(unsigned short *)atp->tid; 1243 scb->attn_flag = 1; 1244 gbuf_rdec(mdata,2); /* attention code */ 1245 1246 mdata = gbuf_strip(mdata); 1247 gbuf_cont(mioc) = mdata; 1248 asp_putnext(scb->gref, mioc); 1249 goto l_done; 1250 1251 default: 1252 dPrintf(D_M_ASP, D_L_WARNING, 1253 (" : UNKNOWN func, func=%d\n", 1254 awp->func)); 1255 1256 break; 1257 } 1258 } 1259 1260 else if (iocbp->ioc_cmd == AT_ATP_REQUEST_COMPLETE) { 1261 if (scb->next_scb) { 1262 /* 1263 * find the responsible scb 1264 */ 1265 scb = (asp_scb_t *)iocbp->ioc_private; 1266 if ((scb == 0) || (scb->magic_num != 222)) { 1267 dPrintf(D_M_ASP, D_L_ERROR, 1268 ("asp_ack_reply: CAN'T find scb 1\n")); 1269 gbuf_freem(mioc); 1270 return; 1271 } 1272 } 1273 dPrintf(D_M_ASP, D_L_INFO, 1274 ("asp_ack_reply: RSP, loc=%d, rem=%x.%x.%d, state=%s\n", 1275 scb->loc_addr.socket, 1276 scb->rem_addr.net, 1277 scb->rem_addr.node, 1278 scb->rem_addr.socket, 1279 aspStateStr(scb->state))); 1280 1281 switch (scb->state) { 1282 case ASPSTATE_Close: 1283 case ASPSTATE_Idle: 1284 scb->rem_addr.node = 0; 1285 gbuf_freem(mioc); 1286 if (scb->get_wait) 1287 wakeup(&scb->event); 1288 else 1289 atalk_notify_sel(gref); 1290 return; 1291 1292 case ASPSTATE_WaitingForGetStatusRsp: 1293 scb->ioc_wait = 0; 1294 scb->state = ASPSTATE_Idle; 1295 mx = gbuf_cont(mioc); 1296 gbuf_cont(mioc) = 0; 1297 mdata = gbuf_cont(mx); 1298 gbuf_cont(mx) = 0; 1299 iocbp->ioc_cmd = ASPIOC_GetStatus; 1300 iocbp->ioc_count = 0; 1301 iocbp->ioc_rval = mdata ? gbuf_msgsize(mdata) : 0; 1302 gbuf_freeb(mx); 1303 atalk_putnext(gref, mioc); 1304 atalk_putnext(gref, mdata); 1305 return; 1306 1307 case ASPSTATE_WaitingForOpenSessRsp: 1308 scb->ioc_wait = 0; 1309 scb->state = ASPSTATE_Idle; 1310 mx = gbuf_cont(mioc); 1311 gbuf_cont(mioc) = 0; 1312 if (gbuf_cont(mx)) { 1313 gbuf_freem(gbuf_cont(mx)); 1314 gbuf_cont(mx) = 0; 1315 } 1316 iocbp->ioc_cmd = ASPIOC_OpenSession; 1317 iocbp->ioc_rval = 0; 1318 iocbp->ioc_count = 0; 1319 atpBDS = (struct atpBDS *)gbuf_rptr(mx); 1320 awp = (asp_word_t *)atpBDS->bdsUserData; 1321 if (awp->param2) { 1322 gbuf_freeb(mx); 1323 asp_iocnak(gref, mioc, ECONNREFUSED); 1324 } else { 1325 scb->rem_addr.node = scb->rem_node; 1326 scb->rem_addr.socket = awp->func; 1327 /* bms: need to set the reply_socket for client side too. 1328 This makes ALO atten replies sent by the client work. */ 1329 scb->reply_socket = scb->rem_addr.socket; 1330 scb->sess_id = awp->param1; 1331 gbuf_freeb(mx); 1332 atalk_putnext(gref, mioc); 1333 asp_timout(asp_hangup, scb, scb->session_timer); 1334 asp_send_tickle(scb); 1335 dPrintf(D_M_ASP, D_L_INFO, 1336 ("asp_ack_reply: CONNECT, loc=%d, rem=%x.%x.%d\n", 1337 scb->loc_addr.socket, 1338 scb->rem_addr.net, 1339 scb->rem_addr.node, 1340 scb->rem_addr.socket)); 1341 } 1342 return; 1343 1344 case ASPSTATE_WaitingForCommandRsp: 1345 case ASPSTATE_WaitingForWriteRsp: 1346 case ASPSTATE_WaitingForWriteContinueRsp: 1347 if (scb->rem_addr.node) 1348 asp_untimout(asp_hangup, scb); 1349 NEXT_SEQ_NUM(scb->snd_seq_num); 1350 scb->state = ASPSTATE_Idle; 1351 gbuf_set_type(mioc, MSG_PROTO); 1352 mx = gbuf_cont(mioc); 1353 mdata = gbuf_cont(mx); 1354 gbuf_cont(mioc) = mdata; 1355 atpBDS = (struct atpBDS *)gbuf_rptr(mx); 1356 cmdreply_ind = (asp_cmdreply_ind_t *)gbuf_rptr(mioc); 1357 cmdreply_ind->Primitive = ASPFUNC_CmdReply; 1358 cmdreply_ind->CmdResult = ntohl(*(int *)atpBDS->bdsUserData); 1359 gbuf_wset(mioc,sizeof(asp_cmdreply_ind_t)); 1360 gbuf_freeb(mx); 1361 asp_putnext(scb->gref, mioc); 1362 goto l_done; 1363 1364 case ASPSTATE_WaitingForCloseSessRsp: 1365 scb->ioc_wait = 0; 1366 scb->state = ASPSTATE_Close; 1367 scb->rem_addr.node = 0; 1368 iocbp->ioc_cmd = ASPIOC_CloseSession; 1369 iocbp->ioc_rval = 0; 1370 if (gbuf_cont(mioc)) { 1371 gbuf_freem(gbuf_cont(mioc)); 1372 gbuf_cont(mioc) = 0; 1373 } 1374 atalk_putnext(scb->gref, mioc); 1375 atp_cancel_req(scb->gref, (unsigned int)scb->tickle_tid); 1376 scb->tickle_tid = 0; 1377 return; 1378 1379 default: 1380 dPrintf(D_M_ASP, D_L_WARNING, 1381 (" : UNKNOWN state, state=%s\n", 1382 aspStateStr(scb->state))); 1383 break; 1384 } 1385 } 1386 1387 else { 1388 if (scb->next_scb) { 1389 /* 1390 * find the responsible scb 1391 */ 1392 scb = (asp_scb_t *)iocbp->ioc_cr; 1393 if ((scb == 0) || (scb->magic_num != 222)) { 1394 dPrintf(D_M_ASP, D_L_ERROR, 1395 ("asp_ack_reply: CAN'T find scb 2\n")); 1396 gbuf_freem(mioc); 1397 return; 1398 } 1399 } 1400 1401 switch (scb->state) { 1402 case ASPSTATE_Close: 1403 scb->rem_addr.node = 0; 1404 break; 1405 } 1406 } 1407 1408 if (mioc != 0) 1409 gbuf_freem(mioc); 1410 1411l_done: 1412 if (scb->rem_addr.node) 1413 asp_timout(asp_hangup, scb, scb->session_timer); 1414} /* asp_ack_reply */ 1415 1416/* 1417 * NAK reply routine 1418 */ 1419void 1420asp_nak_reply(gref, mioc) 1421 register gref_t *gref; 1422 register gbuf_t *mioc; 1423{ 1424 register asp_scb_t *scb; 1425 register ioc_t *iocbp; 1426 1427 iocbp = (ioc_t *)gbuf_rptr(mioc); 1428 1429 if (iocbp->ioc_cmd == AT_ATP_ISSUE_REQUEST_TICKLE) { 1430 /* 1431 * no tickle, close session 1432 */ 1433 scb = (asp_scb_t *)iocbp->ioc_cr; 1434 gbuf_freem(mioc); 1435 asp_hangup(scb); 1436 dPrintf(D_M_ASP, D_L_WARNING, 1437 ("tickle_nak: loc=%d, rem=%x.%x.%d, state=%s\n", 1438 scb->loc_addr.socket, 1439 scb->rem_addr.net, 1440 scb->rem_addr.node, 1441 scb->rem_addr.socket, 1442 aspStateStr(scb->state))); 1443 1444 return; 1445 } 1446 1447 scb = (asp_scb_t *)gref->info; 1448 if (scb == 0) { 1449 gbuf_freem(mioc); 1450 return; 1451 } 1452 1453 if (iocbp->ioc_cmd == AT_ATP_REQUEST_COMPLETE) { 1454 if (scb->next_scb) { 1455 /* 1456 * find the responsible scb 1457 */ 1458 scb = (asp_scb_t *)iocbp->ioc_private; 1459 if ((scb == 0) || (scb->magic_num != 222)) { 1460 dPrintf(D_M_ASP, D_L_ERROR, 1461 ("asp_nak_reply: CAN'T find scb 1\n")); 1462 gbuf_freem(mioc); 1463 return; 1464 } 1465 } 1466 dPrintf(D_M_ASP, D_L_WARNING, 1467 ("asp_nak_reply: RSP, loc=%d, rem=%x.%x.%d, state=%s\n", 1468 scb->loc_addr.socket, 1469 scb->rem_addr.net, 1470 scb->rem_addr.node, 1471 scb->rem_addr.socket, 1472 aspStateStr(scb->state))); 1473 1474 switch (scb->state) { 1475 case ASPSTATE_WaitingForGetStatusRsp: 1476 iocbp->ioc_cmd = ASPIOC_GetStatus; 1477 break; 1478 1479 case ASPSTATE_WaitingForOpenSessRsp: 1480 iocbp->ioc_cmd = ASPIOC_OpenSession; 1481 break; 1482 1483 case ASPSTATE_WaitingForCommandRsp: 1484 case ASPSTATE_WaitingForWriteRsp: 1485 case ASPSTATE_WaitingForWriteContinueRsp: 1486 scb->state = ASPSTATE_Idle; 1487 1488 /* last remaining use of MSG_ERROR */ 1489 gbuf_set_type(mioc, MSG_ERROR); 1490 *gbuf_rptr(mioc) = (u_char)EPROTOTYPE; 1491 gbuf_wset(mioc, 1); 1492 if (gbuf_cont(mioc)) { 1493 gbuf_freem(gbuf_cont(mioc)); 1494 gbuf_cont(mioc) = 0; 1495 } 1496 1497 asp_putnext(scb->gref, mioc); 1498 return; 1499 1500 case ASPSTATE_WaitingForCloseSessRsp: 1501 scb->state = ASPSTATE_Close; 1502 /* fall through */ 1503 case ASPSTATE_Close: /* new for PR-2296832 */ 1504 scb->rem_addr.node = 0; 1505 iocbp->ioc_cmd = ASPIOC_CloseSession; 1506 iocbp->ioc_rval = 0; 1507 if (gbuf_cont(mioc)) { 1508 gbuf_freem(gbuf_cont(mioc)); 1509 gbuf_cont(mioc) = 0; 1510 } 1511 gbuf_set_type(mioc, MSG_IOCACK); 1512 atalk_putnext(scb->gref, mioc); 1513 return; 1514 1515 default: 1516 gbuf_freem(mioc); 1517 return; 1518 } 1519 scb->state = ASPSTATE_Idle; 1520 atalk_putnext(gref, mioc); 1521 } 1522 1523 else { 1524 if (scb->next_scb) { 1525 /* 1526 * find the responsible scb 1527 */ 1528 scb = (asp_scb_t *)iocbp->ioc_cr; 1529 if ((scb == 0) || (scb->magic_num != 222)) { 1530 dPrintf(D_M_ASP, D_L_ERROR, 1531 ("asp_nak_reply: CAN'T find scb 2\n")); 1532 gbuf_freem(mioc); 1533 return; 1534 } 1535 } 1536 1537 switch (scb->state) { 1538 case ASPSTATE_Close: 1539 scb->rem_addr.node = 0; 1540 break; 1541 } 1542 1543 gbuf_freem(mioc); 1544 } 1545} /* asp_nak_reply */ 1546 1547/* 1548 * delete scb from the use list 1549 */ 1550StaticProc void 1551asp_dequeue_scb(scb) 1552 asp_scb_t *scb; 1553{ 1554 1555 if (scb == scb_used_list) { 1556 if ((scb_used_list = scb->next_scb) != 0) 1557 scb->next_scb->prev_scb = 0; 1558 } else { 1559 if ((scb->prev_scb->next_scb = scb->next_scb) != 0) 1560 scb->next_scb->prev_scb = scb->prev_scb; 1561 } 1562 1563 scb->next_scb = 0; 1564 scb->prev_scb = 0; 1565} 1566 1567/* 1568 * find scb routine 1569 */ 1570StaticProc asp_scb_t * 1571asp_find_scb(sock_num, rem_addr) 1572 unsigned char sock_num; 1573 at_inet_t *rem_addr; 1574{ 1575 asp_scb_t *scb; 1576 asp_scb_t *alt_scb = 0; 1577 1578 for (scb = asp_scbQ[sock_num]; scb; scb = scb->next_scb) { 1579 if ((scb->rem_addr.net == rem_addr->net) 1580 && (scb->rem_addr.node == rem_addr->node)) { 1581 if ((scb->rem_addr.socket == rem_addr->socket) 1582 || (scb->rem_socket == rem_addr->socket)) 1583 break; 1584 else if (alt_scb == 0) 1585 alt_scb = scb; 1586 } 1587 } 1588 1589 if ((scb == 0) && ((scb = alt_scb) == 0)) { 1590 dPrintf(D_M_ASP, D_L_ERROR, 1591 ("asp_find_scb: CAN'T find scb, loc=%d, rem=%x.%x.%d\n", 1592 sock_num, 1593 rem_addr->net, 1594 rem_addr->node, 1595 rem_addr->socket)); 1596 } 1597 1598 return scb; 1599} 1600 1601/* 1602 * timout routine 1603 */ 1604StaticProc void 1605asp_timout(func, scb, seconds) 1606 asp_tmo_func func; 1607 register asp_scb_t *scb; 1608 int seconds; 1609{ 1610 unsigned char sum; 1611 register asp_scb_t *curr_scb, *prev_scb; 1612 1613 if (scb->tmo_func) 1614 return; 1615 1616 scb->tmo_func = func; 1617 scb->tmo_delta = (seconds>>SESS_TMO_RES); 1618 scb->tmo_cnt = scb_tmo_cnt; 1619 1620 if (scb_tmo_list == 0) { 1621 scb->next_tmo = scb->prev_tmo = 0; 1622 scb_tmo_list = scb; 1623 return; 1624 } 1625 1626 prev_scb = 0; 1627 curr_scb = scb_tmo_list; 1628 sum = 0; 1629 1630 while (1) { 1631 sum += curr_scb->tmo_delta; 1632 if (sum > scb->tmo_delta) { 1633 sum -= curr_scb->tmo_delta; 1634 scb->tmo_delta -= sum; 1635 curr_scb->tmo_delta -= scb->tmo_delta; 1636 break; 1637 } 1638 prev_scb = curr_scb; 1639 if ((curr_scb = curr_scb->next_tmo) == 0) { 1640 scb->tmo_delta -= sum; 1641 break; 1642 } 1643 } 1644 1645 if (prev_scb) { 1646 scb->prev_tmo = prev_scb; 1647 if ((scb->next_tmo = prev_scb->next_tmo) != 0) 1648 prev_scb->next_tmo->prev_tmo = scb; 1649 prev_scb->next_tmo = scb; 1650 } else { 1651 scb->prev_tmo = 0; 1652 scb->next_tmo = scb_tmo_list; 1653 scb_tmo_list->prev_tmo = scb; 1654 scb_tmo_list = scb; 1655 } 1656} 1657 1658/* 1659 * untimout routine 1660 */ 1661StaticProc void 1662asp_untimout( 1663 __unused asp_tmo_func tmo_func, 1664 register asp_scb_t *scb) 1665{ 1666 1667 if ((scb->tmo_cnt == scb_tmo_cnt) || (scb->tmo_func == 0)) 1668 return; 1669 1670 if (scb_tmo_list == scb) { 1671 if ((scb_tmo_list = scb->next_tmo) != 0) { 1672 scb_tmo_list->prev_tmo = 0; 1673 scb->next_tmo->tmo_delta += scb->tmo_delta; 1674 } 1675 } else if (scb->prev_tmo) { 1676 if ((scb->prev_tmo->next_tmo = scb->next_tmo) != 0) { 1677 scb->next_tmo->prev_tmo = scb->prev_tmo; 1678 scb->next_tmo->tmo_delta += scb->tmo_delta; 1679 } 1680 scb->prev_tmo = 0; 1681 } 1682 scb->tmo_func = 0; 1683} 1684 1685/* 1686 * hangup routine 1687 */ 1688StaticProc void 1689asp_hangup(scb) 1690 asp_scb_t *scb; 1691{ 1692 /* 1693 * set the state to Close 1694 */ 1695 scb->state = ASPSTATE_Close; 1696 if (scb->tickle_tid) { 1697 atp_cancel_req(scb->gref, (unsigned int)scb->tickle_tid); 1698 scb->tickle_tid = 0; 1699 } 1700 1701 /* 1702 * notify upstream of the hangup 1703 */ 1704 if (scb->rem_addr.node) { 1705 if (scb->get_wait) 1706 wakeup(&scb->event); 1707 else 1708 atalk_notify_sel(scb->gref); 1709 } 1710} 1711 1712StaticProc void 1713asp_iocack(gref, mioc) 1714 gref_t *gref; 1715 gbuf_t *mioc; 1716{ 1717 if (gbuf_cont(mioc)) 1718 ((ioc_t *)gbuf_rptr(mioc))->ioc_count = gbuf_msgsize(gbuf_cont(mioc)); 1719 else 1720 ((ioc_t *)gbuf_rptr(mioc))->ioc_count = 0; 1721 1722 gbuf_set_type(mioc, MSG_IOCACK); 1723 atalk_putnext(gref, mioc); 1724} 1725 1726StaticProc void 1727asp_iocnak(gref, mioc, err) 1728 gref_t *gref; 1729 gbuf_t *mioc; 1730 int err; 1731{ 1732 ((ioc_t *)gbuf_rptr(mioc))->ioc_count = 0; 1733 if (err == 0) 1734 err = ENXIO; 1735 ((ioc_t *)gbuf_rptr(mioc))->ioc_error = err; 1736 ((ioc_t *)gbuf_rptr(mioc))->ioc_rval = -1; 1737 if (gbuf_cont(mioc)) { 1738 gbuf_freem(gbuf_cont(mioc)); 1739 gbuf_cont(mioc) = 0; 1740 } 1741 1742 gbuf_set_type(mioc, MSG_IOCNAK); 1743 atalk_putnext(gref, mioc); 1744} 1745 1746/* 1747 * the alloc scb routine 1748 */ 1749StaticProc asp_scb_t * 1750asp_scb_alloc() 1751{ 1752 int i; 1753 gbuf_t *m; 1754 asp_scb_t *scb, *scb_array; 1755 1756 if (scb_free_list == 0) { 1757 if ((m = gbuf_alloc(SCBS_PER_BLK*sizeof(asp_scb_t), PRI_MED)) == 0) 1758 return (asp_scb_t *)0; 1759 bzero((char *)gbuf_rptr(m), SCBS_PER_BLK*sizeof(asp_scb_t)); 1760 gbuf_cont(m) = scb_resource_m; 1761 scb_resource_m = m; 1762 scb_array = (asp_scb_t *)gbuf_rptr(m); 1763 for (i=0; i < SCBS_PER_BLK-1; i++) 1764 scb_array[i].next_scb = (asp_scb_t *)&scb_array[i+1]; 1765 scb_array[i].next_scb = 0; 1766 scb_free_list = (asp_scb_t *)&scb_array[0]; 1767 } 1768 1769 scb = scb_free_list; 1770 scb_free_list = scb->next_scb; 1771 ATEVENTINIT(scb->event); 1772 ATEVENTINIT(scb->delay_event); 1773 1774 return scb; 1775} 1776 1777/* 1778 * the free scb routine 1779 */ 1780StaticProc void 1781asp_scb_free(scb) 1782 asp_scb_t *scb; 1783{ 1784 1785 bzero((char *)scb, sizeof(asp_scb_t)); 1786 scb->next_scb = scb_free_list; 1787 scb_free_list = scb; 1788} 1789 1790/* 1791 * routine to pass up receive data 1792 */ 1793StaticProc void 1794asp_putnext(gref, mproto) 1795 gref_t *gref; 1796 gbuf_t *mproto; 1797{ 1798 gbuf_t *m; 1799 asp_scb_t *scb; 1800 1801 scb = (asp_scb_t *)gref->info; 1802 1803 /* 1804 * queue the message. 1805 */ 1806 gbuf_next(mproto) = 0; 1807 if ((m = scb->sess_ioc) == 0) 1808 scb->sess_ioc = mproto; 1809 else { 1810 while (gbuf_next(m)) 1811 m = gbuf_next(m); 1812 gbuf_next(m) = mproto; 1813 } 1814 scb->rcv_cnt++; 1815 if (scb->rcv_cnt >= MAX_RCV_CNT) 1816 scb->snd_stop = 1; 1817 1818 if (scb->get_wait) 1819 wakeup(&scb->event); 1820 else if (mproto == scb->sess_ioc) 1821 atalk_notify_sel(gref); 1822 1823} /* asp_putnext */ 1824 1825/* 1826 * The following two routines are direct entries from system 1827 * calls to allow fast sending and recving of ASP data. 1828 */ 1829 1830/* in ASPputmsg we expect: 1831 1832 ASPFUNC_CmdReply 1833 ASPFUNC_Attention 1834 ASPFUNC_Command 1835 ASPFUNC_Write 1836 ASPFUNC_WriteContinue 1837 1838 bms: Make this callable from the kernel. 1839 If mreq != NULL, then must be called from kernel space and the following apply: 1840 1) *mreq is data to be sent already in mbuf chains. 1841 2) datptr->len = size of data 1842*/ 1843 1844int ASPputmsg(gref_t *gref, strbuf_t *ctlptr, strbuf_t *datptr, gbuf_t *mreq, __unused int flags, int *errp) 1845{ 1846 int i, err, len, offset, remain, size, copy_len; 1847 gbuf_t *mioc, *mdata, *mx; 1848 ioc_t *iocbp; 1849 strbuf_t ctlbuf; 1850 strbuf_t datbuf; 1851 asp_scb_t *scb; 1852 int nbds, result, msize, Primitive; 1853 unsigned char *wptr; 1854 struct atp_set_default *sd; 1855 at_ddp_t *ddp; 1856 at_atp_t *atp; 1857 struct atpBDS *atpBDS; 1858 asp_word_t *awp; 1859 union asp_primitives *primitives; 1860 unsigned short tid; 1861 caddr_t dataptr; 1862 1863 if ((scb = (asp_scb_t *)gref->info) == 0) { 1864 dPrintf(D_M_ASP, D_L_ERROR, 1865 ("ASPputmsg: stale handle=0x%x, pid=%d\n", 1866 (u_int) gref, gref->pid)); 1867 1868 *errp = EINVAL; 1869 return -1; 1870 } 1871 1872 if (scb->state == ASPSTATE_Close) 1873 return 0; 1874 if (scb->snd_stop) { 1875 *errp = EAGAIN; 1876 return -1; 1877 } 1878 1879 /* 1880 * copy in the control and data info 1881 */ 1882 if (mreq != NULL) { 1883 /* being called from kernel space */ 1884 bcopy (ctlptr, &ctlbuf, sizeof (strbuf_t)); 1885 bcopy (datptr, &datbuf, sizeof (strbuf_t)); 1886 } else { 1887 /* being called from user space */ 1888 if ((err = copyin(CAST_USER_ADDR_T(ctlptr), (caddr_t)&ctlbuf, sizeof(ctlbuf))) != 0) 1889 goto l_err; 1890 if ((err = copyin(CAST_USER_ADDR_T(datptr), (caddr_t)&datbuf, sizeof(datbuf))) != 0) 1891 goto l_err; 1892 } 1893 1894 /* Radar 5398072: check for bogus length 1895 * Max ASP data is 8 ATP packets 1896 */ 1897 1898 if ((ctlbuf.len < 0) || (ctlbuf.len > (ATP_DATA_SIZE * 8))) { 1899 err = EINVAL; 1900 goto l_err; 1901 } 1902 if ((datbuf.len < 0) || (datbuf.len > (ATP_DATA_SIZE * 8))) { 1903 err = EINVAL; 1904 goto l_err; 1905 } 1906 1907 /* 1908 * allocate buffer and copy in the control content 1909 */ 1910 if (!(mioc = gbuf_alloc_wait(ctlbuf.len, TRUE))) { 1911 /* error return should not be possible */ 1912 err = ENOBUFS; 1913 goto l_err; 1914 } 1915 gbuf_set_type(mioc, MSG_IOCTL); /* for later, in ATP */ 1916 gbuf_wset(mioc, ctlbuf.len); 1917 1918 if (mreq != NULL) { 1919 /* being called from kernel space */ 1920 bcopy (ctlbuf.buf, gbuf_rptr(mioc), ctlbuf.len); 1921 } else { 1922 /* being called from user space */ 1923 if ((err = copyin(CAST_USER_ADDR_T(ctlbuf.buf), (caddr_t)gbuf_rptr(mioc), ctlbuf.len)) != 0) { 1924 gbuf_freem(mioc); 1925 goto l_err; 1926 } 1927 } 1928 1929 iocbp = (ioc_t *)gbuf_rptr(mioc); 1930 primitives = (union asp_primitives *)gbuf_rptr(mioc); 1931 Primitive = primitives->Primitive; 1932 dPrintf(D_M_ASP, D_L_INFO, 1933 ("ASPputmsg: %s\n", aspCmdStr(Primitive))); 1934 1935 /* 1936 * copy in the data content into multiple mbuf clusters if 1937 * required. ATP now expects reply data to be placed in 1938 * standard clusters, not the large external clusters that 1939 * were used previously. 1940 */ 1941 1942 /* set offset for use by some commands */ 1943 offset = (Primitive == ASPFUNC_CmdReply) ? 0 : aspCMDsize; 1944 size = 0; 1945 if (mreq != NULL) { 1946 /* The data from the in-kernel call for use by AFP is passed 1947 * in as one large external cluster. This needs to be copied 1948 * to a chain of standard clusters. 1949 */ 1950 remain = gbuf_len(mreq); 1951 dataptr = mtod(mreq, caddr_t); 1952 } else { 1953 /* copyin from user space */ 1954 remain = datbuf.len; 1955 dataptr = (caddr_t)datbuf.buf; 1956 } 1957 1958 /* allocate first buffer */ 1959 if (!(mdata = gbuf_alloc_wait((remain + offset > MCLBYTES ? MCLBYTES : remain + offset), TRUE))) { 1960 /* error return should not be possible */ 1961 err = ENOBUFS; 1962 gbuf_freem(mioc); 1963 goto l_err; 1964 } 1965 gbuf_wset(mdata, 0); /* init length to zero */ 1966 gbuf_cont(mioc) = mdata; 1967 1968 while (remain) { 1969 if (remain + offset > MCLBYTES) 1970 copy_len = MCLBYTES - offset; 1971 else 1972 copy_len = remain; 1973 remain -= copy_len; 1974 if (mreq != NULL) 1975 bcopy (dataptr, (gbuf_rptr(mdata) + offset), copy_len); 1976 else if ((err = copyin(CAST_USER_ADDR_T(dataptr), (caddr_t)(gbuf_rptr(mdata) + offset), copy_len)) != 0) { 1977 gbuf_freem(mioc); 1978 goto l_err; 1979 } 1980 gbuf_wset(mdata, (copy_len + offset)); 1981 size += copy_len + offset; 1982 dataptr += copy_len; 1983 offset = 0; 1984 if (remain) { 1985 /* allocate the next mbuf */ 1986 if ((gbuf_cont(mdata) = m_get((M_WAIT), MSG_DATA)) == 0) { 1987 err = ENOBUFS; 1988 gbuf_freem(mioc); 1989 goto l_err; 1990 } 1991 mdata = gbuf_cont(mdata); 1992 MCLGET(mdata, M_WAIT); 1993 if (!(mdata->m_flags & M_EXT)) { 1994 err = ENOBUFS; 1995 gbuf_freem(mioc); 1996 goto l_err; 1997 } 1998 } 1999 } 2000 mdata = gbuf_cont(mioc); /* code further on down expects this to b e set */ 2001 mdata->m_pkthdr.len = size; /* set packet hdr len */ 2002 2003 if (mreq != 0) 2004 gbuf_freem(mreq); 2005 2006 switch (Primitive) { 2007 2008 case ASPFUNC_Command: 2009 case ASPFUNC_Write: 2010 case ASPFUNC_WriteContinue: 2011 case ASPFUNC_Attention: 2012 /* 2013 * build the command/write/write_continue request 2014 */ 2015 wptr = (unsigned char *)gbuf_rptr(mdata); 2016 atpBDS = (struct atpBDS *)wptr; 2017 wptr += atpBDSsize; 2018 for (i=0; i < ATP_TRESP_MAX; i++) { 2019 *(unsigned long *)atpBDS[i].bdsBuffAddr = 1; 2020 *(unsigned short *)atpBDS[i].bdsBuffSz = ATP_DATA_SIZE; 2021 } 2022 sd = (struct atp_set_default *)wptr; 2023 wptr += sizeof(struct atp_set_default); 2024 sd->def_retries = (scb->cmd_retry.retries == -1) ? 2025 ATP_INFINITE_RETRIES : scb->cmd_retry.retries; 2026 sd->def_rate = scb->cmd_retry.interval*TICKS_PER_SEC; 2027 sd->def_BDSlen = atpBDSsize; 2028 ddp = (at_ddp_t *)wptr; 2029 NET_ASSIGN(ddp->src_net, scb->loc_addr.net); 2030 ddp->src_node = scb->loc_addr.node; 2031 NET_ASSIGN(ddp->dst_net, scb->rem_addr.net); 2032 ddp->dst_node = scb->rem_addr.node; 2033 ddp->dst_socket = scb->rem_addr.socket; 2034 UAS_ASSIGN(ddp->checksum, 0); 2035 atp = ATP_ATP_HDR(wptr); 2036 wptr += TOTAL_ATP_HDR_SIZE; 2037 atp->xo = 1; 2038 atp->xo_relt = 1; 2039 atp->bitmap = 0xff; 2040 awp = (asp_word_t *)atp->user_bytes; 2041 awp->func = (unsigned char)Primitive; 2042 awp->param1 = scb->sess_id; 2043 awp->param2 = htons(scb->snd_seq_num); 2044 iocbp->ioc_private = (void *)scb; 2045 iocbp->ioc_count = gbuf_len(mdata); 2046 iocbp->ioc_rval = 0; 2047 iocbp->ioc_cmd = AT_ATP_ISSUE_REQUEST_DEF; 2048 2049 /* 2050 * send the command/write/write_continue/attention request 2051 */ 2052 switch (awp->func) { 2053 case ASPFUNC_Command: 2054 scb->state = ASPSTATE_WaitingForCommandRsp; 2055 break; 2056 case ASPFUNC_Write: 2057 scb->state = ASPSTATE_WaitingForWriteRsp; 2058 break; 2059 case ASPFUNC_WriteContinue: 2060 scb->state = ASPSTATE_WaitingForWriteContinueRsp; 2061 awp->param2 = htons(scb->wrt_seq_num); 2062 break; 2063 case ASPFUNC_Attention: 2064 scb->state = ASPSTATE_WaitingForCommandRsp; 2065 atp->xo = 0; 2066 atp->xo_relt = 0; 2067 atp->bitmap = 0x01; 2068 gbuf_wdec(mdata,2); 2069 awp->param2 = htons(*(unsigned short *)gbuf_wptr(mdata)); 2070 break; 2071 } 2072 dPrintf(D_M_ASP,D_L_INFO, 2073 ("ASPputmsg: %s, loc=%d, rem=%x.%x.%d\n", 2074 (awp->func == ASPFUNC_Command ? "CommandReq" : 2075 awp->func == ASPFUNC_Write ? "WriteReq" : 2076 awp->func == ASPFUNC_WriteContinue ? "WriteContinue" : 2077 "AttentionReq"),scb->loc_addr.socket, 2078 NET_VALUE(ddp->dst_net),ddp->dst_node,ddp->dst_socket)); 2079 atp_send_req(gref, mioc); 2080 return 0; 2081 2082 case ASPFUNC_CmdReply: 2083 2084 if (scb->req_msgq) { 2085 mx = scb->req_msgq; 2086 scb->req_msgq = gbuf_next(mx); 2087 gbuf_next(mx) = 0; 2088 asp_putnext(scb->gref, mx); 2089 } else 2090 scb->req_flag = 0; 2091 2092 result = primitives->CmdReplyReq.CmdResult; 2093 tid = primitives->CmdReplyReq.ReqRefNum; 2094 2095 /* Re-use the original mioc mbuf to send the response. */ 2096 gbuf_rinc(mioc,sizeof(void *)); 2097 gbuf_wset(mioc,0); 2098 ddp = (at_ddp_t *)gbuf_wptr(mioc); 2099 gbuf_winc(mioc,DDP_X_HDR_SIZE); 2100 atp = (at_atp_t *)gbuf_wptr(mioc); 2101 gbuf_winc(mioc,ATP_HDR_SIZE); 2102 NET_ASSIGN(ddp->src_net, scb->loc_addr.net); 2103 ddp->src_node = scb->loc_addr.node; 2104 NET_ASSIGN(ddp->dst_net, scb->rem_addr.net); 2105 ddp->dst_node = scb->rem_addr.node; 2106 ddp->dst_socket = scb->reply_socket; 2107 ddp->type = DDP_ATP; 2108 UAS_ASSIGN(ddp->checksum, 0); 2109 UAS_ASSIGN(atp->tid, htons(tid)); 2110 if (scb->attn_flag && (tid == scb->attn_tid)) { 2111 scb->attn_flag = 0; 2112 atp->xo = 0; 2113 atp->xo_relt = 0; 2114 } else { 2115 atp->xo = 1; 2116 atp->xo_relt = 1; 2117 } 2118 /* setup the atpBDS struct - only the length field is used, 2119 * except for the first one which contains the bds count in 2120 * bdsDataSz. 2121 */ 2122 atpBDS = (struct atpBDS *)gbuf_wptr(mioc); 2123 msize = mdata ? gbuf_msgsize(mdata) : 0; 2124 for (nbds=0; (nbds < ATP_TRESP_MAX) && (msize > 0); nbds++) { 2125 len = msize < ATP_DATA_SIZE ? msize : ATP_DATA_SIZE; 2126 msize -= ATP_DATA_SIZE; 2127 *(long *)atpBDS[nbds].bdsUserData = 0; 2128 UAL_ASSIGN(atpBDS[nbds].bdsBuffAddr, 1); 2129 UAS_ASSIGN(atpBDS[nbds].bdsBuffSz, len); 2130 } 2131 UAS_ASSIGN(atpBDS[0].bdsDataSz, nbds); 2132 *(long *)atpBDS[0].bdsUserData = (long)result; 2133 *(long *)atp->user_bytes = (long)result; 2134 gbuf_winc(mioc,atpBDSsize); 2135 dPrintf(D_M_ASP, D_L_INFO, 2136 ("ASPputmsg: ATP CmdReplyReq, loc=%d, state=%s, msgsize = %d, result = %d, tid = %d\n", 2137 scb->loc_addr.socket, aspStateStr(scb->state), 2138 (mdata ? gbuf_msgsize(mdata) : 0), result, tid)); 2139 atp_send_rsp(gref, mioc, TRUE); 2140 return 0; 2141 } 2142 2143 /* Not an expected ASPFUNC */ 2144 gbuf_freem(mioc); 2145 err = EOPNOTSUPP; 2146 2147l_err: 2148 *errp = err; 2149 return -1; 2150} /* ASPputmsg */ 2151 2152 2153/* bms: make this callable from kernel. reply date is passed back as a mbuf chain in *mreply */ 2154int ASPgetmsg(gref_t *gref, strbuf_t *ctlptr, strbuf_t *datptr, gbuf_t **mreply, __unused int *flags, int *errp) 2155{ 2156 int err, len, sum, rval; 2157 gbuf_t *mproto, *mdata; 2158 strbuf_t ctlbuf; 2159 strbuf_t datbuf; 2160 asp_scb_t *scb; 2161 unsigned char get_wait; 2162 2163 if ((scb = (asp_scb_t *)gref->info) == 0) { 2164 dPrintf(D_M_ASP, D_L_ERROR, 2165 ("ASPgetmsg: stale handle=0x%x, pid=%d\n", 2166 (u_int) gref, gref->pid)); 2167 2168 *errp = EINVAL; 2169 return -1; 2170 } 2171 2172 if (scb->state == ASPSTATE_Close) 2173 return 0; 2174 2175 /* 2176 * get receive data 2177 */ 2178 while ((mproto = scb->sess_ioc) == 0) { 2179 scb->get_wait = 1; 2180 lck_mtx_assert(atalk_mutex, LCK_MTX_ASSERT_OWNED); 2181 err = msleep(&scb->event, atalk_mutex, PSOCK | PCATCH, "aspgetmsg", 0); 2182 if (err != 0) { 2183 scb->get_wait = 0; 2184 *errp = err; 2185 return -1; 2186 } 2187 if (scb->state == ASPSTATE_Close) { 2188 scb->get_wait = 0; 2189 return 0; 2190 } 2191 } 2192 get_wait = scb->get_wait; 2193 scb->get_wait = 0; 2194 if ((ctlptr == 0) && (datptr == 0)) 2195 return 0; 2196 scb->sess_ioc = gbuf_next(mproto); 2197 mdata = gbuf_cont(mproto); 2198 2199 /* last remaining use of MSG_ERROR */ 2200 if (gbuf_type(mproto) == MSG_ERROR) { 2201 err = (int)gbuf_rptr(mproto)[0]; 2202 goto l_err; 2203 } 2204 2205 /* 2206 * copy in the control and data info 2207 */ 2208 if (mreply != NULL) { 2209 /* called from kernel space */ 2210 bcopy (ctlptr, &ctlbuf, sizeof(ctlbuf)); 2211 bcopy (datptr, &datbuf, sizeof(datbuf)); 2212 } else { 2213 /* called from user space */ 2214 if ((err = copyin(CAST_USER_ADDR_T(ctlptr), 2215 (caddr_t)&ctlbuf, sizeof(ctlbuf))) != 0) 2216 goto l_err; 2217 if ((err = copyin(CAST_USER_ADDR_T(datptr), 2218 (caddr_t)&datbuf, sizeof(datbuf))) != 0) 2219 goto l_err; 2220 } 2221 if ((datbuf.maxlen < 0) || (datbuf.maxlen < gbuf_msgsize(mdata))) { 2222 gbuf_next(mproto) = scb->sess_ioc; 2223 scb->sess_ioc = mproto; 2224 return MOREDATA; 2225 } 2226 2227 if (get_wait == 0) { 2228 /* 2229 * this is a hack to support the select() call. 2230 * we're not supposed to dequeue messages in the Streams 2231 * head's read queue this way; but there is no better way. 2232 */ 2233 if (scb->sess_ioc != 0) 2234 atalk_notify_sel(gref); 2235 2236 } 2237 2238 /* 2239 * copy out the control content and info 2240 */ 2241 ctlbuf.len = gbuf_len(mproto); 2242 2243 if (mreply != NULL) { 2244 /* called from kernel space */ 2245 bcopy (gbuf_rptr(mproto), ctlbuf.buf, ctlbuf.len); 2246 bcopy (&ctlbuf, ctlptr, sizeof(ctlbuf)); 2247 } else { 2248 /* called from user space */ 2249 if ((err = copyout((caddr_t)gbuf_rptr(mproto), 2250 CAST_USER_ADDR_T(ctlbuf.buf), ctlbuf.len)) != 0) 2251 goto l_err; 2252 if ((err = copyout((caddr_t)&ctlbuf, 2253 CAST_USER_ADDR_T(ctlptr), sizeof(ctlbuf))) != 0) 2254 goto l_err; 2255 } 2256 2257 /* 2258 * copy out the data content and info 2259 */ 2260 for (rval = 0, sum = 0; mdata && (rval == 0); mdata = gbuf_cont(mdata)) 2261 { 2262 len = gbuf_len(mdata); 2263 if (len) { 2264 if ((len + sum) > datbuf.maxlen) { 2265 len = datbuf.maxlen - sum; 2266 rval = MOREDATA; 2267 } 2268 2269 if (mreply == NULL) { 2270 /* called from user space */ 2271 if ((err = copyout((caddr_t)gbuf_rptr(mdata), CAST_USER_ADDR_T(&datbuf.buf[sum]), len)) != 0) 2272 goto l_err; 2273 } 2274 sum += len; 2275 } 2276 } 2277 datbuf.len = sum; 2278 if (mreply != NULL) { 2279 /* called from kernel space */ 2280 bcopy (&datbuf, datptr, sizeof(datbuf)); 2281 } else { 2282 /* called from user space */ 2283 if ((err = copyout((caddr_t)&datbuf, CAST_USER_ADDR_T(datptr), sizeof(datbuf))) != 0) 2284 goto l_err; 2285 } 2286 2287 if (mreply != NULL) { 2288 /* called from kernel space */ 2289 /* return the reply data in mbufs, so dont free them. 2290 Just free the proto info */ 2291 mdata = gbuf_cont(mproto); 2292 *mreply = mdata; 2293 gbuf_cont(mproto) = NULL; 2294 gbuf_freem(mproto); 2295 } else { 2296 /* called from user space */ 2297 gbuf_freem(mproto); 2298 } 2299 2300 if (scb->sess_ioc) 2301 scb->rcv_cnt--; 2302 else { 2303 scb->rcv_cnt = 0; 2304 scb->snd_stop = 0; 2305 } 2306 return rval; 2307 2308l_err: 2309 gbuf_next(mproto) = scb->sess_ioc; 2310 scb->sess_ioc = mproto; 2311 *errp = err; 2312 return -1; 2313} 2314