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