]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/ndrv.c
xnu-201.tar.gz
[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 (np == NULL)
237 return (ENOMEM);
238 #if NDRV_DEBUG
239 kprintf("NDRV attach: %x, %x, %x\n", so, proto, np);
240 #endif
241 if ((so->so_pcb = (caddr_t)np))
242 bzero(np, sizeof(*np));
243 else
244 return(ENOBUFS);
245 if ((error = soreserve(so, ndrv_sendspace, ndrv_recvspace)))
246 return(error);
247 TAILQ_INIT(&np->nd_dlist);
248 np->nd_signature = NDRV_SIGNATURE;
249 np->nd_socket = so;
250 np->nd_proto.sp_family = so->so_proto->pr_domain->dom_family;
251 np->nd_proto.sp_protocol = proto;
252 insque((queue_t)np, (queue_t)&ndrvl);
253 return(0);
254 }
255
256 /*
257 * Destroy state just before socket deallocation.
258 * Flush data or not depending on the options.
259 */
260
261 int
262 ndrv_detach(struct socket *so)
263 {
264 register struct ndrv_cb *np = sotondrvcb(so);
265
266 if (np == 0)
267 return EINVAL;
268 return ndrv_do_detach(np);
269 }
270
271
272 /*
273 * If a socket isn't bound to a single address,
274 * the ndrv input routine will hand it anything
275 * within that protocol family (assuming there's
276 * nothing else around it should go to).
277 *
278 * Don't expect this to be used.
279 */
280
281 int ndrv_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
282 {
283 register struct ndrv_cb *np = sotondrvcb(so);
284
285 if (np == 0)
286 return EINVAL;
287
288 if (np->nd_faddr)
289 return EISCONN;
290
291 bcopy((caddr_t) nam, (caddr_t) np->nd_faddr, sizeof(struct sockaddr_ndrv));
292 soisconnected(so);
293 return 0;
294 }
295
296 /*
297 * This is the "driver open" hook - we 'bind' to the
298 * named driver.
299 * Here's where we latch onto the driver and make it ours.
300 */
301 int
302 ndrv_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
303 { register struct sockaddr_ndrv *sa = (struct sockaddr_ndrv *) nam;
304 register char *dname;
305 register struct ndrv_cb *np;
306 register struct ifnet *ifp;
307 extern int name_cmp(struct ifnet *, char *);
308
309 if TAILQ_EMPTY(&ifnet)
310 return(EADDRNOTAVAIL); /* Quick sanity check */
311 np = sotondrvcb(so);
312 if (np == 0)
313 return EINVAL;
314
315 if (np->nd_laddr)
316 return EINVAL; /* XXX */
317
318 /* I think we just latch onto a copy here; the caller frees */
319 np->nd_laddr = _MALLOC(sizeof(struct sockaddr_ndrv), M_IFADDR, M_WAITOK);
320 if (np->nd_laddr == NULL)
321 return(ENOMEM);
322 bcopy((caddr_t) sa, (caddr_t) np->nd_laddr, sizeof(struct sockaddr_ndrv));
323 dname = sa->snd_name;
324 if (*dname == '\0')
325 return(EINVAL);
326 #if NDRV_DEBUG
327 kprintf("NDRV bind: %x, %x, %s\n", so, np, dname);
328 #endif
329 /* Track down the driver and its ifnet structure.
330 * There's no internal call for this so we have to dup the code
331 * in if.c/ifconf()
332 */
333 TAILQ_FOREACH(ifp, &ifnet, if_link) {
334 if (name_cmp(ifp, dname) == 0)
335 break;
336 }
337
338 if (ifp == NULL)
339 return(EADDRNOTAVAIL);
340 np->nd_if = ifp;
341 return(0);
342 }
343
344 int
345 ndrv_disconnect(struct socket *so)
346 {
347 register struct ndrv_cb *np = sotondrvcb(so);
348
349 if (np == 0)
350 return EINVAL;
351
352 if (np->nd_faddr == 0)
353 return ENOTCONN;
354
355 ndrv_do_disconnect(np);
356 return 0;
357 }
358
359 /*
360 * Mark the connection as being incapable of further input.
361 */
362 int
363 ndrv_shutdown(struct socket *so)
364 {
365 socantsendmore(so);
366 return 0;
367 }
368
369 /*
370 * Ship a packet out. The ndrv output will pass it
371 * to the appropriate driver. The really tricky part
372 * is the destination address...
373 */
374 int
375 ndrv_send(struct socket *so, int flags, struct mbuf *m,
376 struct sockaddr *addr, struct mbuf *control,
377 struct proc *p)
378 {
379 int error;
380
381 if (control)
382 return EOPNOTSUPP;
383
384 error = ndrv_output(m, so);
385 m = NULL;
386 return error;
387 }
388
389
390 int
391 ndrv_abort(struct socket *so)
392 {
393 register struct ndrv_cb *np = sotondrvcb(so);
394
395 if (np == 0)
396 return EINVAL;
397
398 ndrv_do_disconnect(np);
399 return 0;
400 }
401
402 int
403 ndrv_sense(struct socket *so, struct stat *sb)
404 {
405 /*
406 * stat: don't bother with a blocksize.
407 */
408 return (0);
409 }
410
411 int
412 ndrv_sockaddr(struct socket *so, struct sockaddr **nam)
413 {
414 register struct ndrv_cb *np = sotondrvcb(so);
415 int len;
416
417 if (np == 0)
418 return EINVAL;
419
420 if (np->nd_laddr == 0)
421 return EINVAL;
422
423 len = np->nd_laddr->snd_len;
424 bcopy((caddr_t)np->nd_laddr, *nam,
425 (unsigned)len);
426 return 0;
427 }
428
429
430 int
431 ndrv_peeraddr(struct socket *so, struct sockaddr **nam)
432 {
433 register struct ndrv_cb *np = sotondrvcb(so);
434 int len;
435
436 if (np == 0)
437 return EINVAL;
438
439 if (np->nd_faddr == 0)
440 return ENOTCONN;
441
442 len = np->nd_faddr->snd_len;
443 bcopy((caddr_t)np->nd_faddr, *nam,
444 (unsigned)len);
445 return 0;
446 }
447
448
449 /* Control input */
450
451 void
452 ndrv_ctlinput(int dummy1, struct sockaddr *dummy2, void *dummy3)
453 {
454 }
455
456 /* Control output */
457
458 int
459 ndrv_ctloutput(struct socket *so, struct sockopt *sopt)
460 { register struct ndrv_cb *np = sotondrvcb(so);
461 struct ndrv_descr nd;
462 int count = 0, error = 0;
463 int ndrv_getspec(struct ndrv_cb *,
464 struct sockopt *,
465 struct ndrv_descr *);
466 int ndrv_setspec(struct ndrv_cb *, struct ndrv_descr *);
467 int ndrv_delspec(struct ndrv_cb *, struct ndrv_descr *);
468
469 if (sopt->sopt_name != NDRV_DMXSPECCNT)
470 error = sooptcopyin(sopt, &nd, sizeof nd, sizeof nd);
471 if (error == 0)
472 { switch(sopt->sopt_name)
473 { case NDRV_DMXSPEC: /* Get/Set(Add) spec list */
474 if (sopt->sopt_dir == SOPT_GET)
475 error = ndrv_getspec(np, sopt, &nd);
476 else
477 error = ndrv_setspec(np, &nd);
478 break;
479 case NDRV_DELDMXSPEC: /* Delete specified specs */
480 error = ndrv_delspec(np, &nd);
481 break;
482 case NDRV_DMXSPECCNT: /* How many are in the list */
483 count = np->nd_descrcnt;
484 error = sooptcopyout(sopt, &count, sizeof count);
485 break;
486 }
487 }
488 #ifdef NDRV_DEBUG
489 log(LOG_WARNING, "NDRV CTLOUT: %x returns %d\n", sopt->sopt_name,
490 error);
491 #endif
492 return(error);
493 }
494
495 /* Drain the queues */
496 void
497 ndrv_drain()
498 {
499 }
500
501 /* Sysctl hook for NDRV */
502 int
503 ndrv_sysctl()
504 {
505 return(0);
506 }
507
508 int
509 ndrv_do_detach(register struct ndrv_cb *np)
510 { register struct socket *so = np->nd_socket;
511 int ndrv_dump_descr(struct ndrv_cb *);
512
513 #if NDRV_DEBUG
514 kprintf("NDRV detach: %x, %x\n", so, np);
515 #endif
516 if (!TAILQ_EMPTY(&np->nd_dlist))
517 ndrv_dump_descr(np);
518
519 remque((queue_t)np);
520 FREE((caddr_t)np, M_PCB);
521 so->so_pcb = 0;
522 sofree(so);
523 return(0);
524 }
525
526 int
527 ndrv_do_disconnect(register struct ndrv_cb *np)
528 {
529 #if NDRV_DEBUG
530 kprintf("NDRV disconnect: %x\n", np);
531 #endif
532 if (np->nd_faddr)
533 { m_freem(dtom(np->nd_faddr));
534 np->nd_faddr = 0;
535 }
536 if (np->nd_socket->so_state & SS_NOFDREF)
537 ndrv_do_detach(np);
538 soisdisconnected(np->nd_socket);
539 return(0);
540 }
541
542 /*
543 * Try to compare a device name (q) with one of the funky ifnet
544 * device names (ifp).
545 */
546 int name_cmp(register struct ifnet *ifp, register char *q)
547 { register char *r;
548 register int len;
549 char buf[IFNAMSIZ];
550 static char *sprint_d();
551
552 r = buf;
553 len = strlen(ifp->if_name);
554 strncpy(r, ifp->if_name, IFNAMSIZ);
555 r += len;
556 (void)sprint_d(ifp->if_unit, r, IFNAMSIZ-(r-buf));
557 #if NDRV_DEBUG
558 kprintf("Comparing %s, %s\n", buf, q);
559 #endif
560 return(strncmp(buf, q, IFNAMSIZ));
561 }
562
563 /* Hackery - return a string version of a decimal number */
564 static char *
565 sprint_d(n, buf, buflen)
566 u_int n;
567 char *buf;
568 int buflen;
569 { char dbuf[IFNAMSIZ];
570 register char *cp = dbuf+IFNAMSIZ-1;
571
572 *cp = 0;
573 do { buflen--;
574 cp--;
575 *cp = "0123456789"[n % 10];
576 n /= 10;
577 } while (n != 0 && buflen > 0);
578 strncpy(buf, cp, IFNAMSIZ-buflen);
579 return (cp);
580 }
581
582 /*
583 * When closing, dump any enqueued mbufs.
584 */
585 void
586 ndrv_flushq(register struct ifqueue *q)
587 { register struct mbuf *m;
588 register int s;
589 for (;;)
590 { s = splimp();
591 IF_DEQUEUE(q, m);
592 if (m == NULL)
593 break;
594 IF_DROP(q);
595 splx(s);
596 if (m)
597 m_freem(m);
598 }
599 splx(s);
600 }
601
602 int
603 ndrv_getspec(struct ndrv_cb *np,
604 struct sockopt *sopt,
605 struct ndrv_descr *nd)
606 { struct dlil_demux_desc *mp, *mp1;
607 int i, k, error = 0;
608
609 /* Compute # structs to copy */
610 i = k = min(np->nd_descrcnt,
611 (nd->nd_len / sizeof (struct dlil_demux_desc)));
612 mp = (struct dlil_demux_desc *)nd->nd_buf;
613 TAILQ_FOREACH(mp1, &np->nd_dlist, next)
614 { if (k-- == 0)
615 break;
616 error = copyout(mp1, mp++, sizeof (struct dlil_demux_desc));
617 if (error)
618 break;
619 }
620 if (error == 0)
621 { nd->nd_len = i * (sizeof (struct dlil_demux_desc));
622 error = sooptcopyout(sopt, nd, sizeof (*nd));
623 }
624 return(error);
625 }
626
627 /*
628 * Install a protocol descriptor, making us a protocol handler.
629 * We expect the client to handle all output tasks (we get fully
630 * formed frames from the client and hand them to the driver
631 * directly). The reason we register is to get those incoming
632 * frames. We do it as a protocol handler because the network layer
633 * already knows how find the ones we want, so there's no need to
634 * duplicate effort.
635 * Since this mechanism is mostly for user mode, most of the procedures
636 * to be registered will be null.
637 * Note that we jam the pair (PF_XXX, native_type) into the native_type
638 * field of the demux descriptor. Yeah, it's a hack.
639 */
640 int
641 ndrv_setspec(struct ndrv_cb *np, struct ndrv_descr *nd)
642 { struct dlil_demux_desc *mp, *mp1;
643 int i = 0, error = 0, j;
644 unsigned long value;
645 int *native_values;
646 struct dlil_proto_reg_str proto_spec;
647 int ndrv_add_descr(struct ndrv_cb *, struct dlil_proto_reg_str *);
648
649 bzero((caddr_t)&proto_spec, sizeof (proto_spec));
650 i = nd->nd_len / (sizeof (struct dlil_demux_desc)); /* # elts */
651 MALLOC(native_values,int *, i * sizeof (int), M_TEMP, M_WAITOK);
652 if (native_values == NULL)
653 return (ENOMEM);
654 mp = (struct dlil_demux_desc *)nd->nd_buf;
655 for (j = 0; j++ < i;)
656 { MALLOC(mp1, struct dlil_demux_desc *,
657 sizeof (struct dlil_demux_desc), M_PCB, M_WAITOK);
658 if (mp1 == NULL)
659 { error = ENOBUFS;
660 break;
661 }
662 error = copyin(mp++, mp1, sizeof (struct dlil_demux_desc));
663 if (error)
664 break;
665 TAILQ_INSERT_TAIL(&np->nd_dlist, mp1, next);
666 value = (unsigned long)mp1->native_type;
667 native_values[j] = (unsigned short)value;
668 mp1->native_type = (char *)&native_values[j];
669 proto_spec.protocol_family = (unsigned char)(value>>16); /* Oy! */
670 proto_spec.interface_family = np->nd_if->if_family;
671 proto_spec.unit_number = np->nd_if->if_unit;
672 /* Our input */
673 proto_spec.input = ndrv_input;
674 proto_spec.pre_output = NULL;
675 /* No event/offer functionality needed */
676 proto_spec.event = NULL;
677 proto_spec.offer = NULL;
678 proto_spec.ioctl = ndrv_ioctl; /* ??? */
679 /* What exactly does this do again? */
680 proto_spec.default_proto = 0;
681
682 np->nd_descrcnt++;
683 }
684 if (error)
685 { struct dlil_demux_desc *mp2;
686
687 while ((mp2 = TAILQ_FIRST(&np->nd_dlist))) {
688 TAILQ_REMOVE(&np->nd_dlist, mp2, next);
689 FREE(mp2, M_PCB);
690 }
691 } else
692 error = ndrv_add_descr(np, &proto_spec);
693 #ifdef NDRV_DEBUG
694 log(LOG_WARNING, "NDRV ADDSPEC: got error %d\n", error);
695 #endif
696 FREE(native_values, M_TEMP);
697 return(error);
698 }
699
700 int
701 ndrv_delspec(struct ndrv_cb *np, struct ndrv_descr *nd)
702 { struct dlil_demux_desc *mp;
703
704 return(EINVAL);
705 }
706
707 struct ndrv_cb *
708 ndrv_find_tag(unsigned int tag)
709 { struct ndrv_tag_map *tmp;
710 int i;
711
712 tmp = ndrv_tags;
713 for (i=0; i++ < tag_map_count; tmp++)
714 if (tmp->tm_tag == tag)
715 return(tmp->tm_np);
716 return(NULL);
717 }
718
719 int
720 ndrv_add_tag(struct ndrv_cb *np, unsigned int tag,
721 struct dlil_demux_desc *mp)
722 { struct ndrv_tag_map *tmp;
723 int i;
724
725 tmp = ndrv_tags;
726 for (i=0; i++ < tag_map_count; tmp++)
727 if (tmp->tm_tag == 0)
728 { tmp->tm_tag = tag;
729 tmp->tm_np = np;
730 #ifdef NDRV_DEBUG
731 log(LOG_WARNING, "NDRV ADDING TAG %d\n", tag);
732 #endif
733 return(0);
734 }
735
736 /* Oops - ran out of space. Realloc */
737 i = tag_map_count + TAG_MAP_COUNT;
738 MALLOC(tmp, struct ndrv_tag_map *, i * sizeof (struct ndrv_tag_map),
739 M_PCB, M_WAITOK);
740 if (tmp == NULL)
741 return(ENOMEM);
742 /* Clear tail of new table, except for the slot we are creating ... */
743 bzero((caddr_t)&tmp[tag_map_count+1],
744 (TAG_MAP_COUNT-1) * sizeof (struct ndrv_tag_map));
745 /* ...and then copy in the original piece */
746 if (tag_map_count)
747 bcopy(ndrv_tags, tmp,
748 tag_map_count * sizeof (struct ndrv_tag_map));
749 /* ...and then install the new tag... */
750 tmp[tag_map_count].tm_tag = tag;
751 tmp[tag_map_count].tm_np = np;
752 tag_map_count = i;
753 if (tag_map_count)
754 FREE(ndrv_tags, M_PCB);
755 ndrv_tags = tmp;
756 #ifdef NDRV_DEBUG
757 log(LOG_WARNING, "NDRV ADDING TAG %d (new chunk)\n", tag);
758 #endif
759 return(0);
760 }
761
762 /*
763 * Attach the proto spec list, and record the tags.
764 */
765 int
766 ndrv_add_descr(struct ndrv_cb *np, struct dlil_proto_reg_str *proto_spec)
767 { unsigned long dl_tag;
768 int error;
769 struct dlil_demux_desc *mp;
770
771 /* Attach to our device to get requested packets */
772 TAILQ_INIT(&proto_spec->demux_desc_head);
773 error = dlil_attach_protocol(proto_spec, &dl_tag);
774
775 if (error == 0)
776 error = ndrv_add_tag(np, dl_tag, mp);
777
778 return(error);
779 }
780
781 int
782 ndrv_dump_descr(struct ndrv_cb *np)
783 { struct dlil_demux_desc *dm1, *dm2;
784 struct ndrv_tag_map *tmp;
785 int i, error = 0;
786
787 if (dm1 = TAILQ_FIRST(&np->nd_dlist))
788 { for (i = 0, tmp = &ndrv_tags[0]; i++ < tag_map_count; tmp++)
789 if (tmp->tm_np == np)
790 { error = dlil_detach_protocol(tmp->tm_tag);
791 while (dm1)
792 { dm2 = TAILQ_NEXT(dm1, next);
793 FREE(dm1, M_PCB);
794 dm1 = dm2;
795 }
796 log(LOG_WARNING,
797 "Detached tag %d (error %d)\n",
798 tmp->tm_tag, error);
799 tmp->tm_np = 0;
800 tmp->tm_tag = 0;
801 }
802 }
803 return(0);
804 }
805
806 void ndrv_dominit()
807 {
808 static int ndrv_dominited = 0;
809
810 if (ndrv_dominited == 0) {
811 net_add_proto(&ndrvsw[0], &ndrvdomain);
812
813 ndrv_dominited = 1;
814 }
815 }
816
817 struct pr_usrreqs ndrv_usrreqs = {
818 ndrv_abort, pru_accept_notsupp, ndrv_attach, ndrv_bind,
819 ndrv_connect, pru_connect2_notsupp, ndrv_control, ndrv_detach,
820 ndrv_disconnect, pru_listen_notsupp, ndrv_peeraddr, pru_rcvd_notsupp,
821 pru_rcvoob_notsupp, ndrv_send, ndrv_sense, ndrv_shutdown,
822 ndrv_sockaddr, sosend, soreceive, sopoll
823 };
824
825 struct protosw ndrvsw[] =
826 { { SOCK_RAW, &ndrvdomain, 0, PR_ATOMIC|PR_ADDR,
827 0, ndrv_output, ndrv_ctlinput, ndrv_ctloutput,
828 0, ndrv_init, 0, 0,
829 ndrv_drain, ndrv_sysctl, &ndrv_usrreqs
830 }
831 };
832
833 struct domain ndrvdomain =
834 { AF_NDRV, "NetDriver", ndrv_dominit, NULL, NULL,
835 NULL,
836 NULL, NULL, 0, 0, 0, 0
837 };