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