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