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