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