]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/ndrv.c
820b8cc7b920ef5d5f2ed082d48fe8a85e02eff7
[apple/xnu.git] / bsd / net / ndrv.c
1 /*
2 * Copyright (c) 2000 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 /* Copyright (c) 1997, 1998 Apple Computer, Inc. All Rights Reserved */
23 /*
24 * @(#)ndrv.c 1.1 (MacOSX) 6/10/43
25 * Justin Walker, 970604
26 * AF_NDRV support
27 * 980130 - Cleanup, reorg, performance improvemements
28 * 000816 - Removal of Y adapter cruft
29 */
30
31 /*
32 * PF_NDRV allows raw access to a specified network device, directly
33 * with a socket. Expected use involves a socket option to request
34 * protocol packets. This lets ndrv_output() call dlil_output(), and
35 * lets DLIL find the proper recipient for incoming packets.
36 * The purpose here is for user-mode protocol implementation.
37 * Note that "pure raw access" will still be accomplished with BPF.
38 *
39 * In addition to the former use, when combined with socket NKEs,
40 * PF_NDRV permits a fairly flexible mechanism for implementing
41 * strange protocol support. One of the main ones will be the
42 * BlueBox/Classic Shared IP Address support.
43 */
44
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/malloc.h>
49 #include <sys/mbuf.h>
50 #include <sys/protosw.h>
51 #include <sys/domain.h>
52 #include <sys/socket.h>
53 #include <sys/socketvar.h>
54 #include <sys/ioctl.h>
55 #include <sys/errno.h>
56 #include <sys/syslog.h>
57 #include <sys/proc.h>
58
59 #include <kern/queue.h>
60
61 #include <net/if.h>
62 #include <net/netisr.h>
63 #include <net/route.h>
64 #include <net/if_llc.h>
65 #include <net/if_dl.h>
66 #include <net/if_types.h>
67 #include <net/dlil.h>
68 #include "ndrv.h"
69
70 #if INET
71 #include <netinet/in.h>
72 #include <netinet/in_var.h>
73 #endif
74 #include <netinet/if_ether.h>
75
76 #if NS
77 #include <netns/ns.h>
78 #include <netns/ns_if.h>
79 #endif
80
81 #if ISO
82 #include <netiso/argo_debug.h>
83 #include <netiso/iso.h>
84 #include <netiso/iso_var.h>
85 #include <netiso/iso_snpac.h>
86 #endif
87
88 #if LLC
89 #include <netccitt/dll.h>
90 #include <netccitt/llc_var.h>
91 #endif
92
93 #include <machine/spl.h>
94
95 int ndrv_do_detach(struct ndrv_cb *);
96 int ndrv_do_disconnect(struct ndrv_cb *);
97
98 unsigned long ndrv_sendspace = NDRVSNDQ;
99 unsigned long ndrv_recvspace = NDRVRCVQ;
100 struct ndrv_cb ndrvl; /* Head of controlblock list */
101
102 /* To handle input, need to map tag to ndrv_cb */
103 struct ndrv_tag_map
104 { unsigned int tm_tag; /* Tag in use */
105 struct ndrv_cb *tm_np; /* Owning device */
106 struct dlil_demux_desc *tm_dm; /* Our local copy */
107 };
108
109 struct ndrv_tag_map *ndrv_tags;
110 #define TAG_MAP_COUNT 10
111 int tag_map_count;
112
113 struct domain ndrvdomain;
114 extern struct protosw ndrvsw[];
115
116
117 /*
118 * Protocol init function for NDRV protocol
119 * Init the control block list.
120 */
121 void
122 ndrv_init()
123 {
124 ndrvl.nd_next = ndrvl.nd_prev = &ndrvl;
125 }
126
127 /*
128 * Protocol output - Called to output a raw network packet directly
129 * to the driver.
130 */
131 int
132 ndrv_output(register struct mbuf *m, register struct socket *so)
133 { register struct ndrv_cb *np = sotondrvcb(so);
134 register struct ifnet *ifp = np->nd_if;
135 int s, error;
136 extern void kprintf(const char *, ...);
137
138 #if NDRV_DEBUG
139 kprintf("NDRV output: %x, %x, %x\n", m, so, np);
140 #endif
141
142 /*
143 * No header is a format error
144 */
145 if ((m->m_flags&M_PKTHDR) == 0)
146 return(EINVAL);
147
148 /*
149 * Can't do multicast accounting because we don't know
150 * (a) if our interface does multicast; and
151 * (b) what a multicast address looks like
152 */
153 s = splimp();
154
155 /*
156 * Can't call DLIL to do the job - we don't have a tag
157 * and we aren't really a protocol
158 */
159
160 (*ifp->if_output)(ifp, m);
161 splx(s);
162 return (0);
163 }
164
165 int
166 ndrv_input(struct mbuf *m,
167 char *frame_header,
168 struct ifnet *ifp,
169 u_long dl_tag,
170 int sync_ok)
171 { int s;
172 struct socket *so;
173 struct sockaddr_dl ndrvsrc = {sizeof (struct sockaddr_dl), AF_NDRV};
174 register struct ndrv_cb *np;
175 extern struct ndrv_cb *ndrv_find_tag(unsigned int);
176
177
178 /* move packet from if queue to socket */
179 /* Should be media-independent */
180 ndrvsrc.sdl_type = IFT_ETHER;
181 ndrvsrc.sdl_nlen = 0;
182 ndrvsrc.sdl_alen = 6;
183 ndrvsrc.sdl_slen = 0;
184 bcopy(frame_header, &ndrvsrc.sdl_data, 6);
185
186 s = splnet();
187 np = ndrv_find_tag(dl_tag);
188 if (np == NULL)
189 { splx(s);
190 return(ENOENT);
191 }
192 so = np->nd_socket;
193 if (sbappendaddr(&(so->so_rcv), (struct sockaddr *)&ndrvsrc,
194 m, (struct mbuf *)0) == 0)
195 { /* yes, sbappendaddr returns zero if the sockbuff is full... */
196 splx(s);
197 return(ENOMEM);
198 } else
199 sorwakeup(so);
200 splx(s);
201 return(0);
202 }
203
204 int
205 ndrv_ioctl(unsigned long dl_tag,
206 struct ifnet *ifp,
207 unsigned long command,
208 caddr_t data)
209 {
210 if (ifp)
211 return((*ifp->if_ioctl)(ifp, command, data));
212 }
213
214 int
215 ndrv_control(struct socket *so, u_long cmd, caddr_t data,
216 struct ifnet *ifp, struct proc *p)
217 {
218 return (0);
219 }
220
221 /*
222 * Allocate an ndrv control block and some buffer space for the socket
223 */
224 int
225 ndrv_attach(struct socket *so, int proto, struct proc *p)
226 { int error;
227 register struct ndrv_cb *np = sotondrvcb(so);
228
229 if ((so->so_state & SS_PRIV) == 0)
230 return(EPERM);
231
232 #if NDRV_DEBUG
233 kprintf("NDRV attach: %x, %x, %x\n", so, proto, np);
234 #endif
235 MALLOC(np, struct ndrv_cb *, sizeof(*np), M_PCB, M_WAITOK);
236 #if NDRV_DEBUG
237 kprintf("NDRV attach: %x, %x, %x\n", so, proto, np);
238 #endif
239 if ((so->so_pcb = (caddr_t)np))
240 bzero(np, sizeof(*np));
241 else
242 return(ENOBUFS);
243 if ((error = soreserve(so, ndrv_sendspace, ndrv_recvspace)))
244 return(error);
245 TAILQ_INIT(&np->nd_dlist);
246 np->nd_signature = NDRV_SIGNATURE;
247 np->nd_socket = so;
248 np->nd_proto.sp_family = so->so_proto->pr_domain->dom_family;
249 np->nd_proto.sp_protocol = proto;
250 insque((queue_t)np, (queue_t)&ndrvl);
251 return(0);
252 }
253
254 /*
255 * Destroy state just before socket deallocation.
256 * Flush data or not depending on the options.
257 */
258
259 int
260 ndrv_detach(struct socket *so)
261 {
262 register struct ndrv_cb *np = sotondrvcb(so);
263
264 if (np == 0)
265 return EINVAL;
266 return ndrv_do_detach(np);
267 }
268
269
270 /*
271 * If a socket isn't bound to a single address,
272 * the ndrv input routine will hand it anything
273 * within that protocol family (assuming there's
274 * nothing else around it should go to).
275 *
276 * Don't expect this to be used.
277 */
278
279 int ndrv_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
280 {
281 register struct ndrv_cb *np = sotondrvcb(so);
282
283 if (np == 0)
284 return EINVAL;
285
286 if (np->nd_faddr)
287 return EISCONN;
288
289 bcopy((caddr_t) nam, (caddr_t) np->nd_faddr, sizeof(struct sockaddr_ndrv));
290 soisconnected(so);
291 return 0;
292 }
293
294 /*
295 * This is the "driver open" hook - we 'bind' to the
296 * named driver.
297 * Here's where we latch onto the driver and make it ours.
298 */
299 int
300 ndrv_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
301 { register struct sockaddr_ndrv *sa = (struct sockaddr_ndrv *) nam;
302 register char *dname;
303 register struct ndrv_cb *np;
304 register struct ifnet *ifp;
305 extern int name_cmp(struct ifnet *, char *);
306
307 if TAILQ_EMPTY(&ifnet)
308 return(EADDRNOTAVAIL); /* Quick sanity check */
309 np = sotondrvcb(so);
310 if (np == 0)
311 return EINVAL;
312
313 if (np->nd_laddr)
314 return EINVAL; /* XXX */
315
316 /* I think we just latch onto a copy here; the caller frees */
317 np->nd_laddr = _MALLOC(sizeof(struct sockaddr_ndrv), M_IFADDR, M_WAITOK);
318 if (np->nd_laddr == NULL)
319 return(ENOMEM);
320 bcopy((caddr_t) sa, (caddr_t) np->nd_laddr, sizeof(struct sockaddr_ndrv));
321 dname = sa->snd_name;
322 if (*dname == '\0')
323 return(EINVAL);
324 #if NDRV_DEBUG
325 kprintf("NDRV bind: %x, %x, %s\n", so, np, dname);
326 #endif
327 /* Track down the driver and its ifnet structure.
328 * There's no internal call for this so we have to dup the code
329 * in if.c/ifconf()
330 */
331 TAILQ_FOREACH(ifp, &ifnet, if_link) {
332 if (name_cmp(ifp, dname) == 0)
333 break;
334 }
335
336 if (ifp == NULL)
337 return(EADDRNOTAVAIL);
338 np->nd_if = ifp;
339 return(0);
340 }
341
342 int
343 ndrv_disconnect(struct socket *so)
344 {
345 register struct ndrv_cb *np = sotondrvcb(so);
346
347 if (np == 0)
348 return EINVAL;
349
350 if (np->nd_faddr == 0)
351 return ENOTCONN;
352
353 ndrv_do_disconnect(np);
354 return 0;
355 }
356
357 /*
358 * Mark the connection as being incapable of further input.
359 */
360 int
361 ndrv_shutdown(struct socket *so)
362 {
363 socantsendmore(so);
364 return 0;
365 }
366
367 /*
368 * Ship a packet out. The ndrv output will pass it
369 * to the appropriate driver. The really tricky part
370 * is the destination address...
371 */
372 int
373 ndrv_send(struct socket *so, int flags, struct mbuf *m,
374 struct sockaddr *addr, struct mbuf *control,
375 struct proc *p)
376 {
377 int error;
378
379 if (control)
380 return EOPNOTSUPP;
381
382 error = ndrv_output(m, so);
383 m = NULL;
384 return error;
385 }
386
387
388 int
389 ndrv_abort(struct socket *so)
390 {
391 register struct ndrv_cb *np = sotondrvcb(so);
392
393 if (np == 0)
394 return EINVAL;
395
396 ndrv_do_disconnect(np);
397 return 0;
398 }
399
400 int
401 ndrv_sense(struct socket *so, struct stat *sb)
402 {
403 /*
404 * stat: don't bother with a blocksize.
405 */
406 return (0);
407 }
408
409 int
410 ndrv_sockaddr(struct socket *so, struct sockaddr **nam)
411 {
412 register struct ndrv_cb *np = sotondrvcb(so);
413 int len;
414
415 if (np == 0)
416 return EINVAL;
417
418 if (np->nd_laddr == 0)
419 return EINVAL;
420
421 len = np->nd_laddr->snd_len;
422 bcopy((caddr_t)np->nd_laddr, *nam,
423 (unsigned)len);
424 return 0;
425 }
426
427
428 int
429 ndrv_peeraddr(struct socket *so, struct sockaddr **nam)
430 {
431 register struct ndrv_cb *np = sotondrvcb(so);
432 int len;
433
434 if (np == 0)
435 return EINVAL;
436
437 if (np->nd_faddr == 0)
438 return ENOTCONN;
439
440 len = np->nd_faddr->snd_len;
441 bcopy((caddr_t)np->nd_faddr, *nam,
442 (unsigned)len);
443 return 0;
444 }
445
446
447 /* Control input */
448
449 void
450 ndrv_ctlinput(int dummy1, struct sockaddr *dummy2, void *dummy3)
451 {
452 }
453
454 /* Control output */
455
456 int
457 ndrv_ctloutput(struct socket *so, struct sockopt *sopt)
458 { register struct ndrv_cb *np = sotondrvcb(so);
459 struct ndrv_descr nd;
460 int count = 0, error = 0;
461 int ndrv_getspec(struct ndrv_cb *,
462 struct sockopt *,
463 struct ndrv_descr *);
464 int ndrv_setspec(struct ndrv_cb *, struct ndrv_descr *);
465 int ndrv_delspec(struct ndrv_cb *, struct ndrv_descr *);
466
467 if (sopt->sopt_name != NDRV_DMXSPECCNT)
468 error = sooptcopyin(sopt, &nd, sizeof nd, sizeof nd);
469 if (error == 0)
470 { switch(sopt->sopt_name)
471 { case NDRV_DMXSPEC: /* Get/Set(Add) spec list */
472 if (sopt->sopt_dir == SOPT_GET)
473 error = ndrv_getspec(np, sopt, &nd);
474 else
475 error = ndrv_setspec(np, &nd);
476 break;
477 case NDRV_DELDMXSPEC: /* Delete specified specs */
478 error = ndrv_delspec(np, &nd);
479 break;
480 case NDRV_DMXSPECCNT: /* How many are in the list */
481 count = np->nd_descrcnt;
482 error = sooptcopyout(sopt, &count, sizeof count);
483 break;
484 }
485 }
486 #ifdef NDRV_DEBUG
487 log(LOG_WARNING, "NDRV CTLOUT: %x returns %d\n", sopt->sopt_name,
488 error);
489 #endif
490 return(error);
491 }
492
493 /* Drain the queues */
494 void
495 ndrv_drain()
496 {
497 }
498
499 /* Sysctl hook for NDRV */
500 int
501 ndrv_sysctl()
502 {
503 return(0);
504 }
505
506 int
507 ndrv_do_detach(register struct ndrv_cb *np)
508 { register struct socket *so = np->nd_socket;
509 int ndrv_dump_descr(struct ndrv_cb *);
510
511 #if NDRV_DEBUG
512 kprintf("NDRV detach: %x, %x\n", so, np);
513 #endif
514 if (!TAILQ_EMPTY(&np->nd_dlist))
515 ndrv_dump_descr(np);
516
517 remque((queue_t)np);
518 FREE((caddr_t)np, M_PCB);
519 so->so_pcb = 0;
520 sofree(so);
521 return(0);
522 }
523
524 int
525 ndrv_do_disconnect(register struct ndrv_cb *np)
526 {
527 #if NDRV_DEBUG
528 kprintf("NDRV disconnect: %x\n", np);
529 #endif
530 if (np->nd_faddr)
531 { m_freem(dtom(np->nd_faddr));
532 np->nd_faddr = 0;
533 }
534 if (np->nd_socket->so_state & SS_NOFDREF)
535 ndrv_do_detach(np);
536 soisdisconnected(np->nd_socket);
537 return(0);
538 }
539
540 /*
541 * Try to compare a device name (q) with one of the funky ifnet
542 * device names (ifp).
543 */
544 int name_cmp(register struct ifnet *ifp, register char *q)
545 { register char *r;
546 register int len;
547 char buf[IFNAMSIZ];
548 static char *sprint_d();
549
550 r = buf;
551 len = strlen(ifp->if_name);
552 strncpy(r, ifp->if_name, IFNAMSIZ);
553 r += len;
554 (void)sprint_d(ifp->if_unit, r, IFNAMSIZ-(r-buf));
555 #if NDRV_DEBUG
556 kprintf("Comparing %s, %s\n", buf, q);
557 #endif
558 return(strncmp(buf, q, IFNAMSIZ));
559 }
560
561 /* Hackery - return a string version of a decimal number */
562 static char *
563 sprint_d(n, buf, buflen)
564 u_int n;
565 char *buf;
566 int buflen;
567 { char dbuf[IFNAMSIZ];
568 register char *cp = dbuf+IFNAMSIZ-1;
569
570 *cp = 0;
571 do { buflen--;
572 cp--;
573 *cp = "0123456789"[n % 10];
574 n /= 10;
575 } while (n != 0 && buflen > 0);
576 strncpy(buf, cp, IFNAMSIZ-buflen);
577 return (cp);
578 }
579
580 /*
581 * When closing, dump any enqueued mbufs.
582 */
583 void
584 ndrv_flushq(register struct ifqueue *q)
585 { register struct mbuf *m;
586 register int s;
587 for (;;)
588 { s = splimp();
589 IF_DEQUEUE(q, m);
590 if (m == NULL)
591 break;
592 IF_DROP(q);
593 splx(s);
594 if (m)
595 m_freem(m);
596 }
597 splx(s);
598 }
599
600 int
601 ndrv_getspec(struct ndrv_cb *np,
602 struct sockopt *sopt,
603 struct ndrv_descr *nd)
604 { struct dlil_demux_desc *mp, *mp1;
605 int i, k, error = 0;
606
607 /* Compute # structs to copy */
608 i = k = min(np->nd_descrcnt,
609 (nd->nd_len / sizeof (struct dlil_demux_desc)));
610 mp = (struct dlil_demux_desc *)nd->nd_buf;
611 TAILQ_FOREACH(mp1, &np->nd_dlist, next)
612 { if (k-- == 0)
613 break;
614 error = copyout(mp1, mp++, sizeof (struct dlil_demux_desc));
615 if (error)
616 break;
617 }
618 if (error == 0)
619 { nd->nd_len = i * (sizeof (struct dlil_demux_desc));
620 error = sooptcopyout(sopt, nd, sizeof (*nd));
621 }
622 return(error);
623 }
624
625 /*
626 * Install a protocol descriptor, making us a protocol handler.
627 * We expect the client to handle all output tasks (we get fully
628 * formed frames from the client and hand them to the driver
629 * directly). The reason we register is to get those incoming
630 * frames. We do it as a protocol handler because the network layer
631 * already knows how find the ones we want, so there's no need to
632 * duplicate effort.
633 * Since this mechanism is mostly for user mode, most of the procedures
634 * to be registered will be null.
635 * Note that we jam the pair (PF_XXX, native_type) into the native_type
636 * field of the demux descriptor. Yeah, it's a hack.
637 */
638 int
639 ndrv_setspec(struct ndrv_cb *np, struct ndrv_descr *nd)
640 { struct dlil_demux_desc *mp, *mp1;
641 int i = 0, error = 0, j;
642 unsigned long value;
643 int *native_values;
644 struct dlil_proto_reg_str proto_spec;
645 int ndrv_add_descr(struct ndrv_cb *, struct dlil_proto_reg_str *);
646
647 bzero((caddr_t)&proto_spec, sizeof (proto_spec));
648 i = nd->nd_len / (sizeof (struct dlil_demux_desc)); /* # elts */
649 MALLOC(native_values,int *, i * sizeof (int), M_TEMP, M_WAITOK);
650 mp = (struct dlil_demux_desc *)nd->nd_buf;
651 for (j = 0; j++ < i;)
652 { MALLOC(mp1, struct dlil_demux_desc *,
653 sizeof (struct dlil_demux_desc), M_PCB, M_WAITOK);
654 if (mp1 == NULL)
655 { error = ENOBUFS;
656 break;
657 }
658 error = copyin(mp++, mp1, sizeof (struct dlil_demux_desc));
659 if (error)
660 break;
661 TAILQ_INSERT_TAIL(&np->nd_dlist, mp1, next);
662 value = (unsigned long)mp1->native_type;
663 native_values[j] = (unsigned short)value;
664 mp1->native_type = (char *)&native_values[j];
665 proto_spec.protocol_family = (unsigned char)(value>>16); /* Oy! */
666 proto_spec.interface_family = np->nd_if->if_family;
667 proto_spec.unit_number = np->nd_if->if_unit;
668 /* Our input */
669 proto_spec.input = ndrv_input;
670 proto_spec.pre_output = NULL;
671 /* No event/offer functionality needed */
672 proto_spec.event = NULL;
673 proto_spec.offer = NULL;
674 proto_spec.ioctl = ndrv_ioctl; /* ??? */
675 /* What exactly does this do again? */
676 proto_spec.default_proto = 0;
677
678 np->nd_descrcnt++;
679 }
680 if (error)
681 { struct dlil_demux_desc *mp2;
682
683 TAILQ_FOREACH(mp2, &np->nd_dlist, next)
684 FREE(mp2, M_PCB);
685 } else
686 error = ndrv_add_descr(np, &proto_spec);
687 #ifdef NDRV_DEBUG
688 log(LOG_WARNING, "NDRV ADDSPEC: got error %d\n", error);
689 #endif
690 FREE(native_values, M_TEMP);
691 return(error);
692 }
693
694 int
695 ndrv_delspec(struct ndrv_cb *np, struct ndrv_descr *nd)
696 { struct dlil_demux_desc *mp;
697
698 return(EINVAL);
699 }
700
701 struct ndrv_cb *
702 ndrv_find_tag(unsigned int tag)
703 { struct ndrv_tag_map *tmp;
704 int i;
705
706 tmp = ndrv_tags;
707 for (i=0; i++ < tag_map_count; tmp++)
708 if (tmp->tm_tag == tag)
709 return(tmp->tm_np);
710 return(NULL);
711 }
712
713 int
714 ndrv_add_tag(struct ndrv_cb *np, unsigned int tag,
715 struct dlil_demux_desc *mp)
716 { struct ndrv_tag_map *tmp;
717 int i;
718
719 tmp = ndrv_tags;
720 for (i=0; i++ < tag_map_count; tmp++)
721 if (tmp->tm_tag == 0)
722 { tmp->tm_tag = tag;
723 tmp->tm_np = np;
724 #ifdef NDRV_DEBUG
725 log(LOG_WARNING, "NDRV ADDING TAG %d\n", tag);
726 #endif
727 return(0);
728 }
729
730 /* Oops - ran out of space. Realloc */
731 i = tag_map_count + TAG_MAP_COUNT;
732 MALLOC(tmp, struct ndrv_tag_map *, i * sizeof (struct ndrv_tag_map),
733 M_PCB, M_WAITOK);
734 if (tmp == NULL)
735 return(ENOMEM);
736 /* Clear tail of new table, except for the slot we are creating ... */
737 bzero((caddr_t)&tmp[tag_map_count+1],
738 (TAG_MAP_COUNT-1) * sizeof (struct ndrv_tag_map));
739 /* ...and then copy in the original piece */
740 if (tag_map_count)
741 bcopy(ndrv_tags, tmp,
742 tag_map_count * sizeof (struct ndrv_tag_map));
743 /* ...and then install the new tag... */
744 tmp[tag_map_count].tm_tag = tag;
745 tmp[tag_map_count].tm_np = np;
746 tag_map_count = i;
747 if (tag_map_count)
748 FREE(ndrv_tags, M_PCB);
749 ndrv_tags = tmp;
750 #ifdef NDRV_DEBUG
751 log(LOG_WARNING, "NDRV ADDING TAG %d (new chunk)\n", tag);
752 #endif
753 return(0);
754 }
755
756 /*
757 * Attach the proto spec list, and record the tags.
758 */
759 int
760 ndrv_add_descr(struct ndrv_cb *np, struct dlil_proto_reg_str *proto_spec)
761 { unsigned long dl_tag;
762 int error;
763 struct dlil_demux_desc *mp;
764
765 /* Attach to our device to get requested packets */
766 TAILQ_INIT(&proto_spec->demux_desc_head);
767 error = dlil_attach_protocol(proto_spec, &dl_tag);
768
769 if (error == 0)
770 error = ndrv_add_tag(np, dl_tag, mp);
771
772 return(error);
773 }
774
775 int
776 ndrv_dump_descr(struct ndrv_cb *np)
777 { struct dlil_demux_desc *dm1, *dm2;
778 struct ndrv_tag_map *tmp;
779 int i, error = 0;
780
781 if (dm1 = TAILQ_FIRST(&np->nd_dlist))
782 { for (i = 0, tmp = &ndrv_tags[0]; i++ < tag_map_count; tmp++)
783 if (tmp->tm_np == np)
784 { error = dlil_detach_protocol(tmp->tm_tag);
785 while (dm1)
786 { dm2 = TAILQ_NEXT(dm1, next);
787 FREE(dm1, M_PCB);
788 dm1 = dm2;
789 }
790 log(LOG_WARNING,
791 "Detached tag %d (error %d)\n",
792 tmp->tm_tag, error);
793 tmp->tm_np = 0;
794 tmp->tm_tag = 0;
795 }
796 }
797 return(0);
798 }
799
800 void ndrv_dominit()
801 {
802 static int ndrv_dominited = 0;
803
804 if (ndrv_dominited == 0) {
805 net_add_proto(&ndrvsw[0], &ndrvdomain);
806
807 ndrv_dominited = 1;
808 }
809 }
810
811 struct pr_usrreqs ndrv_usrreqs = {
812 ndrv_abort, pru_accept_notsupp, ndrv_attach, ndrv_bind,
813 ndrv_connect, pru_connect2_notsupp, ndrv_control, ndrv_detach,
814 ndrv_disconnect, pru_listen_notsupp, ndrv_peeraddr, pru_rcvd_notsupp,
815 pru_rcvoob_notsupp, ndrv_send, ndrv_sense, ndrv_shutdown,
816 ndrv_sockaddr, sosend, soreceive, sopoll
817 };
818
819 struct protosw ndrvsw[] =
820 { { SOCK_RAW, &ndrvdomain, 0, PR_ATOMIC|PR_ADDR,
821 0, ndrv_output, ndrv_ctlinput, ndrv_ctloutput,
822 0, ndrv_init, 0, 0,
823 ndrv_drain, ndrv_sysctl, &ndrv_usrreqs
824 }
825 };
826
827 struct domain ndrvdomain =
828 { AF_NDRV, "NetDriver", ndrv_dominit, NULL, NULL,
829 NULL,
830 NULL, NULL, 0, 0, 0, 0
831 };