]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netgraph/ng_eiface.c
This commit was generated by cvs2svn to compensate for changes in r128671,
[FreeBSD/FreeBSD.git] / sys / netgraph / ng_eiface.c
1 /*-
2  *
3  * Copyright (c) 1999-2001, Vitaly V Belekhov
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice unmodified, this list of conditions, and the following
11  *    disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  */
30
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/errno.h>
35 #include <sys/kernel.h>
36 #include <sys/malloc.h>
37 #include <sys/mbuf.h>
38 #include <sys/errno.h>
39 #include <sys/sockio.h>
40 #include <sys/socket.h>
41 #include <sys/syslog.h>
42
43 #include <net/if.h>
44 #include <net/if_dl.h>
45 #include <net/if_types.h>
46 #include <net/netisr.h>
47
48 #include <netinet/in.h>
49 #include <netinet/if_ether.h>
50
51 #include <netgraph/ng_message.h>
52 #include <netgraph/netgraph.h>
53 #include <netgraph/ng_parse.h>
54 #include <netgraph/ng_eiface.h>
55
56 #include <net/bpf.h>
57 #include <net/ethernet.h>
58 #include <net/if_arp.h>
59
60 static const struct ng_cmdlist ng_eiface_cmdlist[] = {
61         {
62           NGM_EIFACE_COOKIE,
63           NGM_EIFACE_SET,
64           "set",
65           &ng_parse_enaddr_type,
66           NULL
67         },
68         { 0 }
69 };
70
71
72 /* Node private data */
73 struct ng_eiface_private {
74         struct arpcom   arpcom; /* per-interface network data */
75         struct ifnet   *ifp;    /* This interface */
76         int     unit;           /* Interface unit number */
77         node_p          node;   /* Our netgraph node */
78         hook_p          ether;  /* Hook for ethernet stream */
79 };
80 typedef struct ng_eiface_private *priv_p;
81
82 /* Interface methods */
83 static void     ng_eiface_init(void *xsc);
84 static void     ng_eiface_start(struct ifnet *ifp);
85 static int      ng_eiface_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
86 #ifdef DEBUG
87 static void     ng_eiface_print_ioctl(struct ifnet *ifp, int cmd, caddr_t data);
88 #endif
89
90 /* Netgraph methods */
91 static ng_constructor_t ng_eiface_constructor;
92 static ng_rcvmsg_t ng_eiface_rcvmsg;
93 static ng_shutdown_t ng_eiface_rmnode;
94 static ng_newhook_t ng_eiface_newhook;
95 static ng_rcvdata_t ng_eiface_rcvdata;
96 static ng_connect_t ng_eiface_connect;
97 static ng_disconnect_t ng_eiface_disconnect;
98
99 /* Node type descriptor */
100 static struct ng_type typestruct = {
101         NG_ABI_VERSION,
102         NG_EIFACE_NODE_TYPE,
103         NULL,
104         ng_eiface_constructor,
105         ng_eiface_rcvmsg,
106         ng_eiface_rmnode,
107         ng_eiface_newhook,
108         NULL,
109         ng_eiface_connect,
110         ng_eiface_rcvdata,
111         ng_eiface_disconnect,
112         ng_eiface_cmdlist
113 };
114 NETGRAPH_INIT(eiface, &typestruct);
115
116 /* We keep a bitmap indicating which unit numbers are free.
117    One means the unit number is free, zero means it's taken. */
118 static int      *ng_eiface_units = NULL;
119 static int      ng_eiface_units_len = 0;
120 static int      ng_units_in_use = 0;
121
122 #define UNITS_BITSPERWORD       (sizeof(*ng_eiface_units) * NBBY)
123
124
125 /************************************************************************
126                         HELPER STUFF
127  ************************************************************************/
128 /*
129  * Find the first free unit number for a new interface.
130  * Increase the size of the unit bitmap as necessary.
131  */
132 static __inline__ int
133 ng_eiface_get_unit(int *unit)
134 {
135         int index, bit;
136
137         for (index = 0; index < ng_eiface_units_len
138             && ng_eiface_units[index] == 0; index++);
139         if (index == ng_eiface_units_len) {             /* extend array */
140                 int i, *newarray, newlen;
141
142                 newlen = (2 * ng_eiface_units_len) + 4;
143                 MALLOC(newarray, int *, newlen * sizeof(*ng_eiface_units),
144                     M_NETGRAPH, M_NOWAIT);
145                 if (newarray == NULL)
146                         return (ENOMEM);
147                 bcopy(ng_eiface_units, newarray,
148                     ng_eiface_units_len * sizeof(*ng_eiface_units));
149                 for (i = ng_eiface_units_len; i < newlen; i++)
150                         newarray[i] = ~0;
151                 if (ng_eiface_units != NULL)
152                         FREE(ng_eiface_units, M_NETGRAPH);
153                 ng_eiface_units = newarray;
154                 ng_eiface_units_len = newlen;
155         }
156         bit = ffs(ng_eiface_units[index]) - 1;
157         KASSERT(bit >= 0 && bit <= UNITS_BITSPERWORD - 1,
158             ("%s: word=%d bit=%d", __func__, ng_eiface_units[index], bit));
159         ng_eiface_units[index] &= ~(1 << bit);
160         *unit = (index * UNITS_BITSPERWORD) + bit;
161         ng_units_in_use++;
162         return (0);
163 }
164
165 /*
166  * Free a no longer needed unit number.
167  */
168 static __inline__ void
169 ng_eiface_free_unit(int unit)
170 {
171         int index, bit;
172
173         index = unit / UNITS_BITSPERWORD;
174         bit = unit % UNITS_BITSPERWORD;
175         KASSERT(index < ng_eiface_units_len,
176             ("%s: unit=%d len=%d", __func__, unit, ng_eiface_units_len));
177         KASSERT((ng_eiface_units[index] & (1 << bit)) == 0,
178             ("%s: unit=%d is free", __func__, unit));
179         ng_eiface_units[index] |= (1 << bit);
180         /*
181          * XXX We could think about reducing the size of ng_eiface_units[]
182          * XXX here if the last portion is all ones
183          * XXX At least free it if no more units.
184          * Needed if we are to eventually be able to unload.
185          */
186         ng_units_in_use--;
187         if (ng_units_in_use == 0) { /* XXX make SMP safe */
188                 FREE(ng_eiface_units, M_NETGRAPH);
189                 ng_eiface_units_len = 0;
190                 ng_eiface_units = NULL;
191         }
192 }
193
194 /************************************************************************
195                         INTERFACE STUFF
196  ************************************************************************/
197
198 /*
199  * Process an ioctl for the virtual interface
200  */
201 static int
202 ng_eiface_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
203 {
204         struct ifreq   *const ifr = (struct ifreq *)data;
205         int             s, error = 0;
206
207 #ifdef DEBUG
208         ng_eiface_print_ioctl(ifp, command, data);
209 #endif
210         s = splimp();
211         switch (command)
212         {
213         /* These two are mostly handled at a higher layer */
214         case SIOCSIFADDR:
215                 error = ether_ioctl(ifp, command, data);
216                 break;
217         case SIOCGIFADDR:
218                 break;
219
220         /* Set flags */
221         case SIOCSIFFLAGS:
222                 /*
223                  * If the interface is marked up and stopped, then
224                  * start it. If it is marked down and running,
225                  * then stop it.
226                  */
227                 if (ifr->ifr_flags & IFF_UP) {
228                         if (!(ifp->if_flags & IFF_RUNNING)) {
229                                 ifp->if_flags &= ~(IFF_OACTIVE);
230                                 ifp->if_flags |= IFF_RUNNING;
231                         }
232                 } else {
233                         if (ifp->if_flags & IFF_RUNNING)
234                                 ifp->if_flags
235                                         &= ~(IFF_RUNNING | IFF_OACTIVE);
236                 }
237                 break;
238
239         /* Set the interface MTU */
240         case SIOCSIFMTU:
241                 if (ifr->ifr_mtu > NG_EIFACE_MTU_MAX
242                 || ifr->ifr_mtu < NG_EIFACE_MTU_MIN)
243                         error = EINVAL;
244                 else
245                         ifp->if_mtu = ifr->ifr_mtu;
246                 break;
247
248         /* Stuff that's not supported */
249         case SIOCADDMULTI:
250         case SIOCDELMULTI:
251                 error = 0;
252                 break;
253         case SIOCSIFPHYS:
254                 error = EOPNOTSUPP;
255                 break;
256
257         default:
258                 error = EINVAL;
259                 break;
260         }
261         (void)splx(s);
262         return (error);
263 }
264
265 static void
266 ng_eiface_init(void *xsc)
267 {
268         priv_p          sc = xsc;
269         struct ifnet   *ifp = sc->ifp;
270         int             s;
271
272         s = splimp();
273
274         ifp->if_flags |= IFF_RUNNING;
275         ifp->if_flags &= ~IFF_OACTIVE;
276
277         splx(s);
278 }
279
280 /*
281  * We simply relay the packet to the ether hook, if it is connected.
282  * We have been throughthe netgraph locking an are guaranteed to 
283  * be the only code running in this node at this time.
284  */
285 static void
286 ng_eiface_start2(node_p node, hook_p hook, void *arg1, int arg2)
287 {
288         struct ifnet *ifp = arg1;
289         const priv_p priv = (priv_p) ifp->if_softc;
290         int             len, error = 0;
291         struct mbuf    *m;
292
293         /* Check interface flags */
294         if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING))
295                 return;
296
297         /* Don't do anything if output is active */
298         if (ifp->if_flags & IFF_OACTIVE)
299                 return;
300
301         ifp->if_flags |= IFF_OACTIVE;
302
303         /*
304          * Grab a packet to transmit.
305          */
306         IF_DEQUEUE(&ifp->if_snd, m);
307
308         /* If there's nothing to send, return. */
309         if (m == NULL) {
310                 ifp->if_flags &= ~IFF_OACTIVE;
311                 return;
312         }
313
314         /* Berkeley packet filter
315          * Pass packet to bpf if there is a listener.
316          * XXX is this safe? locking?
317          */
318         BPF_MTAP(ifp, m);
319
320         /* Copy length before the mbuf gets invalidated */
321         len = m->m_pkthdr.len;
322
323         /*
324          * Send packet; if hook is not connected, mbuf will get
325          * freed.
326          */
327         NG_SEND_DATA_ONLY(error, priv->ether, m);
328
329         /* Update stats */
330         if (error == 0) {
331                 ifp->if_obytes += len;
332                 ifp->if_opackets++;
333         }
334         ifp->if_flags &= ~IFF_OACTIVE;
335         return;
336 }
337
338 /*
339  * This routine is called to deliver a packet out the interface.
340  * We simply queue the netgraph version to be called when netgraph locking
341  * allows it to happen.
342  * Until we know what the rest of the networking code is doing for
343  * locking, we don't know how we will interact with it.
344  * Take comfort from the fact that the ifnet struct is part of our
345  * private info and can't go away while we are queued.
346  * [Though we don't know it is still there now....]
347  * it is possible we don't gain anything from this because
348  * we would like to get the mbuf and queue it as data
349  * somehow, but we can't and if we did would we solve anything?
350  */
351 static void
352 ng_eiface_start(struct ifnet *ifp)
353 {
354         
355         const priv_p priv = (priv_p) ifp->if_softc;
356
357         ng_send_fn(priv->node, NULL, &ng_eiface_start2, ifp, 0);
358 }
359
360 #ifdef DEBUG
361 /*
362  * Display an ioctl to the virtual interface
363  */
364
365 static void
366 ng_eiface_print_ioctl(struct ifnet *ifp, int command, caddr_t data){
367         char            *str;
368
369         switch (command & IOC_DIRMASK)
370         {
371         case IOC_VOID:
372                 str = "IO";
373                 break;
374         case IOC_OUT:
375                 str = "IOR";
376                 break;
377         case IOC_IN:
378                 str = "IOW";
379                 break;
380         case IOC_INOUT:
381                 str = "IORW";
382                 break;
383         default:
384                 str = "IO??";
385         }
386         log(LOG_DEBUG, "%s: %s('%c', %d, char[%d])\n",
387                         ifp->if_xname,
388                         str,
389                         IOCGROUP(command),
390                         command & 0xff,
391                         IOCPARM_LEN(command));
392 }
393 #endif  /* DEBUG */
394
395 /************************************************************************
396                         NETGRAPH NODE STUFF
397  ************************************************************************/
398
399 /*
400  * Constructor for a node
401  */
402 static int
403 ng_eiface_constructor(node_p node)
404 {
405         struct ifnet   *ifp;
406         priv_p          priv;
407         int             error = 0;
408
409         /* Allocate node and interface private structures */
410         MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_WAITOK);
411         if (priv == NULL) {
412                 return (ENOMEM);
413         }
414         bzero(priv, sizeof(*priv));
415
416         ifp = &(priv->arpcom.ac_if);
417
418         /* Link them together */
419         ifp->if_softc = priv;
420         priv->ifp = ifp;
421
422         /* Get an interface unit number */
423         if ((error = ng_eiface_get_unit(&priv->unit)) != 0) {
424                 FREE(priv, M_NETGRAPH);
425                 return (error);
426         }
427
428         /* Link together node and private info */
429         NG_NODE_SET_PRIVATE(node, priv);
430         priv->node = node;
431
432         /* Initialize interface structure */
433         if_initname(ifp, NG_EIFACE_EIFACE_NAME, priv->unit);
434         ifp->if_init = ng_eiface_init;
435         ifp->if_output = ether_output;
436         ifp->if_start = ng_eiface_start;
437         ifp->if_ioctl = ng_eiface_ioctl;
438         ifp->if_watchdog = NULL;
439         ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
440         ifp->if_flags = (IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST);
441
442         /*
443          * Give this node name * bzero(ifname, sizeof(ifname));
444          * sprintf(ifname, "if%s", ifp->if_xname); (void)
445          * ng_name_node(node, ifname);
446          */
447
448         /* Attach the interface */
449         ether_ifattach(ifp, priv->arpcom.ac_enaddr);
450
451         /* Done */
452         return (0);
453 }
454
455 /*
456  * Give our ok for a hook to be added
457  */
458 static int
459 ng_eiface_newhook(node_p node, hook_p hook, const char *name)
460 {
461         priv_p          priv = NG_NODE_PRIVATE(node);
462
463         if (strcmp(name, NG_EIFACE_HOOK_ETHER))
464                 return (EPFNOSUPPORT);
465         if (priv->ether != NULL)
466                 return (EISCONN);
467         priv->ether = hook;
468         NG_HOOK_SET_PRIVATE(hook, &priv->ether);
469
470         return (0);
471 }
472
473 /*
474  * Receive a control message
475  */
476 static int
477 ng_eiface_rcvmsg(node_p node, item_p item, hook_p lasthook)
478 {
479         priv_p          priv = NG_NODE_PRIVATE(node);
480         struct ifnet   *const ifp = priv->ifp;
481         struct ng_mesg *resp = NULL;
482         int             error = 0;
483         struct ng_mesg *msg;
484
485         NGI_GET_MSG(item, msg);
486         switch          (msg->header.typecookie) {
487         case NGM_EIFACE_COOKIE:
488                 switch (msg->header.cmd) {
489                 case NGM_EIFACE_SET:
490                 {
491                         struct ether_addr *eaddr;
492                         struct ifaddr *ifa;
493                         struct sockaddr_dl *sdl;
494
495                         if (msg->header.arglen != sizeof(struct ether_addr)){
496                                 error = EINVAL;
497                                 break;
498                         }
499                         eaddr = (struct ether_addr *)(msg->data);
500                         bcopy(eaddr, priv->arpcom.ac_enaddr, ETHER_ADDR_LEN);
501
502                         /* And put it in the ifaddr list */
503                         TAILQ_FOREACH(ifa, &(ifp->if_addrhead), ifa_link) {
504                                 sdl = (struct sockaddr_dl *)ifa->ifa_addr;
505                                 if (sdl->sdl_type == IFT_ETHER) {
506                                         bcopy((IFP2AC(ifp))->ac_enaddr,
507                                                 LLADDR(sdl), ifp->if_addrlen);
508                                         break;
509                                 }
510                         }
511                         break;
512                 }
513
514                 case NGM_EIFACE_GET_IFNAME:
515                 {
516                         struct ng_eiface_ifname *arg;
517
518                         NG_MKRESPONSE(resp, msg, sizeof(*arg), M_NOWAIT);
519                         if (resp == NULL) {
520                                 error = ENOMEM;
521                                 break;
522                         }
523                         arg = (struct ng_eiface_ifname *)resp->data;
524                         strlcpy(arg->ngif_name, ifp->if_xname,
525                             sizeof(arg->ngif_name));
526                         break;
527                 }
528
529                 case NGM_EIFACE_GET_IFADDRS:
530                 {
531                         struct ifaddr  *ifa;
532                         caddr_t         ptr;
533                         int             buflen;
534
535 #define SA_SIZE(s)      ((s)->sa_len<sizeof(*(s))? sizeof(*(s)):(s)->sa_len)
536
537                         /* Determine size of response and allocate it */
538                         buflen = 0;
539                         TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
540                         buflen += SA_SIZE(ifa->ifa_addr);
541                         NG_MKRESPONSE(resp, msg, buflen, M_NOWAIT);
542                         if (resp == NULL) {
543                                 error = ENOMEM;
544                                 break;
545                         }
546                         /* Add addresses */
547                         ptr = resp->data;
548                         TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
549                                 const int       len = SA_SIZE(ifa->ifa_addr);
550
551                                 if (buflen < len) {
552                                         log(LOG_ERR, "%s: len changed?\n",
553                                         ifp->if_xname);
554                                         break;
555                                 }
556                                 bcopy(ifa->ifa_addr, ptr, len);
557                                 ptr += len;
558                                 buflen -= len;
559                         }
560                         break;
561 #undef SA_SIZE
562                 }
563
564                 default:
565                         error = EINVAL;
566                         break;
567                 } /* end of inner switch() */
568                 break;
569         default:
570                 error = EINVAL;
571                 break;
572         }
573         NG_RESPOND_MSG(error, node, item, resp);
574         NG_FREE_MSG(msg);
575         return (error);
576 }
577
578 /*
579  * Recive data from a hook. Pass the packet to the ether_input routine.
580  */
581 static int
582 ng_eiface_rcvdata(hook_p hook, item_p item)
583 {
584         priv_p          priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
585         struct ifnet   *const ifp = priv->ifp;
586         struct mbuf *m;
587
588         NGI_GET_M(item, m);
589         /* Meta-data ends its life here... */
590         NG_FREE_ITEM(item);
591
592         if (m == NULL)
593         {
594                 printf("ng_eiface: mbuf is null.\n");
595                 return (EINVAL);
596         }
597         if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
598                 NG_FREE_M(m);
599                 return (ENETDOWN);
600         }
601
602         /* Note receiving interface */
603         m->m_pkthdr.rcvif = ifp;
604
605         /* Update interface stats */
606         ifp->if_ipackets++;
607
608         (*ifp->if_input)(ifp, m);
609
610         /* Done */
611         return (0);
612 }
613
614 /*
615  * the node.
616  */
617 static int
618 ng_eiface_rmnode(node_p node)
619 {
620         priv_p          priv = NG_NODE_PRIVATE(node);
621         struct ifnet   *const ifp = priv->ifp;
622
623         ether_ifdetach(ifp);
624         ng_eiface_free_unit(priv->unit);
625         FREE(priv, M_NETGRAPH);
626         NG_NODE_SET_PRIVATE(node, NULL);
627         NG_NODE_UNREF(node);
628         return (0);
629 }
630
631
632 /*
633  * This is called once we've already connected a new hook to the other node.
634  * It gives us a chance to balk at the last minute.
635  */
636 static int
637 ng_eiface_connect(hook_p hook)
638 {
639         /* be really amiable and just say "YUP that's OK by me! " */
640         return (0);
641 }
642
643 /*
644  * Hook disconnection
645  */
646 static int
647 ng_eiface_disconnect(hook_p hook)
648 {
649         priv_p          priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
650
651         priv->ether = NULL;
652         return (0);
653 }