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