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