]> git.saurik.com Git - apple/xnu.git/blame - bsd/netat/atp_write.c
xnu-517.3.15.tar.gz
[apple/xnu.git] / bsd / netat / atp_write.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
43866e37 6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
1c79356b 7 *
43866e37
A
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
1c79356b
A
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
43866e37
A
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
1c79356b
A
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25/*
26 * Copyright (c) 1996-1998 Apple Computer, Inc.
27 * All Rights Reserved.
28 */
29
30/* Modified for MP, 1996 by Tuyen Nguyen
31 * Modified, March 17, 1997 by Tuyen Nguyen for MacOSX.
32 */
33#define RESOLVE_DBG
34
35#include <sys/errno.h>
36#include <sys/types.h>
37#include <sys/param.h>
38#include <machine/spl.h>
39#include <sys/systm.h>
40#include <sys/kernel.h>
41#include <sys/proc.h>
42#include <sys/filedesc.h>
43#include <sys/fcntl.h>
44#include <sys/mbuf.h>
45#include <sys/ioctl.h>
46#include <sys/malloc.h>
47#include <sys/socket.h>
48#include <sys/socketvar.h>
49
50#include <net/if.h>
51
52#include <netat/sysglue.h>
53#include <netat/appletalk.h>
54#include <netat/ddp.h>
55#include <netat/at_pcb.h>
56#include <netat/atp.h>
57#include <netat/at_var.h>
58#include <netat/asp.h>
59#include <netat/at_pat.h>
60#include <netat/debug.h>
61
62static int loop_cnt; /* for debugging loops */
63#define CHK_LOOP(str) { \
64 if (loop_cnt++ > 100) { \
65 kprintf("%s", str); \
66 break; \
67 } \
68}
69
70static void atp_pack_bdsp(struct atp_trans *, struct atpBDS *);
71static int atp_unpack_bdsp(struct atp_state *, gbuf_t *, struct atp_rcb *,
72 int, int);
55e303ae 73void atp_trp_clock(), asp_clock(), asp_clock_funnel(), atp_trp_clock_funnel();;
1c79356b
A
74
75extern struct atp_rcb_qhead atp_need_rel;
76extern int atp_inited;
77extern struct atp_state *atp_used_list;
78extern asp_scb_t *scb_free_list;
79extern atlock_t atpgen_lock;
80extern atlock_t atpall_lock;
81extern atlock_t atptmo_lock;
82
83extern gbuf_t *scb_resource_m;
84extern gbuf_t *atp_resource_m;
85extern gref_t *atp_inputQ[];
86extern int atp_pidM[];
87extern at_ifaddr_t *ifID_home;
88
89static struct atp_trans *trp_tmo_list;
90struct atp_trans *trp_tmo_rcb;
91
92/* first bds entry gives number of bds entries in total (hack) */
93#define get_bds_entries(m) \
94 ((gbuf_len(m) > TOTAL_ATP_HDR_SIZE)? \
95 (UAS_VALUE(((struct atpBDS *)(AT_ATP_HDR(m)->data))->bdsDataSz)): 0)
96
97#define atpBDSsize (sizeof(struct atpBDS)*ATP_TRESP_MAX)
98
99void atp_link()
100{
101 trp_tmo_list = 0;
102 trp_tmo_rcb = atp_trans_alloc(0);
103 atp_timout(atp_rcb_timer, trp_tmo_rcb, 10 * HZ);
104 atp_trp_clock((void *)&atp_inited);
105 asp_clock((void *)&atp_inited);
106}
107
108void atp_unlink()
109{
110 untimeout(asp_clock_funnel, (void *)&atp_inited);
111 untimeout(atp_trp_clock_funnel, (void *)&atp_inited);
112 atp_untimout(atp_rcb_timer, trp_tmo_rcb);
113 trp_tmo_list = 0;
114
115#ifdef BAD_IDEA
116 /* allocated in asp_scb_alloc(), which is called
117 by asp_open() */
118 if (scb_resource_m) {
119 gbuf_freem(scb_resource_m);
120 scb_resource_m = 0;
121 scb_free_list = 0;
122 }
123 /* allocated in atp_trans_alloc() */
124 if (atp_resource_m) {
125 gbuf_freem(atp_resource_m);
126 atp_resource_m = 0;
127 atp_trans_free_list = 0;
128 }
129#endif
130}
131
132/*
133 * write queue put routine .... filter out other than IOCTLs
134 * Version 1.8 of atp_write.c on 89/02/09 17:53:26
135 */
136
137void
138atp_wput(gref, m)
139 register gref_t *gref;
140 register gbuf_t *m;
141{
142 register ioc_t *iocbp;
143 int i, xcnt, s;
144 struct atp_state *atp;
145 struct atp_trans *trp;
146 struct atp_rcb *rcbp;
147 at_socket skt;
148
149 atp = (struct atp_state *)gref->info;
150 if (atp->dflag)
151 atp = (struct atp_state *)atp->atp_msgq;
152
153 switch(gbuf_type(m)) {
154 case MSG_DATA:
155 if (atp->atp_msgq) {
156 gbuf_freem(m);
157 dPrintf(D_M_ATP, D_L_WARNING,
158 ("atp_wput: atp_msgq discarded\n"));
159 } else
160 atp->atp_msgq = m;
161 break;
162
163 case MSG_IOCTL:
164 /* Need to ensure that all copyin/copyout calls are made at
165 * put routine time which should be in the user context. (true when
166 * we are the stream head). The service routine can be called on an
167 * unpredictable context and copyin/copyout calls will get wrong results
168 * or even panic the kernel.
169 */
170 iocbp = (ioc_t *)gbuf_rptr(m);
171
172 switch (iocbp->ioc_cmd) {
173 case AT_ATP_BIND_REQ:
174 if (gbuf_cont(m) == NULL) {
175 iocbp->ioc_rval = -1;
176 atp_iocnak(atp, m, EINVAL);
177 return;
178 }
179 skt = *(at_socket *)gbuf_rptr(gbuf_cont(m));
180 if ((skt = (at_socket)atp_bind(gref, (unsigned int)skt, 0)) == 0)
181 atp_iocnak(atp, m, EINVAL);
182 else {
183 *(at_socket *)gbuf_rptr(gbuf_cont(m)) = skt;
184 iocbp->ioc_rval = 0;
185 atp_iocack(atp, m);
186 atp_dequeue_atp(atp);
187 }
188 return;
189
190 case AT_ATP_GET_CHANID:
191 if (gbuf_cont(m) == NULL) {
192 iocbp->ioc_rval = -1;
193 atp_iocnak(atp, m, EINVAL);
194 return;
195 }
196 *(gref_t **)gbuf_rptr(gbuf_cont(m)) = gref;
197 atp_iocack(atp, m);
198 return;
199
200 /* not the close and not the tickle(?) */
201 case AT_ATP_ISSUE_REQUEST_DEF:
202 case AT_ATP_ISSUE_REQUEST_DEF_NOTE: {
203 gbuf_t *bds, *tmp, *m2;
204 struct atp_rcb *rcbp;
205 at_ddp_t *ddp;
206 at_atp_t *athp;
207
208 if ((tmp = gbuf_cont(m)) != 0) {
209 if ((bds = gbuf_dupb(tmp)) == NULL) {
210 atp_iocnak(atp, m, ENOBUFS);
211 return;
212 }
213 gbuf_rinc(tmp,atpBDSsize);
214 gbuf_wset(bds,atpBDSsize);
215 iocbp->ioc_count -= atpBDSsize;
216 gbuf_cont(tmp) = bds;
217 }
218
219 /*
220 * send a response to a transaction
221 * first check it out
222 */
223 if (iocbp->ioc_count < TOTAL_ATP_HDR_SIZE) {
224 atp_iocnak(atp, m, EINVAL);
225 break;
226 }
227
228 /*
229 * remove the response from the message
230 */
231 m2 = gbuf_cont(m);
232 gbuf_cont(m) = NULL;
233 iocbp->ioc_count = 0;
234 ddp = AT_DDP_HDR(m2);
235 athp = AT_ATP_HDR(m2);
236 if (atp->atp_msgq) {
237 gbuf_cont(m2) = atp->atp_msgq;
238 atp->atp_msgq = 0;
239 }
240
241 ATDISABLE(s, atp->atp_lock);
242 /*
243 * search for the corresponding rcb
244 */
245 for (rcbp = atp->atp_rcb.head; rcbp; rcbp = rcbp->rc_list.next) {
246 if (rcbp->rc_tid == UAS_VALUE(athp->tid) &&
247 rcbp->rc_socket.node == ddp->dst_node &&
248 rcbp->rc_socket.net == NET_VALUE(ddp->dst_net) &&
249 rcbp->rc_socket.socket == ddp->dst_socket)
250 break;
251 }
252 ATENABLE(s, atp->atp_lock);
253
254 /*
255 * If it has already been sent then return an error
256 */
257 if ((rcbp && rcbp->rc_state != RCB_NOTIFIED) ||
258 (rcbp == NULL && athp->xo)) {
259 atp_iocnak(atp, m, ENOENT);
260 gbuf_freem(m2);
261 return;
262 }
263 if (rcbp == NULL) { /* a response for an ALO transaction */
264 if ((rcbp = atp_rcb_alloc(atp)) == NULL) {
265 atp_iocnak(atp, m, ENOBUFS);
266 gbuf_freem(m2);
267 return;
268 }
269 rcbp->rc_ioctl = 0;
270 rcbp->rc_socket.socket = ddp->dst_socket;
271 rcbp->rc_socket.node = ddp->dst_node;
272 rcbp->rc_socket.net = NET_VALUE(ddp->dst_net);
273 rcbp->rc_tid = UAS_VALUE(athp->tid);
274 rcbp->rc_bitmap = 0xff;
275 rcbp->rc_xo = 0;
276 ATDISABLE(s, atp->atp_lock);
277 rcbp->rc_state = RCB_SENDING;
278 ATP_Q_APPEND(atp->atp_rcb, rcbp, rc_list);
279 ATENABLE(s, atp->atp_lock);
280 }
281 xcnt = get_bds_entries(m2);
282 if ((i = atp_unpack_bdsp(atp, m2, rcbp, xcnt, FALSE))) {
283 if ( !rcbp->rc_xo)
284 atp_rcb_free(rcbp);
285 atp_iocnak(atp, m, i);
286 return;
287 }
288 atp_send_replies(atp, rcbp);
289
290 /*
291 * send the ack back to the responder
292 */
293 atp_iocack(atp, m);
294 return;
295 }
296
297 case AT_ATP_GET_POLL: {
298 if (gbuf_cont(m)) {
299 gbuf_freem(gbuf_cont(m));
300 gbuf_cont(m) = NULL;
301 iocbp->ioc_count = 0;
302 }
303
304 /*
305 * search for a waiting request
306 */
307 ATDISABLE(s, atp->atp_lock);
308 if ((rcbp = atp->atp_attached.head)) {
309 /*
310 * Got one, move it to the active response Q
311 */
312 gbuf_cont(m) = rcbp->rc_ioctl;
313 rcbp->rc_ioctl = NULL;
314 if (rcbp->rc_xo) {
315 ATP_Q_REMOVE(atp->atp_attached, rcbp, rc_list);
316 rcbp->rc_state = RCB_NOTIFIED;
317 ATP_Q_APPEND(atp->atp_rcb, rcbp, rc_list);
318 } else {
319 /* detach rcbp from attached queue,
320 * and free any outstanding resources
321 */
322 atp_rcb_free(rcbp);
323 }
324 ATENABLE(s, atp->atp_lock);
325 atp_iocack(atp, m);
326 } else {
327 /*
328 * None available - can out
329 */
330 ATENABLE(s, atp->atp_lock);
331 atp_iocnak(atp, m, EAGAIN);
332 }
333 break;
334 }
335
336 case AT_ATP_CANCEL_REQUEST: {
337 /*
338 * Cancel a pending request
339 */
340 if (iocbp->ioc_count != sizeof(int)) {
341 atp_iocnak(atp, m, EINVAL);
342 break;
343 }
344 i = *(int *)gbuf_rptr(gbuf_cont(m));
345 gbuf_freem(gbuf_cont(m));
346 gbuf_cont(m) = NULL;
347 ATDISABLE(s, atp->atp_lock);
348 for (trp = atp->atp_trans_wait.head; trp; trp = trp->tr_list.next) {
349 if (trp->tr_tid == i)
350 break;
351 }
352 if (trp == NULL) {
353 ATENABLE(s, atp->atp_lock);
354 atp_iocnak(atp, m, ENOENT);
355 } else {
356 ATENABLE(s, atp->atp_lock);
357 atp_free(trp);
358 atp_iocack(atp, m);
359 }
360 break;
361 }
362
363 case AT_ATP_PEEK: {
364 unsigned char event;
365 if (atalk_peek(gref, &event) == -1)
366 atp_iocnak(atp, m, EAGAIN);
367 else {
368 *gbuf_rptr(gbuf_cont(m)) = event;
369 atp_iocack(atp, m);
370 }
371 break;
372 }
373
374 case DDP_IOC_GET_CFG:
375#ifdef APPLETALK_DEBUG
376 kprintf("atp_wput: DDP_IOC_GET_CFG\n");
377#endif
378 if (gbuf_cont(m) == 0) {
379 atp_iocnak(atp, m, EINVAL);
380 break;
381 }
382 {
383 /* *** was ddp_get_cfg() *** */
384 ddp_addr_t *cfgp =
385 (ddp_addr_t *)gbuf_rptr(gbuf_cont(m));
386 cfgp->inet.net = ifID_home->ifThisNode.s_net;
387 cfgp->inet.node = ifID_home->ifThisNode.s_node;
388 cfgp->inet.socket = atp->atp_socket_no;
389 cfgp->ddptype = DDP_ATP;
390#ifdef NOT_YET
391 cfgp->inet.net = atp->atp_gref->laddr.s_net;
392 cfgp->inet.node = atp->atp_gref->laddr.s_node;
393 cfgp->inet.socket = atp->atp_gref->lport;
394 cfgp->ddptype = atp->atp_gref->ddptype;
395#endif
396 }
397 gbuf_wset(gbuf_cont(m), sizeof(ddp_addr_t));
398 atp_iocack(atp, m);
399 break;
400
401 default:
402 /*
403 * Otherwise pass it on, if possible
404 */
405 iocbp->ioc_private = (void *)gref;
406 DDP_OUTPUT(m);
407 break;
408 }
409 break;
410
411 default:
412 gbuf_freem(m);
413 break;
414 }
415} /* atp_wput */
416
417gbuf_t *atp_build_release(trp)
418register struct atp_trans *trp;
419{
420 register gbuf_t *m;
421 register at_ddp_t *ddp;
422 register at_atp_t *athp;
423
424 /*
425 * Now try and allocate enough space to send the message
426 * if none is available the caller will schedule
427 * a timeout so we can retry for more space soon
428 */
429 if ((m = (gbuf_t *)gbuf_alloc(AT_WR_OFFSET+ATP_HDR_SIZE, PRI_HI)) != NULL) {
430 gbuf_rinc(m,AT_WR_OFFSET);
431 gbuf_wset(m,TOTAL_ATP_HDR_SIZE);
432 ddp = AT_DDP_HDR(m);
433 ddp->type = DDP_ATP;
434 UAS_ASSIGN(ddp->checksum, 0);
435 ddp->dst_socket = trp->tr_socket.socket;
436 ddp->dst_node = trp->tr_socket.node;
437 NET_ASSIGN(ddp->dst_net, trp->tr_socket.net);
438 ddp->src_node = trp->tr_local_node;
439 NET_NET(ddp->src_net, trp->tr_local_net);
440
441 /*
442 * clear the cmd/xo/eom/sts/unused fields
443 */
444 athp = AT_ATP_HDR(m);
445 ATP_CLEAR_CONTROL(athp);
446 athp->cmd = ATP_CMD_TREL;
447 UAS_ASSIGN(athp->tid, trp->tr_tid);
448 }
449
450 return (m);
451}
452
453void atp_send_replies(atp, rcbp)
454 register struct atp_state *atp;
455 register struct atp_rcb *rcbp;
456{ register gbuf_t *m;
457 register int i, len;
55e303ae 458 int s_gen, s, cnt, err, offset, space;
1c79356b
A
459 unsigned char *m0_rptr = NULL, *m0_wptr = NULL;
460 register at_atp_t *athp;
461 register struct atpBDS *bdsp;
55e303ae 462 register gbuf_t *m2, *m1, *m0, *mhdr;
0b4e3aa0 463 caddr_t lastPage;
1c79356b
A
464 gbuf_t *mprev, *mlist = 0;
465 at_socket src_socket = (at_socket)atp->atp_socket_no;
466 gbuf_t *rc_xmt[ATP_TRESP_MAX];
467 struct ddp_atp {
468 char ddp_atp_hdr[TOTAL_ATP_HDR_SIZE];
469 };
470
471 ATDISABLE(s, atp->atp_lock);
472 if (rcbp->rc_queue != atp) {
473 ATENABLE(s, atp->atp_lock);
474 return;
475 }
476 if (rcbp->rc_not_sent_bitmap == 0)
477 goto nothing_to_send;
478
479 dPrintf(D_M_ATP_LOW, D_L_OUTPUT, ("atp_send_replies\n"));
480 /*
481 * Do this for each message that hasn't been sent
482 */
483 cnt = rcbp->rc_pktcnt;
484 for (i = 0; i < cnt; i++) {
485 rc_xmt[i] = 0;
486 if (rcbp->rc_snd[i]) {
487 if ((rc_xmt[i] =
488 gbuf_alloc(AT_WR_OFFSET+TOTAL_ATP_HDR_SIZE,PRI_MED))
489 == NULL) {
490 for (cnt = 0; cnt < i; cnt++)
491 if (rc_xmt[cnt])
492 gbuf_freeb(rc_xmt[cnt]);
493 goto nothing_to_send;
494 }
495 }
496 }
497
498 m = rcbp->rc_xmt;
499 m0 = gbuf_cont(m);
1c79356b
A
500 if (gbuf_len(m) > TOTAL_ATP_HDR_SIZE)
501 bdsp = (struct atpBDS *)(AT_ATP_HDR(m)->data);
502 else
503 bdsp = 0;
55e303ae
A
504 offset = 0;
505 if (m0)
506 space = gbuf_msgsize(m0);
1c79356b 507 for (i = 0; i < cnt; i++) {
55e303ae
A
508 if (rcbp->rc_snd[i] == 0) {
509 if ((len = UAS_VALUE(bdsp->bdsBuffSz))) {
510 offset += len;
511 space -= len;
1c79356b 512 }
55e303ae
A
513 } else {
514 mhdr = rc_xmt[i];
515 /* setup header fields */
516 gbuf_rinc(mhdr,AT_WR_OFFSET);
517 gbuf_wset(mhdr,TOTAL_ATP_HDR_SIZE);
518 *(struct ddp_atp *)(gbuf_rptr(mhdr))= *(struct ddp_atp *)(gbuf_rptr(m));
519 athp = AT_ATP_HDR(mhdr);
520 ATP_CLEAR_CONTROL(athp);
521 athp->cmd = ATP_CMD_TRESP;
522 athp->bitmap = i;
523 if (i == (cnt - 1))
524 athp->eom = 1; /* for the last fragment */
525 if (bdsp) {
526 UAL_UAL(athp->user_bytes, bdsp->bdsUserData);
527 if ((len = UAS_VALUE(bdsp->bdsBuffSz)) && m0 != 0 && space > 0) {
528 if ((m1 = m_copym(m0, offset, len, M_DONTWAIT)) == 0) {
529 for (i = 0; i < cnt; i++)
530 if (rc_xmt[i])
531 gbuf_freem(rc_xmt[i]);
532 goto nothing_to_send;
533 }
534 offset += len;
535 space -= len;
536 gbuf_cont(mhdr) = m1;
1c79356b 537 }
55e303ae 538 }
0b4e3aa0 539
55e303ae
A
540 AT_DDP_HDR(mhdr)->src_socket = src_socket;
541 dPrintf(D_M_ATP_LOW, D_L_OUTPUT,
542 ("atp_send_replies: %d, socket=%d, size=%d\n",
543 i, atp->atp_socket_no, gbuf_msgsize(gbuf_cont(m2))));
544
545 if (mlist)
546 gbuf_next(mprev) = mhdr;
547 else
548 mlist = mhdr;
549 mprev = mhdr;
550
551 rcbp->rc_snd[i] = 0;
552 rcbp->rc_not_sent_bitmap &= ~atp_mask[i];
553 if (rcbp->rc_not_sent_bitmap == 0)
554 break;
1c79356b 555 }
55e303ae
A
556 /*
557 * on to the next frag
558 */
559 bdsp++;
de355530 560 }
1c79356b
A
561 if (mlist) {
562 ATENABLE(s, atp->atp_lock);
563 DDP_OUTPUT(mlist);
564 ATDISABLE(s, atp->atp_lock);
565 }
566
567nothing_to_send:
568 /*
569 * If all replies from this reply block have been sent then
570 * remove it from the queue and mark it so
571 */
572 if (rcbp->rc_queue != atp) {
573 ATENABLE(s, atp->atp_lock);
574 return;
575 }
576 rcbp->rc_rep_waiting = 0;
577
578 /*
579 * If we are doing execute once re-set the rcb timeout
580 * each time we send back any part of the response. Note
581 * that this timer is started when an initial request is
582 * received. Each response reprimes the timer. Duplicate
583 * requests do not reprime the timer.
584 *
585 * We have sent all of a response so free the
586 * resources.
587 */
588 if (rcbp->rc_xo && rcbp->rc_state != RCB_RELEASED) {
589 ATDISABLE(s_gen, atpgen_lock);
590 if (rcbp->rc_timestamp == 0) {
591 rcbp->rc_timestamp = time.tv_sec;
592 if (rcbp->rc_timestamp == 0)
593 rcbp->rc_timestamp = 1;
594 ATP_Q_APPEND(atp_need_rel, rcbp, rc_tlist);
595 }
596 rcbp->rc_state = RCB_RESPONSE_FULL;
597 ATENABLE(s_gen, atpgen_lock);
598 } else
599 atp_rcb_free(rcbp);
600 ATENABLE(s, atp->atp_lock);
601} /* atp_send_replies */
602
603
604static void
605atp_pack_bdsp(trp, bdsp)
606 register struct atp_trans *trp;
607 register struct atpBDS *bdsp;
608{
609 register gbuf_t *m = NULL;
610 register int i, datsize = 0;
611 struct atpBDS *bdsbase = bdsp;
612
613 dPrintf(D_M_ATP, D_L_INFO, ("atp_pack_bdsp: socket=%d\n",
614 trp->tr_queue->atp_socket_no));
615
616 for (i = 0; i < ATP_TRESP_MAX; i++, bdsp++) {
617 short bufsize = UAS_VALUE(bdsp->bdsBuffSz);
618 long bufaddr = UAL_VALUE(bdsp->bdsBuffAddr);
619
620 if ((m = trp->tr_rcv[i]) == NULL)
621 break;
622
623 /* discard ddp hdr on first packet */
624 if (i == 0)
625 gbuf_rinc(m,DDP_X_HDR_SIZE);
626
627 /* this field may contain control information even when
628 no data is present */
629 UAL_UAL(bdsp->bdsUserData,
630 (((at_atp_t *)(gbuf_rptr(m)))->user_bytes));
631 gbuf_rinc(m, ATP_HDR_SIZE);
632
633 if ((bufsize != 0) && (bufaddr != 0)) {
634 /* user expects data back */
635 short tmp = 0;
636 register char *buf = (char *)bufaddr;
637
638 while (m) {
639 short len = (short)(gbuf_len(m));
640 if (len) {
641 if (len > bufsize)
642 len = bufsize;
643 copyout((caddr_t)gbuf_rptr(m),
644 (caddr_t)&buf[tmp],
645 len);
646 bufsize -= len;
647 tmp =+ len;
648 }
649 m = gbuf_cont(m);
650 }
651
652 UAS_ASSIGN(bdsp->bdsDataSz, tmp);
653 datsize += (int)tmp;
654 }
655 gbuf_freem(trp->tr_rcv[i]);
656 trp->tr_rcv[i] = NULL;
657 }
658
659 /* report the number of packets */
660 UAS_ASSIGN(((struct atpBDS *)bdsbase)->bdsBuffSz, i);
661
662 dPrintf(D_M_ATP, D_L_INFO, (" : size=%d\n",
663 datsize));
664} /* atp_pack_bdsp */
665
666
55e303ae
A
667/* create an mbuf chain with mbuf packet headers for each ATP response packet
668 * to be sent. m contains the DDP hdr, ATP hdr, and and array of atpBDS structs.
669 * chained to m is an mbuf that contians the actual data pointed to by the atpBDS
670 * structs.
671 */
1c79356b
A
672static int
673atp_unpack_bdsp(atp, m, rcbp, cnt, wait)
674 struct atp_state *atp;
675 gbuf_t *m; /* ddp, atp and bdsp gbuf_t */
676 register struct atp_rcb *rcbp;
0b4e3aa0 677 register int cnt, wait;
1c79356b
A
678{
679 register struct atpBDS *bdsp;
55e303ae
A
680 register gbuf_t *m2, *m1, *m0, *mhdr;
681 caddr_t lastPage;
682 at_atp_t *athp;
683 int i, len, s_gen;
684 at_socket src_socket;
685
686 struct ddp_atp {
1c79356b
A
687 char ddp_atp_hdr[TOTAL_ATP_HDR_SIZE];
688 };
55e303ae
A
689 gbuf_t *mprev, *mlist = 0;
690 gbuf_t *rc_xmt[ATP_TRESP_MAX];
691 unsigned char *m0_rptr, *m0_wptr;
692 int err, offset, space;
1c79356b
A
693
694 /*
695 * get the user data structure pointer
696 */
697 bdsp = (struct atpBDS *)(AT_ATP_HDR(m)->data);
698
699 /*
700 * Guard against bogus count argument.
701 */
702 if ((unsigned) cnt > ATP_TRESP_MAX) {
703 dPrintf(D_M_ATP, D_L_ERROR,
704 ("atp_unpack_bdsp: bad bds count 0x%x\n", cnt));
705 gbuf_freem(m);
706 return(EINVAL);
707 }
708 if ((src_socket = (at_socket)atp->atp_socket_no) == 0xFF) {
709 /* comparison was to -1, however src_socket is a u_char */
710 gbuf_freem(m);
711 return EPIPE;
712 }
713
714 m0 = gbuf_cont(m);
715 rcbp->rc_xmt = m;
716 rcbp->rc_pktcnt = cnt;
717 rcbp->rc_state = RCB_SENDING;
718 rcbp->rc_not_sent_bitmap = 0;
719
720 if (cnt <= 1) {
721 /*
722 * special case this to
723 * improve AFP write transactions to the server
724 */
725 rcbp->rc_pktcnt = 1;
726 if ((m2 = gbuf_alloc_wait(AT_WR_OFFSET+TOTAL_ATP_HDR_SIZE,
727 wait)) == NULL)
728 return 0;
729 gbuf_rinc(m2,AT_WR_OFFSET);
730 gbuf_wset(m2,TOTAL_ATP_HDR_SIZE);
731 *(struct ddp_atp *)(gbuf_rptr(m2))= *(struct ddp_atp *)(gbuf_rptr(m));
732 athp = AT_ATP_HDR(m2);
733 ATP_CLEAR_CONTROL(athp);
734 athp->cmd = ATP_CMD_TRESP;
735 athp->bitmap = 0;
736 athp->eom = 1; /* there's only 1 fragment */
737
738 /* *** why only if cnt > 0? *** */
739 if (cnt > 0)
740 UAL_UAL(athp->user_bytes, bdsp->bdsUserData);
741 if (m0)
742 if (!append_copy((struct mbuf *)m2,
743 (struct mbuf *)m0, wait)) {
744 gbuf_freeb(m2);
745 return 0;
746 }
747 /*
748 * send the message and mark it as sent
749 */
750 AT_DDP_HDR(m2)->src_socket = src_socket;
751 dPrintf(D_M_ATP_LOW, D_L_INFO,
752 ("atp_unpack_bdsp %d, socket=%d, size=%d, cnt=%d\n",
753 0,atp->atp_socket_no,gbuf_msgsize(gbuf_cont(m2)),cnt));
754 mlist = m2;
755 goto l_send;
756 }
757
55e303ae
A
758 /* create an array of mbuf packet headers for the packets to be sent
759 * to contain the atp and ddp headers with room at the front for the
760 * datalink header.
761 */
1c79356b
A
762 for (i = 0; i < cnt; i++) {
763 /* all hdrs, packet data and dst addr storage */
764 if ((rc_xmt[i] =
55e303ae
A
765 gbuf_alloc_wait(AT_WR_OFFSET+TOTAL_ATP_HDR_SIZE, wait)) == NULL) {
766 for (cnt = 0; cnt < i; cnt++)
767 if (rc_xmt[cnt])
768 gbuf_freeb(rc_xmt[cnt]);
769 return 0;
1c79356b
A
770 }
771 }
1c79356b 772
55e303ae
A
773 /* run through the atpBDS structs and create an mbuf for the data
774 * portion of each packet to be sent. these get chained to the mbufs
775 * containing the ATP and DDP headers. this code assumes that no ATP
776 * packet is contained in more than 2 mbufs (e.i crosses mbuf boundary
777 * no more than one time).
778 */
779 offset = 0;
780 if (m0)
781 space = gbuf_msgsize(m0);
782 for (i = 0; i < cnt; i++) { /* for each hdr mbuf */
783 mhdr = rc_xmt[i];
784 /* setup header fields */
785 gbuf_rinc(mhdr,AT_WR_OFFSET);
786 gbuf_wset(mhdr,TOTAL_ATP_HDR_SIZE);
787 *(struct ddp_atp *)(gbuf_rptr(mhdr))= *(struct ddp_atp *)(gbuf_rptr(m));
788 athp = AT_ATP_HDR(mhdr);
1c79356b
A
789 ATP_CLEAR_CONTROL(athp);
790 athp->cmd = ATP_CMD_TRESP;
791 athp->bitmap = i;
792 if (i == (cnt - 1))
793 athp->eom = 1; /* for the last fragment */
794 UAL_UAL(athp->user_bytes, bdsp->bdsUserData);
55e303ae
A
795
796 if ((len = UAS_VALUE(bdsp->bdsBuffSz)) != 0 && m0 != 0 && space > 0) {
797 if ((m1 = m_copym(m0, offset, len, wait)) == 0) {
1c79356b
A
798 for (i = 0; i < cnt; i++)
799 if (rc_xmt[i])
800 gbuf_freem(rc_xmt[i]);
1c79356b
A
801 return 0;
802 }
55e303ae
A
803 gbuf_cont(mhdr) = m1;
804 space -= len;
805 offset += len;
0b4e3aa0 806 }
55e303ae
A
807
808 AT_DDP_HDR(mhdr)->src_socket = src_socket;
1c79356b
A
809 dPrintf(D_M_ATP_LOW,D_L_INFO,
810 ("atp_unpack_bdsp %d, socket=%d, size=%d, cnt=%d\n",
55e303ae 811 i,atp->atp_socket_no,gbuf_msgsize(gbuf_cont(mhdr)),cnt));
1c79356b 812 if (mlist)
55e303ae 813 gbuf_next(mprev) = mhdr;
1c79356b 814 else
55e303ae
A
815 mlist = mhdr;
816 mprev = mhdr;
1c79356b
A
817 /*
818 * on to the next frag
819 */
820 bdsp++;
821 }
1c79356b
A
822 /*
823 * send the message
824 */
825l_send:
826 if (rcbp->rc_xo) {
827 ATDISABLE(s_gen, atpgen_lock);
828 if (rcbp->rc_timestamp == 0) {
829 if ((rcbp->rc_timestamp = time.tv_sec) == 0)
830 rcbp->rc_timestamp = 1;
831 ATP_Q_APPEND(atp_need_rel, rcbp, rc_tlist);
832 }
833 ATENABLE(s_gen, atpgen_lock);
834 }
835
836 DDP_OUTPUT(mlist);
837 return 0;
55e303ae 838
1c79356b
A
839} /* atp_unpack_bdsp */
840
841#define ATP_SOCKET_LAST (DDP_SOCKET_LAST-6)
14353aa8 842#define ATP_SOCKET_FIRST (DDP_SOCKET_1st_DYNAMIC)
1c79356b
A
843static unsigned int sNext = 0;
844
845int atp_bind(gref, sVal, flag)
846 gref_t *gref;
847 unsigned int sVal;
848 unsigned char *flag;
849{
850 extern unsigned char asp_inpC[];
851 extern asp_scb_t *asp_scbQ[];
852 unsigned char inpC, sNextUsed = 0;
853 unsigned int sMin, sMax, sSav;
854 struct atp_state *atp;
855 int s;
856
857 atp = (struct atp_state *)gref->info;
858 if (atp->dflag)
859 atp = (struct atp_state *)atp->atp_msgq;
860
861 sMax = ATP_SOCKET_LAST;
862 sMin = ATP_SOCKET_FIRST;
863 ATDISABLE(s, atpgen_lock);
864 if (flag && (*flag == 3)) {
865 sMin += 40;
866 if (sMin < sNext) {
867 sMin = sNext;
868 sNextUsed = 1;
869 }
870 }
871
872 if ( (sVal != 0) &&
873 ((sVal > sMax) || (sVal < 2) || (sVal == 6) ||
874 (ddp_socket_inuse(sVal, DDP_ATP) &&
875 (atp_inputQ[sVal] != (gref_t *)1)))) {
876 ATENABLE(s, atpgen_lock);
877 return 0;
878 }
879
880 if (sVal == 0) {
881 inpC = 255;
882again:
883 for (sVal=sMin; sVal <= sMax; sVal++) {
884 if (!ddp_socket_inuse(sVal, DDP_ATP) ||
885 atp_inputQ[sVal] == (gref_t *)1)
886 break;
887 else if (flag && (*flag == 3) && asp_scbQ[sVal]) {
888 if ((asp_scbQ[sVal]->dflag == *flag)
889 && (asp_inpC[sVal] < inpC) ) {
890 inpC = asp_inpC[sVal];
891 sSav = sVal;
892 }
893 }
894 }
895 if (sVal > sMax) {
896 if (flag && (*flag == 3)) {
897 if (sNextUsed) {
898 sNextUsed = 0;
899 sMax = sNext - 1;
900 sMin = ATP_SOCKET_FIRST+40;
901 goto again;
902 }
903 sNext = 0;
904 *flag = (unsigned char)sSav;
905 }
906 ATENABLE(s, atpgen_lock);
907 return 0;
908 }
909 }
910 atp->atp_socket_no = (short)sVal;
911 atp_inputQ[sVal] = gref;
912 if (flag == 0)
913 atp_pidM[sVal] = atp->atp_pid;
914 else if (*flag == 3) {
915 sNext = sVal + 1;
916 if (sNext > ATP_SOCKET_LAST)
917 sNext = 0;
918 }
919
920 ATENABLE(s, atpgen_lock);
921 return (int)sVal;
922}
923
924void atp_req_ind(atp, mioc)
925 register struct atp_state *atp;
926 register gbuf_t *mioc;
927{
928 register struct atp_rcb *rcbp;
929 int s;
930
931 if ((rcbp = atp->atp_attached.head) != 0) {
932 gbuf_cont(mioc) = rcbp->rc_ioctl;
933 rcbp->rc_ioctl = NULL;
934 ATDISABLE(s, atp->atp_lock);
935 if (rcbp->rc_xo) {
936 ATP_Q_REMOVE(atp->atp_attached, rcbp, rc_list);
937 rcbp->rc_state = RCB_NOTIFIED;
938 ATP_Q_APPEND(atp->atp_rcb, rcbp, rc_list);
939 } else
940 atp_rcb_free(rcbp);
941 ATENABLE(s, atp->atp_lock);
942 if (gbuf_cont(mioc))
943 ((ioc_t *)gbuf_rptr(mioc))->ioc_count = gbuf_msgsize(gbuf_cont(mioc));
944 else
945 ((ioc_t *)gbuf_rptr(mioc))->ioc_count = 0;
946 asp_ack_reply(atp->atp_gref, mioc);
947 } else
948 gbuf_freeb(mioc);
949}
950
951void atp_rsp_ind(trp, mioc)
952 register struct atp_trans *trp;
953 register gbuf_t *mioc;
954{
955 register struct atp_state *atp = trp->tr_queue;
956 register int err;
957 gbuf_t *xm = 0;
958
959 err = 0;
960 {
961 switch (trp->tr_state) {
962 case TRANS_DONE:
963 if (asp_pack_bdsp(trp, &xm) < 0)
964 err = EFAULT;
965 gbuf_cont(mioc) = trp->tr_xmt;
966 trp->tr_xmt = NULL;
967 break;
968
969 case TRANS_FAILED:
970 err = ETIMEDOUT;
971 break;
972
973 default:
974 err = ENOENT;
975 break;
976 }
977 atp_free(trp);
978
979 if (err) {
980 dPrintf(D_M_ATP, D_L_ERROR,
981 ("atp_rsp_ind: TRANSACTION error\n"));
982 atp_iocnak(atp, mioc, err);
983 } else {
984 gbuf_cont(gbuf_cont(mioc)) = xm;
985 atp_iocack(atp, mioc);
986 }
987 }
988}
989
990void atp_cancel_req(gref, tid)
991 gref_t *gref;
992 unsigned short tid;
993{
994 int s;
995 struct atp_state *atp;
996 struct atp_trans *trp;
997
998 atp = (struct atp_state *)gref->info;
999 if (atp->dflag)
1000 atp = (struct atp_state *)atp->atp_msgq;
1001
1002 ATDISABLE(s, atp->atp_lock);
1003 for (trp = atp->atp_trans_wait.head; trp; trp = trp->tr_list.next) {
1004 if (trp->tr_tid == tid)
1005 break;
1006 }
1007 ATENABLE(s, atp->atp_lock);
1008 if (trp != NULL)
1009 atp_free(trp);
1010}
1011
1012/*
1013 * remove atp from the use list
1014 */
1015void
1016atp_dequeue_atp(atp)
1017 struct atp_state *atp;
1018{
1019 int s;
1020
1021 ATDISABLE(s, atpall_lock);
1022 if (atp == atp_used_list) {
1023 if ((atp_used_list = atp->atp_trans_waiting) != 0)
1024 atp->atp_trans_waiting->atp_rcb_waiting = 0;
1025 } else if (atp->atp_rcb_waiting) {
1026 if ((atp->atp_rcb_waiting->atp_trans_waiting
1027 = atp->atp_trans_waiting) != 0)
1028 atp->atp_trans_waiting->atp_rcb_waiting = atp->atp_rcb_waiting;
1029 }
1030
1031 atp->atp_trans_waiting = 0;
1032 atp->atp_rcb_waiting = 0;
1033 ATENABLE(s, atpall_lock);
1034}
1035
1036void
1037atp_timout(func, trp, ticks)
1038 void (*func)();
1039 struct atp_trans *trp;
1040 int ticks;
1041{
1042 int s;
1043 unsigned int sum;
1044 struct atp_trans *curr_trp, *prev_trp;
1045
1046 ATDISABLE(s, atptmo_lock);
1047 if (trp->tr_tmo_func) {
1048 ATENABLE(s, atptmo_lock);
1049 return;
1050 }
1051
1052 trp->tr_tmo_func = func;
1053 trp->tr_tmo_delta = 1+(ticks>>5);
1054
1055 if (trp_tmo_list == 0) {
1056 trp->tr_tmo_next = trp->tr_tmo_prev = 0;
1057 trp_tmo_list = trp;
1058 ATENABLE(s, atptmo_lock);
1059 return;
1060 }
1061
1062 prev_trp = 0;
1063 curr_trp = trp_tmo_list;
1064 sum = 0;
1065
1066 while (1) {
1067 sum += curr_trp->tr_tmo_delta;
1068 if (sum > trp->tr_tmo_delta) {
1069 sum -= curr_trp->tr_tmo_delta;
1070 trp->tr_tmo_delta -= sum;
1071 curr_trp->tr_tmo_delta -= trp->tr_tmo_delta;
1072 break;
1073 }
1074 prev_trp = curr_trp;
1075 if ((curr_trp = curr_trp->tr_tmo_next) == 0) {
1076 trp->tr_tmo_delta -= sum;
1077 break;
1078 }
1079 }
1080
1081 if (prev_trp) {
1082 trp->tr_tmo_prev = prev_trp;
1083 if ((trp->tr_tmo_next = prev_trp->tr_tmo_next) != 0)
1084 prev_trp->tr_tmo_next->tr_tmo_prev = trp;
1085 prev_trp->tr_tmo_next = trp;
1086 } else {
1087 trp->tr_tmo_prev = 0;
1088 trp->tr_tmo_next = trp_tmo_list;
1089 trp_tmo_list->tr_tmo_prev = trp;
1090 trp_tmo_list = trp;
1091 }
1092 ATENABLE(s, atptmo_lock);
1093}
1094
1095void
1096atp_untimout(func, trp)
1097 void (*func)();
1098 struct atp_trans *trp;
1099{
1100 int s;
1101
1102 ATDISABLE(s, atptmo_lock);
1103 if (trp->tr_tmo_func == 0) {
1104 ATENABLE(s, atptmo_lock);
1105 return;
1106 }
1107
1108 if (trp_tmo_list == trp) {
1109 if ((trp_tmo_list = trp->tr_tmo_next) != 0) {
1110 trp_tmo_list->tr_tmo_prev = 0;
1111 trp->tr_tmo_next->tr_tmo_delta += trp->tr_tmo_delta;
1112 }
1113 } else {
1114 if ((trp->tr_tmo_prev->tr_tmo_next = trp->tr_tmo_next) != 0) {
1115 trp->tr_tmo_next->tr_tmo_prev = trp->tr_tmo_prev;
1116 trp->tr_tmo_next->tr_tmo_delta += trp->tr_tmo_delta;
1117 }
1118 }
1119 trp->tr_tmo_func = 0;
1120 ATENABLE(s, atptmo_lock);
1121}
1122
1123void
1124atp_trp_clock_funnel(arg)
1125 void *arg;
1126{
1127 thread_funnel_set(network_flock, TRUE);
1128 atp_trp_clock(arg);
1129 thread_funnel_set(network_flock, FALSE);
1130}
1131
1132void
1133atp_trp_clock(arg)
1134 void *arg;
1135{
1136 int s;
1137 struct atp_trans *trp;
1138 void (*tr_tmo_func)();
1139
1140 ATDISABLE(s, atptmo_lock);
1141 if (trp_tmo_list)
1142 trp_tmo_list->tr_tmo_delta--;
1143 while (((trp = trp_tmo_list) != 0) && (trp_tmo_list->tr_tmo_delta == 0)) {
1144 if ((trp_tmo_list = trp->tr_tmo_next) != 0)
1145 trp_tmo_list->tr_tmo_prev = 0;
1146 if ((tr_tmo_func = trp->tr_tmo_func) != 0) {
1147 trp->tr_tmo_func = 0;
1148 ATENABLE(s, atptmo_lock);
1149 (*tr_tmo_func)(trp);
1150 ATDISABLE(s, atptmo_lock);
1151 }
1152 }
1153 ATENABLE(s, atptmo_lock);
1154
1155 timeout(atp_trp_clock_funnel, (void *)arg, (1<<5));
1156}
1157
1158void
1159atp_send_req(gref, mioc)
1160 gref_t *gref;
1161 gbuf_t *mioc;
1162{
1163 register struct atp_state *atp;
1164 register struct atp_trans *trp;
1165 register ioc_t *iocbp;
1166 register at_atp_t *athp;
1167 register at_ddp_t *ddp;
1168 gbuf_t *m, *m2, *bds;
1169 struct atp_set_default *sdb;
1170 int s, old;
1171 unsigned int timer;
1172
1173 atp = (struct atp_state *)((struct atp_state *)gref->info)->atp_msgq;
1174 iocbp = (ioc_t *)gbuf_rptr(mioc);
1175
1176 if ((trp = atp_trans_alloc(atp)) == NULL) {
1177l_retry:
1178 ((asp_scb_t *)gref->info)->stat_msg = mioc;
1179 iocbp->ioc_private = (void *)gref;
1180 timeout(atp_retry_req, mioc, 10);
1181 return;
1182 }
1183
1184 m2 = gbuf_cont(mioc);
1185 if ((bds = gbuf_dupb(m2)) == NULL) {
1186 atp_trans_free(trp);
1187 goto l_retry;
1188 }
1189 gbuf_rinc(m2,atpBDSsize);
1190 gbuf_wset(bds,atpBDSsize);
1191 iocbp->ioc_count -= atpBDSsize;
1192 gbuf_cont(m2) = NULL;
1193
1194 old = iocbp->ioc_cmd;
1195 iocbp->ioc_cmd = AT_ATP_ISSUE_REQUEST;
1196 sdb = (struct atp_set_default *)gbuf_rptr(m2);
1197
1198 /*
1199 * The at_snd_req library routine multiplies seconds by 100.
1200 * We need to divide by 100 in order to obtain the timer.
1201 */
1202 if ((timer = (sdb->def_rate * HZ)/100) == 0)
1203 timer = HZ;
1204 iocbp->ioc_count -= sizeof(struct atp_set_default);
1205 gbuf_rinc(m2,sizeof(struct atp_set_default));
1206
1207 trp->tr_retry = sdb->def_retries;
1208 trp->tr_timeout = timer;
1209 trp->tr_bdsp = bds;
1210 trp->tr_tid = atp_tid(atp);
1211 trp->tr_xmt = mioc;
1212
1213 /*
1214 * Now fill in the header (and remember the bits
1215 * we need to know)
1216 */
1217 athp = AT_ATP_HDR(m2);
1218 athp->cmd = ATP_CMD_TREQ;
1219 UAS_ASSIGN(athp->tid, trp->tr_tid);
1220 athp->eom = 0;
1221 athp->sts = 0;
1222 trp->tr_xo = athp->xo;
1223 trp->tr_bitmap = athp->bitmap;
1224 ddp = AT_DDP_HDR(m2);
1225 ddp->type = DDP_ATP;
1226 ddp->src_socket = (at_socket)atp->atp_socket_no;
1227 trp->tr_socket.socket = ddp->dst_socket;
1228 trp->tr_socket.node = ddp->dst_node;
1229 trp->tr_socket.net = NET_VALUE(ddp->dst_net);
1230 trp->tr_local_socket = atp->atp_socket_no;
1231 trp->tr_local_node = ddp->src_node;
1232 NET_NET(trp->tr_local_net, ddp->src_net);
1233
1234#ifdef NOT_YET
1235 /* save the local information in the gref */
1236 atp->atp_gref->laddr.s_net = NET_VALUE(ddp->src_net);
1237 atp->atp_gref->laddr.s_node = ddp->src_node;
1238 atp->atp_gref->lport = ddp->src_node;
1239 atp->atp_gref->ddptype = DDP_ATP;
1240#endif
1241
1242 /*
1243 * Put us in the transaction waiting queue
1244 */
1245 ATDISABLE(s, atp->atp_lock);
1246 ATP_Q_APPEND(atp->atp_trans_wait, trp, tr_list);
1247 ATENABLE(s, atp->atp_lock);
1248
1249 /*
1250 * Send the message and set the timer
1251 */
1252 m = (gbuf_t *)copy_pkt(m2, sizeof(llc_header_t));
1253 if (!trp->tr_retry && !trp->tr_bitmap && !trp->tr_xo)
1254 atp_x_done(trp); /* no reason to tie up resources */
1255 else
1256 atp_timout(atp_req_timeout, trp, trp->tr_timeout);
1257 if (m) {
1258 trace_mbufs(D_M_ATP_LOW, " s", m);
1259 DDP_OUTPUT(m);
1260 }
1261} /* atp_send_req */
1262
55e303ae
A
1263void atp_retry_req(arg)
1264 void *arg;
1c79356b 1265{
55e303ae 1266 gbuf_t *m = (gbuf_t *)arg;
1c79356b
A
1267 gref_t *gref;
1268 boolean_t funnel_state;
1269
1270 funnel_state = thread_funnel_set(network_flock, TRUE);
1271
1272 gref = (gref_t *)((ioc_t *)gbuf_rptr(m))->ioc_private;
1273 if (gref->info) {
1274 ((asp_scb_t *)gref->info)->stat_msg = 0;
1275 atp_send_req(gref, m);
1276 }
1277 (void) thread_funnel_set(network_flock, FALSE);
1278}
1279
1280void atp_send_rsp(gref, m, wait)
1281 gref_t *gref;
1282 gbuf_t *m;
1283 int wait;
1284{
1285 register struct atp_state *atp;
1286 register struct atp_rcb *rcbp;
1287 register at_atp_t *athp;
1288 register at_ddp_t *ddp;
1289 int s, xcnt;
1290
1291 atp = (struct atp_state *)gref->info;
1292 if (atp->dflag)
1293 atp = (struct atp_state *)atp->atp_msgq;
1294 ddp = AT_DDP_HDR(m);
1295 athp = AT_ATP_HDR(m);
1296
1297 /*
1298 * search for the corresponding rcb
1299 */
1300 ATDISABLE(s, atp->atp_lock);
1301 for (rcbp = atp->atp_rcb.head; rcbp; rcbp = rcbp->rc_list.next) {
1302 if ( (rcbp->rc_tid == UAS_VALUE(athp->tid)) &&
1303 (rcbp->rc_socket.node == ddp->dst_node) &&
1304 (rcbp->rc_socket.net == NET_VALUE(ddp->dst_net)) &&
1305 (rcbp->rc_socket.socket == ddp->dst_socket) )
1306 break;
1307 }
1308
1309 /*
1310 * If it has already been sent then drop the request
1311 */
1312 if ((rcbp && (rcbp->rc_state != RCB_NOTIFIED)) ||
1313 (rcbp == NULL && athp->xo) ) {
1314 ATENABLE(s, atp->atp_lock);
1315 gbuf_freem(m);
1316 return;
1317 }
1318 ATENABLE(s, atp->atp_lock);
1319
1320 if (rcbp == NULL) { /* a response is being sent for an ALO transaction */
1321 if ((rcbp = atp_rcb_alloc(atp)) == NULL) {
1322 gbuf_freem(m);
1323 return;
1324 }
1325 rcbp->rc_ioctl = 0;
1326 rcbp->rc_socket.socket = ddp->dst_socket;
1327 rcbp->rc_socket.node = ddp->dst_node;
1328 rcbp->rc_socket.net = NET_VALUE(ddp->dst_net);
1329 rcbp->rc_tid = UAS_VALUE(athp->tid);
1330 rcbp->rc_bitmap = 0xff;
1331 rcbp->rc_xo = 0;
1332 rcbp->rc_state = RCB_RESPONSE_FULL;
1333 ATDISABLE(s, atp->atp_lock);
1334 ATP_Q_APPEND(atp->atp_rcb, rcbp, rc_list);
1335 ATENABLE(s, atp->atp_lock);
1336 }
1337 else if (ddp->src_node == 0) {
1338 NET_NET(ddp->src_net, rcbp->rc_local_net);
1339 ddp->src_node = rcbp->rc_local_node;
1340 }
1341
1342 xcnt = get_bds_entries(m);
1343 s = atp_unpack_bdsp(atp, m, rcbp, xcnt, wait);
1344 if (s == 0)
1345 atp_send_replies(atp, rcbp);
1346} /* atp_send_rsp */
1347
1348int asp_pack_bdsp(trp, xm)
1349 register struct atp_trans *trp;
1350 gbuf_t **xm;
1351{
1352 register struct atpBDS *bdsp;
1353 register gbuf_t *m, *m2;
1354 register int i;
1355 gbuf_t *m_prev, *m_head = 0;
1356
1357 dPrintf(D_M_ATP, D_L_INFO, ("asp_pack_bdsp: socket=%d\n",
1358 trp->tr_queue->atp_socket_no));
1359
1360 if ((m2 = trp->tr_bdsp) == NULL)
1361 return 0;
1362 trp->tr_bdsp = NULL;
1363 bdsp = (struct atpBDS *)gbuf_rptr(m2);
1364
1365 for (i = 0; (i < ATP_TRESP_MAX &&
1366 bdsp < (struct atpBDS *)(gbuf_wptr(m2))); i++) {
1367 if ((m = trp->tr_rcv[i]) == NULL)
1368 break;
1369 if (i == 0) {
1370 /* discard ddp hdr on first packet */
1371 gbuf_rinc(m,DDP_X_HDR_SIZE);
1372 }
1373
1374 UAL_UAL(bdsp->bdsUserData, (((at_atp_t *)(gbuf_rptr(m)))->user_bytes));
1375 gbuf_rinc(m, ATP_HDR_SIZE);
1376
1377 if (UAL_VALUE(bdsp->bdsBuffAddr)) {
1378 short tmp;
1379
1380 /* user expects data back */
1381 m = gbuf_strip(m);
1382 if (m_head == 0)
1383 m_head = m;
1384 else
1385 gbuf_cont(m_prev) = m;
1386 if (m) {
1387 tmp = (short)gbuf_len(m);
1388 while (gbuf_cont(m)) {
1389 m = gbuf_cont(m);
1390 tmp += (short)(gbuf_len(m));
1391 }
1392 m_prev = m;
1393 }
1394 UAS_ASSIGN(bdsp->bdsDataSz, tmp);
1395 }
1396 trp->tr_rcv[i] = NULL;
1397 bdsp++;
1398
1399 }
1400 /*
1401 * report the number of packets
1402 */
1403 UAS_ASSIGN(((struct atpBDS *)gbuf_rptr(m2))->bdsBuffSz, i);
1404
1405 if (trp->tr_xmt) /* an ioctl block is still held? */
1406 gbuf_cont(trp->tr_xmt) = m2;
1407 else
1408 trp->tr_xmt = m2;
1409
1410 if (m_head)
1411 *xm = m_head;
1412 else
1413 *xm = 0;
1414
1415 dPrintf(D_M_ATP, D_L_INFO, (" : size=%d\n",
1416 gbuf_msgsize(*xm)));
1417
1418 return 0;
1419}
1420
1421/*
1422 * The following routines are direct entries from system
1423 * calls to allow fast sending and recving of ATP data.
1424 */
1425
1426int
1427_ATPsndreq(fd, buf, len, nowait, err, proc)
1428 int fd;
1429 unsigned char *buf;
1430 int len;
1431 int nowait;
1432 int *err;
1433 void *proc;
1434{
1435 gref_t *gref;
1436 int s, rc;
1437 unsigned short tid;
1438 unsigned int timer;
1439 register struct atp_state *atp;
1440 register struct atp_trans *trp;
1441 register ioc_t *iocbp;
1442 register at_atp_t *athp;
1443 register at_ddp_t *ddp;
1444 struct atp_set_default *sdb;
1445 gbuf_t *m2, *m, *mioc;
1446 char bds[atpBDSsize];
1447
1448 if ((*err = atalk_getref(0, fd, &gref, proc)) != 0)
1449 return -1;
1450
1451 if ((gref == 0) || ((atp = (struct atp_state *)gref->info) == 0)
1452 || (atp->atp_flags & ATP_CLOSING)) {
1453 dPrintf(D_M_ATP, D_L_ERROR, ("ATPsndreq: stale handle=0x%x, pid=%d\n",
1454 (u_int) gref, gref->pid));
1455
1456 *err = EINVAL;
1457 return -1;
1458 }
1459
1460 while ((mioc = gbuf_alloc(sizeof(ioc_t), PRI_MED)) == 0) {
1461 ATDISABLE(s, atp->atp_delay_lock);
1462 rc = tsleep(&atp->atp_delay_event, PSOCK | PCATCH, "atpmioc", 10);
1463 ATENABLE(s, atp->atp_delay_lock);
1464 if (rc != 0) {
1465 *err = rc;
1466 return -1;
1467 }
1468
1469 }
1470 gbuf_wset(mioc,sizeof(ioc_t));
1471 len -= atpBDSsize;
1472 while ((m2 = gbuf_alloc(len, PRI_MED)) == 0) {
1473 ATDISABLE(s, atp->atp_delay_lock);
1474 rc = tsleep(&atp->atp_delay_event, PSOCK | PCATCH, "atpm2", 10);
1475 ATENABLE(s, atp->atp_delay_lock);
1476 if (rc != 0) {
1477 gbuf_freeb(mioc);
1478 *err = rc;
1479 return -1;
1480 }
1481 }
1482 gbuf_wset(m2, len);
1483 gbuf_cont(mioc) = m2;
1484 if (((*err = copyin((caddr_t)buf, (caddr_t)bds, atpBDSsize)) != 0)
1485 || ((*err = copyin((caddr_t)&buf[atpBDSsize],
1486 (caddr_t)gbuf_rptr(m2), len)) != 0)) {
1487 gbuf_freem(mioc);
1488 return -1;
1489 }
1490 gbuf_set_type(mioc, MSG_IOCTL);
1491 iocbp = (ioc_t *)gbuf_rptr(mioc);
1492 iocbp->ioc_count = len;
1493 iocbp->ioc_cmd = nowait ? AT_ATP_ISSUE_REQUEST_NOTE : AT_ATP_ISSUE_REQUEST;
1494 sdb = (struct atp_set_default *)gbuf_rptr(m2);
1495
1496 /*
1497 * The at_snd_req library routine multiplies seconds by 100.
1498 * We need to divide by 100 in order to obtain the timer.
1499 */
1500 if ((timer = (sdb->def_rate * HZ)/100) == 0)
1501 timer = HZ;
1502 iocbp->ioc_count -= sizeof(struct atp_set_default);
1503 gbuf_rinc(m2,sizeof(struct atp_set_default));
1504
1505 /*
1506 * allocate and set up the transaction record
1507 */
1508 while ((trp = atp_trans_alloc(atp)) == 0) {
1509 ATDISABLE(s, atp->atp_delay_lock);
1510 rc = tsleep(&atp->atp_delay_event, PSOCK | PCATCH, "atptrp", 10);
1511 ATENABLE(s, atp->atp_delay_lock);
1512 if (rc != 0) {
1513 gbuf_freem(mioc);
1514 *err = rc;
1515 return -1;
1516 }
1517 }
1518 trp->tr_retry = sdb->def_retries;
1519 trp->tr_timeout = timer;
1520 trp->tr_bdsp = NULL;
1521 trp->tr_tid = atp_tid(atp);
1522 tid = trp->tr_tid;
1523
1524 /*
1525 * remember the IOCTL packet so we can ack it
1526 * later
1527 */
1528 trp->tr_xmt = mioc;
1529
1530 /*
1531 * Now fill in the header (and remember the bits
1532 * we need to know)
1533 */
1534 athp = AT_ATP_HDR(m2);
1535 athp->cmd = ATP_CMD_TREQ;
1536 UAS_ASSIGN(athp->tid, trp->tr_tid);
1537 athp->eom = 0;
1538 athp->sts = 0;
1539 trp->tr_xo = athp->xo;
1540 trp->tr_bitmap = athp->bitmap;
1541 ddp = AT_DDP_HDR(m2);
1542 ddp->type = DDP_ATP;
1543 ddp->src_socket = (at_socket)atp->atp_socket_no;
1544 ddp->src_node = 0;
1545 trp->tr_socket.socket = ddp->dst_socket;
1546 trp->tr_socket.node = ddp->dst_node;
1547 trp->tr_socket.net = NET_VALUE(ddp->dst_net);
1548 trp->tr_local_socket = atp->atp_socket_no;
1549
1550#ifdef NOT_YET
1551 /* save the local information in the gref */
1552 atp->atp_gref->laddr.s_net = NET_VALUE(ddp->src_net);
1553 atp->atp_gref->laddr.s_node = ddp->src_node;
1554 atp->atp_gref->lport = ddp->src_node;
1555 atp->atp_gref->ddptype = DDP_ATP;
1556#endif
1557
1558 /*
1559 * Put us in the transaction waiting queue
1560 */
1561 ATDISABLE(s, atp->atp_lock);
1562 ATP_Q_APPEND(atp->atp_trans_wait, trp, tr_list);
1563 ATENABLE(s, atp->atp_lock);
1564
1565 /*
1566 * Send the message and set the timer
1567 */
1568 m = (gbuf_t *)copy_pkt(m2, sizeof(llc_header_t));
1569 if ( !trp->tr_retry && !trp->tr_bitmap && !trp->tr_xo)
1570 atp_x_done(trp); /* no reason to tie up resources */
1571 else
1572 atp_timout(atp_req_timeout, trp, trp->tr_timeout);
1573 if (m)
1574 DDP_OUTPUT(m);
1575
1576 if (nowait)
1577 return (int)tid;
1578
1579 /*
1580 * wait for the transaction to complete
1581 */
1582 ATDISABLE(s, trp->tr_lock);
0b4e3aa0
A
1583 while ((trp->tr_state != TRANS_DONE) && (trp->tr_state != TRANS_FAILED) &&
1584 (trp->tr_state != TRANS_ABORTING)) {
1c79356b
A
1585 trp->tr_rsp_wait = 1;
1586 rc = tsleep(&trp->tr_event, PSOCK | PCATCH, "atpsndreq", 0);
1587 if (rc != 0) {
1588 trp->tr_rsp_wait = 0;
1589 ATENABLE(s, trp->tr_lock);
1590 *err = rc;
1591 return -1;
1592 }
1593 }
1594 trp->tr_rsp_wait = 0;
1595 ATENABLE(s, trp->tr_lock);
1596
0b4e3aa0
A
1597
1598 if (trp->tr_state == TRANS_FAILED || trp->tr_state == TRANS_ABORTING) {
1c79356b
A
1599 /*
1600 * transaction timed out, return error
1601 */
1602 atp_free(trp);
1603 *err = ETIMEDOUT;
1604 return -1;
1605 }
1606
1607 /*
1608 * copy out the recv data
1609 */
55e303ae 1610 atp_pack_bdsp(trp, (struct atpBDS *)bds);
1c79356b
A
1611
1612 /*
1613 * copyout the result info
1614 */
1615 copyout((caddr_t)bds, (caddr_t)buf, atpBDSsize);
1616
1617 atp_free(trp);
1618
1619 return (int)tid;
1620} /* _ATPsndreq */
1621
55e303ae
A
1622
1623/* entry point for ATP send response. respbuf contains a DDP hdr,
1624 * ATP hdr, and atpBDS array. The bdsDataSz field of the first atpBDS
1625 * struct contains the number of atpBDS structs in the array. resplen
1626 * contains the len of the data in respbuf and datalen contains the
1627 * len of the data buffer holding the response packets which the atpBDS
1628 * struct entries point to.
1629 */
1c79356b
A
1630int
1631_ATPsndrsp(fd, respbuff, resplen, datalen, err, proc)
1632 int fd;
1633 unsigned char *respbuff;
1634 int resplen;
1635 int datalen;
1636 int *err;
1637 void *proc;
1638{
55e303ae
A
1639 gref_t *gref;
1640 int s, rc;
1641 long bufaddr;
1642 gbuf_t *m, *mdata;
1643 short space;
1644 int size;
1645 struct atp_state *atp;
1646 struct atpBDS *bdsp;
1647 u_int16_t *bufsz;
1648 char *buf;
1649 int bds_cnt, count, len;
1650 caddr_t dataptr;
1c79356b
A
1651
1652 if ((*err = atalk_getref(0, fd, &gref, proc)) != 0)
1653 return -1;
1654
1655 if ((gref == 0) || ((atp = (struct atp_state *)gref->info) == 0)
1656 || (atp->atp_flags & ATP_CLOSING)) {
1657 dPrintf(D_M_ATP, D_L_ERROR, ("ATPsndrsp: stale handle=0x%x, pid=%d\n",
1658 (u_int) gref, gref->pid));
1659
1660 *err = EINVAL;
1661 return -1;
1662 }
1663
1664 /*
1665 * allocate buffer and copy in the response info
1666 */
0b4e3aa0
A
1667 if ((m = gbuf_alloc_wait(resplen, TRUE)) == 0) {
1668 *err = ENOMEM;
1669 return -1;
1c79356b
A
1670 }
1671 if ((*err = copyin((caddr_t)respbuff, (caddr_t)gbuf_rptr(m), resplen)) != 0) {
1672 gbuf_freeb(m);
1673 return -1;
1674 }
1675 gbuf_wset(m,resplen);
1676 ((at_ddp_t *)gbuf_rptr(m))->src_node = 0;
1677 bdsp = (struct atpBDS *)(gbuf_rptr(m) + TOTAL_ATP_HDR_SIZE);
1c79356b
A
1678
1679 /*
55e303ae
A
1680 * allocate buffers and copy in the response data.
1681 * note that only the size field of the atpBDS field
1682 * is used internally in the kernel.
1c79356b 1683 */
55e303ae
A
1684 bds_cnt = get_bds_entries(m); /* count of # entries */
1685 /* check correctness of parameters */
1686 if (bds_cnt > ATP_TRESP_MAX) {
1687 gbuf_freem(m);
1688 *err = EINVAL;
1689 return -1;
1690 }
1691
1692 for (size = 0, count = 0; count < bds_cnt; count++) {
1693 size += UAS_VALUE(bdsp[count].bdsBuffSz);
1694 }
1695 if (size > datalen) {
1696 gbuf_freem(m);
1697 *err = EINVAL;
1698 return -1;
1699 }
1700
1701 /* get the first mbuf */
1702 if ((mdata = gbuf_alloc_wait((space = (size > MCLBYTES ? MCLBYTES : size)), TRUE)) == 0) {
1703 gbuf_freem(m);
0b4e3aa0
A
1704 *err = ENOMEM;
1705 return -1;
1c79356b
A
1706 }
1707 gbuf_cont(m) = mdata;
55e303ae
A
1708 dataptr = mtod(mdata, caddr_t);
1709 for (count = 0; count < bds_cnt; bdsp++, count++) {
1710 if ((bufaddr = UAL_VALUE(bdsp->bdsBuffAddr)) != 0 &&
1711 (len = UAS_VALUE(bdsp->bdsBuffSz)) != 0) {
1712 if (len > space) { /* enough room ? */
1713 gbuf_wset(mdata, dataptr - mtod(mdata, caddr_t)); /* set len of last mbuf */
1714 /* allocate the next mbuf */
1715 if ((gbuf_cont(mdata) = m_get((M_WAIT), MSG_DATA)) == 0) {
1716 gbuf_freem(m);
1717 *err = ENOMEM;
1718 return -1;
1719 }
1720 mdata = gbuf_cont(mdata);
1721 MCLGET(mdata, M_WAIT);
1722 if (!(mdata->m_flags & M_EXT)) {
1723 m_freem(m);
1724 return(NULL);
1725 }
1726 dataptr = mtod(mdata, caddr_t);
1727 space = MCLBYTES;
1728 }
1729 /* do the copyin */
1730 if ((*err = copyin((caddr_t)bufaddr, dataptr, len)) != 0) {
1c79356b
A
1731 gbuf_freem(m);
1732 return -1;
1733 }
55e303ae
A
1734 dataptr += len;
1735 space -= len;
1c79356b
A
1736 }
1737 }
55e303ae
A
1738 gbuf_wset(mdata, dataptr - mtod(mdata, caddr_t)); /* set len of last mbuf */
1739 gbuf_cont(m)->m_pkthdr.len = size; /* set packet hdr len */
1c79356b
A
1740
1741 atp_send_rsp(gref, m, TRUE);
1742 return 0;
1743}
1744
1745int
1746_ATPgetreq(fd, buf, buflen, err, proc)
1747 int fd;
1748 unsigned char *buf;
1749 int buflen;
1750 int *err;
1751 void *proc;
1752{
1753 gref_t *gref;
1754 register struct atp_state *atp;
1755 register struct atp_rcb *rcbp;
1756 register gbuf_t *m, *m_head;
1757 int s, size, len;
1758
1759 if ((*err = atalk_getref(0, fd, &gref, proc)) != 0)
1760 return -1;
1761
1762 if ((gref == 0) || ((atp = (struct atp_state *)gref->info) == 0)
1763 || (atp->atp_flags & ATP_CLOSING)) {
1764 dPrintf(D_M_ATP, D_L_ERROR, ("ATPgetreq: stale handle=0x%x, pid=%d\n",
1765 (u_int) gref, gref->pid));
1766 *err = EINVAL;
1767 return -1;
1768 }
1769
1770 ATDISABLE(s, atp->atp_lock);
1771 if ((rcbp = atp->atp_attached.head) != NULL) {
1772 /*
1773 * Got one, move it to the active response Q
1774 */
1775 m_head = rcbp->rc_ioctl;
1776 rcbp->rc_ioctl = NULL;
1777
1778 if (rcbp->rc_xo) {
1779 ATP_Q_REMOVE(atp->atp_attached, rcbp, rc_list);
1780 rcbp->rc_state = RCB_NOTIFIED;
1781 ATP_Q_APPEND(atp->atp_rcb, rcbp, rc_list);
1782 } else {
1783 /* detach rcbp from attached queue,
1784 * and free any outstanding resources
1785 */
1786 atp_rcb_free(rcbp);
1787 }
1788 ATENABLE(s, atp->atp_lock);
1789
1790 /*
1791 * copyout the request data, including the protocol header
1792 */
1793 for (size=0, m=m_head; m; m = gbuf_cont(m)) {
1794 if ((len = gbuf_len(m)) > buflen)
1795 len = buflen;
1796 copyout((caddr_t)gbuf_rptr(m), (caddr_t)&buf[size], len);
1797 size += len;
1798 if ((buflen -= len) == 0)
1799 break;
1800 }
1801 gbuf_freem(m_head);
1802
1803 return size;
1804 }
1805 ATENABLE(s, atp->atp_lock);
1806
1807 return -1;
1808}
1809
1810int
1811_ATPgetrsp(fd, bdsp, err, proc)
1812 int fd;
1813 struct atpBDS *bdsp;
1814 int *err;
1815 void *proc;
1816{
1817 gref_t *gref;
1818 register struct atp_state *atp;
1819 register struct atp_trans *trp;
1820 int s, tid;
1821 char bds[atpBDSsize];
1822
1823 if ((*err = atalk_getref(0, fd, &gref, proc)) != 0)
1824 return -1;
1825
1826 if ((gref == 0) || ((atp = (struct atp_state *)gref->info) == 0)
1827 || (atp->atp_flags & ATP_CLOSING)) {
1828 dPrintf(D_M_ATP, D_L_ERROR, ("ATPgetrsp: stale handle=0x%x, pid=%d\n",
1829 (u_int) gref, gref->pid));
1830 *err = EINVAL;
1831 return -1;
1832 }
1833
1834 ATDISABLE(s, atp->atp_lock);
1835 for (trp = atp->atp_trans_wait.head; trp; trp = trp->tr_list.next) {
1836 dPrintf(D_M_ATP, D_L_INFO,
1837 ("ATPgetrsp: atp:0x%x, trp:0x%x, state:%d\n",
1838 (u_int) atp, (u_int) trp, trp->tr_state));
1839
1840 switch (trp->tr_state) {
1841 case TRANS_DONE:
1842 ATENABLE(s, atp->atp_lock);
1843 if ((*err = copyin((caddr_t)bdsp,
1844 (caddr_t)bds, sizeof(bds))) != 0)
1845 return -1;
55e303ae 1846 atp_pack_bdsp(trp, (struct atpBDS *)bds);
1c79356b
A
1847 tid = (int)trp->tr_tid;
1848 atp_free(trp);
1849 copyout((caddr_t)bds, (caddr_t)bdsp, sizeof(bds));
1850 return tid;
1851
1852 case TRANS_FAILED:
1853 /*
1854 * transaction timed out, return error
1855 */
1856 ATENABLE(s, atp->atp_lock);
1857 atp_free(trp);
1858 *err = ETIMEDOUT;
1859 return -1;
1860
1861 default:
1862 continue;
1863 }
1864 }
1865 ATENABLE(s, atp->atp_lock);
1866
1867 *err = EINVAL;
1868 return -1;
1869}
1870
1871void
1872atp_drop_req(gref, m)
1873 gref_t *gref;
1874 gbuf_t *m;
1875{
1876 int s;
1877 struct atp_state *atp;
1878 struct atp_rcb *rcbp;
1879 at_atp_t *athp;
1880 at_ddp_t *ddp;
1881
1882 atp = (struct atp_state *)gref->info;
1883 if (atp->dflag)
1884 atp = (struct atp_state *)atp->atp_msgq;
1885 ddp = AT_DDP_HDR(m);
1886 athp = AT_ATP_HDR(m);
1887
1888 /*
1889 * search for the corresponding rcb
1890 */
1891 ATDISABLE(s, atp->atp_lock);
1892 for (rcbp = atp->atp_rcb.head; rcbp; rcbp = rcbp->rc_list.next) {
1893 if ( (rcbp->rc_tid == UAS_VALUE(athp->tid)) &&
1894 (rcbp->rc_socket.node == ddp->src_node) &&
1895 (rcbp->rc_socket.net == NET_VALUE(ddp->src_net)) &&
1896 (rcbp->rc_socket.socket == ddp->src_socket) )
1897 break;
1898 }
1899
1900 /*
1901 * drop the request
1902 */
1903 if (rcbp)
1904 atp_rcb_free(rcbp);
1905 ATENABLE(s, atp->atp_lock);
1906
1907 gbuf_freem(m);
1908}