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

          Line data    Source code
       1             : /*      $OpenBSD: if_pflow.c,v 1.90 2018/07/30 12:22:14 mpi Exp $       */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2011 Florian Obser <florian@narrans.de>
       5             :  * Copyright (c) 2011 Sebastian Benoit <benoit-lists@fb12.de>
       6             :  * Copyright (c) 2008 Henning Brauer <henning@openbsd.org>
       7             :  * Copyright (c) 2008 Joerg Goltermann <jg@osn.de>
       8             :  *
       9             :  * Permission to use, copy, modify, and distribute this software for any
      10             :  * purpose with or without fee is hereby granted, provided that the above
      11             :  * copyright notice and this permission notice appear in all copies.
      12             :  *
      13             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      14             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      15             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      16             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      17             :  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
      18             :  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
      19             :  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      20             :  */
      21             : 
      22             : #include <sys/param.h>
      23             : #include <sys/malloc.h>
      24             : #include <sys/systm.h>
      25             : #include <sys/mbuf.h>
      26             : #include <sys/socket.h>
      27             : #include <sys/timeout.h>
      28             : #include <sys/ioctl.h>
      29             : #include <sys/kernel.h>
      30             : #include <sys/socket.h>
      31             : #include <sys/socketvar.h>
      32             : #include <sys/sysctl.h>
      33             : 
      34             : #include <net/if.h>
      35             : #include <net/if_types.h>
      36             : #include <net/bpf.h>
      37             : #include <net/route.h>
      38             : #include <netinet/in.h>
      39             : #include <netinet/if_ether.h>
      40             : #include <netinet/tcp.h>
      41             : 
      42             : #include <netinet/ip.h>
      43             : #include <netinet/ip_var.h>
      44             : #include <netinet/udp.h>
      45             : #include <netinet/udp_var.h>
      46             : #include <netinet/in_pcb.h>
      47             : 
      48             : #include <net/pfvar.h>
      49             : #include <net/if_pflow.h>
      50             : 
      51             : #include "bpfilter.h"
      52             : #include "pflow.h"
      53             : 
      54             : #define PFLOW_MINMTU    \
      55             :     (sizeof(struct pflow_header) + sizeof(struct pflow_flow))
      56             : 
      57             : #ifdef PFLOWDEBUG
      58             : #define DPRINTF(x)      do { printf x ; } while (0)
      59             : #else
      60             : #define DPRINTF(x)
      61             : #endif
      62             : 
      63             : SLIST_HEAD(, pflow_softc) pflowif_list;
      64             : struct pflowstats        pflowstats;
      65             : 
      66             : void    pflowattach(int);
      67             : int     pflow_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
      68             :         struct rtentry *rt);
      69             : void    pflow_output_process(void *);
      70             : int     pflow_clone_create(struct if_clone *, int);
      71             : int     pflow_clone_destroy(struct ifnet *);
      72             : int     pflow_set(struct pflow_softc *, struct pflowreq *);
      73             : void    pflow_init_timeouts(struct pflow_softc *);
      74             : int     pflow_calc_mtu(struct pflow_softc *, int, int);
      75             : void    pflow_setmtu(struct pflow_softc *, int);
      76             : int     pflowvalidsockaddr(const struct sockaddr *, int);
      77             : int     pflowioctl(struct ifnet *, u_long, caddr_t);
      78             : 
      79             : struct mbuf     *pflow_get_mbuf(struct pflow_softc *, u_int16_t);
      80             : void    pflow_flush(struct pflow_softc *);
      81             : int     pflow_sendout_v5(struct pflow_softc *);
      82             : int     pflow_sendout_ipfix(struct pflow_softc *, sa_family_t);
      83             : int     pflow_sendout_ipfix_tmpl(struct pflow_softc *);
      84             : int     pflow_sendout_mbuf(struct pflow_softc *, struct mbuf *);
      85             : void    pflow_timeout(void *);
      86             : void    pflow_timeout6(void *);
      87             : void    pflow_timeout_tmpl(void *);
      88             : void    copy_flow_data(struct pflow_flow *, struct pflow_flow *,
      89             :         struct pf_state *, struct pf_state_key *, int, int);
      90             : void    copy_flow_ipfix_4_data(struct pflow_ipfix_flow4 *,
      91             :         struct pflow_ipfix_flow4 *, struct pf_state *, struct pf_state_key *,
      92             :         struct pflow_softc *, int, int);
      93             : void    copy_flow_ipfix_6_data(struct pflow_ipfix_flow6 *,
      94             :         struct pflow_ipfix_flow6 *, struct pf_state *, struct pf_state_key *,
      95             :         struct pflow_softc *, int, int);
      96             : int     pflow_pack_flow(struct pf_state *, struct pf_state_key *,
      97             :         struct pflow_softc *);
      98             : int     pflow_pack_flow_ipfix(struct pf_state *, struct pf_state_key *,
      99             :         struct pflow_softc *);
     100             : int     export_pflow_if(struct pf_state*, struct pf_state_key *,
     101             :         struct pflow_softc *);
     102             : int     copy_flow_to_m(struct pflow_flow *flow, struct pflow_softc *sc);
     103             : int     copy_flow_ipfix_4_to_m(struct pflow_ipfix_flow4 *flow,
     104             :         struct pflow_softc *sc);
     105             : int     copy_flow_ipfix_6_to_m(struct pflow_ipfix_flow6 *flow,
     106             :         struct pflow_softc *sc);
     107             : 
     108             : struct if_clone pflow_cloner =
     109             :     IF_CLONE_INITIALIZER("pflow", pflow_clone_create,
     110             :     pflow_clone_destroy);
     111             : 
     112             : void
     113           0 : pflowattach(int npflow)
     114             : {
     115           0 :         SLIST_INIT(&pflowif_list);
     116           0 :         if_clone_attach(&pflow_cloner);
     117           0 : }
     118             : 
     119             : int
     120           0 : pflow_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
     121             :         struct rtentry *rt)
     122             : {
     123           0 :         m_freem(m);     /* drop packet */
     124           0 :         return (EAFNOSUPPORT);
     125             : }
     126             : 
     127             : void
     128           0 : pflow_output_process(void *arg)
     129             : {
     130           0 :         struct mbuf_list ml;
     131           0 :         struct pflow_softc *sc = arg;
     132             :         struct mbuf *m;
     133             : 
     134           0 :         mq_delist(&sc->sc_outputqueue, &ml);
     135           0 :         KERNEL_LOCK();
     136           0 :         while ((m = ml_dequeue(&ml)) != NULL) {
     137           0 :                 pflow_sendout_mbuf(sc, m);
     138             :         }
     139           0 :         KERNEL_UNLOCK();
     140           0 : }
     141             : 
     142             : int
     143           0 : pflow_clone_create(struct if_clone *ifc, int unit)
     144             : {
     145             :         struct ifnet            *ifp;
     146             :         struct pflow_softc      *pflowif;
     147             : 
     148           0 :         pflowif = malloc(sizeof(*pflowif), M_DEVBUF, M_WAITOK|M_ZERO);
     149           0 :         MGET(pflowif->send_nam, M_WAIT, MT_SONAME);
     150           0 :         pflowif->sc_version = PFLOW_PROTO_DEFAULT;
     151             : 
     152             :         /* ipfix template init */
     153           0 :         bzero(&pflowif->sc_tmpl_ipfix,sizeof(pflowif->sc_tmpl_ipfix));
     154           0 :         pflowif->sc_tmpl_ipfix.set_header.set_id =
     155             :             htons(PFLOW_IPFIX_TMPL_SET_ID);
     156           0 :         pflowif->sc_tmpl_ipfix.set_header.set_length =
     157             :             htons(sizeof(struct pflow_ipfix_tmpl));
     158             : 
     159             :         /* ipfix IPv4 template */
     160           0 :         pflowif->sc_tmpl_ipfix.ipv4_tmpl.h.tmpl_id =
     161             :             htons(PFLOW_IPFIX_TMPL_IPV4_ID);
     162           0 :         pflowif->sc_tmpl_ipfix.ipv4_tmpl.h.field_count
     163           0 :             = htons(PFLOW_IPFIX_TMPL_IPV4_FIELD_COUNT);
     164           0 :         pflowif->sc_tmpl_ipfix.ipv4_tmpl.src_ip.field_id =
     165             :             htons(PFIX_IE_sourceIPv4Address);
     166           0 :         pflowif->sc_tmpl_ipfix.ipv4_tmpl.src_ip.len = htons(4);
     167           0 :         pflowif->sc_tmpl_ipfix.ipv4_tmpl.dest_ip.field_id =
     168             :             htons(PFIX_IE_destinationIPv4Address);
     169           0 :         pflowif->sc_tmpl_ipfix.ipv4_tmpl.dest_ip.len = htons(4);
     170           0 :         pflowif->sc_tmpl_ipfix.ipv4_tmpl.if_index_in.field_id =
     171             :             htons(PFIX_IE_ingressInterface);
     172           0 :         pflowif->sc_tmpl_ipfix.ipv4_tmpl.if_index_in.len = htons(4);
     173           0 :         pflowif->sc_tmpl_ipfix.ipv4_tmpl.if_index_out.field_id =
     174             :             htons(PFIX_IE_egressInterface);
     175           0 :         pflowif->sc_tmpl_ipfix.ipv4_tmpl.if_index_out.len = htons(4);
     176           0 :         pflowif->sc_tmpl_ipfix.ipv4_tmpl.packets.field_id =
     177             :             htons(PFIX_IE_packetDeltaCount);
     178           0 :         pflowif->sc_tmpl_ipfix.ipv4_tmpl.packets.len = htons(8);
     179           0 :         pflowif->sc_tmpl_ipfix.ipv4_tmpl.octets.field_id =
     180             :             htons(PFIX_IE_octetDeltaCount);
     181           0 :         pflowif->sc_tmpl_ipfix.ipv4_tmpl.octets.len = htons(8);
     182           0 :         pflowif->sc_tmpl_ipfix.ipv4_tmpl.start.field_id =
     183             :             htons(PFIX_IE_flowStartMilliseconds);
     184           0 :         pflowif->sc_tmpl_ipfix.ipv4_tmpl.start.len = htons(8);
     185           0 :         pflowif->sc_tmpl_ipfix.ipv4_tmpl.finish.field_id =
     186             :             htons(PFIX_IE_flowEndMilliseconds);
     187           0 :         pflowif->sc_tmpl_ipfix.ipv4_tmpl.finish.len = htons(8);
     188           0 :         pflowif->sc_tmpl_ipfix.ipv4_tmpl.src_port.field_id =
     189             :             htons(PFIX_IE_sourceTransportPort);
     190           0 :         pflowif->sc_tmpl_ipfix.ipv4_tmpl.src_port.len = htons(2);
     191           0 :         pflowif->sc_tmpl_ipfix.ipv4_tmpl.dest_port.field_id =
     192             :             htons(PFIX_IE_destinationTransportPort);
     193           0 :         pflowif->sc_tmpl_ipfix.ipv4_tmpl.dest_port.len = htons(2);
     194           0 :         pflowif->sc_tmpl_ipfix.ipv4_tmpl.tos.field_id =
     195             :             htons(PFIX_IE_ipClassOfService);
     196           0 :         pflowif->sc_tmpl_ipfix.ipv4_tmpl.tos.len = htons(1);
     197           0 :         pflowif->sc_tmpl_ipfix.ipv4_tmpl.protocol.field_id =
     198             :             htons(PFIX_IE_protocolIdentifier);
     199           0 :         pflowif->sc_tmpl_ipfix.ipv4_tmpl.protocol.len = htons(1);
     200             : 
     201             :         /* ipfix IPv6 template */
     202           0 :         pflowif->sc_tmpl_ipfix.ipv6_tmpl.h.tmpl_id =
     203             :             htons(PFLOW_IPFIX_TMPL_IPV6_ID);
     204           0 :         pflowif->sc_tmpl_ipfix.ipv6_tmpl.h.field_count =
     205             :             htons(PFLOW_IPFIX_TMPL_IPV6_FIELD_COUNT);
     206           0 :         pflowif->sc_tmpl_ipfix.ipv6_tmpl.src_ip.field_id =
     207             :             htons(PFIX_IE_sourceIPv6Address);
     208           0 :         pflowif->sc_tmpl_ipfix.ipv6_tmpl.src_ip.len = htons(16);
     209           0 :         pflowif->sc_tmpl_ipfix.ipv6_tmpl.dest_ip.field_id =
     210             :             htons(PFIX_IE_destinationIPv6Address);
     211           0 :         pflowif->sc_tmpl_ipfix.ipv6_tmpl.dest_ip.len = htons(16);
     212           0 :         pflowif->sc_tmpl_ipfix.ipv6_tmpl.if_index_in.field_id =
     213             :             htons(PFIX_IE_ingressInterface);
     214           0 :         pflowif->sc_tmpl_ipfix.ipv6_tmpl.if_index_in.len = htons(4);
     215           0 :         pflowif->sc_tmpl_ipfix.ipv6_tmpl.if_index_out.field_id =
     216             :             htons(PFIX_IE_egressInterface);
     217           0 :         pflowif->sc_tmpl_ipfix.ipv6_tmpl.if_index_out.len = htons(4);
     218           0 :         pflowif->sc_tmpl_ipfix.ipv6_tmpl.packets.field_id =
     219             :             htons(PFIX_IE_packetDeltaCount);
     220           0 :         pflowif->sc_tmpl_ipfix.ipv6_tmpl.packets.len = htons(8);
     221           0 :         pflowif->sc_tmpl_ipfix.ipv6_tmpl.octets.field_id =
     222             :             htons(PFIX_IE_octetDeltaCount);
     223           0 :         pflowif->sc_tmpl_ipfix.ipv6_tmpl.octets.len = htons(8);
     224           0 :         pflowif->sc_tmpl_ipfix.ipv6_tmpl.start.field_id =
     225             :             htons(PFIX_IE_flowStartMilliseconds);
     226           0 :         pflowif->sc_tmpl_ipfix.ipv6_tmpl.start.len = htons(8);
     227           0 :         pflowif->sc_tmpl_ipfix.ipv6_tmpl.finish.field_id =
     228             :             htons(PFIX_IE_flowEndMilliseconds);
     229           0 :         pflowif->sc_tmpl_ipfix.ipv6_tmpl.finish.len = htons(8);
     230           0 :         pflowif->sc_tmpl_ipfix.ipv6_tmpl.src_port.field_id =
     231             :             htons(PFIX_IE_sourceTransportPort);
     232           0 :         pflowif->sc_tmpl_ipfix.ipv6_tmpl.src_port.len = htons(2);
     233           0 :         pflowif->sc_tmpl_ipfix.ipv6_tmpl.dest_port.field_id =
     234             :             htons(PFIX_IE_destinationTransportPort);
     235           0 :         pflowif->sc_tmpl_ipfix.ipv6_tmpl.dest_port.len = htons(2);
     236           0 :         pflowif->sc_tmpl_ipfix.ipv6_tmpl.tos.field_id =
     237             :             htons(PFIX_IE_ipClassOfService);
     238           0 :         pflowif->sc_tmpl_ipfix.ipv6_tmpl.tos.len = htons(1);
     239           0 :         pflowif->sc_tmpl_ipfix.ipv6_tmpl.protocol.field_id =
     240             :             htons(PFIX_IE_protocolIdentifier);
     241           0 :         pflowif->sc_tmpl_ipfix.ipv6_tmpl.protocol.len = htons(1);
     242             : 
     243           0 :         ifp = &pflowif->sc_if;
     244           0 :         snprintf(ifp->if_xname, sizeof ifp->if_xname, "pflow%d", unit);
     245           0 :         ifp->if_softc = pflowif;
     246           0 :         ifp->if_ioctl = pflowioctl;
     247           0 :         ifp->if_output = pflow_output;
     248           0 :         ifp->if_start = NULL;
     249           0 :         ifp->if_xflags = IFXF_CLONED;
     250           0 :         ifp->if_type = IFT_PFLOW;
     251           0 :         IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
     252           0 :         ifp->if_hdrlen = PFLOW_HDRLEN;
     253           0 :         ifp->if_flags = IFF_UP;
     254           0 :         ifp->if_flags &= ~IFF_RUNNING;   /* not running, need receiver */
     255           0 :         mq_init(&pflowif->sc_outputqueue, 8192, IPL_SOFTNET);
     256           0 :         pflow_setmtu(pflowif, ETHERMTU);
     257           0 :         pflow_init_timeouts(pflowif);
     258           0 :         if_attach(ifp);
     259           0 :         if_alloc_sadl(ifp);
     260             : 
     261           0 :         task_set(&pflowif->sc_outputtask, pflow_output_process, pflowif);
     262             : 
     263             :         /* Insert into list of pflows */
     264           0 :         NET_LOCK();
     265           0 :         SLIST_INSERT_HEAD(&pflowif_list, pflowif, sc_next);
     266           0 :         NET_UNLOCK();
     267           0 :         return (0);
     268             : }
     269             : 
     270             : int
     271           0 : pflow_clone_destroy(struct ifnet *ifp)
     272             : {
     273           0 :         struct pflow_softc      *sc = ifp->if_softc;
     274             :         int                      error;
     275             : 
     276             :         error = 0;
     277             : 
     278           0 :         if (timeout_initialized(&sc->sc_tmo))
     279           0 :                 timeout_del(&sc->sc_tmo);
     280           0 :         if (timeout_initialized(&sc->sc_tmo6))
     281           0 :                 timeout_del(&sc->sc_tmo6);
     282           0 :         if (timeout_initialized(&sc->sc_tmo_tmpl))
     283           0 :                 timeout_del(&sc->sc_tmo_tmpl);
     284           0 :         pflow_flush(sc);
     285           0 :         task_del(net_tq(ifp->if_index), &sc->sc_outputtask);
     286           0 :         mq_purge(&sc->sc_outputqueue);
     287           0 :         m_freem(sc->send_nam);
     288           0 :         if (sc->so != NULL) {
     289           0 :                 error = soclose(sc->so, MSG_DONTWAIT);
     290           0 :                 sc->so = NULL;
     291           0 :         }
     292           0 :         if (sc->sc_flowdst != NULL)
     293           0 :                 free(sc->sc_flowdst, M_DEVBUF, sc->sc_flowdst->sa_len);
     294           0 :         if (sc->sc_flowsrc != NULL)
     295           0 :                 free(sc->sc_flowsrc, M_DEVBUF, sc->sc_flowsrc->sa_len);
     296           0 :         if_detach(ifp);
     297           0 :         NET_LOCK();
     298           0 :         SLIST_REMOVE(&pflowif_list, sc, pflow_softc, sc_next);
     299           0 :         NET_UNLOCK();
     300           0 :         free(sc, M_DEVBUF, sizeof(*sc));
     301           0 :         return (error);
     302             : }
     303             : 
     304             : int
     305           0 : pflowvalidsockaddr(const struct sockaddr *sa, int ignore_port)
     306             : {
     307             :         struct sockaddr_in6     *sin6;
     308             :         struct sockaddr_in      *sin;
     309             : 
     310           0 :         if (sa == NULL)
     311           0 :                 return (0);
     312           0 :         switch(sa->sa_family) {
     313             :         case AF_INET:
     314           0 :                 sin = (struct sockaddr_in*) sa;
     315           0 :                 return (sin->sin_addr.s_addr != INADDR_ANY &&
     316           0 :                     (ignore_port || sin->sin_port != 0));
     317             :         case AF_INET6:
     318           0 :                 sin6 = (struct sockaddr_in6*) sa;
     319           0 :                 return (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
     320           0 :                     (ignore_port || sin6->sin6_port != 0));
     321             :         default:
     322           0 :                 return (0);
     323             :         }
     324           0 : }
     325             : 
     326             : int
     327           0 : pflow_set(struct pflow_softc *sc, struct pflowreq *pflowr)
     328             : {
     329           0 :         struct proc             *p = curproc;
     330           0 :         struct socket           *so;
     331             :         struct sockaddr         *sa;
     332             :         int                      error = 0;
     333             : 
     334           0 :         if (pflowr->addrmask & PFLOW_MASK_VERSION) {
     335           0 :                 switch(pflowr->version) {
     336             :                 case PFLOW_PROTO_5:
     337             :                 case PFLOW_PROTO_10:
     338             :                         break;
     339             :                 default:
     340           0 :                         return(EINVAL);
     341             :                 }
     342             :         }
     343             : 
     344           0 :         pflow_flush(sc);
     345             : 
     346           0 :         if (pflowr->addrmask & PFLOW_MASK_DSTIP) {
     347           0 :                 if (sc->sc_flowdst != NULL &&
     348           0 :                     sc->sc_flowdst->sa_family != pflowr->flowdst.ss_family) {
     349           0 :                         free(sc->sc_flowdst, M_DEVBUF, sc->sc_flowdst->sa_len);
     350           0 :                         sc->sc_flowdst = NULL;
     351           0 :                         if (sc->so != NULL) {
     352           0 :                                 soclose(sc->so, MSG_DONTWAIT);
     353           0 :                                 sc->so = NULL;
     354           0 :                         }
     355             :                 }
     356             : 
     357           0 :                 switch (pflowr->flowdst.ss_family) {
     358             :                 case AF_INET:
     359           0 :                         if (sc->sc_flowdst == NULL) {
     360           0 :                                 if ((sc->sc_flowdst = malloc(
     361             :                                     sizeof(struct sockaddr_in),
     362           0 :                                     M_DEVBUF,  M_NOWAIT)) == NULL)
     363           0 :                                         return (ENOMEM);
     364             :                         }
     365           0 :                         memcpy(sc->sc_flowdst, &pflowr->flowdst,
     366             :                             sizeof(struct sockaddr_in));
     367           0 :                         sc->sc_flowdst->sa_len = sizeof(struct
     368             :                             sockaddr_in);
     369           0 :                         break;
     370             :                 case AF_INET6:
     371           0 :                         if (sc->sc_flowdst == NULL) {
     372           0 :                                 if ((sc->sc_flowdst = malloc(
     373             :                                     sizeof(struct sockaddr_in6),
     374           0 :                                     M_DEVBUF, M_NOWAIT)) == NULL)
     375           0 :                                         return (ENOMEM);
     376             :                         }
     377           0 :                         memcpy(sc->sc_flowdst, &pflowr->flowdst,
     378             :                             sizeof(struct sockaddr_in6));
     379           0 :                         sc->sc_flowdst->sa_len = sizeof(struct
     380             :                             sockaddr_in6);
     381           0 :                         break;
     382             :                 default:
     383             :                         break;
     384             :                 }
     385             : 
     386           0 :                 if (sc->sc_flowdst != NULL) {
     387           0 :                         sc->send_nam->m_len = sc->sc_flowdst->sa_len;
     388           0 :                         sa = mtod(sc->send_nam, struct sockaddr *);
     389           0 :                         memcpy(sa, sc->sc_flowdst, sc->sc_flowdst->sa_len);
     390           0 :                 }
     391             :         }
     392             : 
     393           0 :         if (pflowr->addrmask & PFLOW_MASK_SRCIP) {
     394           0 :                 if (sc->sc_flowsrc != NULL)
     395           0 :                         free(sc->sc_flowsrc, M_DEVBUF, sc->sc_flowsrc->sa_len);
     396           0 :                 sc->sc_flowsrc = NULL;
     397           0 :                 if (sc->so != NULL) {
     398           0 :                         soclose(sc->so, MSG_DONTWAIT);
     399           0 :                         sc->so = NULL;
     400           0 :                 }
     401           0 :                 switch(pflowr->flowsrc.ss_family) {
     402             :                 case AF_INET:
     403           0 :                         if ((sc->sc_flowsrc = malloc(
     404             :                             sizeof(struct sockaddr_in),
     405           0 :                             M_DEVBUF, M_NOWAIT)) == NULL)
     406           0 :                                 return (ENOMEM);
     407           0 :                         memcpy(sc->sc_flowsrc, &pflowr->flowsrc,
     408             :                             sizeof(struct sockaddr_in));
     409           0 :                         sc->sc_flowsrc->sa_len = sizeof(struct
     410             :                             sockaddr_in);
     411           0 :                         break;
     412             :                 case AF_INET6:
     413           0 :                         if ((sc->sc_flowsrc = malloc(
     414             :                             sizeof(struct sockaddr_in6),
     415           0 :                             M_DEVBUF, M_NOWAIT)) == NULL)
     416           0 :                                 return (ENOMEM);
     417           0 :                         memcpy(sc->sc_flowsrc, &pflowr->flowsrc,
     418             :                             sizeof(struct sockaddr_in6));
     419           0 :                         sc->sc_flowsrc->sa_len = sizeof(struct
     420             :                             sockaddr_in6);
     421           0 :                         break;
     422             :                 default:
     423             :                         break;
     424             :                 }
     425             :         }
     426             : 
     427           0 :         if (sc->so == NULL) {
     428           0 :                 if (pflowvalidsockaddr(sc->sc_flowdst, 0)) {
     429           0 :                         error = socreate(sc->sc_flowdst->sa_family,
     430             :                             &so, SOCK_DGRAM, 0);
     431           0 :                         if (error)
     432           0 :                                 return (error);
     433           0 :                         if (pflowvalidsockaddr(sc->sc_flowsrc, 1)) {
     434             :                                 struct mbuf *m;
     435             :                                 int s;
     436             : 
     437           0 :                                 MGET(m, M_WAIT, MT_SONAME);
     438           0 :                                 m->m_len = sc->sc_flowsrc->sa_len;
     439           0 :                                 sa = mtod(m, struct sockaddr *);
     440           0 :                                 memcpy(sa, sc->sc_flowsrc,
     441             :                                     sc->sc_flowsrc->sa_len);
     442             : 
     443           0 :                                 s = solock(so);
     444           0 :                                 error = sobind(so, m, p);
     445           0 :                                 sounlock(so, s);
     446           0 :                                 m_freem(m);
     447           0 :                                 if (error) {
     448           0 :                                         soclose(so, MSG_DONTWAIT);
     449           0 :                                         return (error);
     450             :                                 }
     451           0 :                         }
     452           0 :                         sc->so = so;
     453           0 :                 }
     454           0 :         } else if (!pflowvalidsockaddr(sc->sc_flowdst, 0)) {
     455           0 :                 soclose(sc->so, MSG_DONTWAIT);
     456           0 :                 sc->so = NULL;
     457           0 :         }
     458             : 
     459             :         /* error check is above */
     460           0 :         if (pflowr->addrmask & PFLOW_MASK_VERSION)
     461           0 :                 sc->sc_version = pflowr->version;
     462             : 
     463           0 :         pflow_setmtu(sc, ETHERMTU);
     464           0 :         pflow_init_timeouts(sc);
     465             : 
     466           0 :         return (0);
     467           0 : }
     468             : 
     469             : int
     470           0 : pflowioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
     471             : {
     472           0 :         struct proc             *p = curproc;
     473           0 :         struct pflow_softc      *sc = ifp->if_softc;
     474           0 :         struct ifreq            *ifr = (struct ifreq *)data;
     475           0 :         struct pflowreq          pflowr;
     476             :         int                      error;
     477             : 
     478           0 :         switch (cmd) {
     479             :         case SIOCSIFADDR:
     480             :         case SIOCSIFDSTADDR:
     481             :         case SIOCSIFFLAGS:
     482           0 :                 if ((ifp->if_flags & IFF_UP) && sc->so != NULL) {
     483           0 :                         ifp->if_flags |= IFF_RUNNING;
     484           0 :                         sc->sc_gcounter=pflowstats.pflow_flows;
     485             :                         /* send templates on startup */
     486           0 :                         if (sc->sc_version == PFLOW_PROTO_10)
     487           0 :                                 pflow_sendout_ipfix_tmpl(sc);
     488             :                 } else
     489           0 :                         ifp->if_flags &= ~IFF_RUNNING;
     490             :                 break;
     491             :         case SIOCSIFMTU:
     492           0 :                 if (ifr->ifr_mtu < PFLOW_MINMTU)
     493           0 :                         return (EINVAL);
     494           0 :                 if (ifr->ifr_mtu > MCLBYTES)
     495           0 :                         ifr->ifr_mtu = MCLBYTES;
     496           0 :                 if (ifr->ifr_mtu < ifp->if_mtu)
     497           0 :                         pflow_flush(sc);
     498           0 :                 pflow_setmtu(sc, ifr->ifr_mtu);
     499           0 :                 break;
     500             : 
     501             :         case SIOCGETPFLOW:
     502           0 :                 bzero(&pflowr, sizeof(pflowr));
     503             : 
     504           0 :                 if (sc->sc_flowsrc != NULL)
     505           0 :                         memcpy(&pflowr.flowsrc, sc->sc_flowsrc,
     506             :                             sc->sc_flowsrc->sa_len);
     507           0 :                 if (sc->sc_flowdst != NULL)
     508           0 :                         memcpy(&pflowr.flowdst, sc->sc_flowdst,
     509             :                             sc->sc_flowdst->sa_len);
     510           0 :                 pflowr.version = sc->sc_version;
     511             : 
     512           0 :                 if ((error = copyout(&pflowr, ifr->ifr_data,
     513             :                     sizeof(pflowr))))
     514           0 :                         return (error);
     515             :                 break;
     516             : 
     517             :         case SIOCSETPFLOW:
     518           0 :                 if ((error = suser(p)) != 0)
     519           0 :                         return (error);
     520           0 :                 if ((error = copyin(ifr->ifr_data, &pflowr,
     521             :                     sizeof(pflowr))))
     522           0 :                         return (error);
     523             : 
     524             :                 /* XXXSMP breaks atomicity */
     525           0 :                 NET_UNLOCK();
     526           0 :                 error = pflow_set(sc, &pflowr);
     527           0 :                 NET_LOCK();
     528           0 :                 if (error != 0)
     529           0 :                         return (error);
     530             : 
     531           0 :                 if ((ifp->if_flags & IFF_UP) && sc->so != NULL) {
     532           0 :                         ifp->if_flags |= IFF_RUNNING;
     533           0 :                         sc->sc_gcounter=pflowstats.pflow_flows;
     534           0 :                         if (sc->sc_version == PFLOW_PROTO_10)
     535           0 :                                 pflow_sendout_ipfix_tmpl(sc);
     536             :                 } else
     537           0 :                         ifp->if_flags &= ~IFF_RUNNING;
     538             : 
     539             :                 break;
     540             : 
     541             :         default:
     542           0 :                 return (ENOTTY);
     543             :         }
     544           0 :         return (0);
     545           0 : }
     546             : 
     547             : void
     548           0 : pflow_init_timeouts(struct pflow_softc *sc)
     549             : {
     550           0 :         switch (sc->sc_version) {
     551             :         case PFLOW_PROTO_5:
     552           0 :                 if (timeout_initialized(&sc->sc_tmo6))
     553           0 :                         timeout_del(&sc->sc_tmo6);
     554           0 :                 if (timeout_initialized(&sc->sc_tmo_tmpl))
     555           0 :                         timeout_del(&sc->sc_tmo_tmpl);
     556           0 :                 if (!timeout_initialized(&sc->sc_tmo))
     557           0 :                         timeout_set_proc(&sc->sc_tmo, pflow_timeout, sc);
     558             :                 break;
     559             :         case PFLOW_PROTO_10:
     560           0 :                 if (!timeout_initialized(&sc->sc_tmo_tmpl))
     561           0 :                         timeout_set_proc(&sc->sc_tmo_tmpl, pflow_timeout_tmpl,
     562           0 :                             sc);
     563           0 :                 if (!timeout_initialized(&sc->sc_tmo))
     564           0 :                         timeout_set_proc(&sc->sc_tmo, pflow_timeout, sc);
     565           0 :                 if (!timeout_initialized(&sc->sc_tmo6))
     566           0 :                         timeout_set_proc(&sc->sc_tmo6, pflow_timeout6, sc);
     567             : 
     568           0 :                 timeout_add_sec(&sc->sc_tmo_tmpl, PFLOW_TMPL_TIMEOUT);
     569           0 :                 break;
     570             :         default: /* NOTREACHED */
     571             :                 break;
     572             :         }
     573           0 : }
     574             : 
     575             : int
     576           0 : pflow_calc_mtu(struct pflow_softc *sc, int mtu, int hdrsz)
     577             : {
     578             : 
     579           0 :         sc->sc_maxcount4 = (mtu - hdrsz -
     580           0 :             sizeof(struct udpiphdr)) / sizeof(struct pflow_ipfix_flow4);
     581           0 :         sc->sc_maxcount6 = (mtu - hdrsz -
     582           0 :             sizeof(struct udpiphdr)) / sizeof(struct pflow_ipfix_flow6);
     583           0 :         if (sc->sc_maxcount4 > PFLOW_MAXFLOWS)
     584           0 :                 sc->sc_maxcount4 = PFLOW_MAXFLOWS;
     585           0 :         if (sc->sc_maxcount6 > PFLOW_MAXFLOWS)
     586           0 :                 sc->sc_maxcount6 = PFLOW_MAXFLOWS;
     587           0 :         return (hdrsz + sizeof(struct udpiphdr) +
     588           0 :             MIN(sc->sc_maxcount4 * sizeof(struct pflow_ipfix_flow4),
     589             :             sc->sc_maxcount6 * sizeof(struct pflow_ipfix_flow6)));
     590             : }
     591             : 
     592             : void
     593           0 : pflow_setmtu(struct pflow_softc *sc, int mtu_req)
     594             : {
     595             :         int     mtu;
     596             : 
     597           0 :         if (sc->sc_pflow_ifp && sc->sc_pflow_ifp->if_mtu < mtu_req)
     598           0 :                 mtu = sc->sc_pflow_ifp->if_mtu;
     599             :         else
     600             :                 mtu = mtu_req;
     601             : 
     602           0 :         switch (sc->sc_version) {
     603             :         case PFLOW_PROTO_5:
     604           0 :                 sc->sc_maxcount = (mtu - sizeof(struct pflow_header) -
     605           0 :                     sizeof(struct udpiphdr)) / sizeof(struct pflow_flow);
     606           0 :                 if (sc->sc_maxcount > PFLOW_MAXFLOWS)
     607           0 :                     sc->sc_maxcount = PFLOW_MAXFLOWS;
     608           0 :                 sc->sc_if.if_mtu = sizeof(struct pflow_header) +
     609           0 :                     sizeof(struct udpiphdr) +
     610           0 :                     sc->sc_maxcount * sizeof(struct pflow_flow);
     611           0 :                 break;
     612             :         case PFLOW_PROTO_10:
     613           0 :                 sc->sc_if.if_mtu =
     614           0 :                     pflow_calc_mtu(sc, mtu, sizeof(struct pflow_v10_header));
     615           0 :                 break;
     616             :         default: /* NOTREACHED */
     617             :                 break;
     618             :         }
     619           0 : }
     620             : 
     621             : struct mbuf *
     622           0 : pflow_get_mbuf(struct pflow_softc *sc, u_int16_t set_id)
     623             : {
     624           0 :         struct pflow_set_header  set_hdr;
     625           0 :         struct pflow_header      h;
     626             :         struct mbuf             *m;
     627             : 
     628           0 :         MGETHDR(m, M_DONTWAIT, MT_DATA);
     629           0 :         if (m == NULL) {
     630           0 :                 pflowstats.pflow_onomem++;
     631           0 :                 return (NULL);
     632             :         }
     633             : 
     634           0 :         MCLGET(m, M_DONTWAIT);
     635           0 :         if ((m->m_flags & M_EXT) == 0) {
     636           0 :                 m_free(m);
     637           0 :                 pflowstats.pflow_onomem++;
     638           0 :                 return (NULL);
     639             :         }
     640             : 
     641           0 :         m->m_len = m->m_pkthdr.len = 0;
     642           0 :         m->m_pkthdr.ph_ifidx = 0;
     643             : 
     644           0 :         if (sc == NULL)         /* get only a new empty mbuf */
     645           0 :                 return (m);
     646             : 
     647           0 :         switch (sc->sc_version) {
     648             :         case PFLOW_PROTO_5:
     649             :                 /* populate pflow_header */
     650           0 :                 h.reserved1 = 0;
     651           0 :                 h.reserved2 = 0;
     652           0 :                 h.count = 0;
     653           0 :                 h.version = htons(PFLOW_PROTO_5);
     654           0 :                 h.flow_sequence = htonl(sc->sc_gcounter);
     655           0 :                 h.engine_type = PFLOW_ENGINE_TYPE;
     656           0 :                 h.engine_id = PFLOW_ENGINE_ID;
     657           0 :                 m_copyback(m, 0, PFLOW_HDRLEN, &h, M_NOWAIT);
     658             : 
     659           0 :                 sc->sc_count = 0;
     660           0 :                 timeout_add_sec(&sc->sc_tmo, PFLOW_TIMEOUT);
     661           0 :                 break;
     662             :         case PFLOW_PROTO_10:
     663             :                 /* populate pflow_set_header */
     664           0 :                 set_hdr.set_length = 0;
     665           0 :                 set_hdr.set_id = htons(set_id);
     666           0 :                 m_copyback(m, 0, PFLOW_SET_HDRLEN, &set_hdr, M_NOWAIT);
     667           0 :                 break;
     668             :         default: /* NOTREACHED */
     669             :                 break;
     670             :         }
     671             : 
     672           0 :         return (m);
     673           0 : }
     674             : 
     675             : void
     676           0 : copy_flow_data(struct pflow_flow *flow1, struct pflow_flow *flow2,
     677             :     struct pf_state *st, struct pf_state_key *sk, int src, int dst)
     678             : {
     679           0 :         flow1->src_ip = flow2->dest_ip = sk->addr[src].v4.s_addr;
     680           0 :         flow1->src_port = flow2->dest_port = sk->port[src];
     681           0 :         flow1->dest_ip = flow2->src_ip = sk->addr[dst].v4.s_addr;
     682           0 :         flow1->dest_port = flow2->src_port = sk->port[dst];
     683             : 
     684           0 :         flow1->dest_as = flow2->src_as =
     685           0 :             flow1->src_as = flow2->dest_as = 0;
     686           0 :         flow1->if_index_in = htons(st->if_index_in);
     687           0 :         flow1->if_index_out = htons(st->if_index_out);
     688           0 :         flow2->if_index_in = htons(st->if_index_out);
     689           0 :         flow2->if_index_out = htons(st->if_index_in);
     690           0 :         flow1->dest_mask = flow2->src_mask =
     691           0 :             flow1->src_mask = flow2->dest_mask = 0;
     692             : 
     693           0 :         flow1->flow_packets = htonl(st->packets[0]);
     694           0 :         flow2->flow_packets = htonl(st->packets[1]);
     695           0 :         flow1->flow_octets = htonl(st->bytes[0]);
     696           0 :         flow2->flow_octets = htonl(st->bytes[1]);
     697             : 
     698             :         /*
     699             :          * Pretend the flow was created or expired when the machine came up
     700             :          * when creation is in the future of the last time a package was seen
     701             :          * or was created / expired before this machine came up due to pfsync.
     702             :          */
     703           0 :         flow1->flow_start = flow2->flow_start = st->creation < 0 ||
     704           0 :             st->creation > st->expire ? htonl(0) : htonl(st->creation * 1000);
     705           0 :         flow1->flow_finish = flow2->flow_finish = st->expire < 0 ? htonl(0) :
     706           0 :             htonl(st->expire * 1000);
     707           0 :         flow1->tcp_flags = flow2->tcp_flags = 0;
     708           0 :         flow1->protocol = flow2->protocol = sk->proto;
     709           0 :         flow1->tos = flow2->tos = st->rule.ptr->tos;
     710           0 : }
     711             : 
     712             : void
     713           0 : copy_flow_ipfix_4_data(struct pflow_ipfix_flow4 *flow1,
     714             :     struct pflow_ipfix_flow4 *flow2, struct pf_state *st,
     715             :     struct pf_state_key *sk, struct pflow_softc *sc, int src, int dst)
     716             : {
     717           0 :         flow1->src_ip = flow2->dest_ip = sk->addr[src].v4.s_addr;
     718           0 :         flow1->src_port = flow2->dest_port = sk->port[src];
     719           0 :         flow1->dest_ip = flow2->src_ip = sk->addr[dst].v4.s_addr;
     720           0 :         flow1->dest_port = flow2->src_port = sk->port[dst];
     721             : 
     722           0 :         flow1->if_index_in = htonl(st->if_index_in);
     723           0 :         flow1->if_index_out = htonl(st->if_index_out);
     724           0 :         flow2->if_index_in = htonl(st->if_index_out);
     725           0 :         flow2->if_index_out = htonl(st->if_index_in);
     726             : 
     727           0 :         flow1->flow_packets = htobe64(st->packets[0]);
     728           0 :         flow2->flow_packets = htobe64(st->packets[1]);
     729           0 :         flow1->flow_octets = htobe64(st->bytes[0]);
     730           0 :         flow2->flow_octets = htobe64(st->bytes[1]);
     731             : 
     732             :         /*
     733             :          * Pretend the flow was created when the machine came up when creation
     734             :          * is in the future of the last time a package was seen due to pfsync.
     735             :          */
     736           0 :         if (st->creation > st->expire)
     737           0 :                 flow1->flow_start = flow2->flow_start = htobe64((time_second -
     738             :                     time_uptime)*1000);
     739             :         else
     740           0 :                 flow1->flow_start = flow2->flow_start = htobe64((time_second -
     741             :                     (time_uptime - st->creation))*1000);
     742           0 :         flow1->flow_finish = flow2->flow_finish = htobe64((time_second -
     743             :             (time_uptime - st->expire))*1000);
     744             : 
     745           0 :         flow1->protocol = flow2->protocol = sk->proto;
     746           0 :         flow1->tos = flow2->tos = st->rule.ptr->tos;
     747           0 : }
     748             : 
     749             : void
     750           0 : copy_flow_ipfix_6_data(struct pflow_ipfix_flow6 *flow1,
     751             :     struct pflow_ipfix_flow6 *flow2, struct pf_state *st,
     752             :     struct pf_state_key *sk, struct pflow_softc *sc, int src, int dst)
     753             : {
     754           0 :         bcopy(&sk->addr[src].v6, &flow1->src_ip, sizeof(flow1->src_ip));
     755           0 :         bcopy(&sk->addr[src].v6, &flow2->dest_ip, sizeof(flow2->dest_ip));
     756           0 :         flow1->src_port = flow2->dest_port = sk->port[src];
     757           0 :         bcopy(&sk->addr[dst].v6, &flow1->dest_ip, sizeof(flow1->dest_ip));
     758           0 :         bcopy(&sk->addr[dst].v6, &flow2->src_ip, sizeof(flow2->src_ip));
     759           0 :         flow1->dest_port = flow2->src_port = sk->port[dst];
     760             : 
     761           0 :         flow1->if_index_in = htonl(st->if_index_in);
     762           0 :         flow1->if_index_out = htonl(st->if_index_out);
     763           0 :         flow2->if_index_in = htonl(st->if_index_out);
     764           0 :         flow2->if_index_out = htonl(st->if_index_in);
     765             : 
     766           0 :         flow1->flow_packets = htobe64(st->packets[0]);
     767           0 :         flow2->flow_packets = htobe64(st->packets[1]);
     768           0 :         flow1->flow_octets = htobe64(st->bytes[0]);
     769           0 :         flow2->flow_octets = htobe64(st->bytes[1]);
     770             : 
     771             :         /*
     772             :          * Pretend the flow was created when the machine came up when creation
     773             :          * is in the future of the last time a package was seen due to pfsync.
     774             :          */
     775           0 :         if (st->creation > st->expire)
     776           0 :                 flow1->flow_start = flow2->flow_start = htobe64((time_second -
     777             :                     time_uptime)*1000);
     778             :         else
     779           0 :                 flow1->flow_start = flow2->flow_start = htobe64((time_second -
     780             :                     (time_uptime - st->creation))*1000);
     781           0 :         flow1->flow_finish = flow2->flow_finish = htobe64((time_second -
     782             :             (time_uptime - st->expire))*1000);
     783             : 
     784           0 :         flow1->protocol = flow2->protocol = sk->proto;
     785           0 :         flow1->tos = flow2->tos = st->rule.ptr->tos;
     786           0 : }
     787             : 
     788             : int
     789           0 : export_pflow(struct pf_state *st)
     790             : {
     791             :         struct pflow_softc      *sc = NULL;
     792             :         struct pf_state_key     *sk;
     793             : 
     794           0 :         sk = st->key[st->direction == PF_IN ? PF_SK_WIRE : PF_SK_STACK];
     795             : 
     796           0 :         SLIST_FOREACH(sc, &pflowif_list, sc_next) {
     797           0 :                 switch (sc->sc_version) {
     798             :                 case PFLOW_PROTO_5:
     799           0 :                         if( sk->af == AF_INET )
     800           0 :                                 export_pflow_if(st, sk, sc);
     801             :                         break;
     802             :                 case PFLOW_PROTO_10:
     803           0 :                         if( sk->af == AF_INET || sk->af == AF_INET6 )
     804           0 :                                 export_pflow_if(st, sk, sc);
     805             :                         break;
     806             :                 default: /* NOTREACHED */
     807             :                         break;
     808             :                 }
     809             :         }
     810             : 
     811           0 :         return (0);
     812             : }
     813             : 
     814             : int
     815           0 : export_pflow_if(struct pf_state *st, struct pf_state_key *sk,
     816             :     struct pflow_softc *sc)
     817             : {
     818           0 :         struct pf_state          pfs_copy;
     819           0 :         struct ifnet            *ifp = &sc->sc_if;
     820             :         u_int64_t                bytes[2];
     821             :         int                      ret = 0;
     822             : 
     823           0 :         if (!(ifp->if_flags & IFF_RUNNING))
     824           0 :                 return (0);
     825             : 
     826           0 :         if (sc->sc_version == PFLOW_PROTO_10)
     827           0 :                 return (pflow_pack_flow_ipfix(st, sk, sc));
     828             : 
     829             :         /* PFLOW_PROTO_5 */
     830           0 :         if ((st->bytes[0] < (u_int64_t)PFLOW_MAXBYTES)
     831           0 :             && (st->bytes[1] < (u_int64_t)PFLOW_MAXBYTES))
     832           0 :                 return (pflow_pack_flow(st, sk, sc));
     833             : 
     834             :         /* flow > PFLOW_MAXBYTES need special handling */
     835           0 :         bcopy(st, &pfs_copy, sizeof(pfs_copy));
     836           0 :         bytes[0] = pfs_copy.bytes[0];
     837           0 :         bytes[1] = pfs_copy.bytes[1];
     838             : 
     839           0 :         while (bytes[0] > PFLOW_MAXBYTES) {
     840           0 :                 pfs_copy.bytes[0] = PFLOW_MAXBYTES;
     841           0 :                 pfs_copy.bytes[1] = 0;
     842             : 
     843           0 :                 if ((ret = pflow_pack_flow(&pfs_copy, sk, sc)) != 0)
     844           0 :                         return (ret);
     845           0 :                 if ((bytes[0] - PFLOW_MAXBYTES) > 0)
     846           0 :                         bytes[0] -= PFLOW_MAXBYTES;
     847             :         }
     848             : 
     849           0 :         while (bytes[1] > (u_int64_t)PFLOW_MAXBYTES) {
     850           0 :                 pfs_copy.bytes[1] = PFLOW_MAXBYTES;
     851           0 :                 pfs_copy.bytes[0] = 0;
     852             : 
     853           0 :                 if ((ret = pflow_pack_flow(&pfs_copy, sk, sc)) != 0)
     854           0 :                         return (ret);
     855           0 :                 if ((bytes[1] - PFLOW_MAXBYTES) > 0)
     856           0 :                         bytes[1] -= PFLOW_MAXBYTES;
     857             :         }
     858             : 
     859           0 :         pfs_copy.bytes[0] = bytes[0];
     860           0 :         pfs_copy.bytes[1] = bytes[1];
     861             : 
     862           0 :         return (pflow_pack_flow(&pfs_copy, sk, sc));
     863           0 : }
     864             : 
     865             : int
     866           0 : copy_flow_to_m(struct pflow_flow *flow, struct pflow_softc *sc)
     867             : {
     868             :         int             ret = 0;
     869             : 
     870           0 :         if (sc->sc_mbuf == NULL) {
     871           0 :                 if ((sc->sc_mbuf = pflow_get_mbuf(sc, 0)) == NULL)
     872           0 :                         return (ENOBUFS);
     873             :         }
     874           0 :         m_copyback(sc->sc_mbuf, PFLOW_HDRLEN +
     875           0 :             (sc->sc_count * sizeof(struct pflow_flow)),
     876           0 :             sizeof(struct pflow_flow), flow, M_NOWAIT);
     877             : 
     878           0 :         if (pflowstats.pflow_flows == sc->sc_gcounter)
     879           0 :                 pflowstats.pflow_flows++;
     880           0 :         sc->sc_gcounter++;
     881           0 :         sc->sc_count++;
     882             : 
     883           0 :         if (sc->sc_count >= sc->sc_maxcount)
     884           0 :                 ret = pflow_sendout_v5(sc);
     885             : 
     886           0 :         return(ret);
     887           0 : }
     888             : 
     889             : int
     890           0 : copy_flow_ipfix_4_to_m(struct pflow_ipfix_flow4 *flow, struct pflow_softc *sc)
     891             : {
     892             :         int             ret = 0;
     893             : 
     894           0 :         if (sc->sc_mbuf == NULL) {
     895           0 :                 if ((sc->sc_mbuf =
     896           0 :                     pflow_get_mbuf(sc, PFLOW_IPFIX_TMPL_IPV4_ID)) == NULL) {
     897           0 :                         return (ENOBUFS);
     898             :                 }
     899           0 :                 sc->sc_count4 = 0;
     900           0 :                 timeout_add_sec(&sc->sc_tmo, PFLOW_TIMEOUT);
     901           0 :         }
     902           0 :         m_copyback(sc->sc_mbuf, PFLOW_SET_HDRLEN +
     903           0 :             (sc->sc_count4 * sizeof(struct pflow_ipfix_flow4)),
     904           0 :             sizeof(struct pflow_ipfix_flow4), flow, M_NOWAIT);
     905             : 
     906           0 :         if (pflowstats.pflow_flows == sc->sc_gcounter)
     907           0 :                 pflowstats.pflow_flows++;
     908           0 :         sc->sc_gcounter++;
     909           0 :         sc->sc_count4++;
     910             : 
     911           0 :         if (sc->sc_count4 >= sc->sc_maxcount4)
     912           0 :                 ret = pflow_sendout_ipfix(sc, AF_INET);
     913           0 :         return(ret);
     914           0 : }
     915             : 
     916             : int
     917           0 : copy_flow_ipfix_6_to_m(struct pflow_ipfix_flow6 *flow, struct pflow_softc *sc)
     918             : {
     919             :         int             ret = 0;
     920             : 
     921           0 :         if (sc->sc_mbuf6 == NULL) {
     922           0 :                 if ((sc->sc_mbuf6 =
     923           0 :                     pflow_get_mbuf(sc, PFLOW_IPFIX_TMPL_IPV6_ID)) == NULL) {
     924           0 :                         return (ENOBUFS);
     925             :                 }
     926           0 :                 sc->sc_count6 = 0;
     927           0 :                 timeout_add_sec(&sc->sc_tmo6, PFLOW_TIMEOUT);
     928           0 :         }
     929           0 :         m_copyback(sc->sc_mbuf6, PFLOW_SET_HDRLEN +
     930           0 :             (sc->sc_count6 * sizeof(struct pflow_ipfix_flow6)),
     931           0 :             sizeof(struct pflow_ipfix_flow6), flow, M_NOWAIT);
     932             : 
     933           0 :         if (pflowstats.pflow_flows == sc->sc_gcounter)
     934           0 :                 pflowstats.pflow_flows++;
     935           0 :         sc->sc_gcounter++;
     936           0 :         sc->sc_count6++;
     937             : 
     938           0 :         if (sc->sc_count6 >= sc->sc_maxcount6)
     939           0 :                 ret = pflow_sendout_ipfix(sc, AF_INET6);
     940             : 
     941           0 :         return(ret);
     942           0 : }
     943             : 
     944             : int
     945           0 : pflow_pack_flow(struct pf_state *st, struct pf_state_key *sk,
     946             :     struct pflow_softc *sc)
     947             : {
     948           0 :         struct pflow_flow        flow1;
     949           0 :         struct pflow_flow        flow2;
     950             :         int                      ret = 0;
     951             : 
     952           0 :         bzero(&flow1, sizeof(flow1));
     953           0 :         bzero(&flow2, sizeof(flow2));
     954             : 
     955           0 :         if (st->direction == PF_OUT)
     956           0 :                 copy_flow_data(&flow1, &flow2, st, sk, 1, 0);
     957             :         else
     958           0 :                 copy_flow_data(&flow1, &flow2, st, sk, 0, 1);
     959             : 
     960           0 :         if (st->bytes[0] != 0) /* first flow from state */
     961           0 :                 ret = copy_flow_to_m(&flow1, sc);
     962             : 
     963           0 :         if (st->bytes[1] != 0) /* second flow from state */
     964           0 :                 ret = copy_flow_to_m(&flow2, sc);
     965             : 
     966           0 :         return (ret);
     967           0 : }
     968             : 
     969             : int
     970           0 : pflow_pack_flow_ipfix(struct pf_state *st, struct pf_state_key *sk,
     971             :     struct pflow_softc *sc)
     972             : {
     973           0 :         struct pflow_ipfix_flow4         flow4_1, flow4_2;
     974           0 :         struct pflow_ipfix_flow6         flow6_1, flow6_2;
     975             :         int                              ret = 0;
     976           0 :         if (sk->af == AF_INET) {
     977           0 :                 bzero(&flow4_1, sizeof(flow4_1));
     978           0 :                 bzero(&flow4_2, sizeof(flow4_2));
     979             : 
     980           0 :                 if (st->direction == PF_OUT)
     981           0 :                         copy_flow_ipfix_4_data(&flow4_1, &flow4_2, st, sk, sc,
     982             :                             1, 0);
     983             :                 else
     984           0 :                         copy_flow_ipfix_4_data(&flow4_1, &flow4_2, st, sk, sc,
     985             :                             0, 1);
     986             : 
     987           0 :                 if (st->bytes[0] != 0) /* first flow from state */
     988           0 :                         ret = copy_flow_ipfix_4_to_m(&flow4_1, sc);
     989             : 
     990           0 :                 if (st->bytes[1] != 0) /* second flow from state */
     991           0 :                         ret = copy_flow_ipfix_4_to_m(&flow4_2, sc);
     992           0 :         } else if (sk->af == AF_INET6) {
     993           0 :                 bzero(&flow6_1, sizeof(flow6_1));
     994           0 :                 bzero(&flow6_2, sizeof(flow6_2));
     995             : 
     996           0 :                 if (st->direction == PF_OUT)
     997           0 :                         copy_flow_ipfix_6_data(&flow6_1, &flow6_2, st, sk, sc,
     998             :                             1, 0);
     999             :                 else
    1000           0 :                         copy_flow_ipfix_6_data(&flow6_1, &flow6_2, st, sk, sc,
    1001             :                             0, 1);
    1002             : 
    1003           0 :                 if (st->bytes[0] != 0) /* first flow from state */
    1004           0 :                         ret = copy_flow_ipfix_6_to_m(&flow6_1, sc);
    1005             : 
    1006           0 :                 if (st->bytes[1] != 0) /* second flow from state */
    1007           0 :                         ret = copy_flow_ipfix_6_to_m(&flow6_2, sc);
    1008             :         }
    1009           0 :         return (ret);
    1010           0 : }
    1011             : 
    1012             : void
    1013           0 : pflow_timeout(void *v)
    1014             : {
    1015           0 :         struct pflow_softc      *sc = v;
    1016             : 
    1017           0 :         switch (sc->sc_version) {
    1018             :         case PFLOW_PROTO_5:
    1019           0 :                 pflow_sendout_v5(sc);
    1020           0 :                 break;
    1021             :         case PFLOW_PROTO_10:
    1022           0 :                 pflow_sendout_ipfix(sc, AF_INET);
    1023           0 :                 break;
    1024             :         default: /* NOTREACHED */
    1025             :                 break;
    1026             :         }
    1027           0 : }
    1028             : 
    1029             : void
    1030           0 : pflow_timeout6(void *v)
    1031             : {
    1032           0 :         struct pflow_softc      *sc = v;
    1033             : 
    1034           0 :         pflow_sendout_ipfix(sc, AF_INET6);
    1035           0 : }
    1036             : 
    1037             : void
    1038           0 : pflow_timeout_tmpl(void *v)
    1039             : {
    1040           0 :         struct pflow_softc      *sc = v;
    1041             : 
    1042           0 :         pflow_sendout_ipfix_tmpl(sc);
    1043           0 : }
    1044             : 
    1045             : void
    1046           0 : pflow_flush(struct pflow_softc *sc)
    1047             : {
    1048           0 :         switch (sc->sc_version) {
    1049             :         case PFLOW_PROTO_5:
    1050           0 :                 pflow_sendout_v5(sc);
    1051           0 :                 break;
    1052             :         case PFLOW_PROTO_10:
    1053           0 :                 pflow_sendout_ipfix(sc, AF_INET);
    1054           0 :                 pflow_sendout_ipfix(sc, AF_INET6);
    1055           0 :                 break;
    1056             :         default: /* NOTREACHED */
    1057             :                 break;
    1058             :         }
    1059           0 : }
    1060             : 
    1061             : int
    1062           0 : pflow_sendout_v5(struct pflow_softc *sc)
    1063             : {
    1064           0 :         struct mbuf             *m = sc->sc_mbuf;
    1065             :         struct pflow_header     *h;
    1066           0 :         struct ifnet            *ifp = &sc->sc_if;
    1067           0 :         struct timespec         tv;
    1068             : 
    1069           0 :         timeout_del(&sc->sc_tmo);
    1070             : 
    1071           0 :         if (m == NULL)
    1072           0 :                 return (0);
    1073             : 
    1074           0 :         sc->sc_mbuf = NULL;
    1075           0 :         if (!(ifp->if_flags & IFF_RUNNING)) {
    1076           0 :                 m_freem(m);
    1077           0 :                 return (0);
    1078             :         }
    1079             : 
    1080           0 :         pflowstats.pflow_packets++;
    1081           0 :         h = mtod(m, struct pflow_header *);
    1082           0 :         h->count = htons(sc->sc_count);
    1083             : 
    1084             :         /* populate pflow_header */
    1085           0 :         h->uptime_ms = htonl(time_uptime * 1000);
    1086             : 
    1087           0 :         getnanotime(&tv);
    1088           0 :         h->time_sec = htonl(tv.tv_sec);                      /* XXX 2038 */
    1089           0 :         h->time_nanosec = htonl(tv.tv_nsec);
    1090           0 :         if (mq_enqueue(&sc->sc_outputqueue, m) == 0)
    1091           0 :                 task_add(net_tq(ifp->if_index), &sc->sc_outputtask);
    1092           0 :         return (0);
    1093           0 : }
    1094             : 
    1095             : int
    1096           0 : pflow_sendout_ipfix(struct pflow_softc *sc, sa_family_t af)
    1097             : {
    1098             :         struct mbuf                     *m;
    1099             :         struct pflow_v10_header         *h10;
    1100             :         struct pflow_set_header         *set_hdr;
    1101           0 :         struct ifnet                    *ifp = &sc->sc_if;
    1102             :         u_int32_t                        count;
    1103             :         int                              set_length;
    1104             : 
    1105           0 :         switch (af) {
    1106             :         case AF_INET:
    1107           0 :                 m = sc->sc_mbuf;
    1108           0 :                 timeout_del(&sc->sc_tmo);
    1109           0 :                 if (m == NULL)
    1110           0 :                         return (0);
    1111           0 :                 sc->sc_mbuf = NULL;
    1112           0 :                 count = sc->sc_count4;
    1113           0 :                 set_length = sizeof(struct pflow_set_header)
    1114           0 :                     + sc->sc_count4 * sizeof(struct pflow_ipfix_flow4);
    1115           0 :                 break;
    1116             :         case AF_INET6:
    1117           0 :                 m = sc->sc_mbuf6;
    1118           0 :                 timeout_del(&sc->sc_tmo6);
    1119           0 :                 if (m == NULL)
    1120           0 :                         return (0);
    1121           0 :                 sc->sc_mbuf6 = NULL;
    1122           0 :                 count = sc->sc_count6;
    1123           0 :                 set_length = sizeof(struct pflow_set_header)
    1124           0 :                     + sc->sc_count6 * sizeof(struct pflow_ipfix_flow6);
    1125           0 :                 break;
    1126             :         default:
    1127           0 :                 unhandled_af(af);
    1128             :         }
    1129             : 
    1130           0 :         if (!(ifp->if_flags & IFF_RUNNING)) {
    1131           0 :                 m_freem(m);
    1132           0 :                 return (0);
    1133             :         }
    1134             : 
    1135           0 :         pflowstats.pflow_packets++;
    1136           0 :         set_hdr = mtod(m, struct pflow_set_header *);
    1137           0 :         set_hdr->set_length = htons(set_length);
    1138             : 
    1139             :         /* populate pflow_header */
    1140           0 :         M_PREPEND(m, sizeof(struct pflow_v10_header), M_DONTWAIT);
    1141           0 :         if (m == NULL) {
    1142           0 :                 pflowstats.pflow_onomem++;
    1143           0 :                 return (ENOBUFS);
    1144             :         }
    1145           0 :         h10 = mtod(m, struct pflow_v10_header *);
    1146           0 :         h10->version = htons(PFLOW_PROTO_10);
    1147           0 :         h10->length = htons(PFLOW_IPFIX_HDRLEN + set_length);
    1148           0 :         h10->time_sec = htonl(time_second);          /* XXX 2038 */
    1149           0 :         h10->flow_sequence = htonl(sc->sc_sequence);
    1150           0 :         sc->sc_sequence += count;
    1151           0 :         h10->observation_dom = htonl(PFLOW_ENGINE_TYPE);
    1152           0 :         if (mq_enqueue(&sc->sc_outputqueue, m) == 0)
    1153           0 :                 task_add(net_tq(ifp->if_index), &sc->sc_outputtask);
    1154           0 :         return (0);
    1155           0 : }
    1156             : 
    1157             : int
    1158           0 : pflow_sendout_ipfix_tmpl(struct pflow_softc *sc)
    1159             : {
    1160             :         struct mbuf                     *m;
    1161             :         struct pflow_v10_header         *h10;
    1162           0 :         struct ifnet                    *ifp = &sc->sc_if;
    1163             : 
    1164           0 :         timeout_del(&sc->sc_tmo_tmpl);
    1165             : 
    1166           0 :         if (!(ifp->if_flags & IFF_RUNNING)) {
    1167           0 :                 return (0);
    1168             :         }
    1169           0 :         m = pflow_get_mbuf(NULL, 0);
    1170           0 :         if (m == NULL)
    1171           0 :                 return (0);
    1172           0 :         if (m_copyback(m, 0, sizeof(struct pflow_ipfix_tmpl),
    1173           0 :             &sc->sc_tmpl_ipfix, M_NOWAIT)) {
    1174           0 :                 m_freem(m);
    1175           0 :                 return (0);
    1176             :         }
    1177           0 :         pflowstats.pflow_packets++;
    1178             : 
    1179             :         /* populate pflow_header */
    1180           0 :         M_PREPEND(m, sizeof(struct pflow_v10_header), M_DONTWAIT);
    1181           0 :         if (m == NULL) {
    1182           0 :                 pflowstats.pflow_onomem++;
    1183           0 :                 return (ENOBUFS);
    1184             :         }
    1185           0 :         h10 = mtod(m, struct pflow_v10_header *);
    1186           0 :         h10->version = htons(PFLOW_PROTO_10);
    1187           0 :         h10->length = htons(PFLOW_IPFIX_HDRLEN + sizeof(struct
    1188             :             pflow_ipfix_tmpl));
    1189           0 :         h10->time_sec = htonl(time_second);          /* XXX 2038 */
    1190           0 :         h10->flow_sequence = htonl(sc->sc_sequence);
    1191           0 :         h10->observation_dom = htonl(PFLOW_ENGINE_TYPE);
    1192             : 
    1193           0 :         timeout_add_sec(&sc->sc_tmo_tmpl, PFLOW_TMPL_TIMEOUT);
    1194           0 :         if (mq_enqueue(&sc->sc_outputqueue, m) == 0)
    1195           0 :                 task_add(net_tq(ifp->if_index), &sc->sc_outputtask);
    1196           0 :         return (0);
    1197           0 : }
    1198             : 
    1199             : int
    1200           0 : pflow_sendout_mbuf(struct pflow_softc *sc, struct mbuf *m)
    1201             : {
    1202           0 :         sc->sc_if.if_opackets++;
    1203           0 :         sc->sc_if.if_obytes += m->m_pkthdr.len;
    1204             : 
    1205           0 :         if (sc->so == NULL) {
    1206           0 :                 m_freem(m);
    1207           0 :                 return (EINVAL);
    1208             :         }
    1209           0 :         return (sosend(sc->so, sc->send_nam, NULL, m, NULL, 0));
    1210           0 : }
    1211             : 
    1212             : int
    1213           0 : pflow_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
    1214             :     void *newp, size_t newlen)
    1215             : {
    1216           0 :         if (namelen != 1)
    1217           0 :                 return (ENOTDIR);
    1218             : 
    1219           0 :         switch (name[0]) {
    1220             :         case NET_PFLOW_STATS:
    1221           0 :                 if (newp != NULL)
    1222           0 :                         return (EPERM);
    1223           0 :                 return (sysctl_struct(oldp, oldlenp, newp, newlen,
    1224             :                     &pflowstats, sizeof(pflowstats)));
    1225             :         default:
    1226           0 :                 return (EOPNOTSUPP);
    1227             :         }
    1228             :         return (0);
    1229           0 : }

Generated by: LCOV version 1.13