[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]

FreeBSD/Linux Kernel Cross Reference
sys/netgraph/ng_eiface.c

Version: -  FREEBSD  -  FREEBSD7  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  OPENSOLARIS  -  minix-3-1-1  -  TRUSTEDBSD-SEBSD  -  FREEBSD-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  excerpts  -  bigexcerpts 

  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: src/sys/netgraph/ng_eiface.c,v 1.44 2008/12/02 21:37:28 bz Exp $
 29  */
 30 
 31 #include <sys/param.h>
 32 #include <sys/systm.h>
 33 #include <sys/errno.h>
 34 #include <sys/kernel.h>
 35 #include <sys/malloc.h>
 36 #include <sys/mbuf.h>
 37 #include <sys/errno.h>
 38 #include <sys/sockio.h>
 39 #include <sys/socket.h>
 40 #include <sys/syslog.h>
 41 #include <sys/vimage.h>
 42 
 43 #include <net/if.h>
 44 #include <net/if_types.h>
 45 #include <net/netisr.h>
 46 #include <net/route.h>
 47 
 48 #include <netgraph/ng_message.h>
 49 #include <netgraph/netgraph.h>
 50 #include <netgraph/ng_parse.h>
 51 #include <netgraph/ng_eiface.h>
 52 
 53 #include <net/bpf.h>
 54 #include <net/ethernet.h>
 55 #include <net/if_arp.h>
 56 
 57 static const struct ng_cmdlist ng_eiface_cmdlist[] = {
 58         {
 59           NGM_EIFACE_COOKIE,
 60           NGM_EIFACE_GET_IFNAME,
 61           "getifname",
 62           NULL,
 63           &ng_parse_string_type
 64         },
 65         {
 66           NGM_EIFACE_COOKIE,
 67           NGM_EIFACE_SET,
 68           "set",
 69           &ng_parse_enaddr_type,
 70           NULL
 71         },
 72         { 0 }
 73 };
 74 
 75 /* Node private data */
 76 struct ng_eiface_private {
 77         struct ifnet    *ifp;           /* per-interface network data */
 78         int             unit;           /* Interface unit number */
 79         node_p          node;           /* Our netgraph node */
 80         hook_p          ether;          /* Hook for ethernet stream */
 81 };
 82 typedef struct ng_eiface_private *priv_p;
 83 
 84 /* Interface methods */
 85 static void     ng_eiface_init(void *xsc);
 86 static void     ng_eiface_start(struct ifnet *ifp);
 87 static int      ng_eiface_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
 88 #ifdef DEBUG
 89 static void     ng_eiface_print_ioctl(struct ifnet *ifp, int cmd, caddr_t data);
 90 #endif
 91 
 92 /* Netgraph methods */
 93 static int              ng_eiface_mod_event(module_t, int, void *);
 94 static ng_constructor_t ng_eiface_constructor;
 95 static ng_rcvmsg_t      ng_eiface_rcvmsg;
 96 static ng_shutdown_t    ng_eiface_rmnode;
 97 static ng_newhook_t     ng_eiface_newhook;
 98 static ng_rcvdata_t     ng_eiface_rcvdata;
 99 static ng_disconnect_t  ng_eiface_disconnect;
100 
101 /* Node type descriptor */
102 static struct ng_type typestruct = {
103         .version =      NG_ABI_VERSION,
104         .name =         NG_EIFACE_NODE_TYPE,
105         .mod_event =    ng_eiface_mod_event,
106         .constructor =  ng_eiface_constructor,
107         .rcvmsg =       ng_eiface_rcvmsg,
108         .shutdown =     ng_eiface_rmnode,
109         .newhook =      ng_eiface_newhook,
110         .rcvdata =      ng_eiface_rcvdata,
111         .disconnect =   ng_eiface_disconnect,
112         .cmdlist =      ng_eiface_cmdlist
113 };
114 NETGRAPH_INIT(eiface, &typestruct);
115 
116 static struct unrhdr    *ng_eiface_unit;
117 
118 /************************************************************************
119                         INTERFACE STUFF
120  ************************************************************************/
121 
122 /*
123  * Process an ioctl for the virtual interface
124  */
125 static int
126 ng_eiface_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
127 {
128         struct ifreq *const ifr = (struct ifreq *)data;
129         int s, error = 0;
130 
131 #ifdef DEBUG
132         ng_eiface_print_ioctl(ifp, command, data);
133 #endif
134         s = splimp();
135         switch (command) {
136 
137         /* These two are mostly handled at a higher layer */
138         case SIOCSIFADDR:
139                 error = ether_ioctl(ifp, command, data);
140                 break;
141         case SIOCGIFADDR:
142                 break;
143 
144         /* Set flags */
145         case SIOCSIFFLAGS:
146                 /*
147                  * If the interface is marked up and stopped, then start it.
148                  * If it is marked down and running, then stop it.
149                  */
150                 if (ifp->if_flags & IFF_UP) {
151                         if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
152                                 ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE);
153                                 ifp->if_drv_flags |= IFF_DRV_RUNNING;
154                         }
155                 } else {
156                         if (ifp->if_drv_flags & IFF_DRV_RUNNING)
157                                 ifp->if_drv_flags &= ~(IFF_DRV_RUNNING |
158                                     IFF_DRV_OACTIVE);
159                 }
160                 break;
161 
162         /* Set the interface MTU */
163         case SIOCSIFMTU:
164                 if (ifr->ifr_mtu > NG_EIFACE_MTU_MAX ||
165                     ifr->ifr_mtu < NG_EIFACE_MTU_MIN)
166                         error = EINVAL;
167                 else
168                         ifp->if_mtu = ifr->ifr_mtu;
169                 break;
170 
171         /* Stuff that's not supported */
172         case SIOCADDMULTI:
173         case SIOCDELMULTI:
174                 error = 0;
175                 break;
176         case SIOCSIFPHYS:
177                 error = EOPNOTSUPP;
178                 break;
179 
180         default:
181                 error = EINVAL;
182                 break;
183         }
184         splx(s);
185         return (error);
186 }
187 
188 static void
189 ng_eiface_init(void *xsc)
190 {
191         priv_p sc = xsc;
192         struct ifnet *ifp = sc->ifp;
193         int s;
194 
195         s = splimp();
196 
197         ifp->if_drv_flags |= IFF_DRV_RUNNING;
198         ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
199 
200         splx(s);
201 }
202 
203 /*
204  * We simply relay the packet to the "ether" hook, if it is connected.
205  * We have been through the netgraph locking and are guaranteed to
206  * be the only code running in this node at this time.
207  */
208 static void
209 ng_eiface_start2(node_p node, hook_p hook, void *arg1, int arg2)
210 {
211         struct ifnet *ifp = arg1;
212         const priv_p priv = (priv_p)ifp->if_softc;
213         int error = 0;
214         struct mbuf *m;
215 
216         /* Check interface flags */
217 
218         if (!((ifp->if_flags & IFF_UP) &&
219             (ifp->if_drv_flags & IFF_DRV_RUNNING)))
220                 return;
221 
222         for (;;) {
223                 /*
224                  * Grab a packet to transmit.
225                  */
226                 IF_DEQUEUE(&ifp->if_snd, m);
227 
228                 /* If there's nothing to send, break. */
229                 if (m == NULL)
230                         break;
231 
232                 /*
233                  * Berkeley packet filter.
234                  * Pass packet to bpf if there is a listener.
235                  * XXX is this safe? locking?
236                  */
237                 BPF_MTAP(ifp, m);
238 
239                 if (ifp->if_flags & IFF_MONITOR) {
240                         ifp->if_ipackets++;
241                         m_freem(m);
242                         continue;
243                 }
244 
245                 /*
246                  * Send packet; if hook is not connected, mbuf will get
247                  * freed.
248                  */
249                 NG_SEND_DATA_ONLY(error, priv->ether, m);
250 
251                 /* Update stats */
252                 if (error == 0)
253                         ifp->if_opackets++;
254                 else
255                         ifp->if_oerrors++;
256         }
257 
258         ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
259 
260         return;
261 }
262 
263 /*
264  * This routine is called to deliver a packet out the interface.
265  * We simply queue the netgraph version to be called when netgraph locking
266  * allows it to happen.
267  * Until we know what the rest of the networking code is doing for
268  * locking, we don't know how we will interact with it.
269  * Take comfort from the fact that the ifnet struct is part of our
270  * private info and can't go away while we are queued.
271  * [Though we don't know it is still there now....]
272  * it is possible we don't gain anything from this because
273  * we would like to get the mbuf and queue it as data
274  * somehow, but we can't and if we did would we solve anything?
275  */
276 static void
277 ng_eiface_start(struct ifnet *ifp)
278 {
279 
280         const priv_p priv = (priv_p)ifp->if_softc;
281 
282         /* Don't do anything if output is active */
283         if (ifp->if_drv_flags & IFF_DRV_OACTIVE)
284                 return;
285 
286         ifp->if_drv_flags |= IFF_DRV_OACTIVE;
287 
288         if (ng_send_fn(priv->node, NULL, &ng_eiface_start2, ifp, 0) != 0)
289                 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
290 }
291 
292 #ifdef DEBUG
293 /*
294  * Display an ioctl to the virtual interface
295  */
296 
297 static void
298 ng_eiface_print_ioctl(struct ifnet *ifp, int command, caddr_t data)
299 {
300         char *str;
301 
302         switch (command & IOC_DIRMASK) {
303         case IOC_VOID:
304                 str = "IO";
305                 break;
306         case IOC_OUT:
307                 str = "IOR";
308                 break;
309         case IOC_IN:
310                 str = "IOW";
311                 break;
312         case IOC_INOUT:
313                 str = "IORW";
314                 break;
315         default:
316                 str = "IO??";
317         }
318         log(LOG_DEBUG, "%s: %s('%c', %d, char[%d])\n",
319             ifp->if_xname,
320             str,
321             IOCGROUP(command),
322             command & 0xff,
323             IOCPARM_LEN(command));
324 }
325 #endif /* DEBUG */
326 
327 /************************************************************************
328                         NETGRAPH NODE STUFF
329  ************************************************************************/
330 
331 /*
332  * Constructor for a node
333  */
334 static int
335 ng_eiface_constructor(node_p node)
336 {
337         INIT_VNET_NETGRAPH(curvnet);
338         struct ifnet *ifp;
339         priv_p priv;
340         u_char eaddr[6] = {0,0,0,0,0,0};
341 
342         /* Allocate node and interface private structures */
343         priv = malloc(sizeof(*priv), M_NETGRAPH, M_NOWAIT | M_ZERO);
344         if (priv == NULL)
345                 return (ENOMEM);
346 
347         ifp = priv->ifp = if_alloc(IFT_ETHER);
348         if (ifp == NULL) {
349                 free(priv, M_NETGRAPH);
350                 return (ENOSPC);
351         }
352 
353         /* Link them together */
354         ifp->if_softc = priv;
355 
356         /* Get an interface unit number */
357         priv->unit = alloc_unr(V_ng_eiface_unit);
358 
359         /* Link together node and private info */
360         NG_NODE_SET_PRIVATE(node, priv);
361         priv->node = node;
362 
363         /* Initialize interface structure */
364         if_initname(ifp, NG_EIFACE_EIFACE_NAME, priv->unit);
365         ifp->if_init = ng_eiface_init;
366         ifp->if_output = ether_output;
367         ifp->if_start = ng_eiface_start;
368         ifp->if_ioctl = ng_eiface_ioctl;
369         ifp->if_watchdog = NULL;
370         ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
371         ifp->if_flags = (IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST);
372 
373 #if 0
374         /* Give this node name */
375         bzero(ifname, sizeof(ifname));
376         sprintf(ifname, "if%s", ifp->if_xname);
377         (void)ng_name_node(node, ifname);
378 #endif
379 
380         /* Attach the interface */
381         ether_ifattach(ifp, eaddr);
382 
383         /* Done */
384         return (0);
385 }
386 
387 /*
388  * Give our ok for a hook to be added
389  */
390 static int
391 ng_eiface_newhook(node_p node, hook_p hook, const char *name)
392 {
393         priv_p priv = NG_NODE_PRIVATE(node);
394         struct ifnet *ifp = priv->ifp;
395 
396         if (strcmp(name, NG_EIFACE_HOOK_ETHER))
397                 return (EPFNOSUPPORT);
398         if (priv->ether != NULL)
399                 return (EISCONN);
400         priv->ether = hook;
401         NG_HOOK_SET_PRIVATE(hook, &priv->ether);
402 
403         if_link_state_change(ifp, LINK_STATE_UP);
404 
405         return (0);
406 }
407 
408 /*
409  * Receive a control message
410  */
411 static int
412 ng_eiface_rcvmsg(node_p node, item_p item, hook_p lasthook)
413 {
414         const priv_p priv = NG_NODE_PRIVATE(node);
415         struct ifnet *const ifp = priv->ifp;
416         struct ng_mesg *resp = NULL;
417         int error = 0;
418         struct ng_mesg *msg;
419 
420         NGI_GET_MSG(item, msg);
421         switch (msg->header.typecookie) {
422         case NGM_EIFACE_COOKIE:
423                 switch (msg->header.cmd) {
424 
425                 case NGM_EIFACE_SET:
426                     {
427                         if (msg->header.arglen != ETHER_ADDR_LEN) {
428                                 error = EINVAL;
429                                 break;
430                         }
431                         error = if_setlladdr(priv->ifp,
432                             (u_char *)msg->data, ETHER_ADDR_LEN);
433                         break;
434                     }
435 
436                 case NGM_EIFACE_GET_IFNAME:
437                         NG_MKRESPONSE(resp, msg, IFNAMSIZ, M_NOWAIT);
438                         if (resp == NULL) {
439                                 error = ENOMEM;
440                                 break;
441                         }
442                         strlcpy(resp->data, ifp->if_xname, IFNAMSIZ);
443                         break;
444 
445                 case NGM_EIFACE_GET_IFADDRS:
446                     {
447                         struct ifaddr *ifa;
448                         caddr_t ptr;
449                         int buflen;
450 
451                         /* Determine size of response and allocate it */
452                         buflen = 0;
453                         TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
454                                 buflen += SA_SIZE(ifa->ifa_addr);
455                         NG_MKRESPONSE(resp, msg, buflen, M_NOWAIT);
456                         if (resp == NULL) {
457                                 error = ENOMEM;
458                                 break;
459                         }
460 
461                         /* Add addresses */
462                         ptr = resp->data;
463                         TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
464                                 const int len = SA_SIZE(ifa->ifa_addr);
465 
466                                 if (buflen < len) {
467                                         log(LOG_ERR, "%s: len changed?\n",
468                                             ifp->if_xname);
469                                         break;
470                                 }
471                                 bcopy(ifa->ifa_addr, ptr, len);
472                                 ptr += len;
473                                 buflen -= len;
474                         }
475                         break;
476                     }
477 
478                 default:
479                         error = EINVAL;
480                         break;
481                 } /* end of inner switch() */
482                 break;
483         case NGM_FLOW_COOKIE:
484                 switch (msg->header.cmd) {
485                 case NGM_LINK_IS_UP:
486                         if_link_state_change(ifp, LINK_STATE_UP);
487                         break;
488                 case NGM_LINK_IS_DOWN:
489                         if_link_state_change(ifp, LINK_STATE_DOWN);
490                         break;
491                 default:
492                         break;
493                 }
494                 break;
495         default:
496                 error = EINVAL;
497                 break;
498         }
499         NG_RESPOND_MSG(error, node, item, resp);
500         NG_FREE_MSG(msg);
501         return (error);
502 }
503 
504 /*
505  * Receive data from a hook. Pass the packet to the ether_input routine.
506  */
507 static int
508 ng_eiface_rcvdata(hook_p hook, item_p item)
509 {
510         const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
511         struct ifnet *const ifp = priv->ifp;
512         struct mbuf *m;
513 
514         NGI_GET_M(item, m);
515         NG_FREE_ITEM(item);
516 
517         if (!((ifp->if_flags & IFF_UP) &&
518             (ifp->if_drv_flags & IFF_DRV_RUNNING))) {
519                 NG_FREE_M(m);
520                 return (ENETDOWN);
521         }
522 
523         if (m->m_len < ETHER_HDR_LEN) {
524                 m = m_pullup(m, ETHER_HDR_LEN);
525                 if (m == NULL)
526                         return (EINVAL);
527         }
528 
529         /* Note receiving interface */
530         m->m_pkthdr.rcvif = ifp;
531 
532         /* Update interface stats */
533         ifp->if_ipackets++;
534 
535         (*ifp->if_input)(ifp, m);
536 
537         /* Done */
538         return (0);
539 }
540 
541 /*
542  * Shutdown processing.
543  */
544 static int
545 ng_eiface_rmnode(node_p node)
546 {
547         INIT_VNET_NETGRAPH(curvnet);
548         const priv_p priv = NG_NODE_PRIVATE(node);
549         struct ifnet *const ifp = priv->ifp;
550 
551         /*
552          * the ifnet may be in a different vnet than the netgraph node, 
553          * hence we have to change the current vnet context here.
554          */
555         CURVNET_SET_QUIET(ifp->if_vnet);
556         ether_ifdetach(ifp);
557         if_free(ifp);
558         CURVNET_RESTORE();
559         free_unr(V_ng_eiface_unit, priv->unit);
560         free(priv, M_NETGRAPH);
561         NG_NODE_SET_PRIVATE(node, NULL);
562         NG_NODE_UNREF(node);
563         return (0);
564 }
565 
566 /*
567  * Hook disconnection
568  */
569 static int
570 ng_eiface_disconnect(hook_p hook)
571 {
572         const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
573 
574         priv->ether = NULL;
575         return (0);
576 }
577 
578 /*
579  * Handle loading and unloading for this node type.
580  */
581 static int
582 ng_eiface_mod_event(module_t mod, int event, void *data)
583 {
584         int error = 0;
585 
586         switch (event) {
587         case MOD_LOAD:
588                 V_ng_eiface_unit = new_unrhdr(0, 0xffff, NULL);
589                 break;
590         case MOD_UNLOAD:
591                 delete_unrhdr(V_ng_eiface_unit);
592                 break;
593         default:
594                 error = EOPNOTSUPP;
595                 break;
596         }
597         return (error);
598 }
599 

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.