]> git.saurik.com Git - apple/xnu.git/blame - bsd/netat/sys_glue.c
xnu-344.23.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 *
de355530
A
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.
1c79356b 11 *
de355530
A
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
1c79356b
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
de355530
A
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.
1c79356b
A
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
57extern struct atpcb ddp_head;
58
59extern 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);
0b4e3aa0
A
68
69int atp_free_cluster_timeout_set = 0;
70
1c79356b
A
71
72void atalk_putnext(gref_t *gref, gbuf_t *m);
0b4e3aa0
A
73/* bms: make gref_close non static so its callable from kernel */
74int gref_close(gref_t *gref);
1c79356b
A
75
76SYSCTL_DECL(_net_appletalk);
77dbgBits_t dbgBits;
78SYSCTL_STRUCT(_net_appletalk, OID_AUTO, debug, CTLFLAG_WR,
79 &dbgBits, dbgBits, "AppleTalk Debug Flags");
80volatile int RouterMix = RT_MIX_DEFAULT; /* default for nbr of ppsec */
81SYSCTL_INT(_net_appletalk, OID_AUTO, routermix, CTLFLAG_WR,
82 &RouterMix, 0, "Appletalk RouterMix");
83at_ddp_stats_t at_ddp_stats; /* DDP statistics */
84SYSCTL_STRUCT(_net_appletalk, OID_AUTO, ddpstats, CTLFLAG_RD,
85 &at_ddp_stats, at_ddp_stats, "AppleTalk DDP Stats");
86
87atlock_t refall_lock;
88
0b4e3aa0
A
89caddr_t atp_free_cluster_list = 0;
90
91void gref_wput(gref, m)
1c79356b
A
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
127int _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
203int _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:
0b4e3aa0 217 rc = ASPgetmsg(gref, ctlptr, datptr, NULL, flags, err);
1c79356b
A
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
234int _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:
0b4e3aa0 248 rc = ASPputmsg(gref, ctlptr, datptr, NULL, flags, err); break;
1c79356b
A
249 default:
250 *err = EPROTONOSUPPORT; break;
251 }
252 }
253
254/* kprintf("_ATputmsg: return=%d\n", *err); */
255 return rc;
256}
257
258int _ATclose(fp, proc)
259 struct file *fp;
260 struct proc *proc;
261{
262 int err;
263 gref_t *gref;
264
1c79356b
A
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
274int _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
9bccf70c 396int _ATread(fp, uio, cred, flags, p)
1c79356b
A
397 void *fp;
398 struct uio *uio;
399 void *cred;
9bccf70c
A
400 int flags;
401 struct proc *p;
1c79356b
A
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
9bccf70c 411int _ATwrite(fp, uio, cred, flags, p)
1c79356b
A
412 void *fp;
413 struct uio *uio;
414 void *cred;
9bccf70c
A
415 int flags;
416 struct proc *p;
1c79356b
A
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 */
0b4e3aa0
A
430/* bms: update to be callable from kernel */
431int at_ioctl(gref_t *gref, u_long cmd, caddr_t arg, int fromKernel)
1c79356b 432{
0b4e3aa0
A
433 int s, err = 0, len;
434 gbuf_t *m, *mdata;
435 ioc_t *ioc;
436 ioccmd_t ioccmd;
1c79356b 437
0b4e3aa0
A
438 /* error if not for us */
439 if ((cmd & 0xffff) != 0xff99)
440 return EOPNOTSUPP;
1c79356b 441
0b4e3aa0 442 /* copy in ioc command info */
1c79356b 443/*
0b4e3aa0
A
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);
1c79356b 447*/
0b4e3aa0
A
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) {
1c79356b 452#ifdef APPLETALK_DEBUG
0b4e3aa0
A
453 kprintf("at_ioctl: err = %d, copyin(%x, %x, %d)\n", err,
454 (caddr_t)arg, (caddr_t)&ioccmd, sizeof(ioccmd_t));
1c79356b 455#endif
0b4e3aa0
A
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);
1c79356b
A
472#ifdef APPLETALK_DEBUG
473 kprintf("at_ioctl: gbuf_alloc err=%d\n",ENOBUFS);
474#endif
0b4e3aa0
A
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 */
1c79356b
A
494 gref_wput(gref, m);
495
0b4e3aa0
A
496 /* wait for the ioc ack */
497 ATDISABLE(s, gref->lock);
498 while ((m = gref->ichead) == 0) {
499 gref->sevents |= POLLPRI;
1c79356b
A
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
0b4e3aa0
A
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) {
1c79356b 540#ifdef APPLETALK_DEBUG
0b4e3aa0
A
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));
1c79356b 543#endif
0b4e3aa0
A
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) {
1c79356b 555#ifdef APPLETALK_DEBUG
0b4e3aa0
A
556 kprintf("at_ioctl: error copyout2=%d from=%x to=%x len=%d\n",
557 err, &ioccmd, arg, sizeof(ioccmd_t));
1c79356b 558#endif
0b4e3aa0
A
559 goto l_done;
560 }
561 }
562 }
1c79356b
A
563
564l_done:
565 gbuf_freem(m);
566 /*kprintf("at_ioctl: I_done=%d\n", err);*/
567 return err;
568} /* at_ioctl */
569
570int _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
0b4e3aa0 586 err = at_ioctl(gref, cmd, arg, 0);
1c79356b
A
587
588 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
589
590 return err;
591}
592
0b4e3aa0 593int _ATselect(fp, which, wql, proc)
1c79356b
A
594 struct file *fp;
595 int which;
0b4e3aa0 596 void * wql;
1c79356b
A
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;
0b4e3aa0 615 selrecord(proc, &gref->si, wql);
1c79356b
A
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;
0b4e3aa0 624 selrecord(proc, &gref->si, wql);
1c79356b
A
625 }
626 } else
627 rc = 1;
628 }
629 ATENABLE(s, gref->lock);
630 }
631
632 return rc;
633}
634
635void 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
9bccf70c 657 wakeup(&gref->iocevent);
1c79356b
A
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;
9bccf70c 676 wakeup(&gref->event);
1c79356b
A
677 }
678 if (gref->sevents & POLLIN) {
679 gref->sevents &= ~POLLIN;
1c79356b 680 selwakeup(&gref->si);
1c79356b
A
681 }
682 gref->rdtail = m;
683 }
684 } /* switch gbuf_type(m) */
685
686 ATENABLE(s, gref->lock);
687} /* atalk_putnext */
688
689void atalk_enablew(gref)
690 gref_t *gref;
691{
692 if (gref->sevents & POLLSYNC)
9bccf70c 693 wakeup(&gref->event);
1c79356b
A
694}
695
696void 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 */
717void 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;
9bccf70c 744 wakeup(&gref->event);
1c79356b
A
745 }
746 /* select */
747 if (gref->sevents & POLLIN) {
748 gref->sevents &= ~POLLIN;
1c79356b 749 selwakeup(&gref->si);
1c79356b
A
750 }
751 }
752 }
753 ATENABLE(s, gref->lock);
754} /* atalk_notify */
755
756void 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;
1c79356b 764 selwakeup(&gref->si);
1c79356b
A
765 }
766 ATENABLE(s, gref->lock);
767}
768
769int 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
786static gbuf_t *trace_msg;
787
788void 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
811void 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
821static gref_t *gref_free_list = 0;
822
823int 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
0b4e3aa0
A
868/* bms: make gref_close callable from kernel */
869int gref_close(gref_t *gref)
1c79356b
A
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
923struct 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
0b4e3aa0
A
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*/
953void 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
1c79356b
A
979/*
980 Used as the "free" routine for over-size clusters allocated using
0b4e3aa0 981 m_lgbuf_alloc(). Called by m_free while under MBUF_LOCK.
1c79356b
A
982*/
983
984void m_lgbuf_free(buf, size, arg)
985 void *buf;
986 int size, arg; /* not needed, but they're in m_free() */
987{
0b4e3aa0
A
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 }
1c79356b
A
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
1010struct mbuf *m_lgbuf_alloc(size, wait)
1011 int size, wait;
1012{
1013 struct mbuf *m;
1014
0b4e3aa0
A
1015 if (atp_free_cluster_list)
1016 atp_delete_free_clusters(); /* delete any free clusters on the free list */
1017
1c79356b
A
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
1055gbuf_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
1070int 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
1080int 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*/
1105struct 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
1134void 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
1143void 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
1152int 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 */
1166gbuf_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
1181int 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;
1208l_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
1236gbuf_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
1287void 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