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