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