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