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