]> git.saurik.com Git - apple/xnu.git/blame - bsd/netat/sys_glue.c
xnu-792.1.5.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
283int _ATrw(fp, rw, uio, ext)
284 void *fp;
285 enum uio_rw rw;
286 struct uio *uio;
287 int ext;
288{
289 int s, err, len, clen = 0, res;
290 gref_t *gref;
291 gbuf_t *m, *mhead, *mprev;
292
91447636
A
293 /* no need to get/drop iocount as the fp already has one */
294 if ((err = atalk_getref_locked(fp, 0, &gref, 0, 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();
1c79356b 417 stat = _ATrw(fp, UIO_READ, uio, 0);
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();
1c79356b 432 stat = _ATrw(fp, UIO_WRITE, uio, 0);
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
91447636
A
636 atalk_lock();
637 /* no need to drop the iocount as select covers that */
638 err = atalk_getref_locked(fp, 0, &gref, 0, 0);
639 atalk_unlock();
1c79356b
A
640
641 if (err != 0)
642 rc = 1;
643 else {
644 ATDISABLE(s, gref->lock);
645 if (which == FREAD) {
646 if (gref->rdhead || (gref->readable && (*gref->readable)(gref)))
647 rc = 1;
648 else {
649 gref->sevents |= POLLIN;
0b4e3aa0 650 selrecord(proc, &gref->si, wql);
1c79356b
A
651 }
652 }
653 else if (which == POLLOUT) {
654 if (gref->writeable) {
655 if ((*gref->writeable)(gref))
656 rc = 1;
657 else {
658 gref->sevents |= POLLOUT;
0b4e3aa0 659 selrecord(proc, &gref->si, wql);
1c79356b
A
660 }
661 } else
662 rc = 1;
663 }
664 ATENABLE(s, gref->lock);
665 }
666
667 return rc;
668}
669
55e303ae 670int _ATkqfilter(fp, kn, p)
91447636 671 struct fileproc *fp;
55e303ae
A
672 struct knote *kn;
673 struct proc *p;
674{
675 return (EOPNOTSUPP);
676}
677
1c79356b
A
678void atalk_putnext(gref, m)
679 gref_t *gref;
680 gbuf_t *m;
681{
682 int s;
683
684 ATDISABLE(s, gref->lock);
685
686 /* *** potential leak? *** */
687 gbuf_next(m) = 0;
688
689 switch (gbuf_type(m)) {
690 case MSG_IOCACK:
691 case MSG_IOCNAK:
692 if (gref->ichead)
693 gbuf_next(gref->ichead) = m;
694 else {
695 gref->ichead = m;
696 if (gref->sevents & POLLPRI) {
697#ifdef APPLETALK_DEBUG
698 kprintf("wakeup gref = 0x%x\n", (unsigned)gref);
699#endif
9bccf70c 700 wakeup(&gref->iocevent);
1c79356b
A
701 }
702 }
703 break;
704 case MSG_ERROR:
705 /* *** this processing was moved to atalk_notify *** */
706 panic("atalk_putnext receved MSG_ERROR");
707 break;
708 default:
709 if (gref->errno)
710 gbuf_freem(m);
711 else
712 if (gref->rdhead) {
713 gbuf_next(gref->rdtail) = m;
714 gref->rdtail = m;
715 } else {
716 gref->rdhead = m;
717 if (gref->sevents & POLLMSG) {
718 gref->sevents &= ~POLLMSG;
9bccf70c 719 wakeup(&gref->event);
1c79356b
A
720 }
721 if (gref->sevents & POLLIN) {
722 gref->sevents &= ~POLLIN;
1c79356b 723 selwakeup(&gref->si);
1c79356b
A
724 }
725 gref->rdtail = m;
726 }
727 } /* switch gbuf_type(m) */
728
729 ATENABLE(s, gref->lock);
730} /* atalk_putnext */
731
732void atalk_enablew(gref)
733 gref_t *gref;
734{
735 if (gref->sevents & POLLSYNC)
9bccf70c 736 wakeup(&gref->event);
1c79356b
A
737}
738
739void atalk_flush(gref)
740 gref_t *gref;
741{
742 int s;
743
744 ATDISABLE(s, gref->lock);
745 if (gref->rdhead) {
746 gbuf_freel(gref->rdhead);
747 gref->rdhead = 0;
748 }
749 if (gref->ichead) {
750 gbuf_freel(gref->ichead);
751 gref->ichead = 0;
752 }
753 ATENABLE(s, gref->lock);
754}
755
756/*
757 * Notify an appletalk user of an asynchronous error;
758 * just wake up so that he can collect error status.
759 */
760void atalk_notify(gref, errno)
761 register gref_t *gref;
762 int errno;
763{
764 int s;
765 ATDISABLE(s, gref->lock);
766
767 if (gref->atpcb_socket) {
768 /* For DDP --
769 This section is patterned after udp_notify() in
770 netinet/udp_usrreq.c
771 */
772 gref->atpcb_socket->so_error = errno;
773 sorwakeup(gref->atpcb_socket);
774 sowwakeup(gref->atpcb_socket);
775 } else {
776 /* for ATP, ASP, and ADSP */
777 if (gref->errno == 0) {
778 gref->errno = errno;
779 /* clear out data waiting to be read */
780 if (gref->rdhead) {
781 gbuf_freel(gref->rdhead);
782 gref->rdhead = 0;
783 }
784 /* blocked read */
785 if (gref->sevents & POLLMSG) {
786 gref->sevents &= ~POLLMSG;
9bccf70c 787 wakeup(&gref->event);
1c79356b
A
788 }
789 /* select */
790 if (gref->sevents & POLLIN) {
791 gref->sevents &= ~POLLIN;
1c79356b 792 selwakeup(&gref->si);
1c79356b
A
793 }
794 }
795 }
796 ATENABLE(s, gref->lock);
797} /* atalk_notify */
798
799void atalk_notify_sel(gref)
800 gref_t *gref;
801{
802 int s;
803
804 ATDISABLE(s, gref->lock);
805 if (gref->sevents & POLLIN) {
806 gref->sevents &= ~POLLIN;
1c79356b 807 selwakeup(&gref->si);
1c79356b
A
808 }
809 ATENABLE(s, gref->lock);
810}
811
812int atalk_peek(gref, event)
813 gref_t *gref;
814 unsigned char *event;
815{
816 int s, rc;
817
818 ATDISABLE(s, gref->lock);
819 if (gref->rdhead) {
820 *event = *gbuf_rptr(gref->rdhead);
821 rc = 0;
822 } else
823 rc = -1;
824 ATENABLE(s, gref->lock);
825
826 return rc;
827}
828
829static gbuf_t *trace_msg;
830
831void atalk_settrace(str, p1, p2, p3, p4, p5)
832 char *str;
833{
834 int len;
835 gbuf_t *m, *nextm;
836 char trace_buf[256];
837
838 sprintf(trace_buf, str, p1, p2, p3, p4, p5);
839 len = strlen(trace_buf);
840#ifdef APPLETALK_DEBUG
841 kprintf("atalk_settrace: gbufalloc size=%d\n", len+1);
842#endif
843 if ((m = gbuf_alloc(len+1, PRI_MED)) == 0)
844 return;
845 gbuf_wset(m,len);
846 strcpy(gbuf_rptr(m), trace_buf);
847 if (trace_msg) {
848 for (nextm=trace_msg; gbuf_cont(nextm); nextm=gbuf_cont(nextm)) ;
849 gbuf_cont(nextm) = m;
850 } else
851 trace_msg = m;
852}
853
854void atalk_gettrace(m)
855 gbuf_t *m;
856{
857 if (trace_msg) {
858 gbuf_cont(m) = trace_msg;
859 trace_msg = 0;
860 }
861}
862
863#define GREF_PER_BLK 32
864static gref_t *gref_free_list = 0;
865
866int gref_alloc(grefp)
867 gref_t **grefp;
868{
869 extern gbuf_t *atp_resource_m;
870 int i, s;
871 gbuf_t *m;
872 gref_t *gref, *gref_array;
873
874 *grefp = (gref_t *)NULL;
875
876 ATDISABLE(s, refall_lock);
877 if (gref_free_list == 0) {
878 ATENABLE(s, refall_lock);
879#ifdef APPLETALK_DEBUG
880 kprintf("gref_alloc: gbufalloc size=%d\n", GREF_PER_BLK*sizeof(gref_t));
881#endif
882 if ((m = gbuf_alloc(GREF_PER_BLK*sizeof(gref_t),PRI_HI)) == 0)
883 return ENOBUFS;
884 bzero(gbuf_rptr(m), GREF_PER_BLK*sizeof(gref_t));
885 gref_array = (gref_t *)gbuf_rptr(m);
886 for (i=0; i < GREF_PER_BLK-1; i++)
887 gref_array[i].atpcb_next = (gref_t *)&gref_array[i+1];
888 ATDISABLE(s, refall_lock);
889 gbuf_cont(m) = atp_resource_m;
890 atp_resource_m = m;
891 gref_array[i].atpcb_next = gref_free_list;
892 gref_free_list = (gref_t *)&gref_array[0];
893 }
894
895 gref = gref_free_list;
896 gref_free_list = gref->atpcb_next;
897 ATENABLE(s, refall_lock);
898 ATLOCKINIT(gref->lock);
899//### LD Test 08/05/98
900// simple_lock_init(&gref->lock);
901 ATEVENTINIT(gref->event);
902 ATEVENTINIT(gref->iocevent);
903
904 /* *** just for now *** */
905 gref->atpcb_socket = (struct socket *)NULL;
906
907 *grefp = gref;
908 return 0;
909} /* gref_alloc */
910
0b4e3aa0
A
911/* bms: make gref_close callable from kernel */
912int gref_close(gref_t *gref)
1c79356b
A
913{
914 int s, rc;
915
916 switch (gref->proto) {
917
918 /* ATPROTO_DDP and ATPROTO_LAP have been replaced with
919 BSD-style socket interface. */
920
921 case ATPROTO_ATP:
922 rc = atp_close(gref, 1); break;
923 case ATPROTO_ASP:
924 rc = asp_close(gref); break;
925#ifdef AURP_SUPPORT
926 case ATPROTO_AURP:
927 rc = aurp_close(gref); break;
928 break;
929#endif
930 case ATPROTO_ADSP:
931 rc = adsp_close(gref); break;
932 default:
933 rc = 0;
934 break;
935 }
936
937 if (rc == 0) {
938 atalk_flush(gref);
939 selthreadclear(&gref->si);
940
941 /* from original gref_free() */
942 ATDISABLE(s, refall_lock);
943 bzero((char *)gref, sizeof(gref_t));
944 gref->atpcb_next = gref_free_list;
945 gref_free_list = gref;
946 ATENABLE(s, refall_lock);
947 }
948
949 return rc;
950}
951\f
952/*
953 Buffer Routines
954
955 *** Some to be replaced with mbuf routines, some to be re-written
956 as mbuf routines (and moved to kern/uicp_mbuf.c or sys/mbuf.h?).
957 ***
958
959*/
960
961/*
962 * LD 5/12/97 Added for MacOSX, defines a m_clattach function that:
963 * "Allocates an mbuf structure and attaches an external cluster."
964 */
965
966struct mbuf *m_clattach(extbuf, extfree, extsize, extarg, wait)
967 caddr_t extbuf;
55e303ae
A
968 void (*extfree)(caddr_t , u_int, caddr_t);
969 u_int extsize;
970 caddr_t extarg;
1c79356b
A
971 int wait;
972{
973 struct mbuf *m;
974
975 if ((m = m_gethdr(wait, MSG_DATA)) == NULL)
976 return (NULL);
977
978 m->m_ext.ext_buf = extbuf;
979 m->m_ext.ext_free = extfree;
980 m->m_ext.ext_size = extsize;
981 m->m_ext.ext_arg = extarg;
982 m->m_ext.ext_refs.forward =
983 m->m_ext.ext_refs.backward = &m->m_ext.ext_refs;
984 m->m_data = extbuf;
985 m->m_flags |= M_EXT;
986
987 return (m);
988}
989
0b4e3aa0
A
990
991
992/*
993 temp fix for bug 2731148 - until this code is re-written to use standard clusters
994 Deletes any free clusters on the free list.
995*/
996void atp_delete_free_clusters()
997{
998 caddr_t cluster;
999 caddr_t cluster_list;
1000
1001
1002 /* check for free clusters on the free_cluster_list to be deleted */
1003 MBUF_LOCK(); /* lock used by mbuf routines */
1004
1005 untimeout(&atp_delete_free_clusters, NULL);
1006 atp_free_cluster_timeout_set = 0;
1007
1008 cluster_list = atp_free_cluster_list;
1009 atp_free_cluster_list = 0;
1010
1011 MBUF_UNLOCK();
1012
1013 while (cluster = cluster_list)
1014 {
1015 cluster_list = *((caddr_t*)cluster);
1016 FREE(cluster, M_MCLUST);
1017 }
1018
1019}
1020
1021
1c79356b
A
1022/*
1023 Used as the "free" routine for over-size clusters allocated using
0b4e3aa0 1024 m_lgbuf_alloc(). Called by m_free while under MBUF_LOCK.
1c79356b
A
1025*/
1026
1027void m_lgbuf_free(buf, size, arg)
55e303ae
A
1028 caddr_t buf;
1029 u_int size;
1030 caddr_t arg; /* not needed, but they're in m_free() */
1c79356b 1031{
0b4e3aa0
A
1032 /* FREE(buf, M_MCLUST); - can't free here - called from m_free while under lock */
1033
1034 /* move to free_cluster_list to be deleted later */
1035 caddr_t cluster = (caddr_t)buf;
1036
1037 /* don't need a lock because this is only called called from m_free which */
1038 /* is under MBUF_LOCK */
1039 *((caddr_t*)cluster) = atp_free_cluster_list;
1040 atp_free_cluster_list = cluster;
1041
1042 if (atp_free_cluster_timeout_set == 0)
1043 {
1044 atp_free_cluster_timeout_set = 1;
1045 timeout(&atp_delete_free_clusters, NULL, (1 * HZ));
1046 }
1c79356b
A
1047}
1048
1049/*
1050 Used to allocate an mbuf when there is the possibility that it may
1051 need to be larger than the size of a standard cluster.
1052*/
1053
1054struct mbuf *m_lgbuf_alloc(size, wait)
1055 int size, wait;
1056{
1057 struct mbuf *m;
1058
0b4e3aa0
A
1059 if (atp_free_cluster_list)
1060 atp_delete_free_clusters(); /* delete any free clusters on the free list */
1061
1c79356b
A
1062 /* If size is too large, allocate a cluster, otherwise, use the
1063 standard mbuf allocation routines.*/
1064 if (size > MCLBYTES) {
1065 void *buf;
1066 if (NULL ==
1067 (buf = (void *)_MALLOC(size, M_MCLUST,
1068 (wait)? M_WAITOK: M_NOWAIT))) {
1069 return(NULL);
1070 }
1071 if (NULL ==
1072 (m = m_clattach(buf, m_lgbuf_free, size, 0,
1073 (wait)? M_WAIT: M_DONTWAIT))) {
55e303ae 1074 m_lgbuf_free(buf, 0, 0);
1c79356b
A
1075 return(NULL);
1076 }
1077 } else {
1078 m = m_gethdr(((wait)? M_WAIT: M_DONTWAIT), MSG_DATA);
1079 if (m && (size > MHLEN)) {
1080 MCLGET(m, ((wait)? M_WAIT: M_DONTWAIT));
1081 if (!(m->m_flags & M_EXT)) {
1082 (void)m_free(m);
1083 return(NULL);
1084 }
1085 }
1086 }
1087
1088 return(m);
1089} /* m_lgbuf_alloc */
1090
1091/*
1092 gbuf_alloc() is a wrapper for m_lgbuf_alloc(), which is used to
1093 allocate an mbuf when there is the possibility that it may need
1094 to be larger than the size of a standard cluster.
1095
1096 gbuf_alloc() sets the mbuf lengths, unlike the standard mbuf routines.
1097*/
1098
1099gbuf_t *gbuf_alloc_wait(size, wait)
1100 int size, wait;
1101{
1102 gbuf_t *m = (gbuf_t *)m_lgbuf_alloc(size, wait);
1103
1104 /* Standard mbuf allocation routines assume that the caller
1105 will set the size. */
1106 if (m) {
1107 (struct mbuf *)m->m_pkthdr.len = size;
1108 (struct mbuf *)m->m_len = size;
1109 }
1110
1111 return(m);
1112}
1113
1114int gbuf_msgsize(m)
1115 gbuf_t *m;
1116{
1117 int size;
1118
1119 for (size=0; m; m=gbuf_cont(m))
1120 size += gbuf_len(m);
1121 return size;
1122}
1123
1124int append_copy(m1, m2, wait)
1125 struct mbuf *m1, *m2;
1126 int wait;
1127{
1128 if ((!(m1->m_flags & M_EXT)) && (!(m2->m_flags & M_EXT)) &&
1129 (m_trailingspace(m1) >= m2->m_len)) {
1130 /* splat the data from one into the other */
1131 bcopy(mtod(m2, caddr_t), mtod(m1, caddr_t) + m1->m_len,
1132 (u_int)m2->m_len);
1133 m1->m_len += m2->m_len;
1134 if (m1->m_flags & M_PKTHDR)
1135 m1->m_pkthdr.len += m2->m_len;
1136 return 1;
1137 }
1138 if ((m1->m_next = m_copym(m2, 0, m2->m_len,
1139 (wait)? M_WAIT: M_DONTWAIT)) == NULL)
1140 return 0;
1141 return 1;
1142} /* append_copy */
1143
1144/*
1145 Copy an mbuf chain, referencing existing external storage, if any.
1146 Leave space for a header in the new chain, if the space has been
1147 left in the origin chain.
1148*/
1149struct mbuf *copy_pkt(mlist, pad)
1150 struct mbuf *mlist; /* the mbuf chain to be copied */
1151 int pad; /* hint as to how long the header might be
1152 If pad is < 0, leave the same amount of space
1153 as there was in the original. */
1154{
1155 struct mbuf *new_m;
1156 int len;
1157
1158 if (pad < 0)
1159 len = m_leadingspace(mlist);
1160 else
1161 len = min(pad, m_leadingspace(mlist));
1162
1163 /* preserve space for the header at the beginning of the mbuf */
1164 if (len) {
1165 mlist->m_data -= (len);
1166 mlist->m_len += (len);
1167 if (mlist->m_flags & M_PKTHDR)
1168 mlist->m_pkthdr.len += (len);
1169 new_m = m_copym(mlist, 0, M_COPYALL, M_DONTWAIT);
1170 m_adj(mlist, len);
1171 m_adj(new_m, len);
1172 } else
1173 new_m = m_copym(mlist, 0, M_COPYALL, M_DONTWAIT);
1174
1175 return(new_m);
1176}
1177
1178void gbuf_linkb(m1, m2)
1179 gbuf_t *m1;
1180 gbuf_t *m2;
1181{
1182 while (gbuf_cont(m1) != 0)
1183 m1 = gbuf_cont(m1);
1184 gbuf_cont(m1) = m2;
1185}
1186
1187void gbuf_linkpkt(m1, m2)
1188 gbuf_t *m1;
1189 gbuf_t *m2;
1190{
1191 while (gbuf_next(m1) != 0)
1192 m1 = gbuf_next(m1);
1193 gbuf_next(m1) = m2;
1194}
1195
1196int gbuf_freel(m)
1197 gbuf_t *m;
1198{
1199 gbuf_t *tmp_m;
1200
1201 while ((tmp_m = m) != 0) {
1202 m = gbuf_next(m);
1203 gbuf_next(tmp_m) = 0;
1204 gbuf_freem(tmp_m);
1205 }
1206 return (0);
1207}
1208
1209/* free empty mbufs at the front of the chain */
1210gbuf_t *gbuf_strip(m)
1211 gbuf_t *m;
1212{
1213 gbuf_t *tmp_m;
1214
1215 while (m && gbuf_len(m) == 0) {
1216 tmp_m = m;
1217 m = gbuf_cont(m);
1218 gbuf_freeb(tmp_m);
1219 }
1220 return(m);
1221}
1222\f
1223/**************************************/
1224
1225int ddp_adjmsg(m, len)
1226 gbuf_t *m;
1227 int len;
1228{
1229 int buf_len;
1230 gbuf_t *curr_m, *prev_m;
1231
1232 if (m == (gbuf_t *)0)
1233 return 0;
1234
1235 if (len > 0) {
1236 for (curr_m=m; curr_m;) {
1237 buf_len = gbuf_len(curr_m);
1238 if (len < buf_len) {
1239 gbuf_rinc(curr_m,len);
1240 return 1;
1241 }
1242 len -= buf_len;
1243 gbuf_rinc(curr_m,buf_len);
1244 if ((curr_m = gbuf_cont(curr_m)) == 0) {
1245 gbuf_freem(m);
1246 return 0;
1247 }
1248 }
1249
1250 } else if (len < 0) {
1251 len = -len;
1252l_cont: prev_m = 0;
1253 for (curr_m=m; gbuf_cont(curr_m);
1254 prev_m=curr_m, curr_m=gbuf_cont(curr_m)) ;
1255 buf_len = gbuf_len(curr_m);
1256 if (len < buf_len) {
1257 gbuf_wdec(curr_m,len);
1258 return 1;
1259 }
1260 if (prev_m == 0)
1261 return 0;
1262 gbuf_cont(prev_m) = 0;
1263 gbuf_freeb(curr_m);
1264 len -= buf_len;
1265 goto l_cont;
1266
1267 } else
1268 return 1;
1269}
1270
1271/*
1272 * The message chain, m is grown in size by len contiguous bytes.
1273 * If len is non-negative, len bytes are added to the
1274 * end of the gbuf_t chain. If len is negative, the
1275 * bytes are added to the front. ddp_growmsg only adds bytes to
1276 * message blocks of the same type.
1277 * It returns a pointer to the new gbuf_t on sucess, 0 on failure.
1278 */
1279
1280gbuf_t *ddp_growmsg(mp, len)
1281 gbuf_t *mp;
1282 int len;
1283{
1284 gbuf_t *m, *d;
1285
1286 if ((m = mp) == (gbuf_t *) 0)
1287 return ((gbuf_t *) 0);
1288
1289 if (len <= 0) {
1290 len = -len;
1291 if ((d = gbuf_alloc(len, PRI_MED)) == 0)
1292 return ((gbuf_t *) 0);
1293 gbuf_set_type(d, gbuf_type(m));
1294 gbuf_wset(d,len);
1295 /* link in new gbuf_t */
1296 gbuf_cont(d) = m;
1297 return (d);
1298
1299 } else {
1300 register int count;
1301 /*
1302 * Add to tail.
1303 */
1304 if ((count = gbuf_msgsize(m)) < 0)
1305 return ((gbuf_t *) 0);
1306 /* find end of chain */
1307 for ( ; m; m = gbuf_cont(m)) {
1308 if (gbuf_len(m) >= count)
1309 break;
1310 count -= gbuf_len(m);
1311 }
1312 /* m now points to gbuf_t to add to */
1313 if ((d = gbuf_alloc(len, PRI_MED)) == 0)
1314 return ((gbuf_t *) 0);
1315 gbuf_set_type(d, gbuf_type(m));
1316 /* link in new gbuf_t */
1317 gbuf_cont(d) = gbuf_cont(m);
1318 gbuf_cont(m) = d;
1319 gbuf_wset(d,len);
1320 return (d);
1321 }
1322}
1323
1324/*
1325 * return the MSG_IOCACK/MSG_IOCNAK. Note that the same message
1326 * block is used as the vehicle, and that if there is an error return,
1327 * then linked blocks are lopped off. BEWARE of multiple references.
1328 * Used by other appletalk modules, so it is not static!
1329 */
1330
1331void ioc_ack(errno, m, gref)
1332 int errno;
1333 register gbuf_t *m;
1334 register gref_t *gref;
1335{
1336 ioc_t *iocbp = (ioc_t *)gbuf_rptr(m);
1337
1338 /*kprintf("ioc_ack: m=%x gref=%x errno=%d\n", m, gref, errno);*/
1339 if ((iocbp->ioc_error = errno) != 0)
1340 { /* errno != 0, then there is an error, get rid of linked blocks! */
1341
1342 if (gbuf_cont(m)) {
1343 gbuf_freem(gbuf_cont(m));
1344 gbuf_cont(m) = 0;
1345 }
1346 gbuf_set_type(m, MSG_IOCNAK);
1347 iocbp->ioc_count = 0; /* only make zero length if error */
1348 iocbp->ioc_rval = -1;
1349 } else
1350 gbuf_set_type(m, MSG_IOCACK);
1351
1352 atalk_putnext(gref, m);
1353}
1354
91447636
A
1355
1356static void ioccmd_t_32_to_64( ioccmd_t *from_p, user_ioccmd_t *to_p )
1357{
1358 to_p->ic_cmd = from_p->ic_cmd;
1359 to_p->ic_timout = from_p->ic_timout;
1360 to_p->ic_len = from_p->ic_len;
1361 to_p->ic_dp = CAST_USER_ADDR_T(from_p->ic_dp);
1362}
1363
1364
1365static void ioccmd_t_64_to_32( user_ioccmd_t *from_p, ioccmd_t *to_p )
1366{
1367 to_p->ic_cmd = from_p->ic_cmd;
1368 to_p->ic_timout = from_p->ic_timout;
1369 to_p->ic_len = from_p->ic_len;
1370 to_p->ic_dp = CAST_DOWN(caddr_t, from_p->ic_dp);
1371}