LCOV - code coverage report
Current view: top level - net - if_switch.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 801 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 34 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: if_switch.c,v 1.23 2018/02/19 08:59:52 mpi Exp $      */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2016 Kazuya GODA <goda@openbsd.org>
       5             :  * Copyright (c) 2016 Reyk Floeter <reyk@openbsd.org>
       6             :  *
       7             :  * Permission to use, copy, modify, and distribute this software for any
       8             :  * purpose with or without fee is hereby granted, provided that the above
       9             :  * copyright notice and this permission notice appear in all copies.
      10             :  *
      11             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      12             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      13             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      14             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      15             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      16             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      17             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      18             :  */
      19             : 
      20             : #include "bpfilter.h"
      21             : #include "pf.h"
      22             : #include "vlan.h"
      23             : 
      24             : #include <sys/param.h>
      25             : #include <sys/systm.h>
      26             : #include <sys/mbuf.h>
      27             : #include <sys/socket.h>
      28             : #include <sys/ioctl.h>
      29             : #include <sys/queue.h>
      30             : #include <sys/selinfo.h>
      31             : #include <sys/pool.h>
      32             : #include <sys/syslog.h>
      33             : 
      34             : #include <net/if_types.h>
      35             : #include <net/netisr.h>
      36             : #include <net/if.h>
      37             : 
      38             : #include <netinet/in.h>
      39             : #include <netinet/if_ether.h>
      40             : #include <net/ethertypes.h>
      41             : #include <netinet/ip.h>
      42             : #include <netinet/ip6.h>
      43             : #include <netinet/icmp6.h>
      44             : #include <netinet6/nd6.h>
      45             : #include <netinet/udp.h>
      46             : #include <netinet/tcp.h>
      47             : #include <netinet/ip_icmp.h>
      48             : 
      49             : #if NPF > 0
      50             : #include <net/pfvar.h>
      51             : #endif
      52             : 
      53             : #if NBPFILTER > 0
      54             : #include <net/bpf.h>
      55             : #endif
      56             : 
      57             : #include <net/ofp.h>
      58             : #include <net/if_bridge.h>
      59             : #include <net/if_switch.h>
      60             : 
      61             : int      switch_clone_create(struct if_clone *, int);
      62             : int      switch_clone_destroy(struct ifnet *);
      63             : void     switch_process(struct ifnet *, struct mbuf *);
      64             : int      switch_port_set_local(struct switch_softc *, struct switch_port *);
      65             : int      switch_port_unset_local(struct switch_softc *, struct switch_port *);
      66             : int      switch_ioctl(struct ifnet *, unsigned long, caddr_t);
      67             : int      switch_port_add(struct switch_softc *, struct ifbreq *);
      68             : void     switch_port_detach(void *);
      69             : int      switch_port_del(struct switch_softc *, struct ifbreq *);
      70             : int      switch_port_list(struct switch_softc *, struct ifbifconf *);
      71             : int      switch_input(struct ifnet *, struct mbuf *, void *);
      72             : struct mbuf
      73             :         *switch_port_ingress(struct switch_softc *, struct ifnet *,
      74             :             struct mbuf *);
      75             : int      switch_ifenqueue(struct switch_softc *, struct ifnet *,
      76             :             struct mbuf *, int);
      77             : void     switch_port_ifb_start(struct ifnet *);
      78             : 
      79             : struct mbuf
      80             :         *switch_flow_classifier_udp(struct mbuf *, int *,
      81             :             struct switch_flow_classify *);
      82             : struct mbuf
      83             :         *switch_flow_classifier_tcp(struct mbuf *, int *,
      84             :             struct switch_flow_classify *);
      85             : struct mbuf
      86             :         *switch_flow_classifier_icmpv4(struct mbuf *, int *,
      87             :             struct switch_flow_classify *);
      88             : struct mbuf
      89             :         *switch_flow_classifier_nd6(struct mbuf *, int *,
      90             :             struct switch_flow_classify *);
      91             : struct mbuf
      92             :         *switch_flow_classifier_icmpv6(struct mbuf *, int *,
      93             :             struct switch_flow_classify *);
      94             : struct mbuf
      95             :         *switch_flow_classifier_ipv4(struct mbuf *, int *,
      96             :             struct switch_flow_classify *);
      97             : struct mbuf
      98             :         *switch_flow_classifier_ipv6(struct mbuf *, int *,
      99             :             struct switch_flow_classify *);
     100             : struct mbuf
     101             :         *switch_flow_classifier_arp(struct mbuf *, int *,
     102             :             struct switch_flow_classify *);
     103             : struct mbuf
     104             :         *switch_flow_classifier_ether(struct mbuf *, int *,
     105             :             struct switch_flow_classify *);
     106             : struct mbuf
     107             :         *switch_flow_classifier_tunnel(struct mbuf *, int *,
     108             :             struct switch_flow_classify *);
     109             : void     switch_flow_classifier_dump(struct switch_softc *,
     110             :             struct switch_flow_classify *);
     111             : void     switchattach(int);
     112             : 
     113             : struct if_clone switch_cloner =
     114             :     IF_CLONE_INITIALIZER("switch", switch_clone_create, switch_clone_destroy);
     115             : 
     116             : LIST_HEAD(, switch_softc) switch_list;
     117             : struct niqueue switchintrq = NIQUEUE_INITIALIZER(1024, NETISR_SWITCH);
     118             : struct rwlock switch_ifs_lk = RWLOCK_INITIALIZER("switchifs");
     119             : 
     120             : struct pool swfcl_pool;
     121             : 
     122             : void
     123           0 : switchattach(int n)
     124             : {
     125           0 :         pool_init(&swfcl_pool, sizeof(union switch_field), 0, 0, 0,
     126             :             "swfcl", NULL);
     127           0 :         swofp_attach();
     128           0 :         LIST_INIT(&switch_list);
     129           0 :         if_clone_attach(&switch_cloner);
     130           0 : }
     131             : 
     132             : struct switch_softc *
     133           0 : switch_lookup(int unit)
     134             : {
     135             :         struct switch_softc     *sc;
     136             : 
     137             :         /* must hold switch_ifs_lk */
     138           0 :         LIST_FOREACH(sc, &switch_list, sc_switch_next) {
     139           0 :                 if (sc->sc_unit == unit)
     140           0 :                         return (sc);
     141             :         }
     142             : 
     143           0 :         return (NULL);
     144           0 : }
     145             : 
     146             : int
     147           0 : switch_clone_create(struct if_clone *ifc, int unit)
     148             : {
     149             :         struct switch_softc     *sc;
     150             :         struct ifnet            *ifp;
     151             : 
     152           0 :         sc = malloc(sizeof(struct switch_softc), M_DEVBUF, M_WAITOK|M_ZERO);
     153           0 :         ifp = &sc->sc_if;
     154           0 :         snprintf(ifp->if_xname, sizeof ifp->if_xname, "switch%d", unit);
     155           0 :         ifp->if_softc = sc;
     156           0 :         ifp->if_mtu = ETHERMTU;
     157           0 :         ifp->if_ioctl = switch_ioctl;
     158           0 :         ifp->if_output = NULL;
     159           0 :         ifp->if_start = NULL;
     160           0 :         ifp->if_type = IFT_BRIDGE;
     161           0 :         ifp->if_hdrlen = ETHER_HDR_LEN;
     162           0 :         TAILQ_INIT(&sc->sc_swpo_list);
     163             : 
     164           0 :         sc->sc_unit = unit;
     165           0 :         sc->sc_stp = bstp_create(&sc->sc_if);
     166           0 :         if (!sc->sc_stp) {
     167           0 :                 free(sc, M_DEVBUF, sizeof(*sc));
     168           0 :                 return (ENOMEM);
     169             :         }
     170             : 
     171           0 :         if_attach(ifp);
     172           0 :         if_alloc_sadl(ifp);
     173             : 
     174             : #if NBPFILTER > 0
     175           0 :         bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, ETHER_HDR_LEN);
     176             : #endif
     177             : 
     178           0 :         swofp_create(sc);
     179             : 
     180           0 :         LIST_INSERT_HEAD(&switch_list, sc, sc_switch_next);
     181             : 
     182           0 :         return (0);
     183           0 : }
     184             : 
     185             : int
     186           0 : switch_clone_destroy(struct ifnet *ifp)
     187             : {
     188           0 :         struct switch_softc     *sc = ifp->if_softc;
     189             :         struct switch_port      *swpo, *tp;
     190             :         struct ifnet            *ifs;
     191             : 
     192           0 :         TAILQ_FOREACH_SAFE(swpo, &sc->sc_swpo_list, swpo_list_next, tp) {
     193           0 :                 if ((ifs = if_get(swpo->swpo_ifindex)) != NULL) {
     194           0 :                         switch_port_detach(ifs);
     195           0 :                         if_put(ifs);
     196           0 :                 } else
     197           0 :                         log(LOG_ERR, "failed to cleanup on ifindex(%d)\n",
     198           0 :                             swpo->swpo_ifindex);
     199             :         }
     200           0 :         LIST_REMOVE(sc, sc_switch_next);
     201           0 :         bstp_destroy(sc->sc_stp);
     202           0 :         swofp_destroy(sc);
     203           0 :         switch_dev_destroy(sc);
     204           0 :         if_deactivate(ifp);
     205           0 :         if_detach(ifp);
     206           0 :         free(sc, M_DEVBUF, sizeof(*sc));
     207             : 
     208           0 :         return (0);
     209             : }
     210             : 
     211             : 
     212             : void
     213           0 : switchintr(void)
     214             : {
     215           0 :         struct mbuf_list         ml;
     216             :         struct mbuf             *m;
     217             :         struct ifnet            *ifp;
     218             : 
     219           0 :         niq_delist(&switchintrq, &ml);
     220           0 :         if (ml_empty(&ml))
     221           0 :                 return;
     222             : 
     223           0 :         while ((m = ml_dequeue(&ml)) != NULL) {
     224           0 :                 ifp = if_get(m->m_pkthdr.ph_ifidx);
     225           0 :                 if (ifp == NULL) {
     226           0 :                         m_freem(m);
     227           0 :                         continue;
     228             :                 }
     229           0 :                 switch_process(ifp, m);
     230           0 :                 if_put(ifp);
     231             :         }
     232             : 
     233           0 : }
     234             : 
     235             : void
     236           0 : switch_process(struct ifnet *ifp, struct mbuf *m)
     237             : {
     238             :         struct switch_softc             *sc = NULL;
     239             :         struct switch_port              *swpo;
     240           0 :         struct switch_flow_classify      swfcl = { 0 };
     241             : 
     242           0 :         swpo = (struct switch_port *)ifp->if_switchport;
     243           0 :         if (swpo == NULL)
     244             :                 goto discard;
     245           0 :         sc = swpo->swpo_switch;
     246           0 :         if ((sc->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
     247             :                 goto discard;
     248             : 
     249             : #if NBPFILTER > 0
     250           0 :         if (sc->sc_if.if_bpf)
     251           0 :                 bpf_mtap_ether(sc->sc_if.if_bpf, m, BPF_DIRECTION_IN);
     252             : #endif
     253             : 
     254           0 :         if (m->m_pkthdr.len < sizeof(struct ether_header))
     255             :                 goto discard;
     256             : 
     257           0 :         if ((m = switch_port_ingress(sc, ifp, m)) == NULL)
     258           0 :                 return; /* m was freed in switch_process_ingress */
     259             : 
     260           0 :         if ((m = switch_flow_classifier(m, swpo->swpo_port_no,
     261           0 :             &swfcl)) == NULL) {
     262           0 :                 switch_swfcl_free(&swfcl);
     263           0 :                 return;  /* m was freed in switch_flow_classifier */
     264             :         }
     265             : 
     266           0 :         if (sc->sc_if.if_flags & IFF_DEBUG)
     267           0 :                 switch_flow_classifier_dump(sc, &swfcl);
     268             : 
     269           0 :         if (!sc->switch_process_forward)
     270             :                 goto discard;
     271             : 
     272           0 :         (sc->switch_process_forward)(sc, &swfcl, m);
     273             : 
     274           0 :         switch_swfcl_free(&swfcl);
     275           0 :         return;
     276             : 
     277             : discard:
     278           0 :         m_freem(m);
     279           0 :         switch_swfcl_free(&swfcl);
     280           0 :         if (sc)
     281           0 :                 sc->sc_if.if_oerrors++;
     282           0 : }
     283             : 
     284             : int
     285           0 : switch_port_set_local(struct switch_softc *sc, struct switch_port *swpo)
     286             : {
     287             :         struct switch_port      *tswpo;
     288           0 :         struct ifreq             ifreq;
     289             :         struct ifnet            *ifs;
     290             :         int                     error = 0, re_up = 0;
     291             : 
     292             :         /*
     293             :          * Only one local interface can exist per switch device.
     294             :          */
     295           0 :         TAILQ_FOREACH(tswpo, &sc->sc_swpo_list, swpo_list_next) {
     296           0 :                 if (tswpo->swpo_flags & IFBIF_LOCAL)
     297           0 :                         return (EEXIST);
     298             :         }
     299             : 
     300           0 :         ifs = if_get(swpo->swpo_ifindex);
     301           0 :         if (ifs == NULL)
     302           0 :                 return (ENOENT);
     303             : 
     304           0 :         if (ifs->if_flags & IFF_UP) {
     305             :                 re_up = 1;
     306           0 :                 memset(&ifreq, 0, sizeof(ifreq));
     307           0 :                 strlcpy(ifreq.ifr_name, ifs->if_xname, IFNAMSIZ);
     308           0 :                 ifs->if_flags &= ~IFF_UP;
     309           0 :                 ifreq.ifr_flags = ifs->if_flags;
     310           0 :                 error = (*ifs->if_ioctl)(ifs, SIOCSIFFLAGS, (caddr_t)&ifreq);
     311           0 :                 if (error)
     312             :                         goto error;
     313             :         }
     314             : 
     315           0 :         swpo->swpo_flags |= IFBIF_LOCAL;
     316           0 :         swpo->swpo_port_no = OFP_PORT_LOCAL;
     317           0 :         swpo->swop_bk_start = ifs->if_start;
     318           0 :         ifs->if_start = switch_port_ifb_start;
     319             : 
     320           0 :         if (re_up) {
     321           0 :                 memset(&ifreq, 0, sizeof(ifreq));
     322           0 :                 strlcpy(ifreq.ifr_name, ifs->if_xname, IFNAMSIZ);
     323           0 :                 ifs->if_flags &= IFF_UP;
     324           0 :                 ifreq.ifr_flags = ifs->if_flags;
     325           0 :                 error = (*ifs->if_ioctl)(ifs, SIOCSIFFLAGS, (caddr_t)&ifreq);
     326           0 :                 if (error)
     327             :                         goto error;
     328             :         }
     329             : 
     330             :  error:
     331           0 :         if_put(ifs);
     332           0 :         return (error);
     333           0 : }
     334             : 
     335             : int
     336           0 : switch_port_unset_local(struct switch_softc *sc, struct switch_port *swpo)
     337             : {
     338           0 :         struct ifreq    ifreq;
     339             :         struct ifnet    *ifs;
     340             :         int             error = 0, re_up = 0;
     341             : 
     342           0 :         ifs = if_get(swpo->swpo_ifindex);
     343           0 :         if (ifs == NULL)
     344           0 :                 return (ENOENT);
     345             : 
     346           0 :         if (ifs->if_flags & IFF_UP) {
     347             :                 re_up = 1;
     348           0 :                 memset(&ifreq, 0, sizeof(ifreq));
     349           0 :                 strlcpy(ifreq.ifr_name, ifs->if_xname, IFNAMSIZ);
     350           0 :                 ifs->if_flags &= ~IFF_UP;
     351           0 :                 ifreq.ifr_flags = ifs->if_flags;
     352           0 :                 error = (*ifs->if_ioctl)(ifs, SIOCSIFFLAGS, (caddr_t)&ifreq);
     353           0 :                 if (error)
     354             :                         goto error;
     355             :         }
     356             : 
     357           0 :         swpo->swpo_flags &= ~IFBIF_LOCAL;
     358           0 :         swpo->swpo_port_no = swofp_assign_portno(sc, ifs->if_index);
     359           0 :         ifs->if_start = swpo->swop_bk_start;
     360           0 :         swpo->swop_bk_start = NULL;
     361             : 
     362           0 :         if (re_up) {
     363           0 :                 memset(&ifreq, 0, sizeof(ifreq));
     364           0 :                 strlcpy(ifreq.ifr_name, ifs->if_xname, IFNAMSIZ);
     365           0 :                 ifs->if_flags &= IFF_UP;
     366           0 :                 ifreq.ifr_flags = ifs->if_flags;
     367           0 :                 error = (*ifs->if_ioctl)(ifs, SIOCSIFFLAGS, (caddr_t)&ifreq);
     368           0 :                 if (error)
     369             :                         goto error;
     370             :         }
     371             : 
     372             :  error:
     373           0 :         if_put(ifs);
     374           0 :         return (error);
     375           0 : }
     376             : 
     377             : int
     378           0 : switch_ioctl(struct ifnet *ifp, unsigned long cmd, caddr_t data)
     379             : {
     380           0 :         struct ifbaconf         *baconf = (struct ifbaconf *)data;
     381           0 :         struct ifbropreq        *brop = (struct ifbropreq *)data;
     382           0 :         struct ifbrlconf        *bc = (struct ifbrlconf *)data;
     383           0 :         struct ifbreq           *breq = (struct ifbreq *)data;
     384           0 :         struct switch_softc     *sc = ifp->if_softc;
     385           0 :         struct bstp_state       *bs = sc->sc_stp;
     386             :         struct bstp_port        *bp;
     387             :         struct ifnet            *ifs;
     388             :         struct switch_port      *swpo;
     389             :         int                      error = 0;
     390             : 
     391           0 :         switch (cmd) {
     392             :         case SIOCBRDGADD:
     393           0 :                 if ((error = suser(curproc)) != 0)
     394             :                         break;
     395           0 :                 error = switch_port_add(sc, (struct ifbreq *)data);
     396           0 :                 break;
     397             :         case SIOCBRDGDEL:
     398           0 :                 if ((error = suser(curproc)) != 0)
     399             :                         break;
     400           0 :                 error = switch_port_del(sc, (struct ifbreq *)data);
     401           0 :                 break;
     402             :         case SIOCBRDGIFS:
     403           0 :                 error = switch_port_list(sc, (struct ifbifconf *)data);
     404           0 :                 break;
     405             :         case SIOCBRDGADDL:
     406           0 :                 if ((error = suser(curproc)) != 0)
     407             :                         break;
     408           0 :                 error = switch_port_add(sc, (struct ifbreq *)data);
     409           0 :                 if (error && error != EEXIST)
     410             :                         break;
     411           0 :                 ifs = ifunit(breq->ifbr_ifsname);
     412           0 :                 if (ifs == NULL) {
     413             :                         error = ENOENT;
     414           0 :                         break;
     415             :                 }
     416           0 :                 swpo = (struct switch_port *)ifs->if_switchport;
     417           0 :                 if (swpo == NULL || swpo->swpo_switch != sc) {
     418             :                         error = ESRCH;
     419           0 :                         break;
     420             :                 }
     421           0 :                 error = switch_port_set_local(sc, swpo);
     422           0 :                 break;
     423             :         case SIOCBRDGGIFFLGS:
     424           0 :                 ifs = ifunit(breq->ifbr_ifsname);
     425           0 :                 if (ifs == NULL) {
     426             :                         error = ENOENT;
     427           0 :                         break;
     428             :                 }
     429           0 :                 swpo = (struct switch_port *)ifs->if_switchport;
     430           0 :                 if (swpo == NULL || swpo->swpo_switch != sc) {
     431             :                         error = ESRCH;
     432           0 :                         break;
     433             :                 }
     434           0 :                 breq->ifbr_ifsflags = swpo->swpo_flags;
     435           0 :                 breq->ifbr_portno = swpo->swpo_port_no;
     436           0 :                 break;
     437             :         case SIOCSIFFLAGS:
     438           0 :                 if ((ifp->if_flags & IFF_UP) == IFF_UP)
     439           0 :                         ifp->if_flags |= IFF_RUNNING;
     440             : 
     441           0 :                 if ((ifp->if_flags & IFF_UP) == 0)
     442           0 :                         ifp->if_flags &= ~IFF_RUNNING;
     443             : 
     444             :                 break;
     445             :         case SIOCBRDGRTS:
     446           0 :                 baconf->ifbac_len = 0;
     447           0 :                 break;
     448             :         case SIOCBRDGGRL:
     449           0 :                 bc->ifbrl_len = 0;
     450           0 :                 break;
     451             :         case SIOCBRDGGPARAM:
     452           0 :                 if ((bp = bs->bs_root_port) == NULL)
     453           0 :                         brop->ifbop_root_port = 0;
     454             :                 else
     455           0 :                         brop->ifbop_root_port = bp->bp_ifp->if_index;
     456           0 :                 brop->ifbop_maxage = bs->bs_bridge_max_age >> 8;
     457           0 :                 brop->ifbop_hellotime = bs->bs_bridge_htime >> 8;
     458           0 :                 brop->ifbop_fwddelay = bs->bs_bridge_fdelay >> 8;
     459           0 :                 brop->ifbop_holdcount = bs->bs_txholdcount;
     460           0 :                 brop->ifbop_priority = bs->bs_bridge_priority;
     461           0 :                 brop->ifbop_protocol = bs->bs_protover;
     462           0 :                 brop->ifbop_root_bridge = bs->bs_root_pv.pv_root_id;
     463           0 :                 brop->ifbop_root_path_cost = bs->bs_root_pv.pv_cost;
     464           0 :                 brop->ifbop_root_port = bs->bs_root_pv.pv_port_id;
     465           0 :                 brop->ifbop_desg_bridge = bs->bs_root_pv.pv_dbridge_id;
     466           0 :                 brop->ifbop_last_tc_time.tv_sec = bs->bs_last_tc_time.tv_sec;
     467           0 :                 brop->ifbop_last_tc_time.tv_usec = bs->bs_last_tc_time.tv_usec;
     468           0 :                 break;
     469             :         case SIOCSWGDPID:
     470             :         case SIOCSWSDPID:
     471             :         case SIOCSWGMAXFLOW:
     472             :         case SIOCSWGMAXGROUP:
     473             :         case SIOCSWSPORTNO:
     474           0 :                 error = swofp_ioctl(ifp, cmd, data);
     475           0 :                 break;
     476             :         default:
     477             :                 error = ENOTTY;
     478           0 :                 break;
     479             :         }
     480             : 
     481           0 :         return (error);
     482             : }
     483             : 
     484             : int
     485           0 : switch_port_add(struct switch_softc *sc, struct ifbreq *req)
     486             : {
     487             :         struct ifnet            *ifs;
     488             :         struct switch_port      *swpo;
     489             :         int                      error;
     490             : 
     491           0 :         if ((ifs = ifunit(req->ifbr_ifsname)) == NULL)
     492           0 :                 return (ENOENT);
     493             : 
     494           0 :         if (ifs->if_bridgeport != NULL)
     495           0 :                 return (EBUSY);
     496             : 
     497           0 :         if (ifs->if_switchport != NULL) {
     498           0 :                 swpo = (struct switch_port *)ifs->if_switchport;
     499           0 :                 if (swpo->swpo_switch == sc)
     500           0 :                         return (EEXIST);
     501             :                 else
     502           0 :                         return (EBUSY);
     503             :         }
     504             : 
     505           0 :         if (ifs->if_type == IFT_ETHER) {
     506           0 :                 if ((error = ifpromisc(ifs, 1)) != 0)
     507           0 :                         return (error);
     508             :         }
     509             : 
     510           0 :         swpo = malloc(sizeof(*swpo), M_DEVBUF, M_NOWAIT|M_ZERO);
     511           0 :         if (swpo == NULL) {
     512           0 :                 if (ifs->if_type == IFT_ETHER)
     513           0 :                         ifpromisc(ifs, 0);
     514           0 :                 return (ENOMEM);
     515             :         }
     516           0 :         swpo->swpo_switch = sc;
     517           0 :         swpo->swpo_ifindex = ifs->if_index;
     518           0 :         ifs->if_switchport = (caddr_t)swpo;
     519           0 :         if_ih_insert(ifs, switch_input, NULL);
     520           0 :         swpo->swpo_port_no = swofp_assign_portno(sc, ifs->if_index);
     521           0 :         swpo->swpo_dhcookie = hook_establish(ifs->if_detachhooks, 0,
     522           0 :             switch_port_detach, ifs);
     523             : 
     524           0 :         nanouptime(&swpo->swpo_appended);
     525             : 
     526           0 :         TAILQ_INSERT_TAIL(&sc->sc_swpo_list, swpo, swpo_list_next);
     527             : 
     528           0 :         return (0);
     529           0 : }
     530             : 
     531             : int
     532           0 : switch_port_list(struct switch_softc *sc, struct ifbifconf *bifc)
     533             : {
     534             :         struct switch_port      *swpo;
     535             :         struct ifnet            *ifs;
     536           0 :         struct ifbreq            breq;
     537             :         int                      total = 0, n = 0, error = 0;
     538             : 
     539           0 :         TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next)
     540           0 :                 total++;
     541             : 
     542           0 :         if (bifc->ifbic_len == 0)
     543             :                 goto done;
     544             : 
     545           0 :         TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) {
     546           0 :                 memset(&breq, 0, sizeof(breq));
     547             : 
     548           0 :                 if (bifc->ifbic_len < sizeof(breq))
     549             :                         break;
     550             : 
     551           0 :                 ifs = if_get(swpo->swpo_ifindex);
     552           0 :                 if (ifs == NULL) {
     553             :                         error = ENOENT;
     554           0 :                         goto done;
     555             :                 }
     556           0 :                 strlcpy(breq.ifbr_ifsname, ifs->if_xname, IFNAMSIZ);
     557           0 :                 if_put(ifs);
     558             : 
     559           0 :                 strlcpy(breq.ifbr_name, sc->sc_if.if_xname, IFNAMSIZ);
     560           0 :                 breq.ifbr_ifsflags = swpo->swpo_flags;
     561           0 :                 breq.ifbr_portno = swpo->swpo_port_no;
     562             : 
     563           0 :                 if ((error = copyout((caddr_t)&breq,
     564           0 :                     (caddr_t)(bifc->ifbic_req + n), sizeof(breq))) != 0)
     565             :                         goto done;
     566             : 
     567           0 :                 bifc->ifbic_len -= sizeof(breq);
     568           0 :                 n++;
     569             :         }
     570             : 
     571             : done:
     572           0 :         bifc->ifbic_len = n * sizeof(breq);
     573           0 :         return (error);
     574           0 : }
     575             : 
     576             : void
     577           0 : switch_port_detach(void *arg)
     578             : {
     579           0 :         struct ifnet            *ifp = (struct ifnet *)arg;
     580             :         struct switch_softc     *sc;
     581             :         struct switch_port      *swpo;
     582             : 
     583           0 :         swpo = (struct switch_port *)ifp->if_switchport;
     584           0 :         sc = swpo->swpo_switch;
     585           0 :         if (swpo->swpo_flags & IFBIF_LOCAL)
     586           0 :                 switch_port_unset_local(sc, swpo);
     587             : 
     588           0 :         ifp->if_switchport = NULL;
     589           0 :         hook_disestablish(ifp->if_detachhooks, swpo->swpo_dhcookie);
     590           0 :         ifpromisc(ifp, 0);
     591           0 :         if_ih_remove(ifp, switch_input, NULL);
     592           0 :         TAILQ_REMOVE(&sc->sc_swpo_list, swpo, swpo_list_next);
     593           0 :         free(swpo, M_DEVBUF, sizeof(*swpo));
     594           0 : }
     595             : 
     596             : int
     597           0 : switch_port_del(struct switch_softc *sc, struct ifbreq *req)
     598             : {
     599             :         struct switch_port      *swpo;
     600             :         struct ifnet            *ifs;
     601             :         int                      error = 0;
     602             : 
     603           0 :         TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) {
     604           0 :                 if ((ifs = if_get(swpo->swpo_ifindex)) == NULL)
     605             :                         continue;
     606           0 :                 if (strncmp(ifs->if_xname, req->ifbr_ifsname, IFNAMSIZ) == 0)
     607             :                         break;
     608           0 :                 if_put(ifs);
     609           0 :         }
     610             : 
     611           0 :         if (swpo) {
     612           0 :                 switch_port_detach(ifs);
     613           0 :                 if_put(ifs);
     614             :                 error = 0;
     615           0 :         } else
     616             :                 error = ENOENT;
     617             : 
     618           0 :         return (error);
     619             : }
     620             : 
     621             : int
     622           0 : switch_input(struct ifnet *ifp, struct mbuf *m, void *cookie)
     623             : {
     624           0 :         KASSERT(m->m_flags & M_PKTHDR);
     625             : 
     626           0 :         if (m->m_flags & M_PROTO1) {
     627           0 :                 m->m_flags &= ~M_PROTO1;
     628           0 :                 return (0);
     629             :         }
     630             : 
     631           0 :         niq_enqueue(&switchintrq, m);
     632             : 
     633           0 :         return (1);
     634           0 : }
     635             : 
     636             : 
     637             : struct mbuf *
     638           0 : switch_port_ingress(struct switch_softc *sc, struct ifnet *src_if,
     639             :     struct mbuf *m)
     640             : {
     641             :         struct switch_port      *swpo;
     642           0 :         struct ether_header      eh;
     643             : 
     644           0 :         swpo = (struct switch_port *)src_if->if_switchport;
     645             : 
     646           0 :         sc->sc_if.if_ipackets++;
     647           0 :         sc->sc_if.if_ibytes += m->m_pkthdr.len;
     648             : 
     649           0 :         m_copydata(m, 0, ETHER_HDR_LEN, (caddr_t)&eh);
     650             : #if 0
     651             :         /* It's the "#if 0" because it doesn't test switch(4) with pf(4)
     652             :          * or with ipsec(4).
     653             :          */
     654             :         if ((m = bridge_ip((struct bridge_softc *)sc,
     655             :             PF_IN, src_if, &eh, m)) == NULL) {
     656             :                 sc->sc_if.if_ierrors++;
     657             :                 return (NULL);
     658             :         }
     659             : #endif /* NPF */
     660             : 
     661           0 :         return (m);
     662           0 : }
     663             : 
     664             : void
     665           0 : switch_port_egress(struct switch_softc *sc, struct switch_fwdp_queue *fwdp_q,
     666             :     struct mbuf *m)
     667             : {
     668             :         struct switch_port      *swpo;
     669             :         struct ifnet            *dst_if;
     670             :         struct mbuf             *mc;
     671           0 :         struct ether_header      eh;
     672             :         int                      len, used = 0;
     673             : 
     674             : #if NBPFILTER > 0
     675           0 :         if (sc->sc_if.if_bpf)
     676           0 :                 bpf_mtap(sc->sc_if.if_bpf, m, BPF_DIRECTION_OUT);
     677             : #endif
     678             : 
     679           0 :         m_copydata(m, 0, ETHER_HDR_LEN, (caddr_t)&eh);
     680           0 :         TAILQ_FOREACH(swpo, fwdp_q, swpo_fwdp_next) {
     681             : 
     682           0 :                 if ((dst_if = if_get(swpo->swpo_ifindex)) == NULL)
     683             :                         continue;
     684             : 
     685           0 :                 if ((dst_if->if_flags & IFF_RUNNING) == 0)
     686             :                         goto out;
     687             : 
     688           0 :                 if (TAILQ_NEXT(swpo, swpo_fwdp_next) == NULL) {
     689             :                         mc = m;
     690             :                         used = 1;
     691           0 :                 } else {
     692           0 :                         mc = m_dup_pkt(m, ETHER_ALIGN, M_NOWAIT);
     693           0 :                         if (mc == NULL)
     694             :                                 goto out;
     695             :                 }
     696             : 
     697             : #if 0
     698             :                 /* It's the "#if 0" because it doesn't test switch(4) with pf(4)
     699             :                  * or with ipsec(4).
     700             :                  */
     701             :                 if ((mc = bridge_ip((struct bridge_softc *)sc,
     702             :                     PF_OUT, dst_if, &eh, mc)) == NULL) {
     703             :                         sc->sc_if.if_ierrors++;
     704             :                         goto out;
     705             :                 }
     706             : #endif
     707             : 
     708           0 :                 len = mc->m_pkthdr.len;
     709             : #if NVLAN > 0
     710           0 :                 if ((mc->m_flags & M_VLANTAG) &&
     711           0 :                     (dst_if->if_capabilities & IFCAP_VLAN_HWTAGGING) == 0)
     712           0 :                         len += ETHER_VLAN_ENCAP_LEN;
     713             : #endif
     714             : 
     715             :                 /*
     716             :                  * Only if egress port has local port capabilities, it doesn't
     717             :                  * need fragment because a frame sends up local network stack.
     718             :                  */
     719           0 :                 if (!(swpo->swpo_flags & IFBIF_LOCAL) &&
     720           0 :                     ((len - ETHER_HDR_LEN) > dst_if->if_mtu))
     721           0 :                         bridge_fragment((struct bridge_softc *)sc,
     722             :                             dst_if, &eh, mc);
     723             :                 else
     724           0 :                         switch_ifenqueue(sc, dst_if, mc,
     725           0 :                             (swpo->swpo_flags & IFBIF_LOCAL));
     726             :  out:
     727             : 
     728           0 :                 if_put(dst_if);
     729           0 :         }
     730             : 
     731           0 :         if (!used)
     732           0 :                 m_freem(m);
     733           0 : }
     734             : 
     735             : int
     736           0 : switch_ifenqueue(struct switch_softc *sc, struct ifnet *ifp,
     737             :     struct mbuf *m, int local)
     738             : {
     739           0 :         struct mbuf_list         ml = MBUF_LIST_INITIALIZER();
     740             :         int                      error, len;
     741             : 
     742             :         /* Loop prevention. */
     743           0 :         m->m_flags |= M_PROTO1;
     744             : 
     745           0 :         len = m->m_pkthdr.len;
     746             : 
     747           0 :         if (local) {
     748           0 :                 ml_enqueue(&ml, m);
     749           0 :                 if_input(ifp, &ml);
     750           0 :         } else {
     751           0 :                 error = if_enqueue(ifp, m);
     752           0 :                 if (error) {
     753           0 :                         sc->sc_if.if_oerrors++;
     754           0 :                         return (error);
     755             :                 }
     756           0 :                 sc->sc_if.if_opackets++;
     757           0 :                 sc->sc_if.if_obytes += len;
     758             :         }
     759             : 
     760           0 :         return (0);
     761           0 : }
     762             : 
     763             : void
     764           0 : switch_port_ifb_start(struct ifnet *ifp)
     765             : {
     766             :         struct mbuf             *m;
     767           0 :         struct mbuf_list         ml = MBUF_LIST_INITIALIZER();
     768             : 
     769           0 :         for (;;) {
     770           0 :                 IFQ_DEQUEUE(&ifp->if_snd, m);
     771           0 :                 if (m == NULL)
     772             :                         return;
     773             : 
     774             : #if NBPFILTER > 0
     775           0 :                 if (ifp->if_bpf)
     776           0 :                         bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
     777             : #endif /* NBPFILTER > 0 */
     778             : 
     779           0 :                 ml_enqueue(&ml, m);
     780           0 :                 if_input(ifp, &ml);
     781             :         }
     782           0 : }
     783             : 
     784             : /*
     785             :  * Flow Classifier
     786             :  */
     787             : 
     788             : int
     789           0 : switch_swfcl_dup(struct switch_flow_classify *from,
     790             :     struct switch_flow_classify *to)
     791             : {
     792           0 :         memset(to, 0, sizeof(*to));
     793             : 
     794           0 :         to->swfcl_flow_hash = from->swfcl_flow_hash;
     795           0 :         to->swfcl_metadata = from->swfcl_metadata;
     796           0 :         to->swfcl_cookie = from->swfcl_cookie;
     797           0 :         to->swfcl_table_id = from->swfcl_table_id;
     798           0 :         to->swfcl_in_port = from->swfcl_in_port;
     799             : 
     800           0 :         if (from->swfcl_tunnel) {
     801           0 :                 to->swfcl_tunnel = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
     802           0 :                 if (to->swfcl_tunnel == NULL)
     803             :                         goto failed;
     804           0 :                 memcpy(to->swfcl_tunnel, from->swfcl_tunnel,
     805             :                     sizeof(*from->swfcl_tunnel));
     806           0 :         }
     807           0 :         if (from->swfcl_ether) {
     808           0 :                 to->swfcl_ether = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
     809           0 :                 if (to->swfcl_ether == NULL)
     810             :                         goto failed;
     811           0 :                 memcpy(to->swfcl_ether, from->swfcl_ether,
     812             :                     sizeof(*from->swfcl_ether));
     813           0 :         }
     814           0 :         if (from->swfcl_vlan) {
     815           0 :                 to->swfcl_vlan = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
     816           0 :                 if (to->swfcl_vlan == NULL)
     817             :                         goto failed;
     818           0 :                 memcpy(to->swfcl_vlan, from->swfcl_vlan,
     819             :                     sizeof(*from->swfcl_vlan));
     820           0 :         }
     821           0 :         if (from->swfcl_ipv4) {
     822           0 :                 to->swfcl_ipv4 = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
     823           0 :                 if (to->swfcl_ipv4 == NULL)
     824             :                         goto failed;
     825           0 :                 memcpy(to->swfcl_ipv4, from->swfcl_ipv4,
     826             :                     sizeof(*from->swfcl_ipv4));
     827           0 :         }
     828           0 :         if (from->swfcl_ipv6) {
     829           0 :                 to->swfcl_ipv6 = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
     830           0 :                 if (to->swfcl_ipv6 == NULL)
     831             :                         goto failed;
     832           0 :                 memcpy(to->swfcl_ipv6, from->swfcl_ipv6,
     833             :                     sizeof(*from->swfcl_ipv6));
     834           0 :         }
     835           0 :         if (from->swfcl_arp) {
     836           0 :                 to->swfcl_arp = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
     837           0 :                 if (to->swfcl_arp == NULL)
     838             :                         goto failed;
     839           0 :                 memcpy(to->swfcl_arp, from->swfcl_arp,
     840             :                     sizeof(*from->swfcl_arp));
     841             : 
     842           0 :         }
     843           0 :         if (from->swfcl_nd6) {
     844           0 :                 to->swfcl_nd6 = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
     845           0 :                 if (to->swfcl_nd6 == NULL)
     846             :                         goto failed;
     847           0 :                 memcpy(to->swfcl_nd6, from->swfcl_nd6,
     848             :                     sizeof(*from->swfcl_nd6));
     849           0 :         }
     850           0 :         if (from->swfcl_icmpv4) {
     851           0 :                 to->swfcl_icmpv4 = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
     852           0 :                 if (to->swfcl_icmpv4 == NULL)
     853             :                         goto failed;
     854           0 :                 memcpy(to->swfcl_icmpv4, from->swfcl_icmpv4,
     855             :                     sizeof(*from->swfcl_icmpv4));
     856           0 :         }
     857           0 :         if (from->swfcl_icmpv6) {
     858           0 :                 to->swfcl_icmpv6 = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
     859           0 :                 if (to->swfcl_icmpv6 == NULL)
     860             :                         goto failed;
     861           0 :                 memcpy(to->swfcl_icmpv6, from->swfcl_icmpv6,
     862             :                     sizeof(*from->swfcl_icmpv6));
     863           0 :         }
     864           0 :         if (from->swfcl_tcp) {
     865           0 :                 to->swfcl_tcp = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
     866           0 :                 if (to->swfcl_tcp == NULL)
     867             :                         goto failed;
     868           0 :                 memcpy(to->swfcl_tcp, from->swfcl_tcp,
     869             :                     sizeof(*from->swfcl_tcp));
     870           0 :         }
     871           0 :         if (from->swfcl_udp) {
     872           0 :                 to->swfcl_udp = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
     873           0 :                 if (to->swfcl_udp == NULL)
     874             :                         goto failed;
     875           0 :                 memcpy(to->swfcl_udp, from->swfcl_udp,
     876             :                     sizeof(*from->swfcl_udp));
     877           0 :         }
     878           0 :         if (from->swfcl_sctp) {
     879           0 :                 to->swfcl_sctp = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
     880           0 :                 if (to->swfcl_sctp == NULL)
     881             :                         goto failed;
     882           0 :                 memcpy(to->swfcl_sctp, from->swfcl_sctp,
     883             :                     sizeof(*from->swfcl_sctp));
     884           0 :         }
     885             : 
     886           0 :         return (0);
     887             :  failed:
     888           0 :         switch_swfcl_free(to);
     889           0 :         return (ENOBUFS);
     890           0 : }
     891             : 
     892             : void
     893           0 : switch_swfcl_free(struct switch_flow_classify *swfcl)
     894             : {
     895           0 :         if (swfcl->swfcl_tunnel)
     896           0 :                 pool_put(&swfcl_pool, swfcl->swfcl_tunnel);
     897           0 :         if (swfcl->swfcl_ether)
     898           0 :                 pool_put(&swfcl_pool, swfcl->swfcl_ether);
     899           0 :         if (swfcl->swfcl_vlan)
     900           0 :                 pool_put(&swfcl_pool, swfcl->swfcl_vlan);
     901           0 :         if (swfcl->swfcl_ipv4)
     902           0 :                 pool_put(&swfcl_pool, swfcl->swfcl_ipv4);
     903           0 :         if (swfcl->swfcl_ipv6)
     904           0 :                 pool_put(&swfcl_pool, swfcl->swfcl_ipv6);
     905           0 :         if (swfcl->swfcl_arp)
     906           0 :                 pool_put(&swfcl_pool, swfcl->swfcl_arp);
     907           0 :         if (swfcl->swfcl_nd6)
     908           0 :                 pool_put(&swfcl_pool, swfcl->swfcl_nd6);
     909           0 :         if (swfcl->swfcl_icmpv4)
     910           0 :                 pool_put(&swfcl_pool, swfcl->swfcl_icmpv4);
     911           0 :         if (swfcl->swfcl_icmpv6)
     912           0 :                 pool_put(&swfcl_pool, swfcl->swfcl_icmpv6);
     913           0 :         if (swfcl->swfcl_tcp)
     914           0 :                 pool_put(&swfcl_pool, swfcl->swfcl_tcp);
     915           0 :         if (swfcl->swfcl_udp)
     916           0 :                 pool_put(&swfcl_pool, swfcl->swfcl_udp);
     917           0 :         if (swfcl->swfcl_sctp)
     918           0 :                 pool_put(&swfcl_pool, swfcl->swfcl_sctp);
     919             : 
     920           0 :         memset(swfcl, 0, sizeof(*swfcl));
     921           0 : }
     922             : 
     923             : struct mbuf *
     924           0 : switch_flow_classifier_udp(struct mbuf *m, int *offset,
     925             :     struct switch_flow_classify *swfcl)
     926             : {
     927             :         struct udphdr   *uh;
     928             : 
     929           0 :         swfcl->swfcl_udp = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
     930           0 :         if (swfcl->swfcl_udp == NULL) {
     931           0 :                 m_freem(m);
     932           0 :                 return (NULL);
     933             :         }
     934             : 
     935           0 :         if (m->m_len < (*offset + sizeof(*uh)) &&
     936           0 :             (m = m_pullup(m, *offset + sizeof(*uh))) == NULL)
     937           0 :                 return (NULL);
     938             : 
     939           0 :         uh = (struct udphdr *)((m)->m_data + *offset);
     940             : 
     941           0 :         swfcl->swfcl_udp->udp_src = uh->uh_sport;
     942           0 :         swfcl->swfcl_udp->udp_dst = uh->uh_dport;
     943             : 
     944           0 :         return (m);
     945           0 : }
     946             : 
     947             : struct mbuf *
     948           0 : switch_flow_classifier_tcp(struct mbuf *m, int *offset,
     949             :     struct switch_flow_classify *swfcl)
     950             : {
     951             :         struct tcphdr   *th;
     952             : 
     953           0 :         swfcl->swfcl_tcp = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
     954           0 :         if (swfcl->swfcl_tcp == NULL) {
     955           0 :                 m_freem(m);
     956           0 :                 return (NULL);
     957             :         }
     958             : 
     959           0 :         if (m->m_len < (*offset + sizeof(*th)) &&
     960           0 :             (m = m_pullup(m, *offset + sizeof(*th))) == NULL)
     961           0 :                 return (NULL);
     962             : 
     963           0 :         th = (struct tcphdr *)((m)->m_data + *offset);
     964             : 
     965           0 :         swfcl->swfcl_tcp->tcp_src = th->th_sport;
     966           0 :         swfcl->swfcl_tcp->tcp_dst = th->th_dport;
     967           0 :         swfcl->swfcl_tcp->tcp_flags = th->th_flags;
     968             : 
     969           0 :         return (m);
     970           0 : }
     971             : 
     972             : struct mbuf *
     973           0 : switch_flow_classifier_icmpv4(struct mbuf *m, int *offset,
     974             :     struct switch_flow_classify *swfcl)
     975             : {
     976             :         struct icmp     *icmp;
     977             : 
     978           0 :         swfcl->swfcl_icmpv4 = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
     979           0 :         if (swfcl->swfcl_icmpv4 == NULL) {
     980           0 :                 m_freem(m);
     981           0 :                 return (NULL);
     982             :         }
     983             : 
     984           0 :         if (m->m_len < (*offset + ICMP_MINLEN) &&
     985           0 :             (m = m_pullup(m, (*offset + ICMP_MINLEN))) == NULL)
     986           0 :                 return (NULL);
     987             : 
     988           0 :         icmp = (struct icmp *)((m)->m_data + *offset);
     989             : 
     990           0 :         swfcl->swfcl_icmpv4->icmpv4_type = icmp->icmp_type;
     991           0 :         swfcl->swfcl_icmpv4->icmpv4_code = icmp->icmp_code;
     992             : 
     993           0 :         return (m);
     994           0 : }
     995             : 
     996             : #ifdef INET6
     997             : struct mbuf *
     998           0 : switch_flow_classifier_nd6(struct mbuf *m, int *offset,
     999             :     struct switch_flow_classify *swfcl)
    1000             : {
    1001             :         struct icmp6_hdr                *icmp6;
    1002             :         struct nd_neighbor_advert       *nd_na;
    1003             :         struct nd_neighbor_solicit      *nd_ns;
    1004           0 :         union nd_opts                    ndopts;
    1005             :         uint8_t                         *lladdr;
    1006             :         int                              lladdrlen;
    1007           0 :         int                              icmp6len = m->m_pkthdr.len - *offset;
    1008             : 
    1009           0 :         IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, *offset, sizeof(*icmp6));
    1010           0 :         if (icmp6 == NULL)
    1011             :                 goto failed;
    1012             : 
    1013           0 :         switch (icmp6->icmp6_type) {
    1014             :         case ND_NEIGHBOR_ADVERT:
    1015           0 :                 if (icmp6len < sizeof(struct nd_neighbor_advert))
    1016             :                         goto failed;
    1017             :                 break;
    1018             :         case ND_NEIGHBOR_SOLICIT:
    1019           0 :                 if (icmp6len < sizeof(struct nd_neighbor_solicit))
    1020             :                         goto failed;
    1021             :                 break;
    1022             :         }
    1023             : 
    1024           0 :         swfcl->swfcl_nd6 = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
    1025           0 :         if (swfcl->swfcl_nd6 == NULL)
    1026             :                 goto failed;
    1027             : 
    1028           0 :         switch (icmp6->icmp6_type) {
    1029             :         case ND_NEIGHBOR_ADVERT:
    1030           0 :                 IP6_EXTHDR_GET(nd_na, struct nd_neighbor_advert *, m,
    1031             :                     *offset, icmp6len);
    1032             : 
    1033           0 :                 if (nd_na == NULL)
    1034             :                         goto failed;
    1035             : 
    1036           0 :                 swfcl->swfcl_nd6->nd6_target = nd_na->nd_na_target;
    1037           0 :                 icmp6len -= sizeof(*nd_na);
    1038           0 :                 nd6_option_init(nd_na + 1, icmp6len, &ndopts);
    1039           0 :                 if (nd6_options(&ndopts) < 0)
    1040             :                         goto failed;
    1041             : 
    1042           0 :                 if (!ndopts.nd_opts_tgt_lladdr)
    1043             :                         goto failed;
    1044             : 
    1045           0 :                 lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1);
    1046           0 :                 lladdrlen = (ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3) - 2;
    1047             : 
    1048             :                 /* switch(4) only supports Ethernet interfaces */
    1049           0 :                 if (lladdrlen != ETHER_ADDR_LEN)
    1050             :                         goto failed;
    1051           0 :                 memcpy(swfcl->swfcl_nd6->nd6_lladdr, lladdr, ETHER_ADDR_LEN);
    1052           0 :                 break;
    1053             :         case ND_NEIGHBOR_SOLICIT:
    1054           0 :                 IP6_EXTHDR_GET(nd_ns, struct nd_neighbor_solicit *, m,
    1055             :                     *offset, icmp6len);
    1056           0 :                 if (nd_ns == NULL)
    1057             :                         goto failed;
    1058           0 :                 swfcl->swfcl_nd6->nd6_target = nd_ns->nd_ns_target;
    1059           0 :                 icmp6len -= sizeof(*nd_ns);
    1060             : 
    1061           0 :                 nd6_option_init(nd_ns + 1, icmp6len, &ndopts);
    1062           0 :                 if (nd6_options(&ndopts) < 0)
    1063             :                         goto failed;
    1064             : 
    1065           0 :                 if (!ndopts.nd_opts_src_lladdr)
    1066             :                         goto failed;
    1067           0 :                 lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
    1068           0 :                 lladdrlen = (ndopts.nd_opts_src_lladdr->nd_opt_len << 3) - 2;
    1069             : 
    1070             :                 /* switch(4) only supports Ethernet interfaces */
    1071           0 :                 if (lladdrlen != ETHER_ADDR_LEN)
    1072             :                         goto failed;
    1073           0 :                 memcpy(swfcl->swfcl_nd6->nd6_lladdr, lladdr, ETHER_ADDR_LEN);
    1074             : 
    1075           0 :                 break;
    1076             :         }
    1077             : 
    1078           0 :         return (m);
    1079             : 
    1080             :  failed:
    1081           0 :         m_freem(m);
    1082           0 :         return (NULL);
    1083           0 : }
    1084             : 
    1085             : struct mbuf *
    1086           0 : switch_flow_classifier_icmpv6(struct mbuf *m, int *offset,
    1087             :     struct switch_flow_classify *swfcl)
    1088             : {
    1089             :         struct icmp6_hdr        *icmp6;
    1090             : 
    1091           0 :         swfcl->swfcl_icmpv6 = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
    1092           0 :         if (swfcl->swfcl_icmpv6 == NULL) {
    1093           0 :                 m_freem(m);
    1094           0 :                 return (NULL);
    1095             :         }
    1096             : 
    1097           0 :         IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, *offset, sizeof(*icmp6));
    1098           0 :         if (icmp6 == NULL)
    1099           0 :                 return (NULL); /* m was already freed */
    1100             : 
    1101           0 :         swfcl->swfcl_icmpv6->icmpv6_type = icmp6->icmp6_type;
    1102           0 :         swfcl->swfcl_icmpv6->icmpv6_code = icmp6->icmp6_code;
    1103             : 
    1104           0 :         switch (icmp6->icmp6_type) {
    1105             :         case ND_NEIGHBOR_SOLICIT:
    1106             :         case ND_NEIGHBOR_ADVERT:
    1107           0 :                 return switch_flow_classifier_nd6(m, offset, swfcl);
    1108             :         }
    1109             : 
    1110           0 :         return (m);
    1111           0 : }
    1112             : #endif /* INET6 */
    1113             : 
    1114             : struct mbuf *
    1115           0 : switch_flow_classifier_ipv4(struct mbuf *m, int *offset,
    1116             :     struct switch_flow_classify *swfcl)
    1117             : {
    1118             :         struct ip       *ip;
    1119             : 
    1120           0 :         swfcl->swfcl_ipv4 = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
    1121           0 :         if (swfcl->swfcl_ipv4 == NULL) {
    1122           0 :                 m_freem(m);
    1123           0 :                 return (NULL);
    1124             :         }
    1125             : 
    1126           0 :         if (m->m_len < (*offset + sizeof(*ip)) &&
    1127           0 :             (m = m_pullup(m, *offset + sizeof(*ip))) == NULL)
    1128           0 :                 return (NULL);
    1129             : 
    1130           0 :         ip = (struct ip *)((m)->m_data + *offset);
    1131             : 
    1132           0 :         swfcl->swfcl_ipv4->ipv4_tos = ip->ip_tos;
    1133           0 :         swfcl->swfcl_ipv4->ipv4_ttl = ip->ip_ttl;
    1134           0 :         swfcl->swfcl_ipv4->ipv4_proto = ip->ip_p;
    1135             : 
    1136           0 :         memcpy(&swfcl->swfcl_ipv4->ipv4_src, &ip->ip_src.s_addr,
    1137             :             sizeof(uint32_t));
    1138           0 :         memcpy(&swfcl->swfcl_ipv4->ipv4_dst, &ip->ip_dst.s_addr,
    1139             :             sizeof(uint32_t));
    1140             : 
    1141           0 :         *offset += (ip->ip_hl << 2);
    1142             : 
    1143           0 :         switch (ip->ip_p) {
    1144             :         case IPPROTO_UDP:
    1145           0 :                 return switch_flow_classifier_udp(m, offset, swfcl);
    1146             :         case IPPROTO_TCP:
    1147           0 :                 return switch_flow_classifier_tcp(m, offset, swfcl);
    1148             :         case IPPROTO_ICMP:
    1149           0 :                 return switch_flow_classifier_icmpv4(m, offset, swfcl);
    1150             :         }
    1151             : 
    1152           0 :         return (m);
    1153           0 : }
    1154             : 
    1155             : #ifdef INET6
    1156             : struct mbuf *
    1157           0 : switch_flow_classifier_ipv6(struct mbuf *m, int *offset,
    1158             :     struct switch_flow_classify *swfcl)
    1159             : {
    1160             :         struct ip6_hdr  *ip6;
    1161             : 
    1162           0 :         swfcl->swfcl_ipv6 = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
    1163           0 :         if (swfcl->swfcl_ipv6 == NULL) {
    1164           0 :                 m_freem(m);
    1165           0 :                 return (NULL);
    1166             :         }
    1167             : 
    1168           0 :         if (m->m_len < (*offset + sizeof(*ip6)) &&
    1169           0 :             (m = m_pullup(m, *offset + sizeof(*ip6))) == NULL)
    1170           0 :                 return (NULL);
    1171             : 
    1172           0 :         ip6 = (struct ip6_hdr *)((m)->m_data + *offset);
    1173             : 
    1174           0 :         swfcl->swfcl_ipv6->ipv6_src = ip6->ip6_src;
    1175           0 :         swfcl->swfcl_ipv6->ipv6_dst = ip6->ip6_dst;
    1176           0 :         swfcl->swfcl_ipv6->ipv6_flow_label =
    1177           0 :             (ip6->ip6_flow & IPV6_FLOWLABEL_MASK);
    1178           0 :         swfcl->swfcl_ipv6->ipv6_tclass = (ntohl(ip6->ip6_flow) >> 20);
    1179           0 :         swfcl->swfcl_ipv6->ipv6_hlimit = ip6->ip6_hlim;
    1180           0 :         swfcl->swfcl_ipv6->ipv6_nxt = ip6->ip6_nxt;
    1181             : 
    1182           0 :         *offset += sizeof(*ip6);
    1183             : 
    1184           0 :         switch (ip6->ip6_nxt) {
    1185             :         case IPPROTO_UDP:
    1186           0 :                 return switch_flow_classifier_udp(m, offset, swfcl);
    1187             :         case IPPROTO_TCP:
    1188           0 :                 return switch_flow_classifier_tcp(m, offset, swfcl);
    1189             :         case IPPROTO_ICMPV6:
    1190           0 :                 return switch_flow_classifier_icmpv6(m, offset, swfcl);
    1191             :         }
    1192             : 
    1193           0 :         return (m);
    1194           0 : }
    1195             : #endif /* INET6 */
    1196             : 
    1197             : struct mbuf *
    1198           0 : switch_flow_classifier_arp(struct mbuf *m, int *offset,
    1199             :     struct switch_flow_classify *swfcl)
    1200             : {
    1201             :         struct ether_arp        *ea;
    1202             : 
    1203           0 :         swfcl->swfcl_arp = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
    1204           0 :         if (swfcl->swfcl_arp == NULL) {
    1205           0 :                 m_freem(m);
    1206           0 :                 return (NULL);
    1207             :         }
    1208             : 
    1209           0 :         if (m->m_len < (*offset + sizeof(*ea)) &&
    1210           0 :             (m = m_pullup(m, *offset + sizeof(*ea))) == NULL)
    1211           0 :                 return (NULL);
    1212             : 
    1213           0 :         ea = (struct ether_arp *)((m)->m_data + *offset);
    1214             : 
    1215           0 :         swfcl->swfcl_arp->_arp_op = ea->arp_op;
    1216             : 
    1217           0 :         memcpy(swfcl->swfcl_arp->arp_sha, &ea->arp_sha, ETHER_ADDR_LEN);
    1218           0 :         memcpy(swfcl->swfcl_arp->arp_tha, &ea->arp_tha, ETHER_ADDR_LEN);
    1219           0 :         memcpy(&swfcl->swfcl_arp->arp_sip, &ea->arp_spa, sizeof(uint32_t));
    1220           0 :         memcpy(&swfcl->swfcl_arp->arp_tip, &ea->arp_tpa, sizeof(uint32_t));
    1221             : 
    1222           0 :         return (m);
    1223           0 : }
    1224             : 
    1225             : struct mbuf *
    1226           0 : switch_flow_classifier_ether(struct mbuf *m, int *offset,
    1227             :     struct switch_flow_classify *swfcl)
    1228             : {
    1229             :         struct ether_header             *eh;
    1230             :         struct ether_vlan_header        *evl;
    1231             :         uint16_t                         ether_type;
    1232             : 
    1233           0 :         swfcl->swfcl_ether = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
    1234           0 :         if (swfcl->swfcl_ether == NULL) {
    1235           0 :                 m_freem(m);
    1236           0 :                 return (NULL);
    1237             :         }
    1238             : 
    1239           0 :         if (m->m_len < sizeof(*eh) && (m = m_pullup(m, sizeof(*eh))) == NULL)
    1240           0 :                 return (NULL);
    1241           0 :         eh = mtod(m, struct ether_header *);
    1242             : 
    1243           0 :         memcpy(swfcl->swfcl_ether->eth_src, eh->ether_shost, ETHER_ADDR_LEN);
    1244           0 :         memcpy(swfcl->swfcl_ether->eth_dst, eh->ether_dhost, ETHER_ADDR_LEN);
    1245             : 
    1246           0 :         if ((m->m_flags & M_VLANTAG) ||
    1247           0 :             (ntohs(eh->ether_type) == ETHERTYPE_VLAN) ||
    1248           0 :             (ntohs(eh->ether_type) == ETHERTYPE_QINQ)) {
    1249           0 :                 swfcl->swfcl_vlan = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
    1250           0 :                 if (swfcl->swfcl_vlan == NULL) {
    1251           0 :                         m_freem(m);
    1252           0 :                         return (NULL);
    1253             :                 }
    1254             :         }
    1255             : 
    1256           0 :         if (m->m_flags & M_VLANTAG) {
    1257             :                 /*
    1258             :                  * Hardware VLAN tagging is only supported for 801.1Q VLAN,
    1259             :                  * but not for 802.1ad QinQ.
    1260             :                  */
    1261           0 :                 swfcl->swfcl_vlan->vlan_tpid = htons(ETHERTYPE_VLAN);
    1262           0 :                 swfcl->swfcl_vlan->vlan_vid =
    1263           0 :                     htons(EVL_VLANOFTAG(m->m_pkthdr.ether_vtag));
    1264           0 :                 swfcl->swfcl_vlan->vlan_pcp =
    1265           0 :                     EVL_PRIOFTAG(m->m_pkthdr.ether_vtag);
    1266           0 :                 ether_type = eh->ether_type;
    1267           0 :                 *offset += sizeof(*eh);
    1268           0 :         } else if (ntohs(eh->ether_type) == ETHERTYPE_VLAN) {
    1269           0 :                 if (m->m_len < sizeof(*evl) &&
    1270           0 :                     (m = m_pullup(m, sizeof(*evl))) == NULL)
    1271           0 :                         return (NULL);
    1272           0 :                 evl = mtod(m, struct ether_vlan_header *);
    1273             : 
    1274             :                 /*
    1275             :                  * Software VLAN tagging is currently only supported for
    1276             :                  * 801.1Q VLAN, but not for 802.1ad QinQ.
    1277             :                  */
    1278           0 :                 swfcl->swfcl_vlan->vlan_tpid = htons(ETHERTYPE_VLAN);
    1279           0 :                 swfcl->swfcl_vlan->vlan_vid =
    1280           0 :                     (evl->evl_tag & htons(EVL_VLID_MASK));
    1281           0 :                 swfcl->swfcl_vlan->vlan_pcp =
    1282           0 :                     EVL_PRIOFTAG(ntohs(evl->evl_tag));
    1283           0 :                 ether_type = evl->evl_proto;
    1284           0 :                 *offset += sizeof(*evl);
    1285           0 :         } else {
    1286             :                 ether_type = eh->ether_type;
    1287           0 :                 *offset += sizeof(*eh);
    1288             :         }
    1289             : 
    1290           0 :         swfcl->swfcl_ether->eth_type = ether_type;
    1291             : 
    1292           0 :         ether_type = ntohs(ether_type);
    1293           0 :         switch (ether_type) {
    1294             :         case ETHERTYPE_ARP:
    1295           0 :                 return switch_flow_classifier_arp(m, offset, swfcl);
    1296             :         case ETHERTYPE_IP:
    1297           0 :                 return switch_flow_classifier_ipv4(m, offset, swfcl);
    1298             : #ifdef INET6
    1299             :         case ETHERTYPE_IPV6:
    1300           0 :                 return switch_flow_classifier_ipv6(m, offset, swfcl);
    1301             : #endif /* INET6 */
    1302             :         case ETHERTYPE_MPLS:
    1303             :                 /* unsupported yet */
    1304             :                 break;
    1305             :         }
    1306             : 
    1307           0 :         return (m);
    1308           0 : }
    1309             : 
    1310             : struct mbuf *
    1311           0 : switch_flow_classifier_tunnel(struct mbuf *m, int *offset,
    1312             :     struct switch_flow_classify *swfcl)
    1313             : {
    1314             :         struct bridge_tunneltag *brtag;
    1315             : 
    1316           0 :         if ((brtag = bridge_tunnel(m)) == NULL)
    1317             :                 goto out;
    1318             : 
    1319           0 :         if ((brtag->brtag_peer.sa.sa_family != AF_INET) &&
    1320           0 :             (brtag->brtag_peer.sa.sa_family != AF_INET6))
    1321             :                 goto out;
    1322             : 
    1323           0 :         swfcl->swfcl_tunnel = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
    1324           0 :         if (swfcl->swfcl_tunnel == NULL) {
    1325           0 :                 m_freem(m);
    1326           0 :                 return (NULL);
    1327             :         }
    1328             : 
    1329           0 :         swfcl->swfcl_tunnel->tun_af = brtag->brtag_peer.sa.sa_family;
    1330           0 :         swfcl->swfcl_tunnel->tun_key = htobe64(brtag->brtag_id);
    1331           0 :         if (swfcl->swfcl_tunnel->tun_af == AF_INET) {
    1332           0 :                 swfcl->swfcl_tunnel->tun_ipv4_src =
    1333           0 :                     brtag->brtag_local.sin.sin_addr;
    1334           0 :                 swfcl->swfcl_tunnel->tun_ipv4_dst =
    1335           0 :                     brtag->brtag_peer.sin.sin_addr;
    1336           0 :         } else {
    1337           0 :                 swfcl->swfcl_tunnel->tun_ipv6_src =
    1338           0 :                     brtag->brtag_local.sin6.sin6_addr;
    1339           0 :                 swfcl->swfcl_tunnel->tun_ipv6_dst =
    1340           0 :                     brtag->brtag_peer.sin6.sin6_addr;
    1341             :         }
    1342           0 :         bridge_tunneluntag(m);
    1343             :  out:
    1344           0 :         return switch_flow_classifier_ether(m, offset, swfcl);
    1345           0 : }
    1346             : 
    1347             : struct mbuf *
    1348           0 : switch_flow_classifier(struct mbuf *m, uint32_t in_port,
    1349             :     struct switch_flow_classify *swfcl)
    1350             : {
    1351           0 :         int      offset = 0;
    1352             : 
    1353           0 :         memset(swfcl, 0, sizeof(*swfcl));
    1354           0 :         swfcl->swfcl_in_port = in_port;
    1355             : 
    1356           0 :         return switch_flow_classifier_tunnel(m, &offset, swfcl);
    1357           0 : }
    1358             : 
    1359             : void
    1360           0 : switch_flow_classifier_dump(struct switch_softc *sc,
    1361             :     struct switch_flow_classify *swfcl)
    1362             : {
    1363           0 :         char    saddr[INET6_ADDRSTRLEN], daddr[INET6_ADDRSTRLEN];
    1364             : 
    1365           0 :         log(LOG_DEBUG, "%s: ", sc->sc_if.if_xname);
    1366           0 :         addlog("in_port(%u),", swfcl->swfcl_in_port);
    1367             : 
    1368           0 :         if (swfcl->swfcl_tunnel) {
    1369           0 :                 if (swfcl->swfcl_tunnel->tun_af == AF_INET) {
    1370           0 :                         inet_ntop(AF_INET,
    1371           0 :                             (void *)&swfcl->swfcl_tunnel->tun_ipv4_src,
    1372           0 :                             saddr, sizeof(saddr));
    1373           0 :                         inet_ntop(AF_INET,
    1374           0 :                             (void *)&swfcl->swfcl_tunnel->tun_ipv4_dst,
    1375           0 :                             daddr, sizeof(daddr));
    1376           0 :                         addlog("tun_ipv4_src(%s),tun_ipv4_dst(%s),"
    1377             :                             "tun_id(%llu),", saddr, daddr,
    1378           0 :                             be64toh(swfcl->swfcl_tunnel->tun_key));
    1379           0 :                 } else if (swfcl->swfcl_tunnel->tun_af == AF_INET6) {
    1380           0 :                         inet_ntop(AF_INET6,
    1381           0 :                             (void *)&swfcl->swfcl_tunnel->tun_ipv6_src,
    1382           0 :                             saddr, sizeof(saddr));
    1383           0 :                         inet_ntop(AF_INET6,
    1384           0 :                             (void *)&swfcl->swfcl_tunnel->tun_ipv6_dst,
    1385           0 :                             daddr, sizeof(daddr));
    1386           0 :                         addlog("tun_ipv6_src(%s) tun_ipv6_dst(%s),"
    1387             :                             "tun_id(%llu),", saddr, daddr,
    1388           0 :                             be64toh(swfcl->swfcl_tunnel->tun_key));
    1389           0 :                 }
    1390             :         }
    1391             : 
    1392           0 :         if (swfcl->swfcl_vlan) {
    1393           0 :                 addlog("vlan_tpid(0x%0x4x),vlan_pcp(%u),vlan_vid(%u),",
    1394           0 :                     ntohs(swfcl->swfcl_vlan->vlan_tpid),
    1395           0 :                     swfcl->swfcl_vlan->vlan_pcp,
    1396           0 :                     ntohs(swfcl->swfcl_vlan->vlan_vid));
    1397           0 :         }
    1398             : 
    1399           0 :         if (swfcl->swfcl_ether) {
    1400           0 :                 addlog("eth_dst(%s),eth_src(%s),eth_type(0x%04x)",
    1401           0 :                     ether_sprintf(swfcl->swfcl_ether->eth_dst),
    1402           0 :                     ether_sprintf(swfcl->swfcl_ether->eth_src),
    1403           0 :                     ntohs(swfcl->swfcl_ether->eth_type));
    1404           0 :         }
    1405             : 
    1406           0 :         if (swfcl->swfcl_arp) {
    1407           0 :                 inet_ntop(AF_INET, (void *)&swfcl->swfcl_arp->arp_sip,
    1408           0 :                     saddr, sizeof(saddr));
    1409           0 :                 inet_ntop(AF_INET, (void *)&swfcl->swfcl_arp->arp_tip,
    1410           0 :                     daddr, sizeof(daddr));
    1411           0 :                 addlog("arp_op(%x),arp_tha(%s),arp_sha(%s),arp_sip(%s),"
    1412           0 :                     "arp_tip(%s),", swfcl->swfcl_arp->_arp_op,
    1413           0 :                     ether_sprintf(swfcl->swfcl_arp->arp_tha),
    1414           0 :                     ether_sprintf(swfcl->swfcl_arp->arp_sha), saddr, daddr);
    1415           0 :         }
    1416             : 
    1417           0 :         if (swfcl->swfcl_ipv4) {
    1418           0 :                 inet_ntop(AF_INET, (void *)&swfcl->swfcl_ipv4->ipv4_src,
    1419           0 :                     saddr, sizeof(saddr));
    1420           0 :                 inet_ntop(AF_INET, (void *)&swfcl->swfcl_ipv4->ipv4_dst,
    1421           0 :                     daddr, sizeof(daddr));
    1422           0 :                 addlog("ip_proto(%u),ip_tos(%u),ip_ttl(%u),ip_src(%s),"
    1423           0 :                     "ip_dst(%s),", swfcl->swfcl_ipv4->ipv4_proto,
    1424           0 :                     swfcl->swfcl_ipv4->ipv4_tos, swfcl->swfcl_ipv4->ipv4_ttl,
    1425             :                     saddr, daddr);
    1426           0 :         }
    1427             : 
    1428           0 :         if (swfcl->swfcl_ipv6) {
    1429           0 :                 inet_ntop(AF_INET6, (void *)&swfcl->swfcl_ipv6->ipv6_src,
    1430           0 :                     saddr, sizeof(saddr));
    1431           0 :                 inet_ntop(AF_INET6, (void *)&swfcl->swfcl_ipv6->ipv6_dst,
    1432           0 :                     daddr, sizeof(daddr));
    1433           0 :                 addlog("ip6_nxt(%u),ip6_flow_label(%u),ip6_tclass(%d),"
    1434             :                     "ip6_hlimit(%u),ip6_src(%s),ip6_dst(%s),",
    1435           0 :                     swfcl->swfcl_ipv6->ipv6_nxt,
    1436           0 :                     ntohl(swfcl->swfcl_ipv6->ipv6_flow_label),
    1437           0 :                     swfcl->swfcl_ipv6->ipv6_tclass,
    1438           0 :                     swfcl->swfcl_ipv6->ipv6_hlimit, saddr, daddr);
    1439           0 :         }
    1440             : 
    1441           0 :         if (swfcl->swfcl_icmpv4) {
    1442           0 :                 addlog("icmp_type(%u),icmp_code(%u),",
    1443           0 :                     swfcl->swfcl_icmpv4->icmpv4_type,
    1444           0 :                     swfcl->swfcl_icmpv4->icmpv4_code);
    1445           0 :         }
    1446             : 
    1447           0 :         if (swfcl->swfcl_icmpv6) {
    1448           0 :                 addlog("icmp6_type(%u),icmp6_code(%u),",
    1449           0 :                     swfcl->swfcl_icmpv6->icmpv6_type,
    1450           0 :                     swfcl->swfcl_icmpv6->icmpv6_code);
    1451           0 :         }
    1452             : 
    1453           0 :         if (swfcl->swfcl_nd6) {
    1454           0 :                 inet_ntop(AF_INET6, (void *)&swfcl->swfcl_nd6->nd6_target,
    1455           0 :                     saddr, sizeof(saddr));
    1456           0 :                 addlog("nd_target(%s),nd_lladdr(%s),", saddr,
    1457           0 :                     ether_sprintf(swfcl->swfcl_nd6->nd6_lladdr));
    1458           0 :         }
    1459             : 
    1460           0 :         if (swfcl->swfcl_tcp) {
    1461           0 :                 addlog("tcp_src(%u),tcp_dst(%u),tcp_flags(%x),",
    1462           0 :                     ntohs(swfcl->swfcl_tcp->tcp_src),
    1463           0 :                     ntohs(swfcl->swfcl_tcp->tcp_dst),
    1464           0 :                     swfcl->swfcl_tcp->tcp_flags);
    1465           0 :         }
    1466             : 
    1467           0 :         if (swfcl->swfcl_udp) {
    1468           0 :                 addlog("udp_src(%u),udp_dst(%u),",
    1469           0 :                     ntohs(swfcl->swfcl_udp->udp_src),
    1470           0 :                     ntohs(swfcl->swfcl_udp->udp_dst));
    1471           0 :         }
    1472             : 
    1473           0 :         addlog("\n");
    1474           0 : }
    1475             : 
    1476             : int
    1477           0 : switch_mtap(caddr_t arg, struct mbuf *m, int dir, uint64_t datapath_id)
    1478             : {
    1479           0 :         struct dlt_openflow_hdr  of;
    1480             : 
    1481           0 :         of.of_datapath_id = htobe64(datapath_id);
    1482           0 :         of.of_direction = htonl(dir == BPF_DIRECTION_IN ?
    1483             :             DLT_OPENFLOW_TO_SWITCH : DLT_OPENFLOW_TO_CONTROLLER);
    1484             : 
    1485           0 :         return (bpf_mtap_hdr(arg, (caddr_t)&of, sizeof(of), m, dir, NULL));
    1486           0 : }
    1487             : 
    1488             : int
    1489           0 : ofp_split_mbuf(struct mbuf *m, struct mbuf **mtail)
    1490             : {
    1491             :         struct ofp_header       *oh;
    1492             :         uint16_t                 ohlen;
    1493             : 
    1494           0 :         *mtail = NULL;
    1495             : 
    1496             :  again:
    1497             :         /* We need more data. */
    1498           0 :         if (m->m_pkthdr.len < sizeof(*oh))
    1499           0 :                 return (-1);
    1500             : 
    1501           0 :         oh = mtod(m, struct ofp_header *);
    1502           0 :         ohlen = ntohs(oh->oh_length);
    1503             : 
    1504             :         /* We got an invalid packet header, skip it. */
    1505           0 :         if (ohlen < sizeof(*oh)) {
    1506           0 :                 m_adj(m, sizeof(*oh));
    1507           0 :                 goto again;
    1508             :         }
    1509             : 
    1510             :         /* Nothing to split. */
    1511           0 :         if (m->m_pkthdr.len == ohlen)
    1512           0 :                 return (0);
    1513           0 :         else if (m->m_pkthdr.len < ohlen)
    1514           0 :                 return (-1);
    1515             : 
    1516           0 :         *mtail = m_split(m, ohlen, M_NOWAIT);
    1517             :         /* No memory, try again later. */
    1518           0 :         if (*mtail == NULL)
    1519           0 :                 return (-1);
    1520             : 
    1521           0 :         return (0);
    1522           0 : }

Generated by: LCOV version 1.13