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