The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netpfil/ipfilter/netinet/ip_sync.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $FreeBSD$       */
    2 
    3 /*
    4  * Copyright (C) 2012 by Darren Reed.
    5  *
    6  * See the IPFILTER.LICENCE file for details on licencing.
    7  */
    8 #if defined(KERNEL) || defined(_KERNEL)
    9 # undef KERNEL
   10 # undef _KERNEL
   11 # define        KERNEL  1
   12 # define        _KERNEL 1
   13 #endif
   14 #include <sys/errno.h>
   15 #include <sys/types.h>
   16 #include <sys/param.h>
   17 #include <sys/file.h>
   18 #if !defined(_KERNEL) && !defined(__KERNEL__)
   19 # include <stdio.h>
   20 # include <stdlib.h>
   21 # include <string.h>
   22 # define _KERNEL
   23 # define KERNEL
   24 # include <sys/uio.h>
   25 # undef _KERNEL
   26 # undef KERNEL
   27 #else
   28 # include <sys/systm.h>
   29 # if !defined(__SVR4)
   30 #  include <sys/mbuf.h>
   31 # endif
   32 # include <sys/select.h>
   33 # ifdef __FreeBSD__
   34 #  include <sys/selinfo.h>
   35 # endif
   36 #endif
   37 #if defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000)
   38 # include <sys/proc.h>
   39 #endif
   40 #if defined(_KERNEL) && defined(__FreeBSD__)
   41 # include <sys/filio.h>
   42 # include <sys/fcntl.h>
   43 #else
   44 # include <sys/ioctl.h>
   45 #endif
   46 #include <sys/time.h>
   47 # include <sys/protosw.h>
   48 #include <sys/socket.h>
   49 #if defined(__SVR4)
   50 # include <sys/filio.h>
   51 # include <sys/byteorder.h>
   52 # ifdef _KERNEL
   53 #  include <sys/dditypes.h>
   54 # endif
   55 # include <sys/stream.h>
   56 # include <sys/kmem.h>
   57 #endif
   58 
   59 #include <net/if.h>
   60 #ifdef sun
   61 # include <net/af.h>
   62 #endif
   63 #include <netinet/in.h>
   64 #include <netinet/in_systm.h>
   65 #include <netinet/ip.h>
   66 #include <netinet/tcp.h>
   67 # include <netinet/ip_var.h>
   68 # include <netinet/tcp_fsm.h>
   69 #include <netinet/udp.h>
   70 #include <netinet/ip_icmp.h>
   71 #include "netinet/ip_compat.h"
   72 #include <netinet/tcpip.h>
   73 #include "netinet/ip_fil.h"
   74 #include "netinet/ip_nat.h"
   75 #include "netinet/ip_frag.h"
   76 #include "netinet/ip_state.h"
   77 #include "netinet/ip_proxy.h"
   78 #include "netinet/ip_sync.h"
   79 #ifdef  USE_INET6
   80 #include <netinet/icmp6.h>
   81 #endif
   82 #if defined(__FreeBSD__)
   83 # include <sys/malloc.h>
   84 # if defined(_KERNEL) && !defined(IPFILTER_LKM)
   85 #  include <sys/libkern.h>
   86 #  include <sys/systm.h>
   87 # endif
   88 #endif
   89 /* END OF INCLUDES */
   90 
   91 #if !defined(lint)
   92 static const char rcsid[] = "@(#)$Id$";
   93 #endif
   94 
   95 #define SYNC_STATETABSZ 256
   96 #define SYNC_NATTABSZ   256
   97 
   98 typedef struct ipf_sync_softc_s {
   99         ipfmutex_t      ipf_syncadd;
  100         ipfmutex_t      ipsl_mutex;
  101         ipfrwlock_t     ipf_syncstate;
  102         ipfrwlock_t     ipf_syncnat;
  103 #if SOLARIS && defined(_KERNEL)
  104         kcondvar_t      ipslwait;
  105 #endif
  106         synclist_t      **syncstatetab;
  107         synclist_t      **syncnattab;
  108         synclogent_t    *synclog;
  109         syncupdent_t    *syncupd;
  110         u_int           ipf_sync_num;
  111         u_int           ipf_sync_wrap;
  112         u_int           sl_idx;         /* next available sync log entry */
  113         u_int           su_idx;         /* next available sync update entry */
  114         u_int           sl_tail;        /* next sync log entry to read */
  115         u_int           su_tail;        /* next sync update entry to read */
  116         int             ipf_sync_log_sz;
  117         int             ipf_sync_nat_tab_sz;
  118         int             ipf_sync_state_tab_sz;
  119         int             ipf_sync_debug;
  120         int             ipf_sync_events;
  121         u_32_t          ipf_sync_lastwakeup;
  122         int             ipf_sync_wake_interval;
  123         int             ipf_sync_event_high_wm;
  124         int             ipf_sync_queue_high_wm;
  125         int             ipf_sync_inited;
  126 } ipf_sync_softc_t;
  127 
  128 static int ipf_sync_flush_table(ipf_sync_softc_t *, int, synclist_t **);
  129 static void ipf_sync_wakeup(ipf_main_softc_t *);
  130 static void ipf_sync_del(ipf_sync_softc_t *, synclist_t *);
  131 static void ipf_sync_poll_wakeup(ipf_main_softc_t *);
  132 static int ipf_sync_nat(ipf_main_softc_t *, synchdr_t *, void *);
  133 static int ipf_sync_state(ipf_main_softc_t *, synchdr_t *, void *);
  134 
  135 # if !defined(sparc) && !defined(__hppa)
  136 void ipf_sync_tcporder(int, struct tcpdata *);
  137 void ipf_sync_natorder(int, struct nat *);
  138 void ipf_sync_storder(int, struct ipstate *);
  139 # endif
  140 
  141 
  142 void *
  143 ipf_sync_soft_create(ipf_main_softc_t *softc)
  144 {
  145         ipf_sync_softc_t *softs;
  146 
  147         KMALLOC(softs, ipf_sync_softc_t *);
  148         if (softs == NULL) {
  149                 IPFERROR(110024);
  150                 return (NULL);
  151         }
  152 
  153         bzero((char *)softs, sizeof(*softs));
  154 
  155         softs->ipf_sync_log_sz = SYNCLOG_SZ;
  156         softs->ipf_sync_nat_tab_sz = SYNC_STATETABSZ;
  157         softs->ipf_sync_state_tab_sz = SYNC_STATETABSZ;
  158         softs->ipf_sync_event_high_wm = SYNCLOG_SZ * 100 / 90;  /* 90% */
  159         softs->ipf_sync_queue_high_wm = SYNCLOG_SZ * 100 / 90;  /* 90% */
  160 
  161         return (softs);
  162 }
  163 
  164 
  165 /* ------------------------------------------------------------------------ */
  166 /* Function:    ipf_sync_init                                               */
  167 /* Returns:     int - 0 == success, -1 == failure                           */
  168 /* Parameters:  Nil                                                         */
  169 /*                                                                          */
  170 /* Initialise all of the locks required for the sync code and initialise    */
  171 /* any data structures, as required.                                        */
  172 /* ------------------------------------------------------------------------ */
  173 int
  174 ipf_sync_soft_init(ipf_main_softc_t *softc, void *arg)
  175 {
  176         ipf_sync_softc_t *softs = arg;
  177 
  178         KMALLOCS(softs->synclog, synclogent_t *,
  179                  softs->ipf_sync_log_sz * sizeof(*softs->synclog));
  180         if (softs->synclog == NULL)
  181                 return (-1);
  182         bzero((char *)softs->synclog,
  183               softs->ipf_sync_log_sz * sizeof(*softs->synclog));
  184 
  185         KMALLOCS(softs->syncupd, syncupdent_t *,
  186                  softs->ipf_sync_log_sz * sizeof(*softs->syncupd));
  187         if (softs->syncupd == NULL)
  188                 return (-2);
  189         bzero((char *)softs->syncupd,
  190               softs->ipf_sync_log_sz * sizeof(*softs->syncupd));
  191 
  192         KMALLOCS(softs->syncstatetab, synclist_t **,
  193                  softs->ipf_sync_state_tab_sz * sizeof(*softs->syncstatetab));
  194         if (softs->syncstatetab == NULL)
  195                 return (-3);
  196         bzero((char *)softs->syncstatetab,
  197               softs->ipf_sync_state_tab_sz * sizeof(*softs->syncstatetab));
  198 
  199         KMALLOCS(softs->syncnattab, synclist_t **,
  200                  softs->ipf_sync_nat_tab_sz * sizeof(*softs->syncnattab));
  201         if (softs->syncnattab == NULL)
  202                 return (-3);
  203         bzero((char *)softs->syncnattab,
  204               softs->ipf_sync_nat_tab_sz * sizeof(*softs->syncnattab));
  205 
  206         softs->ipf_sync_num = 1;
  207         softs->ipf_sync_wrap = 0;
  208         softs->sl_idx = 0;
  209         softs->su_idx = 0;
  210         softs->sl_tail = 0;
  211         softs->su_tail = 0;
  212         softs->ipf_sync_events = 0;
  213         softs->ipf_sync_lastwakeup = 0;
  214 
  215 
  216 # if SOLARIS && defined(_KERNEL)
  217         cv_init(&softs->ipslwait, "ipsl condvar", CV_DRIVER, NULL);
  218 # endif
  219         RWLOCK_INIT(&softs->ipf_syncstate, "add things to state sync table");
  220         RWLOCK_INIT(&softs->ipf_syncnat, "add things to nat sync table");
  221         MUTEX_INIT(&softs->ipf_syncadd, "add things to sync table");
  222         MUTEX_INIT(&softs->ipsl_mutex, "read ring lock");
  223 
  224         softs->ipf_sync_inited = 1;
  225 
  226         return (0);
  227 }
  228 
  229 
  230 /* ------------------------------------------------------------------------ */
  231 /* Function:    ipf_sync_unload                                             */
  232 /* Returns:     int - 0 == success, -1 == failure                           */
  233 /* Parameters:  Nil                                                         */
  234 /*                                                                          */
  235 /* Destroy the locks created when initialising and free any memory in use   */
  236 /* with the synchronisation tables.                                         */
  237 /* ------------------------------------------------------------------------ */
  238 int
  239 ipf_sync_soft_fini(ipf_main_softc_t *softc, void *arg)
  240 {
  241         ipf_sync_softc_t *softs = arg;
  242 
  243         if (softs->syncnattab != NULL) {
  244                 ipf_sync_flush_table(softs, softs->ipf_sync_nat_tab_sz,
  245                                      softs->syncnattab);
  246                 KFREES(softs->syncnattab,
  247                        softs->ipf_sync_nat_tab_sz * sizeof(*softs->syncnattab));
  248                 softs->syncnattab = NULL;
  249         }
  250 
  251         if (softs->syncstatetab != NULL) {
  252                 ipf_sync_flush_table(softs, softs->ipf_sync_state_tab_sz,
  253                                      softs->syncstatetab);
  254                 KFREES(softs->syncstatetab,
  255                        softs->ipf_sync_state_tab_sz *
  256                        sizeof(*softs->syncstatetab));
  257                 softs->syncstatetab = NULL;
  258         }
  259 
  260         if (softs->syncupd != NULL) {
  261                 KFREES(softs->syncupd,
  262                        softs->ipf_sync_log_sz * sizeof(*softs->syncupd));
  263                 softs->syncupd = NULL;
  264         }
  265 
  266         if (softs->synclog != NULL) {
  267                 KFREES(softs->synclog,
  268                        softs->ipf_sync_log_sz * sizeof(*softs->synclog));
  269                 softs->synclog = NULL;
  270         }
  271 
  272         if (softs->ipf_sync_inited == 1) {
  273                 MUTEX_DESTROY(&softs->ipsl_mutex);
  274                 MUTEX_DESTROY(&softs->ipf_syncadd);
  275                 RW_DESTROY(&softs->ipf_syncnat);
  276                 RW_DESTROY(&softs->ipf_syncstate);
  277                 softs->ipf_sync_inited = 0;
  278         }
  279 
  280         return (0);
  281 }
  282 
  283 void
  284 ipf_sync_soft_destroy(ipf_main_softc_t *softc, void *arg)
  285 {
  286         ipf_sync_softc_t *softs = arg;
  287 
  288         KFREE(softs);
  289 }
  290 
  291 
  292 # if !defined(sparc)
  293 /* ------------------------------------------------------------------------ */
  294 /* Function:    ipf_sync_tcporder                                           */
  295 /* Returns:     Nil                                                         */
  296 /* Parameters:  way(I) - direction of byte order conversion.                */
  297 /*              td(IO) - pointer to data to be converted.                   */
  298 /*                                                                          */
  299 /* Do byte swapping on values in the TCP state information structure that   */
  300 /* need to be used at both ends by the host in their native byte order.     */
  301 /* ------------------------------------------------------------------------ */
  302 void
  303 ipf_sync_tcporder(int way, tcpdata_t *td)
  304 {
  305         if (way) {
  306                 td->td_maxwin = htons(td->td_maxwin);
  307                 td->td_end = htonl(td->td_end);
  308                 td->td_maxend = htonl(td->td_maxend);
  309         } else {
  310                 td->td_maxwin = ntohs(td->td_maxwin);
  311                 td->td_end = ntohl(td->td_end);
  312                 td->td_maxend = ntohl(td->td_maxend);
  313         }
  314 }
  315 
  316 
  317 /* ------------------------------------------------------------------------ */
  318 /* Function:    ipf_sync_natorder                                           */
  319 /* Returns:     Nil                                                         */
  320 /* Parameters:  way(I)  - direction of byte order conversion.               */
  321 /*              nat(IO) - pointer to data to be converted.                  */
  322 /*                                                                          */
  323 /* Do byte swapping on values in the NAT data structure that need to be     */
  324 /* used at both ends by the host in their native byte order.                */
  325 /* ------------------------------------------------------------------------ */
  326 void
  327 ipf_sync_natorder(int way, nat_t *n)
  328 {
  329         if (way) {
  330                 n->nat_age = htonl(n->nat_age);
  331                 n->nat_flags = htonl(n->nat_flags);
  332                 n->nat_ipsumd = htonl(n->nat_ipsumd);
  333                 n->nat_use = htonl(n->nat_use);
  334                 n->nat_dir = htonl(n->nat_dir);
  335         } else {
  336                 n->nat_age = ntohl(n->nat_age);
  337                 n->nat_flags = ntohl(n->nat_flags);
  338                 n->nat_ipsumd = ntohl(n->nat_ipsumd);
  339                 n->nat_use = ntohl(n->nat_use);
  340                 n->nat_dir = ntohl(n->nat_dir);
  341         }
  342 }
  343 
  344 
  345 /* ------------------------------------------------------------------------ */
  346 /* Function:    ipf_sync_storder                                            */
  347 /* Returns:     Nil                                                         */
  348 /* Parameters:  way(I)  - direction of byte order conversion.               */
  349 /*              ips(IO) - pointer to data to be converted.                  */
  350 /*                                                                          */
  351 /* Do byte swapping on values in the IP state data structure that need to   */
  352 /* be used at both ends by the host in their native byte order.             */
  353 /* ------------------------------------------------------------------------ */
  354 void
  355 ipf_sync_storder(int way, ipstate_t *ips)
  356 {
  357         ipf_sync_tcporder(way, &ips->is_tcp.ts_data[0]);
  358         ipf_sync_tcporder(way, &ips->is_tcp.ts_data[1]);
  359 
  360         if (way) {
  361                 ips->is_hv = htonl(ips->is_hv);
  362                 ips->is_die = htonl(ips->is_die);
  363                 ips->is_pass = htonl(ips->is_pass);
  364                 ips->is_flags = htonl(ips->is_flags);
  365                 ips->is_opt[0] = htonl(ips->is_opt[0]);
  366                 ips->is_opt[1] = htonl(ips->is_opt[1]);
  367                 ips->is_optmsk[0] = htonl(ips->is_optmsk[0]);
  368                 ips->is_optmsk[1] = htonl(ips->is_optmsk[1]);
  369                 ips->is_sec = htons(ips->is_sec);
  370                 ips->is_secmsk = htons(ips->is_secmsk);
  371                 ips->is_auth = htons(ips->is_auth);
  372                 ips->is_authmsk = htons(ips->is_authmsk);
  373                 ips->is_s0[0] = htonl(ips->is_s0[0]);
  374                 ips->is_s0[1] = htonl(ips->is_s0[1]);
  375                 ips->is_smsk[0] = htons(ips->is_smsk[0]);
  376                 ips->is_smsk[1] = htons(ips->is_smsk[1]);
  377         } else {
  378                 ips->is_hv = ntohl(ips->is_hv);
  379                 ips->is_die = ntohl(ips->is_die);
  380                 ips->is_pass = ntohl(ips->is_pass);
  381                 ips->is_flags = ntohl(ips->is_flags);
  382                 ips->is_opt[0] = ntohl(ips->is_opt[0]);
  383                 ips->is_opt[1] = ntohl(ips->is_opt[1]);
  384                 ips->is_optmsk[0] = ntohl(ips->is_optmsk[0]);
  385                 ips->is_optmsk[1] = ntohl(ips->is_optmsk[1]);
  386                 ips->is_sec = ntohs(ips->is_sec);
  387                 ips->is_secmsk = ntohs(ips->is_secmsk);
  388                 ips->is_auth = ntohs(ips->is_auth);
  389                 ips->is_authmsk = ntohs(ips->is_authmsk);
  390                 ips->is_s0[0] = ntohl(ips->is_s0[0]);
  391                 ips->is_s0[1] = ntohl(ips->is_s0[1]);
  392                 ips->is_smsk[0] = ntohl(ips->is_smsk[0]);
  393                 ips->is_smsk[1] = ntohl(ips->is_smsk[1]);
  394         }
  395 }
  396 # else /* !defined(sparc) */
  397 #  define       ipf_sync_tcporder(x,y)
  398 #  define       ipf_sync_natorder(x,y)
  399 #  define       ipf_sync_storder(x,y)
  400 # endif /* !defined(sparc) */
  401 
  402 
  403 /* ------------------------------------------------------------------------ */
  404 /* Function:    ipf_sync_write                                              */
  405 /* Returns:     int    - 0 == success, else error value.                    */
  406 /* Parameters:  uio(I) - pointer to information about data to write         */
  407 /*                                                                          */
  408 /* Moves data from user space into the kernel and uses it for updating data */
  409 /* structures in the state/NAT tables.                                      */
  410 /* ------------------------------------------------------------------------ */
  411 int
  412 ipf_sync_write(ipf_main_softc_t *softc, struct uio *uio)
  413 {
  414         ipf_sync_softc_t *softs = softc->ipf_sync_soft;
  415         synchdr_t sh;
  416 
  417         /*
  418          * THIS MUST BE SUFFICIENT LARGE TO STORE
  419          * ANY POSSIBLE DATA TYPE
  420          */
  421         char data[2048];
  422 
  423         int err = 0;
  424 
  425 #  if defined(__NetBSD__) || defined(__FreeBSD__)
  426         uio->uio_rw = UIO_WRITE;
  427 #  endif
  428 
  429         /* Try to get bytes */
  430         while (uio->uio_resid > 0) {
  431 
  432                 if (uio->uio_resid >= sizeof(sh)) {
  433 
  434                         err = UIOMOVE(&sh, sizeof(sh), UIO_WRITE, uio);
  435 
  436                         if (err) {
  437                                 if (softs->ipf_sync_debug > 2)
  438                                         printf("uiomove(header) failed: %d\n",
  439                                                 err);
  440                                 return (err);
  441                         }
  442 
  443                         /* convert to host order */
  444                         sh.sm_magic = ntohl(sh.sm_magic);
  445                         sh.sm_len = ntohl(sh.sm_len);
  446                         sh.sm_num = ntohl(sh.sm_num);
  447 
  448                         if (softs->ipf_sync_debug > 8)
  449                                 printf("[%d] Read v:%d p:%d cmd:%d table:%d rev:%d len:%d magic:%x\n",
  450                                         sh.sm_num, sh.sm_v, sh.sm_p, sh.sm_cmd,
  451                                         sh.sm_table, sh.sm_rev, sh.sm_len,
  452                                         sh.sm_magic);
  453 
  454                         if (sh.sm_magic != SYNHDRMAGIC) {
  455                                 if (softs->ipf_sync_debug > 2)
  456                                         printf("uiomove(header) invalid %s\n",
  457                                                 "magic");
  458                                 IPFERROR(110001);
  459                                 return (EINVAL);
  460                         }
  461 
  462                         if (sh.sm_v != 4 && sh.sm_v != 6) {
  463                                 if (softs->ipf_sync_debug > 2)
  464                                         printf("uiomove(header) invalid %s\n",
  465                                                 "protocol");
  466                                 IPFERROR(110002);
  467                                 return (EINVAL);
  468                         }
  469 
  470                         if (sh.sm_cmd > SMC_MAXCMD) {
  471                                 if (softs->ipf_sync_debug > 2)
  472                                         printf("uiomove(header) invalid %s\n",
  473                                                 "command");
  474                                 IPFERROR(110003);
  475                                 return (EINVAL);
  476                         }
  477 
  478 
  479                         if (sh.sm_table > SMC_MAXTBL) {
  480                                 if (softs->ipf_sync_debug > 2)
  481                                         printf("uiomove(header) invalid %s\n",
  482                                                 "table");
  483                                 IPFERROR(110004);
  484                                 return (EINVAL);
  485                         }
  486 
  487                 } else {
  488                         /* unsufficient data, wait until next call */
  489                         if (softs->ipf_sync_debug > 2)
  490                                 printf("uiomove(header) insufficient data");
  491                         IPFERROR(110005);
  492                         return (EAGAIN);
  493                 }
  494 
  495 
  496                 /*
  497                  * We have a header, so try to read the amount of data
  498                  * needed for the request
  499                  */
  500 
  501                 /* not supported */
  502                 if (sh.sm_len == 0) {
  503                         if (softs->ipf_sync_debug > 2)
  504                                 printf("uiomove(data zero length %s\n",
  505                                         "not supported");
  506                         IPFERROR(110006);
  507                         return (EINVAL);
  508                 }
  509 
  510                 if (uio->uio_resid >= sh.sm_len) {
  511 
  512                         err = UIOMOVE(data, sh.sm_len, UIO_WRITE, uio);
  513 
  514                         if (err) {
  515                                 if (softs->ipf_sync_debug > 2)
  516                                         printf("uiomove(data) failed: %d\n",
  517                                                 err);
  518                                 return (err);
  519                         }
  520 
  521                         if (softs->ipf_sync_debug > 7)
  522                                 printf("uiomove(data) %d bytes read\n",
  523                                         sh.sm_len);
  524 
  525                         if (sh.sm_table == SMC_STATE)
  526                                 err = ipf_sync_state(softc, &sh, data);
  527                         else if (sh.sm_table == SMC_NAT)
  528                                 err = ipf_sync_nat(softc, &sh, data);
  529                         if (softs->ipf_sync_debug > 7)
  530                                 printf("[%d] Finished with error %d\n",
  531                                         sh.sm_num, err);
  532 
  533                 } else {
  534                         /* insufficient data, wait until next call */
  535                         if (softs->ipf_sync_debug > 2)
  536                                 printf("uiomove(data) %s %d bytes, got %d\n",
  537                                         "insufficient data, need",
  538                                         sh.sm_len, (int)uio->uio_resid);
  539                         IPFERROR(110007);
  540                         return (EAGAIN);
  541                 }
  542         }
  543 
  544         /* no more data */
  545         return (0);
  546 }
  547 
  548 
  549 /* ------------------------------------------------------------------------ */
  550 /* Function:    ipf_sync_read                                               */
  551 /* Returns:     int    - 0 == success, else error value.                    */
  552 /* Parameters:  uio(O) - pointer to information about where to store data   */
  553 /*                                                                          */
  554 /* This function is called when a user program wants to read some data      */
  555 /* for pending state/NAT updates.  If no data is available, the caller is   */
  556 /* put to sleep, pending a wakeup from the "lower half" of this code.       */
  557 /* ------------------------------------------------------------------------ */
  558 int
  559 ipf_sync_read(ipf_main_softc_t *softc, struct uio *uio)
  560 {
  561         ipf_sync_softc_t *softs = softc->ipf_sync_soft;
  562         syncupdent_t *su;
  563         synclogent_t *sl;
  564         int err = 0;
  565 
  566         if ((uio->uio_resid & 3) || (uio->uio_resid < 8)) {
  567                 IPFERROR(110008);
  568                 return (EINVAL);
  569         }
  570 
  571 #  if defined(__NetBSD__) || defined(__FreeBSD__)
  572         uio->uio_rw = UIO_READ;
  573 #  endif
  574 
  575         MUTEX_ENTER(&softs->ipsl_mutex);
  576         while ((softs->sl_tail == softs->sl_idx) &&
  577                (softs->su_tail == softs->su_idx)) {
  578 #  if defined(_KERNEL)
  579 #   if SOLARIS
  580                 if (!cv_wait_sig(&softs->ipslwait, &softs->ipsl_mutex.ipf_lk)) {
  581                         MUTEX_EXIT(&softs->ipsl_mutex);
  582                         IPFERROR(110009);
  583                         return (EINTR);
  584                 }
  585 #   else
  586                 MUTEX_EXIT(&softs->ipsl_mutex);
  587                 err = SLEEP(&softs->sl_tail, "ipl sleep");
  588                 if (err) {
  589                         IPFERROR(110012);
  590                         return (EINTR);
  591                 }
  592                 MUTEX_ENTER(&softs->ipsl_mutex);
  593 #   endif /* SOLARIS */
  594 #  endif /* _KERNEL */
  595         }
  596 
  597         while ((softs->sl_tail < softs->sl_idx) &&
  598                (uio->uio_resid > sizeof(*sl))) {
  599                 sl = softs->synclog + softs->sl_tail++;
  600                 MUTEX_EXIT(&softs->ipsl_mutex);
  601                 err = UIOMOVE(sl, sizeof(*sl), UIO_READ, uio);
  602                 if (err != 0)
  603                         goto goterror;
  604                 MUTEX_ENTER(&softs->ipsl_mutex);
  605         }
  606 
  607         while ((softs->su_tail < softs->su_idx) &&
  608                (uio->uio_resid > sizeof(*su))) {
  609                 su = softs->syncupd + softs->su_tail;
  610                 softs->su_tail++;
  611                 MUTEX_EXIT(&softs->ipsl_mutex);
  612                 err = UIOMOVE(su, sizeof(*su), UIO_READ, uio);
  613                 if (err != 0)
  614                         goto goterror;
  615                 MUTEX_ENTER(&softs->ipsl_mutex);
  616                 if (su->sup_hdr.sm_sl != NULL)
  617                         su->sup_hdr.sm_sl->sl_idx = -1;
  618         }
  619         if (softs->sl_tail == softs->sl_idx)
  620                 softs->sl_tail = softs->sl_idx = 0;
  621         if (softs->su_tail == softs->su_idx)
  622                 softs->su_tail = softs->su_idx = 0;
  623         MUTEX_EXIT(&softs->ipsl_mutex);
  624 goterror:
  625         return (err);
  626 }
  627 
  628 
  629 /* ------------------------------------------------------------------------ */
  630 /* Function:    ipf_sync_state                                              */
  631 /* Returns:     int    - 0 == success, else error value.                    */
  632 /* Parameters:  sp(I)  - pointer to sync packet data header                 */
  633 /*              uio(I) - pointer to user data for further information       */
  634 /*                                                                          */
  635 /* Updates the state table according to information passed in the sync      */
  636 /* header.  As required, more data is fetched from the uio structure but    */
  637 /* varies depending on the contents of the sync header.  This function can  */
  638 /* create a new state entry or update one.  Deletion is left to the state   */
  639 /* structures being timed out correctly.                                    */
  640 /* ------------------------------------------------------------------------ */
  641 static int
  642 ipf_sync_state(ipf_main_softc_t *softc, synchdr_t *sp, void *data)
  643 {
  644         ipf_sync_softc_t *softs = softc->ipf_sync_soft;
  645         synctcp_update_t su;
  646         ipstate_t *is, sn;
  647         synclist_t *sl;
  648         frentry_t *fr;
  649         u_int hv;
  650         int err = 0;
  651 
  652         hv = sp->sm_num & (softs->ipf_sync_state_tab_sz - 1);
  653 
  654         switch (sp->sm_cmd)
  655         {
  656         case SMC_CREATE :
  657 
  658                 bcopy(data, &sn, sizeof(sn));
  659                 KMALLOC(is, ipstate_t *);
  660                 if (is == NULL) {
  661                         IPFERROR(110013);
  662                         err = ENOMEM;
  663                         break;
  664                 }
  665 
  666                 KMALLOC(sl, synclist_t *);
  667                 if (sl == NULL) {
  668                         IPFERROR(110014);
  669                         err = ENOMEM;
  670                         KFREE(is);
  671                         break;
  672                 }
  673 
  674                 bzero((char *)is, offsetof(ipstate_t, is_die));
  675                 bcopy((char *)&sn.is_die, (char *)&is->is_die,
  676                       sizeof(*is) - offsetof(ipstate_t, is_die));
  677                 ipf_sync_storder(0, is);
  678 
  679                 /*
  680                  * We need to find the same rule on the slave as was used on
  681                  * the master to create this state entry.
  682                  */
  683                 READ_ENTER(&softc->ipf_mutex);
  684                 fr = ipf_getrulen(softc, IPL_LOGIPF, sn.is_group, sn.is_rulen);
  685                 if (fr != NULL) {
  686                         MUTEX_ENTER(&fr->fr_lock);
  687                         fr->fr_ref++;
  688                         fr->fr_statecnt++;
  689                         MUTEX_EXIT(&fr->fr_lock);
  690                 }
  691                 RWLOCK_EXIT(&softc->ipf_mutex);
  692 
  693                 if (softs->ipf_sync_debug > 4)
  694                         printf("[%d] Filter rules = %p\n", sp->sm_num, fr);
  695 
  696                 is->is_rule = fr;
  697                 is->is_sync = sl;
  698 
  699                 sl->sl_idx = -1;
  700                 sl->sl_ips = is;
  701                 bcopy(sp, &sl->sl_hdr, sizeof(struct synchdr));
  702 
  703                 WRITE_ENTER(&softs->ipf_syncstate);
  704                 WRITE_ENTER(&softc->ipf_state);
  705 
  706                 sl->sl_pnext = softs->syncstatetab + hv;
  707                 sl->sl_next = softs->syncstatetab[hv];
  708                 if (softs->syncstatetab[hv] != NULL)
  709                         softs->syncstatetab[hv]->sl_pnext = &sl->sl_next;
  710                 softs->syncstatetab[hv] = sl;
  711                 MUTEX_DOWNGRADE(&softs->ipf_syncstate);
  712                 ipf_state_insert(softc, is, sp->sm_rev);
  713                 /*
  714                  * Do not initialise the interface pointers for the state
  715                  * entry as the full complement of interface names may not
  716                  * be present.
  717                  *
  718                  * Put this state entry on its timeout queue.
  719                  */
  720                 /*fr_setstatequeue(is, sp->sm_rev);*/
  721                 break;
  722 
  723         case SMC_UPDATE :
  724                 bcopy(data, &su, sizeof(su));
  725 
  726                 if (softs->ipf_sync_debug > 4)
  727                         printf("[%d] Update age %lu state %d/%d \n",
  728                                 sp->sm_num, su.stu_age, su.stu_state[0],
  729                                 su.stu_state[1]);
  730 
  731                 READ_ENTER(&softs->ipf_syncstate);
  732                 for (sl = softs->syncstatetab[hv]; (sl != NULL);
  733                      sl = sl->sl_next)
  734                         if (sl->sl_hdr.sm_num == sp->sm_num)
  735                                 break;
  736                 if (sl == NULL) {
  737                         if (softs->ipf_sync_debug > 1)
  738                                 printf("[%d] State not found - can't update\n",
  739                                         sp->sm_num);
  740                         RWLOCK_EXIT(&softs->ipf_syncstate);
  741                         IPFERROR(110015);
  742                         err = ENOENT;
  743                         break;
  744                 }
  745 
  746                 READ_ENTER(&softc->ipf_state);
  747 
  748                 if (softs->ipf_sync_debug > 6)
  749                         printf("[%d] Data from state v:%d p:%d cmd:%d table:%d rev:%d\n",
  750                                 sp->sm_num, sl->sl_hdr.sm_v, sl->sl_hdr.sm_p,
  751                                 sl->sl_hdr.sm_cmd, sl->sl_hdr.sm_table,
  752                                 sl->sl_hdr.sm_rev);
  753 
  754                 is = sl->sl_ips;
  755 
  756                 MUTEX_ENTER(&is->is_lock);
  757                 switch (sp->sm_p)
  758                 {
  759                 case IPPROTO_TCP :
  760                         /* XXX FV --- shouldn't we do ntohl/htonl???? XXX */
  761                         is->is_send = su.stu_data[0].td_end;
  762                         is->is_maxsend = su.stu_data[0].td_maxend;
  763                         is->is_maxswin = su.stu_data[0].td_maxwin;
  764                         is->is_state[0] = su.stu_state[0];
  765                         is->is_dend = su.stu_data[1].td_end;
  766                         is->is_maxdend = su.stu_data[1].td_maxend;
  767                         is->is_maxdwin = su.stu_data[1].td_maxwin;
  768                         is->is_state[1] = su.stu_state[1];
  769                         break;
  770                 default :
  771                         break;
  772                 }
  773 
  774                 if (softs->ipf_sync_debug > 6)
  775                         printf("[%d] Setting timers for state\n", sp->sm_num);
  776 
  777                 ipf_state_setqueue(softc, is, sp->sm_rev);
  778 
  779                 MUTEX_EXIT(&is->is_lock);
  780                 break;
  781 
  782         default :
  783                 IPFERROR(110016);
  784                 err = EINVAL;
  785                 break;
  786         }
  787 
  788         if (err == 0) {
  789                 RWLOCK_EXIT(&softc->ipf_state);
  790                 RWLOCK_EXIT(&softs->ipf_syncstate);
  791         }
  792 
  793         if (softs->ipf_sync_debug > 6)
  794                 printf("[%d] Update completed with error %d\n",
  795                         sp->sm_num, err);
  796 
  797         return (err);
  798 }
  799 
  800 
  801 /* ------------------------------------------------------------------------ */
  802 /* Function:    ipf_sync_del                                                */
  803 /* Returns:     Nil                                                         */
  804 /* Parameters:  sl(I) - pointer to synclist object to delete                */
  805 /*                                                                          */
  806 /* Deletes an object from the synclist.                                     */
  807 /* ------------------------------------------------------------------------ */
  808 static void
  809 ipf_sync_del(ipf_sync_softc_t *softs, synclist_t *sl)
  810 {
  811         *sl->sl_pnext = sl->sl_next;
  812         if (sl->sl_next != NULL)
  813                 sl->sl_next->sl_pnext = sl->sl_pnext;
  814         if (sl->sl_idx != -1)
  815                 softs->syncupd[sl->sl_idx].sup_hdr.sm_sl = NULL;
  816 }
  817 
  818 
  819 /* ------------------------------------------------------------------------ */
  820 /* Function:    ipf_sync_del_state                                          */
  821 /* Returns:     Nil                                                         */
  822 /* Parameters:  sl(I) - pointer to synclist object to delete                */
  823 /*                                                                          */
  824 /* Deletes an object from the synclist state table and free's its memory.   */
  825 /* ------------------------------------------------------------------------ */
  826 void
  827 ipf_sync_del_state(void *arg, synclist_t *sl)
  828 {
  829         ipf_sync_softc_t *softs = arg;
  830 
  831         WRITE_ENTER(&softs->ipf_syncstate);
  832         ipf_sync_del(softs, sl);
  833         RWLOCK_EXIT(&softs->ipf_syncstate);
  834         KFREE(sl);
  835 }
  836 
  837 
  838 /* ------------------------------------------------------------------------ */
  839 /* Function:    ipf_sync_del_nat                                            */
  840 /* Returns:     Nil                                                         */
  841 /* Parameters:  sl(I) - pointer to synclist object to delete                */
  842 /*                                                                          */
  843 /* Deletes an object from the synclist nat table and free's its memory.     */
  844 /* ------------------------------------------------------------------------ */
  845 void
  846 ipf_sync_del_nat(void *arg, synclist_t *sl)
  847 {
  848         ipf_sync_softc_t *softs = arg;
  849 
  850         WRITE_ENTER(&softs->ipf_syncnat);
  851         ipf_sync_del(softs, sl);
  852         RWLOCK_EXIT(&softs->ipf_syncnat);
  853         KFREE(sl);
  854 }
  855 
  856 
  857 /* ------------------------------------------------------------------------ */
  858 /* Function:    ipf_sync_nat                                                */
  859 /* Returns:     int    - 0 == success, else error value.                    */
  860 /* Parameters:  sp(I)  - pointer to sync packet data header                 */
  861 /*              uio(I) - pointer to user data for further information       */
  862 /*                                                                          */
  863 /* Updates the NAT  table according to information passed in the sync       */
  864 /* header.  As required, more data is fetched from the uio structure but    */
  865 /* varies depending on the contents of the sync header.  This function can  */
  866 /* create a new NAT entry or update one.  Deletion is left to the NAT       */
  867 /* structures being timed out correctly.                                    */
  868 /* ------------------------------------------------------------------------ */
  869 static int
  870 ipf_sync_nat(ipf_main_softc_t *softc, synchdr_t *sp, void *data)
  871 {
  872         ipf_sync_softc_t *softs = softc->ipf_sync_soft;
  873         syncupdent_t su;
  874         nat_t *n, *nat;
  875         synclist_t *sl;
  876         u_int hv = 0;
  877         int err = 0;
  878 
  879         READ_ENTER(&softs->ipf_syncnat);
  880 
  881         switch (sp->sm_cmd)
  882         {
  883         case SMC_CREATE :
  884                 KMALLOC(n, nat_t *);
  885                 if (n == NULL) {
  886                         IPFERROR(110017);
  887                         err = ENOMEM;
  888                         break;
  889                 }
  890 
  891                 KMALLOC(sl, synclist_t *);
  892                 if (sl == NULL) {
  893                         IPFERROR(110018);
  894                         err = ENOMEM;
  895                         KFREE(n);
  896                         break;
  897                 }
  898 
  899                 nat = (nat_t *)data;
  900                 bzero((char *)n, offsetof(nat_t, nat_age));
  901                 bcopy((char *)&nat->nat_age, (char *)&n->nat_age,
  902                       sizeof(*n) - offsetof(nat_t, nat_age));
  903                 ipf_sync_natorder(0, n);
  904                 n->nat_sync = sl;
  905                 n->nat_rev = sl->sl_rev;
  906 
  907                 sl->sl_idx = -1;
  908                 sl->sl_ipn = n;
  909                 sl->sl_num = ntohl(sp->sm_num);
  910 
  911                 WRITE_ENTER(&softc->ipf_nat);
  912                 sl->sl_pnext = softs->syncnattab + hv;
  913                 sl->sl_next = softs->syncnattab[hv];
  914                 if (softs->syncnattab[hv] != NULL)
  915                         softs->syncnattab[hv]->sl_pnext = &sl->sl_next;
  916                 softs->syncnattab[hv] = sl;
  917                 (void) ipf_nat_insert(softc, softc->ipf_nat_soft, n);
  918                 RWLOCK_EXIT(&softc->ipf_nat);
  919                 break;
  920 
  921         case SMC_UPDATE :
  922                 bcopy(data, &su, sizeof(su));
  923 
  924                 for (sl = softs->syncnattab[hv]; (sl != NULL);
  925                      sl = sl->sl_next)
  926                         if (sl->sl_hdr.sm_num == sp->sm_num)
  927                                 break;
  928                 if (sl == NULL) {
  929                         IPFERROR(110019);
  930                         err = ENOENT;
  931                         break;
  932                 }
  933 
  934                 READ_ENTER(&softc->ipf_nat);
  935 
  936                 nat = sl->sl_ipn;
  937                 nat->nat_rev = sl->sl_rev;
  938 
  939                 MUTEX_ENTER(&nat->nat_lock);
  940                 ipf_nat_setqueue(softc, softc->ipf_nat_soft, nat);
  941                 MUTEX_EXIT(&nat->nat_lock);
  942 
  943                 RWLOCK_EXIT(&softc->ipf_nat);
  944 
  945                 break;
  946 
  947         default :
  948                 IPFERROR(110020);
  949                 err = EINVAL;
  950                 break;
  951         }
  952 
  953         RWLOCK_EXIT(&softs->ipf_syncnat);
  954         return (err);
  955 }
  956 
  957 
  958 /* ------------------------------------------------------------------------ */
  959 /* Function:    ipf_sync_new                                                */
  960 /* Returns:     synclist_t* - NULL == failure, else pointer to new synclist */
  961 /*                            data structure.                               */
  962 /* Parameters:  tab(I) - type of synclist_t to create                       */
  963 /*              fin(I) - pointer to packet information                      */
  964 /*              ptr(I) - pointer to owning object                           */
  965 /*                                                                          */
  966 /* Creates a new sync table entry and notifies any sleepers that it's there */
  967 /* waiting to be processed.                                                 */
  968 /* ------------------------------------------------------------------------ */
  969 synclist_t *
  970 ipf_sync_new(ipf_main_softc_t *softc, int tab, fr_info_t *fin, void *ptr)
  971 {
  972         ipf_sync_softc_t *softs = softc->ipf_sync_soft;
  973         synclist_t *sl, *ss;
  974         synclogent_t *sle;
  975         u_int hv, sz;
  976 
  977         if (softs->sl_idx == softs->ipf_sync_log_sz)
  978                 return (NULL);
  979         KMALLOC(sl, synclist_t *);
  980         if (sl == NULL)
  981                 return (NULL);
  982 
  983         MUTEX_ENTER(&softs->ipf_syncadd);
  984         /*
  985          * Get a unique number for this synclist_t.  The number is only meant
  986          * to be unique for the lifetime of the structure and may be reused
  987          * later.
  988          */
  989         softs->ipf_sync_num++;
  990         if (softs->ipf_sync_num == 0) {
  991                 softs->ipf_sync_num = 1;
  992                 softs->ipf_sync_wrap++;
  993         }
  994 
  995         /*
  996          * Use the synch number of the object as the hash key.  Should end up
  997          * with relatively even distribution over time.
  998          * XXX - an attacker could lunch an DoS attack, of sorts, if they are
  999          * the only one causing new table entries by only keeping open every
 1000          * nth connection they make, where n is a value in the interval
 1001          * [0, SYNC_STATETABSZ-1].
 1002          */
 1003         switch (tab)
 1004         {
 1005         case SMC_STATE :
 1006                 hv = softs->ipf_sync_num & (softs->ipf_sync_state_tab_sz - 1);
 1007                 while (softs->ipf_sync_wrap != 0) {
 1008                         for (ss = softs->syncstatetab[hv]; ss; ss = ss->sl_next)
 1009                                 if (ss->sl_hdr.sm_num == softs->ipf_sync_num)
 1010                                         break;
 1011                         if (ss == NULL)
 1012                                 break;
 1013                         softs->ipf_sync_num++;
 1014                         hv = softs->ipf_sync_num &
 1015                              (softs->ipf_sync_state_tab_sz - 1);
 1016                 }
 1017                 sl->sl_pnext = softs->syncstatetab + hv;
 1018                 sl->sl_next = softs->syncstatetab[hv];
 1019                 softs->syncstatetab[hv] = sl;
 1020                 break;
 1021 
 1022         case SMC_NAT :
 1023                 hv = softs->ipf_sync_num & (softs->ipf_sync_nat_tab_sz - 1);
 1024                 while (softs->ipf_sync_wrap != 0) {
 1025                         for (ss = softs->syncnattab[hv]; ss; ss = ss->sl_next)
 1026                                 if (ss->sl_hdr.sm_num == softs->ipf_sync_num)
 1027                                         break;
 1028                         if (ss == NULL)
 1029                                 break;
 1030                         softs->ipf_sync_num++;
 1031                         hv = softs->ipf_sync_num &
 1032                              (softs->ipf_sync_nat_tab_sz - 1);
 1033                 }
 1034                 sl->sl_pnext = softs->syncnattab + hv;
 1035                 sl->sl_next = softs->syncnattab[hv];
 1036                 softs->syncnattab[hv] = sl;
 1037                 break;
 1038 
 1039         default :
 1040                 break;
 1041         }
 1042 
 1043         sl->sl_num = softs->ipf_sync_num;
 1044         MUTEX_EXIT(&softs->ipf_syncadd);
 1045 
 1046         sl->sl_magic = htonl(SYNHDRMAGIC);
 1047         sl->sl_v = fin->fin_v;
 1048         sl->sl_p = fin->fin_p;
 1049         sl->sl_cmd = SMC_CREATE;
 1050         sl->sl_idx = -1;
 1051         sl->sl_table = tab;
 1052         sl->sl_rev = fin->fin_rev;
 1053         if (tab == SMC_STATE) {
 1054                 sl->sl_ips = ptr;
 1055                 sz = sizeof(*sl->sl_ips);
 1056         } else if (tab == SMC_NAT) {
 1057                 sl->sl_ipn = ptr;
 1058                 sz = sizeof(*sl->sl_ipn);
 1059         } else {
 1060                 ptr = NULL;
 1061                 sz = 0;
 1062         }
 1063         sl->sl_len = sz;
 1064 
 1065         /*
 1066          * Create the log entry to be read by a user daemon.  When it has been
 1067          * finished and put on the queue, send a signal to wakeup any waiters.
 1068          */
 1069         MUTEX_ENTER(&softs->ipf_syncadd);
 1070         sle = softs->synclog + softs->sl_idx++;
 1071         bcopy((char *)&sl->sl_hdr, (char *)&sle->sle_hdr,
 1072               sizeof(sle->sle_hdr));
 1073         sle->sle_hdr.sm_num = htonl(sle->sle_hdr.sm_num);
 1074         sle->sle_hdr.sm_len = htonl(sle->sle_hdr.sm_len);
 1075         if (ptr != NULL) {
 1076                 bcopy((char *)ptr, (char *)&sle->sle_un, sz);
 1077                 if (tab == SMC_STATE) {
 1078                         ipf_sync_storder(1, &sle->sle_un.sleu_ips);
 1079                 } else if (tab == SMC_NAT) {
 1080                         ipf_sync_natorder(1, &sle->sle_un.sleu_ipn);
 1081                 }
 1082         }
 1083         MUTEX_EXIT(&softs->ipf_syncadd);
 1084 
 1085         ipf_sync_wakeup(softc);
 1086         return (sl);
 1087 }
 1088 
 1089 
 1090 /* ------------------------------------------------------------------------ */
 1091 /* Function:    ipf_sync_update                                             */
 1092 /* Returns:     Nil                                                         */
 1093 /* Parameters:  tab(I) - type of synclist_t to create                       */
 1094 /*              fin(I) - pointer to packet information                      */
 1095 /*              sl(I)  - pointer to synchronisation object                  */
 1096 /*                                                                          */
 1097 /* For outbound packets, only, create an sync update record for the user    */
 1098 /* process to read.                                                         */
 1099 /* ------------------------------------------------------------------------ */
 1100 void
 1101 ipf_sync_update(ipf_main_softc_t *softc, int tab, fr_info_t *fin,
 1102         synclist_t *sl)
 1103 {
 1104         ipf_sync_softc_t *softs = softc->ipf_sync_soft;
 1105         synctcp_update_t *st;
 1106         syncupdent_t *slu;
 1107         ipstate_t *ips;
 1108         nat_t *nat;
 1109         ipfrwlock_t *lock;
 1110 
 1111         if (fin->fin_out == 0 || sl == NULL)
 1112                 return;
 1113 
 1114         if (tab == SMC_STATE) {
 1115                 lock = &softs->ipf_syncstate;
 1116         } else {
 1117                 lock = &softs->ipf_syncnat;
 1118         }
 1119 
 1120         READ_ENTER(lock);
 1121         if (sl->sl_idx == -1) {
 1122                 MUTEX_ENTER(&softs->ipf_syncadd);
 1123                 slu = softs->syncupd + softs->su_idx;
 1124                 sl->sl_idx = softs->su_idx++;
 1125                 MUTEX_EXIT(&softs->ipf_syncadd);
 1126 
 1127                 bcopy((char *)&sl->sl_hdr, (char *)&slu->sup_hdr,
 1128                       sizeof(slu->sup_hdr));
 1129                 slu->sup_hdr.sm_magic = htonl(SYNHDRMAGIC);
 1130                 slu->sup_hdr.sm_sl = sl;
 1131                 slu->sup_hdr.sm_cmd = SMC_UPDATE;
 1132                 slu->sup_hdr.sm_table = tab;
 1133                 slu->sup_hdr.sm_num = htonl(sl->sl_num);
 1134                 slu->sup_hdr.sm_len = htonl(sizeof(struct synctcp_update));
 1135                 slu->sup_hdr.sm_rev = fin->fin_rev;
 1136 # if 0
 1137                 if (fin->fin_p == IPPROTO_TCP) {
 1138                         st->stu_len[0] = 0;
 1139                         st->stu_len[1] = 0;
 1140                 }
 1141 # endif
 1142         } else
 1143                 slu = softs->syncupd + sl->sl_idx;
 1144 
 1145         /*
 1146          * Only TCP has complex timeouts, others just use default timeouts.
 1147          * For TCP, we only need to track the connection state and window.
 1148          */
 1149         if (fin->fin_p == IPPROTO_TCP) {
 1150                 st = &slu->sup_tcp;
 1151                 if (tab == SMC_STATE) {
 1152                         ips = sl->sl_ips;
 1153                         st->stu_age = htonl(ips->is_die);
 1154                         st->stu_data[0].td_end = ips->is_send;
 1155                         st->stu_data[0].td_maxend = ips->is_maxsend;
 1156                         st->stu_data[0].td_maxwin = ips->is_maxswin;
 1157                         st->stu_state[0] = ips->is_state[0];
 1158                         st->stu_data[1].td_end = ips->is_dend;
 1159                         st->stu_data[1].td_maxend = ips->is_maxdend;
 1160                         st->stu_data[1].td_maxwin = ips->is_maxdwin;
 1161                         st->stu_state[1] = ips->is_state[1];
 1162                 } else if (tab == SMC_NAT) {
 1163                         nat = sl->sl_ipn;
 1164                         st->stu_age = htonl(nat->nat_age);
 1165                 }
 1166         }
 1167         RWLOCK_EXIT(lock);
 1168 
 1169         ipf_sync_wakeup(softc);
 1170 }
 1171 
 1172 
 1173 /* ------------------------------------------------------------------------ */
 1174 /* Function:    ipf_sync_flush_table                                        */
 1175 /* Returns:     int - number of entries freed by flushing table             */
 1176 /* Parameters:  tabsize(I) - size of the array pointed to by table          */
 1177 /*              table(I)   - pointer to sync table to empty                 */
 1178 /*                                                                          */
 1179 /* Walk through a table of sync entries and free each one.  It is assumed   */
 1180 /* that some lock is held so that nobody else tries to access the table     */
 1181 /* during this cleanup.                                                     */
 1182 /* ------------------------------------------------------------------------ */
 1183 static int
 1184 ipf_sync_flush_table(ipf_sync_softc_t *softs, int tabsize, synclist_t **table)
 1185 {
 1186         synclist_t *sl;
 1187         int i, items;
 1188 
 1189         items = 0;
 1190 
 1191         for (i = 0; i < tabsize; i++) {
 1192                 while ((sl = table[i]) != NULL) {
 1193                         switch (sl->sl_table) {
 1194                         case SMC_STATE :
 1195                                 if (sl->sl_ips != NULL)
 1196                                         sl->sl_ips->is_sync = NULL;
 1197                                 break;
 1198                         case SMC_NAT :
 1199                                 if (sl->sl_ipn != NULL)
 1200                                         sl->sl_ipn->nat_sync = NULL;
 1201                                 break;
 1202                         }
 1203                         if (sl->sl_next != NULL)
 1204                                 sl->sl_next->sl_pnext = sl->sl_pnext;
 1205                         table[i] = sl->sl_next;
 1206                         if (sl->sl_idx != -1)
 1207                                 softs->syncupd[sl->sl_idx].sup_hdr.sm_sl = NULL;
 1208                         KFREE(sl);
 1209                         items++;
 1210                 }
 1211         }
 1212 
 1213         return (items);
 1214 }
 1215 
 1216 
 1217 /* ------------------------------------------------------------------------ */
 1218 /* Function:    ipf_sync_ioctl                                              */
 1219 /* Returns:     int - 0 == success, != 0 == failure                         */
 1220 /* Parameters:  data(I) - pointer to ioctl data                             */
 1221 /*              cmd(I)  - ioctl command integer                             */
 1222 /*              mode(I) - file mode bits used with open                     */
 1223 /*                                                                          */
 1224 /* This function currently does not handle any ioctls and so just returns   */
 1225 /* EINVAL on all occasions.                                                 */
 1226 /* ------------------------------------------------------------------------ */
 1227 int
 1228 ipf_sync_ioctl(ipf_main_softc_t *softc, caddr_t data, ioctlcmd_t cmd,
 1229         int mode, int uid, void *ctx)
 1230 {
 1231         ipf_sync_softc_t *softs = softc->ipf_sync_soft;
 1232         int error, i;
 1233         SPL_INT(s);
 1234 
 1235         switch (cmd)
 1236         {
 1237         case SIOCIPFFL:
 1238                 error = BCOPYIN(data, &i, sizeof(i));
 1239                 if (error != 0) {
 1240                         IPFERROR(110023);
 1241                         error = EFAULT;
 1242                         break;
 1243                 }
 1244 
 1245                 switch (i)
 1246                 {
 1247                 case SMC_RLOG :
 1248                         SPL_NET(s);
 1249                         MUTEX_ENTER(&softs->ipsl_mutex);
 1250                         i = (softs->sl_tail - softs->sl_idx) +
 1251                             (softs->su_tail - softs->su_idx);
 1252                         softs->sl_idx = 0;
 1253                         softs->su_idx = 0;
 1254                         softs->sl_tail = 0;
 1255                         softs->su_tail = 0;
 1256                         MUTEX_EXIT(&softs->ipsl_mutex);
 1257                         SPL_X(s);
 1258                         break;
 1259 
 1260                 case SMC_NAT :
 1261                         SPL_NET(s);
 1262                         WRITE_ENTER(&softs->ipf_syncnat);
 1263                         i = ipf_sync_flush_table(softs, SYNC_NATTABSZ,
 1264                                                  softs->syncnattab);
 1265                         RWLOCK_EXIT(&softs->ipf_syncnat);
 1266                         SPL_X(s);
 1267                         break;
 1268 
 1269                 case SMC_STATE :
 1270                         SPL_NET(s);
 1271                         WRITE_ENTER(&softs->ipf_syncstate);
 1272                         i = ipf_sync_flush_table(softs, SYNC_STATETABSZ,
 1273                                                  softs->syncstatetab);
 1274                         RWLOCK_EXIT(&softs->ipf_syncstate);
 1275                         SPL_X(s);
 1276                         break;
 1277                 }
 1278 
 1279                 error = BCOPYOUT(&i, data, sizeof(i));
 1280                 if (error != 0) {
 1281                         IPFERROR(110022);
 1282                         error = EFAULT;
 1283                 }
 1284                 break;
 1285 
 1286         default :
 1287                 IPFERROR(110021);
 1288                 error = EINVAL;
 1289                 break;
 1290         }
 1291 
 1292         return (error);
 1293 }
 1294 
 1295 
 1296 /* ------------------------------------------------------------------------ */
 1297 /* Function:    ipf_sync_canread                                            */
 1298 /* Returns:     int - 0 == success, != 0 == failure                         */
 1299 /* Parameters:  Nil                                                         */
 1300 /*                                                                          */
 1301 /* This function provides input to the poll handler about whether or not    */
 1302 /* there is data waiting to be read from the /dev/ipsync device.            */
 1303 /* ------------------------------------------------------------------------ */
 1304 int
 1305 ipf_sync_canread(void *arg)
 1306 {
 1307         ipf_sync_softc_t *softs = arg;
 1308         return (!((softs->sl_tail == softs->sl_idx) &&
 1309                  (softs->su_tail == softs->su_idx)));
 1310 }
 1311 
 1312 
 1313 /* ------------------------------------------------------------------------ */
 1314 /* Function:    ipf_sync_canwrite                                           */
 1315 /* Returns:     int - 1 == can always write                                 */
 1316 /* Parameters:  Nil                                                         */
 1317 /*                                                                          */
 1318 /* This function lets the poll handler know that it is always ready willing */
 1319 /* to accept write events.                                                  */
 1320 /* XXX Maybe this should return false if the sync table is full?            */
 1321 /* ------------------------------------------------------------------------ */
 1322 int
 1323 ipf_sync_canwrite(void *arg)
 1324 {
 1325         return (1);
 1326 }
 1327 
 1328 
 1329 /* ------------------------------------------------------------------------ */
 1330 /* Function:    ipf_sync_wakeup                                             */
 1331 /* Parameters:  Nil                                                         */
 1332 /* Returns:     Nil                                                         */
 1333 /*                                                                          */
 1334 /* This function implements the heuristics that decide how often to         */
 1335 /* generate a poll wakeup for programs that are waiting for information     */
 1336 /* about when they can do a read on /dev/ipsync.                            */
 1337 /*                                                                          */
 1338 /* There are three different considerations here:                           */
 1339 /* - do not keep a program waiting too long: ipf_sync_wake_interval is the  */
 1340 /*   maximum number of ipf ticks to let pass by;                            */
 1341 /* - do not let the queue of ouststanding things to generate notifies for   */
 1342 /*   get too full (ipf_sync_queue_high_wm is the high water mark);          */
 1343 /* - do not let too many events get collapsed in before deciding that the   */
 1344 /*   other host(s) need an update (ipf_sync_event_high_wm is the high water */
 1345 /*   mark for this counter.)                                                */
 1346 /* ------------------------------------------------------------------------ */
 1347 static void
 1348 ipf_sync_wakeup(ipf_main_softc_t *softc)
 1349 {
 1350         ipf_sync_softc_t *softs = softc->ipf_sync_soft;
 1351 
 1352         softs->ipf_sync_events++;
 1353         if ((softc->ipf_ticks >
 1354             softs->ipf_sync_lastwakeup + softs->ipf_sync_wake_interval) ||
 1355             (softs->ipf_sync_events > softs->ipf_sync_event_high_wm) ||
 1356             ((softs->sl_tail - softs->sl_idx) >
 1357              softs->ipf_sync_queue_high_wm) ||
 1358             ((softs->su_tail - softs->su_idx) >
 1359              softs->ipf_sync_queue_high_wm)) {
 1360 
 1361                 ipf_sync_poll_wakeup(softc);
 1362         }
 1363 }
 1364 
 1365 
 1366 /* ------------------------------------------------------------------------ */
 1367 /* Function:    ipf_sync_poll_wakeup                                        */
 1368 /* Parameters:  Nil                                                         */
 1369 /* Returns:     Nil                                                         */
 1370 /*                                                                          */
 1371 /* Deliver a poll wakeup and reset counters for two of the three heuristics */
 1372 /* ------------------------------------------------------------------------ */
 1373 static void
 1374 ipf_sync_poll_wakeup(ipf_main_softc_t *softc)
 1375 {
 1376         ipf_sync_softc_t *softs = softc->ipf_sync_soft;
 1377 
 1378         softs->ipf_sync_events = 0;
 1379         softs->ipf_sync_lastwakeup = softc->ipf_ticks;
 1380 
 1381 # ifdef _KERNEL
 1382 #  if SOLARIS
 1383         MUTEX_ENTER(&softs->ipsl_mutex);
 1384         cv_signal(&softs->ipslwait);
 1385         MUTEX_EXIT(&softs->ipsl_mutex);
 1386         pollwakeup(&softc->ipf_poll_head[IPL_LOGSYNC], POLLIN|POLLRDNORM);
 1387 #  else
 1388         WAKEUP(&softs->sl_tail, 0);
 1389         POLLWAKEUP(IPL_LOGSYNC);
 1390 #  endif
 1391 # endif
 1392 }
 1393 
 1394 
 1395 /* ------------------------------------------------------------------------ */
 1396 /* Function:    ipf_sync_expire                                             */
 1397 /* Parameters:  Nil                                                         */
 1398 /* Returns:     Nil                                                         */
 1399 /*                                                                          */
 1400 /* This is the function called even ipf_tick.  It implements one of the     */
 1401 /* three heuristics above *IF* there are events waiting.                    */
 1402 /* ------------------------------------------------------------------------ */
 1403 void
 1404 ipf_sync_expire(ipf_main_softc_t *softc)
 1405 {
 1406         ipf_sync_softc_t *softs = softc->ipf_sync_soft;
 1407 
 1408         if ((softs->ipf_sync_events > 0) &&
 1409             (softc->ipf_ticks >
 1410              softs->ipf_sync_lastwakeup + softs->ipf_sync_wake_interval)) {
 1411                 ipf_sync_poll_wakeup(softc);
 1412         }
 1413 }

Cache object: c9ca6ed1c95176f96d0c76751bb71218


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


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