]> git.saurik.com Git - apple/xnu.git/blame - bsd/netat/sys_glue.c
xnu-1699.22.73.tar.gz
[apple/xnu.git] / bsd / netat / sys_glue.c
CommitLineData
1c79356b 1/*
2d21ac55 2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
8f6c56a5 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/*
29 * Copyright (c) 1995 Apple Computer, Inc.
30 *
31 * Change Log:
32 * Created, March 17, 1997 by Tuyen Nguyen for MacOSX.
33 */
34
35#include <sys/errno.h>
36#include <sys/types.h>
37#include <sys/param.h>
38#include <machine/spl.h>
39#include <sys/systm.h>
40#include <sys/kernel.h>
41#include <sys/proc.h>
42#include <sys/filedesc.h>
43#include <sys/fcntl.h>
91447636 44#include <sys/file_internal.h>
1c79356b
A
45#include <sys/mbuf.h>
46#include <sys/ioctl.h>
47#include <sys/malloc.h>
91447636 48#include <kern/locks.h>
1c79356b
A
49#include <sys/socket.h>
50#include <sys/socketvar.h>
51#include <sys/ioccom.h>
91447636 52#include <sys/uio_internal.h>
2d21ac55
A
53#include <sys/file.h>
54#include <sys/vnode.h>
1c79356b
A
55
56#include <sys/sysctl.h>
57
58#include <net/if.h>
59
60#include <netat/sysglue.h>
61#include <netat/appletalk.h>
62#include <netat/ddp.h>
63#include <netat/at_pcb.h>
64#include <netat/at_var.h>
65#include <netat/routing_tables.h>
2d21ac55
A
66#include <netat/adsp.h>
67#include <netat/adsp_internal.h>
68#include <netat/asp.h>
6601e61a 69#include <netat/atp.h>
1c79356b
A
70#include <netat/debug.h>
71
2d21ac55
A
72int _ATkqfilter(struct fileproc *, struct knote *, vfs_context_t);
73int _ATselect(struct fileproc *, int, void *, vfs_context_t);
74int _ATioctl(struct fileproc *, u_long, caddr_t, vfs_context_t);
75int _ATwrite(struct fileproc *, struct uio *, int, vfs_context_t);
76int _ATread(struct fileproc *, struct uio *, int, vfs_context_t);
77int _ATclose(struct fileglob *, vfs_context_t);
78
79int _ATrw(struct fileproc *, enum uio_rw, struct uio *, vfs_context_t);
80
1c79356b 81extern struct atpcb ddp_head;
91447636 82extern lck_mtx_t * atalk_mutex;
0b4e3aa0
A
83
84int atp_free_cluster_timeout_set = 0;
85
2d21ac55
A
86int gref_alloc(gref_t **);
87
1c79356b 88
0b4e3aa0
A
89/* bms: make gref_close non static so its callable from kernel */
90int gref_close(gref_t *gref);
1c79356b
A
91
92SYSCTL_DECL(_net_appletalk);
93dbgBits_t dbgBits;
94SYSCTL_STRUCT(_net_appletalk, OID_AUTO, debug, CTLFLAG_WR,
95 &dbgBits, dbgBits, "AppleTalk Debug Flags");
2d21ac55 96int RouterMix = RT_MIX_DEFAULT; /* default for nbr of ppsec */
1c79356b 97SYSCTL_INT(_net_appletalk, OID_AUTO, routermix, CTLFLAG_WR,
2d21ac55 98 &RouterMix, 0, "Appletalk RouterMix");
1c79356b 99at_ddp_stats_t at_ddp_stats; /* DDP statistics */
6d2010ae 100SYSCTL_STRUCT(_net_appletalk, OID_AUTO, ddpstats, CTLFLAG_RD | CTLFLAG_LOCKED,
1c79356b 101 &at_ddp_stats, at_ddp_stats, "AppleTalk DDP Stats");
e2fac8b1 102extern int atp_resp_seqno2big;
6d2010ae 103SYSCTL_INT(_net_appletalk, OID_AUTO, atp_resp_seqno2big, CTLFLAG_RD | CTLFLAG_LOCKED,
e2fac8b1 104 &atp_resp_seqno2big, 0, "Appletalk ATP seqno too big count");
1c79356b 105
91447636
A
106static void ioccmd_t_32_to_64( ioccmd_t *from_p, user_ioccmd_t *to_p );
107static void ioccmd_t_64_to_32( user_ioccmd_t *from_p, ioccmd_t *to_p );
108
2d21ac55
A
109extern lck_mtx_t *atalk_cluster_lock;
110caddr_t atp_free_cluster_list = NULL;
1c79356b 111
2d21ac55 112void gref_wput(gref_t *, gbuf_t *m);
0b4e3aa0
A
113
114void gref_wput(gref, m)
1c79356b
A
115 gref_t *gref;
116 gbuf_t *m;
117{
118 switch (gref->proto) {
119 case ATPROTO_DDP:
120 ddp_putmsg(gref, m); break;
121 case ATPROTO_LAP:
122 elap_wput(gref, m); break;
123 case ATPROTO_ATP:
124 atp_wput(gref, m); break;
125 case ATPROTO_ASP:
126 asp_wput(gref, m); break;
127#ifdef AURP_SUPPORT
128 case ATPROTO_AURP:
129 aurp_wput(gref, m); break;
130#endif
131 case ATPROTO_ADSP:
132 adsp_wput(gref, m); break;
133 case ATPROTO_NONE:
134 if (gbuf_type(m) == MSG_IOCTL) {
135 gbuf_freem(gbuf_cont(m));
136 gbuf_cont(m) = 0;
137 ((ioc_t *)gbuf_rptr(m))->ioc_rval = -1;
91447636 138 ((ioc_t *)gbuf_rptr(m))->ioc_error = EPROTOTYPE;
1c79356b
A
139 gbuf_set_type(m, MSG_IOCNAK);
140 atalk_putnext(gref, m);
141 } else
142 gbuf_freem(m);
143 break;
144 default:
145 gbuf_freem(m);
146 break;
147 }
148}
149
150int _ATsocket(proto, err, proc)
151 int proto;
152 int *err;
153 void *proc;
154{
155 int fd;
156 gref_t *gref;
157
158 /* make sure the specified protocol id is valid */
159 switch (proto) {
160
161 /* ATPROTO_DDP and ATPROTO_LAP have been replaced with
162 BSD-style socket interface. */
163
164 case ATPROTO_ATP:
165 case ATPROTO_ASP:
8f6c56a5 166#ifdef AURP_SUPPORT
1c79356b 167 case ATPROTO_AURP:
8f6c56a5 168#endif
1c79356b
A
169 case ATPROTO_ADSP:
170 break;
171 default:
172 *err = EPROTOTYPE;
173#ifdef APPLETALK_DEBUG
174 kprintf("_ATsocket: error EPROTOTYPE =%d\n", *err);
175#endif
176 return -1;
177 }
178
179 /* allocate a protocol channel */
180 if ((*err = gref_alloc(&gref)) != 0) {
181#ifdef APPLETALK_DEBUG
182 kprintf("_ATsocket: error gref_open =%d\n", *err);
183#endif
184 return -1;
185 }
186 gref->proto = proto;
91447636 187 gref->pid = proc_pid((struct proc *)proc);
1c79356b
A
188
189 /* open the specified protocol */
190 switch (gref->proto) {
191
192 /* ATPROTO_DDP and ATPROTO_LAP have been replaced with
193 BSD-style socket interface. */
194
195 case ATPROTO_ATP:
196 *err = atp_open(gref, 1); break;
197 case ATPROTO_ASP:
198 *err = asp_open(gref); break;
199#ifdef AURP_SUPPORT
200 case ATPROTO_AURP:
201 *err = aurp_open(gref); break;
202#endif
203 case ATPROTO_ADSP:
204 *err = adsp_open(gref); break;
205 }
206
207 /* create the descriptor for the channel */
208 if (*err) {
209#ifdef APPLETALK_DEBUG
210 kprintf("_ATsocket: open failed for %d proto; err = %d\n",
211 gref->proto, *err);
212#endif
213 gref->proto = ATPROTO_NONE;
214 }
215 if (*err || (*err = atalk_openref(gref, &fd, proc))) {
216#ifdef APPLETALK_DEBUG
217 kprintf("_ATsocket: error atalk_openref =%d\n", *err);
218#endif
219 (void)gref_close(gref);
220 return -1;
221 }
222/*
223 kprintf("_ATsocket: proto=%d return=%d fd=%d\n", proto, *err, fd);
224*/
225 return fd;
226} /* _ATsocket */
227
228int _ATgetmsg(fd, ctlptr, datptr, flags, err, proc)
229 int fd;
230 strbuf_t *ctlptr;
231 strbuf_t *datptr;
232 int *flags;
233 int *err;
234 void *proc;
235{
236 int rc = -1;
237 gref_t *gref;
238
91447636 239 if ((*err = atalk_getref(0, fd, &gref, proc, 1)) == 0) {
1c79356b
A
240 switch (gref->proto) {
241 case ATPROTO_ASP:
0b4e3aa0 242 rc = ASPgetmsg(gref, ctlptr, datptr, NULL, flags, err);
1c79356b
A
243 break;
244 case ATPROTO_AURP:
245#ifdef AURP_SUPPORT
246 rc = AURPgetmsg(err);
247 break;
248#endif
249 default:
250 *err = EPROTONOSUPPORT;
251 break;
252 }
91447636 253 file_drop(fd);
1c79356b
A
254 }
255
256/* kprintf("_ATgetmsg: return=%d\n", *err);*/
257 return rc;
258}
259
260int _ATputmsg(fd, ctlptr, datptr, flags, err, proc)
261 int fd;
262 strbuf_t *ctlptr;
263 strbuf_t *datptr;
264 int flags;
265 int *err;
266 void *proc;
267{
268 int rc = -1;
269 gref_t *gref;
270
91447636 271 if ((*err = atalk_getref(0, fd, &gref, proc, 1)) == 0) {
1c79356b
A
272 switch (gref->proto) {
273 case ATPROTO_ASP:
0b4e3aa0 274 rc = ASPputmsg(gref, ctlptr, datptr, NULL, flags, err); break;
1c79356b
A
275 default:
276 *err = EPROTONOSUPPORT; break;
277 }
91447636 278 file_drop(fd);
1c79356b
A
279 }
280
281/* kprintf("_ATputmsg: return=%d\n", *err); */
282 return rc;
283}
284
2d21ac55
A
285int _ATclose(
286 struct fileglob *fg,
287 __unused vfs_context_t ctx)
1c79356b
A
288{
289 int err;
290 gref_t *gref;
291
91447636
A
292 if ((err = atalk_closeref(fg, &gref)) == 0) {
293 atalk_lock();
1c79356b 294 (void)gref_close(gref);
91447636 295 atalk_unlock();
1c79356b
A
296 }
297
298 return err;
299}
300
2d21ac55
A
301int _ATrw(fp, rw, uio, ctx)
302 struct fileproc *fp;
1c79356b
A
303 enum uio_rw rw;
304 struct uio *uio;
2d21ac55 305 vfs_context_t ctx;
1c79356b 306{
0c530ab8 307 int err, len, clen = 0, res;
1c79356b
A
308 gref_t *gref;
309 gbuf_t *m, *mhead, *mprev;
2d21ac55 310 proc_t p = vfs_context_proc(ctx);
1c79356b 311
91447636 312 /* no need to get/drop iocount as the fp already has one */
cc9f6e38 313 if ((err = atalk_getref_locked(fp, 0, &gref, p, 1)) != 0)
1c79356b
A
314 return err;
315
91447636
A
316 // LP64todo - fix this!
317 if ((len = uio_resid(uio)) == 0)
1c79356b
A
318 return 0;
319
1c79356b
A
320
321 if (rw == UIO_READ) {
322 KERNEL_DEBUG(DBG_ADSP_ATRW, 0, gref, len, gref->rdhead, 0);
323 while ((gref->errno == 0) && ((mhead = gref->rdhead) == 0)) {
324 gref->sevents |= POLLMSG;
91447636 325 err = msleep(&gref->event, atalk_mutex, PSOCK | PCATCH, "AT read", 0);
1c79356b 326 gref->sevents &= ~POLLMSG;
0c530ab8 327 if (err != 0)
1c79356b 328 return err;
1c79356b
A
329 KERNEL_DEBUG(DBG_ADSP_ATRW, 1, gref, gref->rdhead, mhead, gbuf_next(mhead));
330 }
331
0c530ab8 332 if (gref->errno)
1c79356b 333 return EPIPE;
1c79356b
A
334 if ((gref->rdhead = gbuf_next(mhead)) == 0)
335 gref->rdtail = 0;
336
337 KERNEL_DEBUG(DBG_ADSP_ATRW, 2, gref, gref->rdhead, mhead, gbuf_next(mhead));
338
1c79356b
A
339
340//##### LD TEST 08/05
341// simple_lock(&gref->lock);
342
343 gbuf_next(mhead) = 0;
344
345 for (mprev=0, m=mhead; m && len; len-=clen) {
346 if ((clen = gbuf_len(m)) > 0) {
347 if (clen > len)
348 clen = len;
349 uio->uio_rw = UIO_READ;
350 if ((res = uiomove((caddr_t)gbuf_rptr(m),
351 clen, uio))) {
352 KERNEL_DEBUG(DBG_ADSP_ATRW, 3, m, clen,
353 len, gbuf_cont(m));
354 break;
355 }
356 if (gbuf_len(m) > len) {
357 gbuf_rinc(m,clen);
358 break;
359 }
360 }
361 mprev = m;
362 m = gbuf_cont(m);
363 }
364 if (m) {
365 KERNEL_DEBUG(DBG_ADSP_ATRW, 4, m, gbuf_len(m), mprev, gref->rdhead);
366 if (mprev)
367 gbuf_cont(mprev) = 0;
368 else
369 mhead = 0;
1c79356b
A
370 if (gref->rdhead == 0)
371 gref->rdtail = m;
372 gbuf_next(m) = gref->rdhead;
373 gref->rdhead = m;
1c79356b
A
374 }
375 if (mhead)
376 gbuf_freem(mhead);
377//### LD TEST
378// simple_unlock(&gref->lock);
379 } else {
380 if (gref->writeable) {
381 while (!(*gref->writeable)(gref)) {
382 /* flow control on, wait to be enabled to write */
383 gref->sevents |= POLLSYNC;
91447636 384 err = msleep(&gref->event, atalk_mutex, PSOCK | PCATCH, "AT write", 0);
1c79356b 385 gref->sevents &= ~POLLSYNC;
0c530ab8 386 if (err != 0)
1c79356b 387 return err;
1c79356b
A
388 }
389 }
390
1c79356b
A
391
392 /* allocate a buffer to copy in the write data */
393 if ((m = gbuf_alloc(AT_WR_OFFSET+len, PRI_MED)) == 0)
394 return ENOBUFS;
395 gbuf_rinc(m,AT_WR_OFFSET);
396 gbuf_wset(m,len);
397
398 /* copy in the write data */
399 uio->uio_rw = UIO_WRITE;
400 if ((res = uiomove((caddr_t)gbuf_rptr(m), len, uio))) {
401#ifdef APPLETALK_DEBUG
402 kprintf("_ATrw: UIO_WRITE: res=%d\n", res);
403#endif
404 gbuf_freeb(m);
405 return EIO;
406 }
407
408 /* forward the write data to the appropriate protocol module */
409 gref_wput(gref, m);
410 }
411
412 return 0;
413} /* _ATrw */
414
2d21ac55
A
415int _ATread(
416 struct fileproc *fp,
417 struct uio *uio,
418 __unused int flags,
419 vfs_context_t ctx)
1c79356b
A
420{
421 int stat;
422
91447636 423 atalk_lock();
2d21ac55 424 stat = _ATrw(fp, UIO_READ, uio, ctx);
91447636 425 atalk_unlock();
1c79356b
A
426 return stat;
427}
428
2d21ac55
A
429int _ATwrite(
430 struct fileproc *fp,
431 struct uio *uio,
432 __unused int flags,
433 vfs_context_t ctx)
1c79356b 434{
2d21ac55 435 int stat;
1c79356b 436
91447636 437 atalk_lock();
2d21ac55 438 stat = _ATrw(fp, UIO_WRITE, uio, ctx);
91447636 439 atalk_unlock();
1c79356b
A
440
441 return stat;
442}
443
444/* Most of the processing from _ATioctl, so that it can be called
445 from the new ioctl code */
0b4e3aa0
A
446/* bms: update to be callable from kernel */
447int at_ioctl(gref_t *gref, u_long cmd, caddr_t arg, int fromKernel)
1c79356b 448{
0c530ab8 449 int err = 0, len;
91447636 450 u_int size;
0b4e3aa0
A
451 gbuf_t *m, *mdata;
452 ioc_t *ioc;
91447636
A
453 user_addr_t user_arg;
454 user_ioccmd_t user_ioccmd;
455 boolean_t is64bit;
1c79356b 456
0b4e3aa0
A
457 /* error if not for us */
458 if ((cmd & 0xffff) != 0xff99)
459 return EOPNOTSUPP;
1c79356b 460
91447636
A
461 size = IOCPARM_LEN(cmd);
462 if (size != sizeof(user_addr_t))
463 return EINVAL;
464
465 user_arg = *((user_addr_t *)arg);
466
0b4e3aa0 467 /* copy in ioc command info */
91447636
A
468 is64bit = proc_is64bit(current_proc());
469 if (fromKernel) {
470 ioccmd_t tmp;
471 bcopy (CAST_DOWN(caddr_t, user_arg), &tmp, sizeof (tmp));
472 ioccmd_t_32_to_64(&tmp, &user_ioccmd);
473 }
0b4e3aa0 474 else {
91447636
A
475 if (is64bit) {
476 err = copyin(user_arg, (caddr_t)&user_ioccmd, sizeof(user_ioccmd));
477 }
478 else {
479 ioccmd_t tmp;
480 err = copyin(user_arg, (caddr_t)&tmp, sizeof(tmp));
481 ioccmd_t_32_to_64(&tmp, &user_ioccmd);
482 }
483 if (err != 0) {
1c79356b 484#ifdef APPLETALK_DEBUG
91447636
A
485 kprintf("at_ioctl: err = %d, copyin(%llx, %x, %d)\n", err,
486 user_arg, (caddr_t)&user_ioccmd, sizeof(user_ioccmd));
1c79356b 487#endif
0b4e3aa0
A
488 return err;
489 }
490 }
491
492 /* allocate a buffer to create an ioc command
493 first mbuf contains ioc command */
494 if ((m = gbuf_alloc(sizeof(ioc_t), PRI_HI)) == 0)
495 return ENOBUFS;
496 gbuf_wset(m, sizeof(ioc_t)); /* mbuf->m_len */
497 gbuf_set_type(m, MSG_IOCTL); /* mbuf->m_type */
498
499 /* create the ioc command
500 second mbuf contains the actual ASP command */
91447636
A
501 if (user_ioccmd.ic_len) {
502 if ((gbuf_cont(m) = gbuf_alloc(user_ioccmd.ic_len, PRI_HI)) == 0) {
0b4e3aa0 503 gbuf_freem(m);
1c79356b
A
504#ifdef APPLETALK_DEBUG
505 kprintf("at_ioctl: gbuf_alloc err=%d\n",ENOBUFS);
506#endif
0b4e3aa0
A
507 return ENOBUFS;
508 }
91447636 509 gbuf_wset(gbuf_cont(m), user_ioccmd.ic_len); /* mbuf->m_len */
0b4e3aa0 510 if (fromKernel)
91447636 511 bcopy (CAST_DOWN(caddr_t, user_ioccmd.ic_dp), gbuf_rptr(gbuf_cont(m)), user_ioccmd.ic_len);
0b4e3aa0 512 else {
91447636 513 if ((err = copyin(user_ioccmd.ic_dp, (caddr_t)gbuf_rptr(gbuf_cont(m)), user_ioccmd.ic_len)) != 0) {
0b4e3aa0
A
514 gbuf_freem(m);
515 return err;
516 }
517 }
518 }
519 ioc = (ioc_t *) gbuf_rptr(m);
91447636
A
520 ioc->ioc_cmd = user_ioccmd.ic_cmd;
521 ioc->ioc_count = user_ioccmd.ic_len;
0b4e3aa0
A
522 ioc->ioc_error = 0;
523 ioc->ioc_rval = 0;
524
525 /* send the ioc command to the appropriate recipient */
1c79356b
A
526 gref_wput(gref, m);
527
0b4e3aa0 528 /* wait for the ioc ack */
0b4e3aa0
A
529 while ((m = gref->ichead) == 0) {
530 gref->sevents |= POLLPRI;
1c79356b
A
531#ifdef APPLETALK_DEBUG
532 kprintf("sleep gref = 0x%x\n", (unsigned)gref);
533#endif
91447636 534 err = msleep(&gref->iocevent, atalk_mutex, PSOCK | PCATCH, "AT ioctl", 0);
1c79356b
A
535 gref->sevents &= ~POLLPRI;
536 if (err != 0) {
1c79356b
A
537#ifdef APPLETALK_DEBUG
538 kprintf("at_ioctl: EINTR\n");
539#endif
540 return err;
541 }
542 }
543
544 /* PR-2224797 */
545 if (gbuf_next(m) == m) /* error case */
546 gbuf_next(m) = 0;
547
548 gref->ichead = gbuf_next(m);
549
1c79356b
A
550
551#ifdef APPLETALK_DEBUG
552 kprintf("at_ioctl: woke up from ioc sleep gref = 0x%x\n",
553 (unsigned)gref);
554#endif
0b4e3aa0
A
555
556 /* process the ioc response */
557 ioc = (ioc_t *) gbuf_rptr(m);
558 if ((err = ioc->ioc_error) == 0) {
91447636
A
559 user_ioccmd.ic_timout = ioc->ioc_rval;
560 user_ioccmd.ic_len = 0;
0b4e3aa0 561 mdata = gbuf_cont(m);
91447636
A
562 if (mdata && user_ioccmd.ic_dp) {
563 user_ioccmd.ic_len = gbuf_msgsize(mdata);
0b4e3aa0
A
564 for (len = 0; mdata; mdata = gbuf_cont(mdata)) {
565 if (fromKernel)
91447636 566 bcopy (gbuf_rptr(mdata), CAST_DOWN(caddr_t, (user_ioccmd.ic_dp + len)), gbuf_len(mdata));
0b4e3aa0 567 else {
91447636 568 if ((err = copyout((caddr_t)gbuf_rptr(mdata), (user_ioccmd.ic_dp + len), gbuf_len(mdata))) < 0) {
1c79356b 569#ifdef APPLETALK_DEBUG
0b4e3aa0 570 kprintf("at_ioctl: len=%d error copyout=%d from=%x to=%x gbuf_len=%x\n",
91447636 571 len, err, (caddr_t)gbuf_rptr(mdata), (caddr_t)&user_ioccmd.ic_dp[len], gbuf_len(mdata));
1c79356b 572#endif
0b4e3aa0
A
573 goto l_done;
574 }
575 }
576 len += gbuf_len(mdata);
577 }
578 }
579
91447636
A
580 if (fromKernel) {
581 ioccmd_t tmp;
582 ioccmd_t_64_to_32(&user_ioccmd, &tmp);
583 bcopy (&tmp, CAST_DOWN(caddr_t, user_arg), sizeof(tmp));
584 }
0b4e3aa0 585 else {
91447636
A
586 if (is64bit) {
587 err = copyout((caddr_t)&user_ioccmd, user_arg, sizeof(user_ioccmd));
588 }
589 else {
590 ioccmd_t tmp;
591 ioccmd_t_64_to_32(&user_ioccmd, &tmp);
592 err = copyout((caddr_t)&tmp, user_arg, sizeof(tmp));
593 }
594 if (err != 0) {
0b4e3aa0
A
595 goto l_done;
596 }
597 }
598 }
1c79356b
A
599
600l_done:
601 gbuf_freem(m);
602 /*kprintf("at_ioctl: I_done=%d\n", err);*/
603 return err;
604} /* at_ioctl */
605
2d21ac55
A
606int _ATioctl(
607 struct fileproc *fp,
608 u_long cmd,
609 register caddr_t arg,
610 __unused vfs_context_t ctx)
1c79356b
A
611{
612 int err;
613 gref_t *gref;
614
91447636
A
615 atalk_lock();
616 /* No need to get a reference on fp as it already has one */
617 if ((err = atalk_getref_locked(fp, 0, &gref, 0, 0)) != 0) {
1c79356b
A
618#ifdef APPLETALK_DEBUG
619 kprintf("_ATioctl: atalk_getref err = %d\n", err);
620#endif
621 }
622 else
0b4e3aa0 623 err = at_ioctl(gref, cmd, arg, 0);
1c79356b 624
91447636 625 atalk_unlock();
1c79356b
A
626
627 return err;
628}
629
2d21ac55 630int _ATselect(fp, which, wql, ctx)
91447636 631 struct fileproc *fp;
1c79356b 632 int which;
0b4e3aa0 633 void * wql;
2d21ac55 634 vfs_context_t ctx;
1c79356b 635{
0c530ab8 636 int err, rc = 0;
1c79356b 637 gref_t *gref;
2d21ac55 638 proc_t proc = vfs_context_proc(ctx);
1c79356b 639
cc9f6e38
A
640 /* Radar 4128949: Drop the proc_fd lock here to avoid lock inversion issues with the other AT calls
641 * select() is already holding a reference on the fd, so it won't go away during the time it is unlocked.
642 */
643 proc_fdunlock(proc);
644
91447636
A
645 atalk_lock();
646 /* no need to drop the iocount as select covers that */
647 err = atalk_getref_locked(fp, 0, &gref, 0, 0);
648 atalk_unlock();
1c79356b 649
cc9f6e38
A
650 /* Safe to re-grab the proc_fdlock at that point */
651 proc_fdlock(proc);
1c79356b
A
652 if (err != 0)
653 rc = 1;
654 else {
1c79356b
A
655 if (which == FREAD) {
656 if (gref->rdhead || (gref->readable && (*gref->readable)(gref)))
657 rc = 1;
658 else {
659 gref->sevents |= POLLIN;
0b4e3aa0 660 selrecord(proc, &gref->si, wql);
1c79356b
A
661 }
662 }
663 else if (which == POLLOUT) {
664 if (gref->writeable) {
665 if ((*gref->writeable)(gref))
666 rc = 1;
667 else {
668 gref->sevents |= POLLOUT;
0b4e3aa0 669 selrecord(proc, &gref->si, wql);
1c79356b
A
670 }
671 } else
672 rc = 1;
673 }
1c79356b
A
674 }
675
676 return rc;
677}
678
2d21ac55
A
679int _ATkqfilter(
680 __unused struct fileproc *fp,
681 __unused struct knote *kn,
682 __unused vfs_context_t ctx)
55e303ae
A
683{
684 return (EOPNOTSUPP);
685}
686
1c79356b
A
687void atalk_putnext(gref, m)
688 gref_t *gref;
689 gbuf_t *m;
690{
1c79356b 691
1c79356b
A
692
693 /* *** potential leak? *** */
694 gbuf_next(m) = 0;
695
696 switch (gbuf_type(m)) {
697 case MSG_IOCACK:
698 case MSG_IOCNAK:
699 if (gref->ichead)
700 gbuf_next(gref->ichead) = m;
701 else {
702 gref->ichead = m;
703 if (gref->sevents & POLLPRI) {
704#ifdef APPLETALK_DEBUG
705 kprintf("wakeup gref = 0x%x\n", (unsigned)gref);
706#endif
9bccf70c 707 wakeup(&gref->iocevent);
1c79356b
A
708 }
709 }
710 break;
711 case MSG_ERROR:
712 /* *** this processing was moved to atalk_notify *** */
713 panic("atalk_putnext receved MSG_ERROR");
714 break;
715 default:
716 if (gref->errno)
717 gbuf_freem(m);
718 else
719 if (gref->rdhead) {
720 gbuf_next(gref->rdtail) = m;
721 gref->rdtail = m;
722 } else {
723 gref->rdhead = m;
724 if (gref->sevents & POLLMSG) {
725 gref->sevents &= ~POLLMSG;
9bccf70c 726 wakeup(&gref->event);
1c79356b
A
727 }
728 if (gref->sevents & POLLIN) {
729 gref->sevents &= ~POLLIN;
1c79356b 730 selwakeup(&gref->si);
1c79356b
A
731 }
732 gref->rdtail = m;
733 }
734 } /* switch gbuf_type(m) */
735
1c79356b
A
736} /* atalk_putnext */
737
738void atalk_enablew(gref)
739 gref_t *gref;
740{
741 if (gref->sevents & POLLSYNC)
9bccf70c 742 wakeup(&gref->event);
1c79356b
A
743}
744
745void atalk_flush(gref)
746 gref_t *gref;
747{
1c79356b 748
1c79356b
A
749 if (gref->rdhead) {
750 gbuf_freel(gref->rdhead);
751 gref->rdhead = 0;
752 }
753 if (gref->ichead) {
754 gbuf_freel(gref->ichead);
755 gref->ichead = 0;
756 }
1c79356b
A
757}
758
759/*
760 * Notify an appletalk user of an asynchronous error;
761 * just wake up so that he can collect error status.
762 */
763void atalk_notify(gref, errno)
764 register gref_t *gref;
765 int errno;
766{
1c79356b
A
767
768 if (gref->atpcb_socket) {
769 /* For DDP --
770 This section is patterned after udp_notify() in
771 netinet/udp_usrreq.c
772 */
773 gref->atpcb_socket->so_error = errno;
774 sorwakeup(gref->atpcb_socket);
775 sowwakeup(gref->atpcb_socket);
776 } else {
777 /* for ATP, ASP, and ADSP */
778 if (gref->errno == 0) {
779 gref->errno = errno;
780 /* clear out data waiting to be read */
781 if (gref->rdhead) {
782 gbuf_freel(gref->rdhead);
783 gref->rdhead = 0;
784 }
785 /* blocked read */
786 if (gref->sevents & POLLMSG) {
787 gref->sevents &= ~POLLMSG;
9bccf70c 788 wakeup(&gref->event);
1c79356b
A
789 }
790 /* select */
791 if (gref->sevents & POLLIN) {
792 gref->sevents &= ~POLLIN;
1c79356b 793 selwakeup(&gref->si);
1c79356b
A
794 }
795 }
796 }
1c79356b
A
797} /* atalk_notify */
798
799void atalk_notify_sel(gref)
800 gref_t *gref;
801{
1c79356b 802
1c79356b
A
803 if (gref->sevents & POLLIN) {
804 gref->sevents &= ~POLLIN;
1c79356b 805 selwakeup(&gref->si);
1c79356b 806 }
1c79356b
A
807}
808
809int atalk_peek(gref, event)
810 gref_t *gref;
811 unsigned char *event;
812{
0c530ab8 813 int rc;
1c79356b 814
1c79356b
A
815 if (gref->rdhead) {
816 *event = *gbuf_rptr(gref->rdhead);
817 rc = 0;
818 } else
819 rc = -1;
1c79356b
A
820
821 return rc;
822}
823
2d21ac55 824#if 0
1c79356b
A
825static gbuf_t *trace_msg;
826
2d21ac55 827void atalk_settrace(char * str, p1, p2, p3, p4, p5)
1c79356b
A
828{
829 int len;
830 gbuf_t *m, *nextm;
831 char trace_buf[256];
832
833 sprintf(trace_buf, str, p1, p2, p3, p4, p5);
834 len = strlen(trace_buf);
835#ifdef APPLETALK_DEBUG
836 kprintf("atalk_settrace: gbufalloc size=%d\n", len+1);
837#endif
838 if ((m = gbuf_alloc(len+1, PRI_MED)) == 0)
839 return;
840 gbuf_wset(m,len);
841 strcpy(gbuf_rptr(m), trace_buf);
842 if (trace_msg) {
843 for (nextm=trace_msg; gbuf_cont(nextm); nextm=gbuf_cont(nextm)) ;
844 gbuf_cont(nextm) = m;
845 } else
846 trace_msg = m;
847}
848
849void atalk_gettrace(m)
850 gbuf_t *m;
851{
852 if (trace_msg) {
853 gbuf_cont(m) = trace_msg;
854 trace_msg = 0;
855 }
856}
2d21ac55 857#endif /* 0 */
1c79356b
A
858
859#define GREF_PER_BLK 32
860static gref_t *gref_free_list = 0;
2d21ac55 861extern gbuf_t *atp_resource_m;
1c79356b
A
862
863int gref_alloc(grefp)
864 gref_t **grefp;
865{
0c530ab8 866 int i;
1c79356b
A
867 gbuf_t *m;
868 gref_t *gref, *gref_array;
869
870 *grefp = (gref_t *)NULL;
871
1c79356b 872 if (gref_free_list == 0) {
1c79356b
A
873#ifdef APPLETALK_DEBUG
874 kprintf("gref_alloc: gbufalloc size=%d\n", GREF_PER_BLK*sizeof(gref_t));
875#endif
876 if ((m = gbuf_alloc(GREF_PER_BLK*sizeof(gref_t),PRI_HI)) == 0)
877 return ENOBUFS;
878 bzero(gbuf_rptr(m), GREF_PER_BLK*sizeof(gref_t));
879 gref_array = (gref_t *)gbuf_rptr(m);
880 for (i=0; i < GREF_PER_BLK-1; i++)
881 gref_array[i].atpcb_next = (gref_t *)&gref_array[i+1];
1c79356b
A
882 gbuf_cont(m) = atp_resource_m;
883 atp_resource_m = m;
884 gref_array[i].atpcb_next = gref_free_list;
885 gref_free_list = (gref_t *)&gref_array[0];
886 }
887
888 gref = gref_free_list;
889 gref_free_list = gref->atpcb_next;
1c79356b
A
890 ATEVENTINIT(gref->event);
891 ATEVENTINIT(gref->iocevent);
892
893 /* *** just for now *** */
894 gref->atpcb_socket = (struct socket *)NULL;
895
896 *grefp = gref;
897 return 0;
898} /* gref_alloc */
899
0b4e3aa0
A
900/* bms: make gref_close callable from kernel */
901int gref_close(gref_t *gref)
1c79356b 902{
0c530ab8 903 int rc;
1c79356b
A
904
905 switch (gref->proto) {
906
907 /* ATPROTO_DDP and ATPROTO_LAP have been replaced with
908 BSD-style socket interface. */
909
910 case ATPROTO_ATP:
911 rc = atp_close(gref, 1); break;
912 case ATPROTO_ASP:
913 rc = asp_close(gref); break;
914#ifdef AURP_SUPPORT
915 case ATPROTO_AURP:
916 rc = aurp_close(gref); break;
917 break;
918#endif
919 case ATPROTO_ADSP:
920 rc = adsp_close(gref); break;
921 default:
922 rc = 0;
923 break;
924 }
925
926 if (rc == 0) {
927 atalk_flush(gref);
928 selthreadclear(&gref->si);
929
930 /* from original gref_free() */
1c79356b
A
931 bzero((char *)gref, sizeof(gref_t));
932 gref->atpcb_next = gref_free_list;
933 gref_free_list = gref;
1c79356b
A
934 }
935
936 return rc;
937}
938\f
0b4e3aa0
A
939/*
940 temp fix for bug 2731148 - until this code is re-written to use standard clusters
941 Deletes any free clusters on the free list.
942*/
2d21ac55 943void atp_delete_free_clusters(__unused void *junk)
0b4e3aa0
A
944{
945 caddr_t cluster;
946 caddr_t cluster_list;
2d21ac55 947
0b4e3aa0 948 /* check for free clusters on the free_cluster_list to be deleted */
0b4e3aa0 949
2d21ac55 950 untimeout(&atp_delete_free_clusters, NULL);
0b4e3aa0 951
2d21ac55
A
952 lck_mtx_lock(atalk_cluster_lock);
953
954 atp_free_cluster_timeout_set = 0;
955
956 cluster_list = atp_free_cluster_list;
957 atp_free_cluster_list = NULL;
958
959 lck_mtx_unlock(atalk_cluster_lock);
960
961 while ((cluster = cluster_list))
0b4e3aa0
A
962 {
963 cluster_list = *((caddr_t*)cluster);
964 FREE(cluster, M_MCLUST);
965 }
0b4e3aa0
A
966}
967
968
1c79356b
A
969/*
970 Used as the "free" routine for over-size clusters allocated using
2d21ac55 971 m_lgbuf_alloc().
1c79356b
A
972*/
973
2d21ac55
A
974void m_lgbuf_free(caddr_t, u_int, caddr_t);
975
976void m_lgbuf_free(
977 caddr_t buf,
978 __unused u_int size,
979 __unused caddr_t arg) /* not needed, but they're in m_free() */
1c79356b 980{
2d21ac55
A
981 int t;
982
0b4e3aa0
A
983 /* move to free_cluster_list to be deleted later */
984 caddr_t cluster = (caddr_t)buf;
2d21ac55
A
985
986 lck_mtx_lock(atalk_cluster_lock);
987
0b4e3aa0
A
988 *((caddr_t*)cluster) = atp_free_cluster_list;
989 atp_free_cluster_list = cluster;
2d21ac55
A
990
991 if ((t = atp_free_cluster_timeout_set) == 0)
0b4e3aa0 992 atp_free_cluster_timeout_set = 1;
2d21ac55
A
993
994 lck_mtx_unlock(atalk_cluster_lock);
995
996 if (t == 0)
0b4e3aa0 997 timeout(&atp_delete_free_clusters, NULL, (1 * HZ));
1c79356b
A
998}
999
1000/*
1001 Used to allocate an mbuf when there is the possibility that it may
1002 need to be larger than the size of a standard cluster.
1003*/
1004
1005struct mbuf *m_lgbuf_alloc(size, wait)
1006 int size, wait;
1007{
1008 struct mbuf *m;
1009
0b4e3aa0 1010 if (atp_free_cluster_list)
6601e61a
A
1011 atp_delete_free_clusters(NULL); /* delete any free clusters on the free list */
1012
2d21ac55 1013 /* Radar 5398094
6601e61a
A
1014 * check that the passed size is within admissible boundaries
1015 * The max data size being ASP of 4576 (8 * ATP_DATA_SIZE),
1016 * allow for extra space for control data
1017 */
1018
1019 if (size < 0 || size > (ATP_DATA_SIZE * 10))
1020 return(NULL);
1021
1c79356b
A
1022 /* If size is too large, allocate a cluster, otherwise, use the
1023 standard mbuf allocation routines.*/
1024 if (size > MCLBYTES) {
1025 void *buf;
1026 if (NULL ==
1027 (buf = (void *)_MALLOC(size, M_MCLUST,
1028 (wait)? M_WAITOK: M_NOWAIT))) {
1029 return(NULL);
1030 }
1031 if (NULL ==
2d21ac55 1032 (m = m_clattach(NULL, MSG_DATA, buf, m_lgbuf_free, size, 0,
1c79356b 1033 (wait)? M_WAIT: M_DONTWAIT))) {
55e303ae 1034 m_lgbuf_free(buf, 0, 0);
1c79356b
A
1035 return(NULL);
1036 }
1037 } else {
1038 m = m_gethdr(((wait)? M_WAIT: M_DONTWAIT), MSG_DATA);
2d21ac55 1039 if (m && ((size_t)size > MHLEN)) {
1c79356b
A
1040 MCLGET(m, ((wait)? M_WAIT: M_DONTWAIT));
1041 if (!(m->m_flags & M_EXT)) {
1042 (void)m_free(m);
1043 return(NULL);
1044 }
1045 }
1046 }
1047
1048 return(m);
1049} /* m_lgbuf_alloc */
1050
1051/*
1052 gbuf_alloc() is a wrapper for m_lgbuf_alloc(), which is used to
1053 allocate an mbuf when there is the possibility that it may need
1054 to be larger than the size of a standard cluster.
1055
1056 gbuf_alloc() sets the mbuf lengths, unlike the standard mbuf routines.
1057*/
1058
1059gbuf_t *gbuf_alloc_wait(size, wait)
1060 int size, wait;
1061{
1062 gbuf_t *m = (gbuf_t *)m_lgbuf_alloc(size, wait);
1063
1064 /* Standard mbuf allocation routines assume that the caller
1065 will set the size. */
1066 if (m) {
2d21ac55
A
1067 m->m_pkthdr.len = size;
1068 m->m_len = size;
1c79356b
A
1069 }
1070
1071 return(m);
1072}
1073
1074int gbuf_msgsize(m)
1075 gbuf_t *m;
1076{
1077 int size;
1078
1079 for (size=0; m; m=gbuf_cont(m))
1080 size += gbuf_len(m);
1081 return size;
1082}
1083
1084int append_copy(m1, m2, wait)
1085 struct mbuf *m1, *m2;
1086 int wait;
1087{
1088 if ((!(m1->m_flags & M_EXT)) && (!(m2->m_flags & M_EXT)) &&
1089 (m_trailingspace(m1) >= m2->m_len)) {
1090 /* splat the data from one into the other */
1091 bcopy(mtod(m2, caddr_t), mtod(m1, caddr_t) + m1->m_len,
1092 (u_int)m2->m_len);
1093 m1->m_len += m2->m_len;
1094 if (m1->m_flags & M_PKTHDR)
1095 m1->m_pkthdr.len += m2->m_len;
1096 return 1;
1097 }
1098 if ((m1->m_next = m_copym(m2, 0, m2->m_len,
1099 (wait)? M_WAIT: M_DONTWAIT)) == NULL)
1100 return 0;
1101 return 1;
1102} /* append_copy */
1103
1104/*
1105 Copy an mbuf chain, referencing existing external storage, if any.
1106 Leave space for a header in the new chain, if the space has been
1107 left in the origin chain.
1108*/
1109struct mbuf *copy_pkt(mlist, pad)
1110 struct mbuf *mlist; /* the mbuf chain to be copied */
1111 int pad; /* hint as to how long the header might be
1112 If pad is < 0, leave the same amount of space
1113 as there was in the original. */
1114{
1115 struct mbuf *new_m;
1116 int len;
1117
1118 if (pad < 0)
1119 len = m_leadingspace(mlist);
1120 else
1121 len = min(pad, m_leadingspace(mlist));
1122
1123 /* preserve space for the header at the beginning of the mbuf */
1124 if (len) {
1125 mlist->m_data -= (len);
1126 mlist->m_len += (len);
1127 if (mlist->m_flags & M_PKTHDR)
1128 mlist->m_pkthdr.len += (len);
1129 new_m = m_copym(mlist, 0, M_COPYALL, M_DONTWAIT);
1130 m_adj(mlist, len);
1131 m_adj(new_m, len);
1132 } else
1133 new_m = m_copym(mlist, 0, M_COPYALL, M_DONTWAIT);
1134
1135 return(new_m);
1136}
1137
1138void gbuf_linkb(m1, m2)
1139 gbuf_t *m1;
1140 gbuf_t *m2;
1141{
1142 while (gbuf_cont(m1) != 0)
1143 m1 = gbuf_cont(m1);
1144 gbuf_cont(m1) = m2;
1145}
1146
1147void gbuf_linkpkt(m1, m2)
1148 gbuf_t *m1;
1149 gbuf_t *m2;
1150{
1151 while (gbuf_next(m1) != 0)
1152 m1 = gbuf_next(m1);
1153 gbuf_next(m1) = m2;
1154}
1155
1156int gbuf_freel(m)
1157 gbuf_t *m;
1158{
1159 gbuf_t *tmp_m;
1160
1161 while ((tmp_m = m) != 0) {
1162 m = gbuf_next(m);
1163 gbuf_next(tmp_m) = 0;
1164 gbuf_freem(tmp_m);
1165 }
1166 return (0);
1167}
1168
1169/* free empty mbufs at the front of the chain */
1170gbuf_t *gbuf_strip(m)
1171 gbuf_t *m;
1172{
1173 gbuf_t *tmp_m;
1174
1175 while (m && gbuf_len(m) == 0) {
1176 tmp_m = m;
1177 m = gbuf_cont(m);
1178 gbuf_freeb(tmp_m);
1179 }
1180 return(m);
1181}
1182\f
1183/**************************************/
1184
1185int ddp_adjmsg(m, len)
1186 gbuf_t *m;
1187 int len;
1188{
1189 int buf_len;
1190 gbuf_t *curr_m, *prev_m;
1191
1192 if (m == (gbuf_t *)0)
1193 return 0;
1194
1195 if (len > 0) {
1196 for (curr_m=m; curr_m;) {
1197 buf_len = gbuf_len(curr_m);
1198 if (len < buf_len) {
1199 gbuf_rinc(curr_m,len);
1200 return 1;
1201 }
1202 len -= buf_len;
1203 gbuf_rinc(curr_m,buf_len);
1204 if ((curr_m = gbuf_cont(curr_m)) == 0) {
1205 gbuf_freem(m);
1206 return 0;
1207 }
1208 }
1209
1210 } else if (len < 0) {
1211 len = -len;
1212l_cont: prev_m = 0;
1213 for (curr_m=m; gbuf_cont(curr_m);
1214 prev_m=curr_m, curr_m=gbuf_cont(curr_m)) ;
1215 buf_len = gbuf_len(curr_m);
1216 if (len < buf_len) {
1217 gbuf_wdec(curr_m,len);
1218 return 1;
1219 }
1220 if (prev_m == 0)
1221 return 0;
1222 gbuf_cont(prev_m) = 0;
1223 gbuf_freeb(curr_m);
1224 len -= buf_len;
1225 goto l_cont;
1226
2d21ac55
A
1227 }
1228
1229 return 1;
1c79356b
A
1230}
1231
1232/*
1233 * The message chain, m is grown in size by len contiguous bytes.
1234 * If len is non-negative, len bytes are added to the
1235 * end of the gbuf_t chain. If len is negative, the
1236 * bytes are added to the front. ddp_growmsg only adds bytes to
1237 * message blocks of the same type.
1238 * It returns a pointer to the new gbuf_t on sucess, 0 on failure.
1239 */
1240
1241gbuf_t *ddp_growmsg(mp, len)
1242 gbuf_t *mp;
1243 int len;
1244{
1245 gbuf_t *m, *d;
1246
1247 if ((m = mp) == (gbuf_t *) 0)
1248 return ((gbuf_t *) 0);
1249
1250 if (len <= 0) {
1251 len = -len;
1252 if ((d = gbuf_alloc(len, PRI_MED)) == 0)
1253 return ((gbuf_t *) 0);
1254 gbuf_set_type(d, gbuf_type(m));
1255 gbuf_wset(d,len);
1256 /* link in new gbuf_t */
1257 gbuf_cont(d) = m;
1258 return (d);
1259
1260 } else {
1261 register int count;
1262 /*
1263 * Add to tail.
1264 */
1265 if ((count = gbuf_msgsize(m)) < 0)
1266 return ((gbuf_t *) 0);
1267 /* find end of chain */
1268 for ( ; m; m = gbuf_cont(m)) {
1269 if (gbuf_len(m) >= count)
1270 break;
1271 count -= gbuf_len(m);
1272 }
1273 /* m now points to gbuf_t to add to */
1274 if ((d = gbuf_alloc(len, PRI_MED)) == 0)
1275 return ((gbuf_t *) 0);
1276 gbuf_set_type(d, gbuf_type(m));
1277 /* link in new gbuf_t */
1278 gbuf_cont(d) = gbuf_cont(m);
1279 gbuf_cont(m) = d;
1280 gbuf_wset(d,len);
1281 return (d);
1282 }
1283}
1284
1285/*
1286 * return the MSG_IOCACK/MSG_IOCNAK. Note that the same message
1287 * block is used as the vehicle, and that if there is an error return,
1288 * then linked blocks are lopped off. BEWARE of multiple references.
1289 * Used by other appletalk modules, so it is not static!
1290 */
1291
1292void ioc_ack(errno, m, gref)
1293 int errno;
1294 register gbuf_t *m;
1295 register gref_t *gref;
1296{
1297 ioc_t *iocbp = (ioc_t *)gbuf_rptr(m);
1298
1299 /*kprintf("ioc_ack: m=%x gref=%x errno=%d\n", m, gref, errno);*/
1300 if ((iocbp->ioc_error = errno) != 0)
1301 { /* errno != 0, then there is an error, get rid of linked blocks! */
1302
1303 if (gbuf_cont(m)) {
1304 gbuf_freem(gbuf_cont(m));
1305 gbuf_cont(m) = 0;
1306 }
1307 gbuf_set_type(m, MSG_IOCNAK);
1308 iocbp->ioc_count = 0; /* only make zero length if error */
1309 iocbp->ioc_rval = -1;
1310 } else
1311 gbuf_set_type(m, MSG_IOCACK);
1312
1313 atalk_putnext(gref, m);
1314}
1315
91447636
A
1316
1317static void ioccmd_t_32_to_64( ioccmd_t *from_p, user_ioccmd_t *to_p )
1318{
1319 to_p->ic_cmd = from_p->ic_cmd;
1320 to_p->ic_timout = from_p->ic_timout;
1321 to_p->ic_len = from_p->ic_len;
1322 to_p->ic_dp = CAST_USER_ADDR_T(from_p->ic_dp);
1323}
1324
1325
1326static void ioccmd_t_64_to_32( user_ioccmd_t *from_p, ioccmd_t *to_p )
1327{
1328 to_p->ic_cmd = from_p->ic_cmd;
1329 to_p->ic_timout = from_p->ic_timout;
1330 to_p->ic_len = from_p->ic_len;
1331 to_p->ic_dp = CAST_DOWN(caddr_t, from_p->ic_dp);
1332}