home *** CD-ROM | disk | FTP | other *** search
/ sustworks.com / 2014.06.sustworks.com.tar / sustworks.com / open_source_IPNetSentry_NKE.dmg / IPNetSentry_NKE.c < prev    next >
C/C++ Source or Header  |  2005-08-08  |  55KB  |  1,676 lines

  1. //
  2. //  IPNetSentry_NKE.c
  3. //  Mac OS X Interface Filter NKE
  4. //
  5. //  Created by psichel [PAS] on Teus Nov 12 2002.
  6. //  Based on SharedIP and TCPLogger provided as Open Source sample code
  7. //    from Apple Computer.
  8. //
  9. //    See IPNetSentry_NKE.h for high level design overview.
  10. //    You can send comments or suggestions to psichel@sustworks.com
  11. //    The companion IPNetSentryX controller application is available from
  12. //        http://www.sustworks.com
  13. //
  14. // ---------------------------------------------------------------------------------
  15. //    Portions Copyright (c) 1999-2002 Apple Computer, Inc. All Rights Reserved.
  16. //
  17. //    This file contains Original Code and/or Modifications of Original Code as defined
  18. //    in and that are subject to the Apple Public Source License Version 1.2 (the 'License').
  19. //    You may not use this file except in compliance with the License.
  20. //    Please obtain a copy of the License at http://www.apple.com/publicsource
  21. //    and read it before using this file.
  22. //
  23. //    The Original Code and all software distributed under the License are distributed
  24. //    on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
  25. //    AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION,
  26. //    ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
  27. //    ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the specific
  28. //    language governing rights and limitations under the License." 
  29. // ---------------------------------------------------------------------------------
  30.  
  31. #define DEBUG_IPK 0
  32. #if DEBUG_IPK
  33. #include <sys/syslog.h>
  34. #endif
  35. #include <sys/param.h>
  36. #include <sys/systm.h>
  37. #include <sys/socket.h>
  38. #include <sys/protosw.h>
  39. #include <sys/socketvar.h>
  40. #include <sys/fcntl.h>
  41. #include <sys/malloc.h>
  42. #include <sys/queue.h>
  43. #include <sys/domain.h>
  44. #include <sys/mbuf.h>
  45. #include <net/route.h>
  46. #include <net/if.h>
  47. #include <net/if_types.h>
  48. #include <net/if_dl.h>
  49. #include <net/ndrv.h>
  50. #include <net/kext_net.h>
  51. #include <net/dlil.h>
  52. #include <netinet/in.h>        // Needed for (*&^%$#@ arpcom in if_arp.h
  53. #include <net/ethernet.h>
  54. #include <net/if_arp.h>
  55. #include <machine/spl.h>
  56. #include <kern/thread.h>
  57. #include <libkern/OSAtomic.h>
  58.  
  59. #include PS_NKE_INCLUDE
  60. #include "IPTypes.h"
  61. #include "kft.h"
  62. #include "kftDelay.h"
  63. #include "kftTrigger.h"
  64. #include "kftConnectionTable.h"
  65. #if IPNetRouter
  66. #include "kftPortMapTable.h"
  67. #include "kftNatTable.h"
  68. #endif
  69. #include "FilterTypes.h"
  70.  
  71. // macro to convert kernel to external socket
  72. //#define sotoextcb(so) (struct kextcb *)(so->so_ext)
  73.  
  74. //extern void kprintf(const char *, ...);
  75.  
  76. //
  77. //    Forward function declarations
  78. //        Use unix style names (words separated by "_") for intercepts and callbacks
  79. //        Use Mac style names for internal functions (initial caps)
  80. //        Use ipk_ or ik_ prefix to avoid kernel name space conflicts
  81. //        ipk_ for PF_NKE and DLIL filter functions, ik_ for socket functions
  82. //
  83. //    PF_NKE socket functions
  84. int        ipk_connect();
  85. int        ipk_read();
  86. int     ipk_write();
  87. int        ipk_get();
  88. int        ipk_put();
  89. void    ipk_disconnect();
  90.  
  91. // socket interface functions our NKE will intercept
  92. int ik_close();
  93. int ik_connect();
  94. int ik_control();
  95. int ik_disconnect();
  96.  
  97. // dlil protocol filter functions our NKE can intercept
  98. int ipk_filter_pr_input();
  99. int ipk_filter_pr_output();
  100.  
  101. // dlil interface filter functions our NKE can intercept
  102. int ipk_filter_if_input();
  103. int ipk_filter_if_output();
  104.  
  105. // timer callbacks
  106. void ipk_timeout(void *cookie);
  107. // send message to controlling socket
  108. void PROJECT_sendMessage(struct socket *ctl, ipk_message_t *message);
  109.  
  110. // internal support functions
  111. static int ik_attachCount(int controlIndex);
  112. static int ik_controlCount(int attachIndex);
  113. static int ik_controlIndexForSocket(struct socket *so);
  114. static int ik_emptyControlIndex();
  115. static int ik_attachIndexForName(char *inName);
  116. static int ik_emptyAttachIndex();
  117. static int ik_findIFNet(char *inName, ifnet_t *ifnet_ref);
  118. static int ik_detachController(int controlIndex);
  119. static int ik_detachIndex(int attachIndex);
  120.  
  121. //
  122. // Global structures and data storage
  123. //
  124. // Dispatch vector for IPNetRouter_NKE/IPNetSentry_NKE socket intercepts
  125. struct sockif IKsockif = {
  126.     NULL,        // soabort
  127.     NULL,        // soaccept
  128.     NULL,        // sobind
  129.     ik_close,        // soclose
  130.     ik_connect,        // soconnect
  131.     NULL,        // soconnect2
  132.     ik_control,    // soset/getopt
  133.     NULL,        // socreate
  134.     ik_disconnect,        // sodisconnect
  135.     NULL,        // sofree
  136.     NULL,        // sogetopt
  137.     NULL,        // sohasoutofband
  138.     NULL,        // solisten
  139.     NULL,        // soreceive
  140.     NULL,        // sorflush
  141.     NULL,        // sosend
  142.     NULL,        // sosetopt
  143.     NULL,        // soshutdown
  144.     NULL,        // socantrcvmore
  145.     NULL,        // socantsendmore
  146.     NULL,        // soisconnected
  147.     NULL,        // soisconnecting
  148.     NULL,        // soisdisconnected
  149.     NULL,        // soisdisconnecting
  150.     NULL,        // sonewconn1
  151.     NULL,        // soqinsque
  152.     NULL,        // soqremque
  153.     NULL,        // soreserve
  154.     NULL,        // sowakeup
  155. };
  156.  
  157. // Dispatch vector for IPNetRouter_NKE/IPNetSentry socket buffer functions
  158. struct sockutil IKsockutil = {
  159.     NULL,    // sb_lock
  160.     NULL,    // sbappend
  161.     NULL,    // sbappendaddr
  162.     NULL,    // sbappendcontrol
  163.     NULL,    // sbappendrecord
  164.     NULL,    // sbcompress
  165.     NULL,    // sbdrop
  166.     NULL,    // sbdroprecord
  167.     NULL,    // sbflush
  168.     NULL,    // sbinsertoob
  169.     NULL,    // sbrelease
  170.     NULL,    // sbreserve
  171.     NULL,    // sbwait
  172. };
  173.  
  174. // Dispatch vector for PF_NKE socket control functions
  175. struct NFDescriptor IPNetSentry_NKE = {
  176.     {NULL, NULL},
  177.     {NULL, NULL},
  178.     IPNetSentry_NKE_Handle,
  179.     NFD_PROG|NFD_VISIBLE,    // Ask for me by name
  180. //    NFD_GLOBAL|NFS_VISIBLE,    // only if we want global filtering
  181.     ipk_connect,
  182.     ipk_disconnect,
  183.     ipk_read,
  184.     ipk_write,
  185.     ipk_get,
  186.     ipk_put,
  187.     &IKsockif, &IKsockutil
  188. };
  189.  
  190. // I include code for both DLIL protocol and DLIL interface filters.
  191. // I tried using a protocol filter first and discovered it did not
  192. // see traffic from the classic networking stack.  When using an
  193. // interface filter, we need to sort the traffic for different
  194. // protocols ourselves (IP vs AppleTalk...).
  195.  
  196. // Dispatch vector for DLIL protocol filter intercepts
  197. struct dlil_pr_flt_str IKprotocol_filter = {
  198.     NULL, // caddr_t cookie
  199.     ipk_filter_pr_input, // filter_dl_input
  200.     ipk_filter_pr_output, // filter_dl_output
  201.     NULL, // filter_dl_event
  202.     NULL, // filter_dl_ioctl
  203.     NULL, // filter_detach
  204. };
  205.  
  206. // Dispatch vector for DLIL interface filter intercepts
  207. struct dlil_if_flt_str IKinterface_filter = {
  208.     NULL, // caddr_t cookie
  209.     ipk_filter_if_input, // filter_if_input
  210.     NULL, // filter_if_event
  211.     ipk_filter_if_output, // filter_if_output
  212.     NULL, // filter_if_ioctl
  213.     NULL, // filter_if_free
  214.     NULL, // filter_detach
  215. };
  216.  
  217. // max size of drop Response
  218. #define KFT_dropResponseMax 1000
  219. // drop Connection response
  220. u_int8_t PROJECT_dropResponseBuffer[KFT_dropResponseMax];
  221. int PROJECT_dropResponseLength;
  222. // time of day info
  223. sopt_timeParam_t PROJECT_timeOfDay;
  224. // flags
  225. u_int32_t PROJECT_flags;
  226. // timer Ref Count (firewall enabled)
  227. int32_t PROJECT_timerRefCount;
  228.     // ipk_timeout reschedules itself when PROJECT_timerRefCount>0
  229. int PROJECT_doRateLimit;            // packet matched a rate limit rule
  230.     // index of failover requested 0=none, 1=default, 2=alternate gateway
  231. int PROJECT_failoverRequest;
  232.     // reserve bandwidth info
  233. KFT_reserveInfo_t PROJECT_rReserveInfo;
  234. KFT_reserveInfo_t PROJECT_sReserveInfo;
  235.  
  236.  
  237. //
  238. // Module wide variables (not exported)
  239. //
  240. // socket highwater mark for flow control
  241. //    make these big enough to hold our report data without starving kernel memory
  242. static int IPK_recvspace = 8192;
  243. static int IPK_sendspace = 8192;
  244.  
  245. static int32_t ipk_timerPending;
  246. static int ipk_initted = 0;
  247.  
  248.  
  249. //
  250. // Setup per instance structures and storage
  251. //
  252.  
  253. // maximum number of controllers and DLIL attachments use index values 1..n
  254. // 0 is reserved for "not found"
  255. //#define kMaxControl    8
  256. //#define kMaxAttach 8
  257.  
  258. // Array of controller instances
  259. static control_t PROJECT_control[kMaxControl+1];
  260.  
  261. // Global Array of DLIL attach instances
  262. attach_t PROJECT_attach[kMaxAttach+1];
  263.  
  264.  
  265. #pragma mark -- Load and unload kernel extension
  266. //
  267. // Load and unload kernel extension
  268. //
  269. // ---------------------------------------------------------------------------------
  270. //    Ñ IPNetSentry_NKE_start
  271. // ---------------------------------------------------------------------------------
  272. kern_return_t IPNetSentry_NKE_start (kmod_info_t * ki, void * d)
  273. {
  274.     int returnValue = KERN_SUCCESS;
  275.     struct protosw *pp;
  276.     int s;
  277.     int    funnel_state;
  278.     int i;
  279.     
  280.     #if IPNetRouter
  281.         printf("IPNetRouter_NKE has loaded!\n");
  282.     #else
  283.         printf("IPNetSentry_NKE has loaded!\n");
  284.     #endif
  285.  
  286.     // grab the network funnel and prevent other network threads from pre-empting us
  287.     funnel_state = thread_funnel_set(network_flock, TRUE);
  288.     s = splnet();
  289.  
  290.     do {
  291.         // already initialized?
  292.         if (ipk_initted) break;
  293.         
  294.         // initialize global storage
  295.         PROJECT_timerRefCount = 0;
  296.         ipk_timerPending = 0;
  297.         PROJECT_timeOfDay.timeStamp = 0;
  298.         PROJECT_flags = 0;
  299.         PROJECT_dropResponseLength = 0;
  300.         
  301.         // initialize our instance storage
  302.         for (i=0; i<=kMaxControl; i++) {
  303.             bzero(&PROJECT_control[i], sizeof(control_t));
  304.         }
  305.         for (i=0; i<=kMaxAttach; i++) {
  306.             bzero(&PROJECT_attach[i], sizeof(attach_t));
  307.         }
  308.         // setup KFT structures
  309.         KFT_init();
  310.         
  311.         // find the protosw we want to sidle up to
  312.             // we will use UDP for the control connection to our NKE
  313.         pp = pffindproto(AF_INET, IPPROTO_UDP, SOCK_DGRAM);
  314.         if (pp == NULL) {
  315.             returnValue = EPFNOSUPPORT;
  316.             break;
  317.         }
  318.         
  319.         // register our NKE
  320.         returnValue = register_sockfilter(&IPNetSentry_NKE, NULL, pp, NFF_AFTER);
  321.         if (returnValue == 0) {
  322.             ipk_initted = 1;
  323.             returnValue = KERN_SUCCESS;
  324.         }
  325.  
  326.     } while (FALSE);
  327.  
  328.     // restore previous priority level and thread funnel
  329.     splx(s);
  330.     thread_funnel_set(network_flock, funnel_state);
  331.  
  332.     return returnValue;
  333. }
  334.  
  335.  
  336. // ---------------------------------------------------------------------------------
  337. //    Ñ IPNetSentry_NKE_stop
  338. // ---------------------------------------------------------------------------------
  339. kern_return_t IPNetSentry_NKE_stop (kmod_info_t * ki, void * d) {
  340.     int returnValue = KERN_SUCCESS;
  341.     struct protosw *pp;
  342.     int s;
  343.     int    funnel_state;
  344.     int i;
  345.     u_long filterID;
  346.  
  347.     funnel_state = thread_funnel_set(network_flock, TRUE);
  348.     s = splnet();
  349.     do {
  350.         // if not initted
  351.         if (!ipk_initted) break;
  352.         
  353.         // unlink controllers and remove any DLIL attach instances
  354.         for (i=1; i<=kMaxControl; i++) {
  355.             if (PROJECT_control[i].ctl != 0) {
  356.                 ik_detachController(i);
  357.                 // tell any clients the socket has gone away
  358.                 // not sure how to do this, so just fail for now
  359.                 returnValue = KERN_FAILURE;    // fail until all sockets are disconnected
  360.                 break;
  361.             }
  362.         }
  363.         if (returnValue != 0) break;
  364.         
  365.         // remove any remaining attach instances (defensive)
  366.         for (i=1; i<=kMaxAttach; i++) {
  367.             if (filterID = PROJECT_attach[i].filterID != 0) {
  368.                 ik_detachIndex(i);
  369.                 #if DEBUG_IPK
  370.                     log(LOG_WARNING, "NKE_stop: detach protocol filter: %d\n",filterID);
  371.                 #endif
  372.             }
  373.         }
  374.         
  375.         // release KFT structures
  376.         KFT_terminate();
  377.         // need to cancel any pending kernel callbacks (timeout)
  378.             // fortunately we don't normally unload and can warn the user
  379.             // not to unload while any tools are running
  380.         // force timer ref count to zero
  381.         if (PROJECT_timerRefCount || ipk_timerPending) {
  382.             untimeout(ipk_timeout, (void *)0);
  383.             PROJECT_timerRefCount = 0;
  384.         }
  385.         
  386.         // unplug our socket filter
  387.         pp = pffindproto(AF_INET, IPPROTO_UDP, SOCK_DGRAM);
  388.         if (pp == NULL) {
  389.             returnValue = EPFNOSUPPORT;
  390.             break;
  391.         }
  392.         returnValue = unregister_sockfilter(&IPNetSentry_NKE, pp, 0);
  393.         if (returnValue == 0) {
  394.             ipk_initted = 0;    // don't allow multiples
  395.             returnValue = KERN_SUCCESS;
  396.         }
  397.     } while (FALSE);
  398.  
  399.     splx(s);
  400.     thread_funnel_set(network_flock, funnel_state);
  401.     
  402.     if (returnValue == 0) printf("IPNetSentry_NKE has unloaded!\n");
  403.  
  404.     return returnValue;
  405. }
  406.  
  407.  
  408. // ---------------------------------------------------------------------------------
  409. //    Ñ ik_control
  410. // ---------------------------------------------------------------------------------
  411. // intercept socket options (soset and soget)
  412. int ik_control(struct socket *so, struct sockopt *sopt, struct kextcb *kp)
  413. {
  414.     int returnValue = 0;    // continue normall processing (pass it on)
  415.     int result;
  416.     int controlIndex=0;
  417.     int attachIndex=0;
  418.     unsigned long count;    // copy out a single u_long
  419.  
  420.     int s;
  421.     int    funnel_state;
  422.  
  423.     do {
  424.         // find our controller instance
  425.         controlIndex = ik_controlIndexForSocket(so);
  426.         if (!controlIndex) {
  427.             // not yet connected, try to connect
  428.             returnValue = ipk_connect(so);
  429.             if (returnValue != EJUSTRETURN) break;
  430.             controlIndex = ik_controlIndexForSocket(so);
  431.             if (!controlIndex) {
  432.                 returnValue = ENOTCONN;
  433.                 break;
  434.             }
  435.         }
  436.     
  437.         switch(sopt->sopt_name) {
  438.             case SO_ATTACH_LINK:
  439.                 // grab the network funnel and prevent other network threads from pre-empting us
  440.                 funnel_state = thread_funnel_set(network_flock, TRUE);
  441.                 s = splnet();
  442.                 do {
  443.                     // attach a controller socket to an IP interface (data link)
  444.                     struct sopt_attachParam attachParam;
  445.                     u_long filterID;
  446.                     ifnet_t ifnet_ref;
  447.             // Reference: copyin and copyout option parameters
  448.             //int    sooptcopyin __P((struct sockopt *sopt, void *buf, size_t len, size_t minlen));
  449.             //int    sooptcopyout __P((struct sockopt *sopt, void *buf, size_t len));
  450.                     #if DEBUG_IPK
  451.                             log(LOG_WARNING, "ik_control: received SO_ATTACH_LINK\n");
  452.                     #endif
  453.                     // copyin option parameter
  454.                     returnValue = sooptcopyin(sopt, &attachParam, sizeof (struct sopt_attachParam),
  455.                                                                     sizeof (attachParam));
  456.                     if (returnValue != 0) break;
  457.  
  458.                     // look for existing DLIL attach by bsdName
  459.                     attachIndex = ik_attachIndexForName(attachParam.bsdName);
  460.                     if (attachIndex) {
  461.                         // found existing DLIL attach
  462.                         // associate this controller with DLIL attach
  463.                         PROJECT_control[controlIndex].attachMap[attachIndex] = 1;
  464.                         returnValue = EJUSTRETURN;
  465.                         break;            
  466.                     }                                    
  467.                     // did not find previous attachment
  468.                     // create a new DLIL attach instance for requested interface
  469.                         // find slot for attach instance
  470.                     attachIndex = ik_emptyAttachIndex();
  471.                     if (!attachIndex) {
  472.                         returnValue = EBUSY;
  473.                         break;
  474.                     }
  475.                         // set dlil dispatch cookie to point to this attach instance
  476.                     IKprotocol_filter.cookie = (caddr_t)&PROJECT_attach[attachIndex];
  477.                     IKinterface_filter.cookie = (caddr_t)&PROJECT_attach[attachIndex];
  478.                         // get ifnet_ref for corresponding interface
  479.                     returnValue = ik_findIFNet(attachParam.bsdName, &ifnet_ref);
  480.                     if (returnValue != 0) break;
  481.                         // attach our NKE as a protocol filter using dl_tag or
  482.                         // an interface filter using ifnet_ref
  483.                     if (attachParam.protocolFilter) {
  484.                         // get DLIL tag for protocol interface pair we're interested in
  485.                         u_long dl_tag;
  486.                         returnValue = dlil_find_dltag(ifnet_ref->if_family, ifnet_ref->if_unit, PF_INET, &dl_tag);
  487.                         if (returnValue != 0) break;
  488.                         // attach our NKE as a protocol filter
  489.                         returnValue = dlil_attach_protocol_filter(dl_tag, &IKprotocol_filter,
  490.                                 &filterID, DLIL_LAST_FILTER);
  491.                         if (returnValue != 0) break;            
  492.                         #if DEBUG_IPK
  493.                         log(LOG_WARNING, "ik_control: protocol filter on %s\n", attachParam.bsdName);
  494.                         #endif
  495.                     }
  496.                     else {
  497.                         returnValue = dlil_attach_interface_filter(ifnet_ref, &IKinterface_filter,
  498.                                 &filterID, DLIL_LAST_FILTER);
  499.                         if (returnValue != 0) break;
  500.                         #if DEBUG_IPK
  501.                         log(LOG_WARNING, "ik_control: interface filter on %s\n", attachParam.bsdName);
  502.                         #endif
  503.                     }
  504.  
  505.                     // initialize attach instance and remember dlil attach info
  506.                     {
  507.                         int len;
  508.                         bzero(&PROJECT_attach[attachIndex], sizeof(attach_t));
  509.                         PROJECT_attach[attachIndex].filterID = filterID;
  510.                         PROJECT_attach[attachIndex].ifnet_ref = ifnet_ref;
  511.                         PROJECT_attach[attachIndex].attachIndex = attachIndex;
  512.                         // default to filter on
  513.                         PROJECT_attach[attachIndex].kftInterfaceEntry.filterOn = 1;
  514.                         // remember interface name as CString
  515.                         len = strlen(attachParam.bsdName);
  516.                         memcpy(&PROJECT_attach[attachIndex].kftInterfaceEntry.bsdName[0],
  517.                                         &attachParam.bsdName[0], len+1);
  518.                         // associate this controller with DLIL attach
  519.                         PROJECT_control[controlIndex].attachMap[attachIndex] = 1;
  520.                         #if DEBUG_IPK
  521.                                 log(LOG_WARNING, "ik_control control instance: %d attach instance: %d attach filterID: %d\n",
  522.                                         controlIndex, attachIndex, filterID);
  523.                         #endif
  524.                     }
  525.                     // Everything worked, Yay!
  526.                     returnValue = EJUSTRETURN;                    
  527.                 } while (FALSE);
  528.                 // restore previous priority level and thread funnel
  529.                 splx(s);
  530.                 thread_funnel_set(network_flock, funnel_state);    
  531.                 break;
  532.             case SO_DETACH_LINK:
  533.                 // grab the network funnel and prevent other network threads from pre-empting us
  534.                 funnel_state = thread_funnel_set(network_flock, TRUE);
  535.                 s = splnet();
  536.                 do {
  537.                     // detach specified interface from controller socket
  538.                     struct sopt_attachParam attachParam;
  539.                     #if DEBUG_IPK
  540.                         log(LOG_WARNING, "ik_control: received SO_DETACH_LINK\n");
  541.                     #endif
  542.                     // make sure delay table is empty before detaching from any interfaces
  543.                     KFT_delayAge(0);                
  544.                     // if name is nil, detach controller and any dlil attachments
  545.                     if (sopt->sopt_valsize == 0) {
  546.                         #if DEBUG_IPK
  547.                             log(LOG_WARNING, "ik_control detach all interfaces\n");
  548.                         #endif
  549.                         returnValue = ik_detachController(controlIndex);
  550.                         if (returnValue != 0) break;
  551.                         returnValue = EJUSTRETURN;
  552.                         break;
  553.                     }
  554.                     // copyin option parameter
  555.                     returnValue = sooptcopyin(sopt, &attachParam, sizeof(struct sopt_attachParam),
  556.                                             sopt->sopt_valsize);
  557.                     if (returnValue != 0) break;
  558.                     // look for existing DLIL attach by bsdName
  559.                     attachIndex = ik_attachIndexForName(attachParam.bsdName);
  560.                     if (attachIndex) {
  561.                         // found existing DLIL attach
  562.                         // dis-associate this controller with DLIL attach
  563.                         PROJECT_control[controlIndex].attachMap[attachIndex] = 0;
  564.                         // are there any more references?
  565.                         if (ik_controlCount(attachIndex) == 0) {
  566.                             #if DEBUG_IPK
  567.                             u_long filterID = PROJECT_attach[attachIndex].filterID;
  568.                             #endif
  569.                             // no more references to this attach instance
  570.                             // detach our NKE from this interface
  571.                             returnValue = ik_detachIndex(attachIndex);
  572.                             #if DEBUG_IPK
  573.                                 log(LOG_WARNING, "ik_control control instance: %d attach instance: %d detach filterID: %d\n",
  574.                                     controlIndex, attachIndex, filterID);
  575.                             #endif
  576.                         }
  577.                     }
  578.                     else {
  579.                         returnValue = ENOENT;
  580.                         break;
  581.                     }
  582.                     returnValue = EJUSTRETURN;
  583.                 } while (FALSE);
  584.                 // restore previous priority level and thread funnel
  585.                 splx(s);
  586.                 thread_funnel_set(network_flock, funnel_state);
  587.                 break;
  588.             case SO_MONITOR_ON:
  589.                 do {
  590.                     #if DEBUG_IPK
  591.                         log(LOG_WARNING, "ik_control: received SO_MONITOR_ON\n");
  592.                     #endif
  593.                     // reset nkeSends to tell NKE we want more
  594.                     PROJECT_control[controlIndex].nkeSends = 0;
  595.                     // check for attachment to an interface
  596.                     if (ik_attachCount(controlIndex) == 0) {
  597.                         returnValue = ENOENT;
  598.                         break;
  599.                     }
  600.                     // if monitoring is not already on
  601.                     if (PROJECT_control[controlIndex].monitorOn == 0) {
  602.                         PROJECT_control[controlIndex].monitorOn = 1;
  603.                         // start 1-second timer to send interface stats upstream
  604.                         //PROJECT_timerRefCount += 1;
  605.                         result = OSAddAtomic(1, (SInt32*)&PROJECT_timerRefCount);
  606.                         result = OSAddAtomic(1, (SInt32*)&ipk_timerPending);
  607.                         if (result == 0) {    // timer is not running
  608.                             #if DEBUG_IPK
  609.                                 log(LOG_WARNING, "ik_control: start timer\n");
  610.                             #endif
  611.                             ipk_timeout((void *)0);
  612.                         }
  613.                     }
  614.                     returnValue = EJUSTRETURN;
  615.                 } while (FALSE);
  616.                 break;
  617.             case SO_MONITOR_OFF:
  618.                 do {
  619.                     #if DEBUG_IPK
  620.                         log(LOG_WARNING, "ik_control: received SO_MONITOR_OFF\n");
  621.                     #endif
  622.                     PROJECT_control[controlIndex].monitorOn = 0;
  623.                     // bump timer ref count
  624.                     //PROJECT_timerRefCount -= 1;
  625.                     result = OSAddAtomic(-1, (SInt32*)&PROJECT_timerRefCount);
  626.                     if (result <= 0) PROJECT_timerRefCount = 0;    // defensive
  627.                     // report current connection table
  628.                     {
  629.                         // grab the network funnel and prevent other network threads from pre-empting us
  630.                         funnel_state = thread_funnel_set(network_flock, TRUE);
  631.                         s = splnet();
  632.                         
  633.                         KFT_connectionReport();
  634.                         // restore previous priority level and thread funnel
  635.                         splx(s);
  636.                         thread_funnel_set(network_flock, funnel_state);                    
  637.                     }
  638.                     returnValue = EJUSTRETURN;
  639.                 } while (FALSE);
  640.                 break;
  641.             case SO_FILTER_DOWNLOAD:
  642.                 // grab the network funnel and prevent other network threads from pre-empting us
  643.                 funnel_state = thread_funnel_set(network_flock, TRUE);
  644.                 s = splnet();
  645.                 do {
  646.                     #if DEBUG_IPK
  647.                         log(LOG_WARNING, "ik_control: received SO_FILTER_DOWNLOAD\n");
  648.                     #endif
  649.                     // copyin option parameter
  650.                     returnValue = sooptcopyin(sopt, kft_filterTableD.bytes,
  651.                         kft_filterTableD.bufferLength, sopt->sopt_valsize);
  652.                     if (returnValue != 0) break;
  653.                     #if DEBUG_IPK
  654.                         log(LOG_WARNING, "ik_control: sooptcopyin OK\n");
  655.                     #endif
  656.                     kft_filterTableD.length = sopt->sopt_valsize;
  657.                     if (kft_filterTableD.length >= kft_filterTableD.bufferLength) {
  658.                         kft_filterTableD.length = kft_filterTableD.bufferLength;
  659.                         #if DEBUG_IPK
  660.                         log(LOG_WARNING, "SO_FILTER_DOWNLOAD buffer space exceeded.\n");
  661.                         #endif
  662.                         returnValue = EMSGSIZE;
  663.                         break;
  664.                     }
  665.                     kft_filterTableD.offset = kft_filterTableD.length/sizeof(KFT_filterEntry_t);
  666.                     returnValue = EJUSTRETURN;
  667.                 } while (FALSE);
  668.                 // restore previous priority level and thread funnel
  669.                 splx(s);
  670.                 thread_funnel_set(network_flock, funnel_state);    
  671.                 break;
  672.             case SO_FILTER_UPLOAD: {
  673.                 #if DEBUG_IPK
  674.                     log(LOG_WARNING, "ik_control: received SO_FILTER_UPLOAD\n");
  675.                 #endif
  676.                 returnValue = sooptcopyout(sopt, kft_filterTableD.bytes, kft_filterTableD.length);
  677.                 if (returnValue != 0) break;
  678.                 #if DEBUG_IPK
  679.                     log(LOG_WARNING, "ik_control: sooptcopyout OK %d\n",outBuf.length);
  680.                 #endif
  681.                 returnValue = EJUSTRETURN;
  682.                 break;
  683.             }
  684.             case SO_KFT_RESET: {
  685.                 #if DEBUG_IPK
  686.                     log(LOG_WARNING, "ik_control: received SO_KFT_RESET\n");
  687.                 #endif
  688.                 // grab the network funnel and prevent other network threads from pre-empting us
  689.                     funnel_state = thread_funnel_set(network_flock, TRUE);
  690.                     s = splnet();
  691.                 // reset selected state before downloading
  692.                 KFT_reset();
  693.                 // restore previous priority level and thread funnel
  694.                     splx(s);
  695.                     thread_funnel_set(network_flock, funnel_state);    
  696.                 returnValue = EJUSTRETURN;
  697.                 break;
  698.             }
  699.             case SO_FILTER_COUNT: {
  700.                 #if DEBUG_IPK
  701.                     log(LOG_WARNING, "ik_control: received SO_FILTER_COUNT\n");
  702.                 #endif
  703.                 count = KFT_filterCount();
  704.                 returnValue = sooptcopyout(sopt, &count, sizeof(count));
  705.                 if (returnValue != 0) break;
  706.                 returnValue = EJUSTRETURN;
  707.                 break;
  708.             }
  709.             case SO_TRIGGER_COUNT: {
  710.                 #if DEBUG_IPK
  711.                     log(LOG_WARNING, "ik_control: received SO_TRIGGER_COUNT\n");
  712.                 #endif
  713.                 count = KFT_triggerCount();
  714.                 returnValue = sooptcopyout(sopt, &count, sizeof(count));
  715.                 if (returnValue != 0) break;
  716.                 returnValue = EJUSTRETURN;
  717.                 break;
  718.             }
  719.             case SO_INTERFACE_COUNT: {
  720.                 #if DEBUG_IPK
  721.                     log(LOG_WARNING, "ik_control: received SO_INTERFACE_COUNT\n");
  722.                 #endif
  723.                 count = ik_attachCount(controlIndex);
  724.                 returnValue = sooptcopyout(sopt, &count, sizeof(count));
  725.                 if (returnValue != 0) break;
  726.                 returnValue = EJUSTRETURN;
  727.                 break;
  728.             }
  729. #ifdef IPNetRouter
  730.             case SO_PORTMAP_COUNT: {
  731.                 #if DEBUG_IPK
  732.                     log(LOG_WARNING, "ik_control: received SO_PORTMAP_COUNT\n");
  733.                 #endif
  734.                 count = KFT_portMapCount();
  735.                 returnValue = sooptcopyout(sopt, &count, sizeof(count));
  736.                 if (returnValue != 0) break;
  737.                 returnValue = EJUSTRETURN;
  738.                 break;
  739.             }
  740. #endif
  741.             case SO_SET_TIME: {
  742.                 // set time of day info for NKE
  743.                 #if DEBUG_IPK
  744.                     log(LOG_WARNING, "ik_control: received SO_SET_TIME\n");
  745.                 #endif
  746.                 // copyin option parameter
  747.                 returnValue = sooptcopyin(sopt, &PROJECT_timeOfDay, sizeof (struct sopt_timeParam),
  748.                                         sopt->sopt_valsize);
  749.                 if (returnValue != 0) break;
  750.                 returnValue = EJUSTRETURN;
  751.                 break;
  752.             }
  753.             
  754.             case SO_SET_FLAGS: {
  755.                 // set global NKE flags
  756.                 sopt_flagsParam_t flagsParam;
  757.                 // copyin option parameter
  758.                 returnValue = sooptcopyin(sopt, &flagsParam, sizeof(struct sopt_flagsParam), sopt->sopt_valsize);
  759.                 if (returnValue != 0) break;
  760.                 PROJECT_flags &= ~flagsParam.mask;    // clear bits we're going to modify
  761.                 PROJECT_flags |= flagsParam.flags;    // set bits to effect change
  762.                 returnValue = EJUSTRETURN;
  763.                 break;
  764.             }
  765.             case SO_GET_FLAGS: {
  766.                 // get global NKE flags
  767.                 sopt_flagsParam_t flagsParam;
  768.                 flagsParam.flags = PROJECT_flags;
  769.                 flagsParam.mask = 0xFFFFFFFF;
  770.                 // return current value
  771.                 returnValue = sooptcopyout(sopt, &flagsParam, sizeof(flagsParam));
  772.                 if (returnValue != 0) break;
  773.                 returnValue = EJUSTRETURN;
  774.                 break;
  775.             }
  776.             
  777.             case SO_DROP_RESPONSE: {
  778.                 #if DEBUG_IPK
  779.                     log(LOG_WARNING, "ik_control: received SO_DROP_RESPONSE\n");
  780.                 #endif
  781.                 // copyin option parameter
  782.                 // leave room for link header, ip header, tcp header
  783.                 returnValue = sooptcopyin(sopt, &PROJECT_dropResponseBuffer[60], KFT_dropResponseMax-60, sopt->sopt_valsize);
  784.                 PROJECT_dropResponseLength = sopt->sopt_valsize;
  785.                 if (returnValue != 0) break;
  786.                 #if DEBUG_IPK
  787.                     log(LOG_WARNING, "ik_control: sooptcopyin OK %d\n",PROJECT_dropResponseLength);
  788.                 #endif
  789.                 returnValue = EJUSTRETURN;
  790.                 break;
  791.             }
  792.             case SO_TRIGGER_DURATION: {
  793.                 #if DEBUG_IPK
  794.                     log(LOG_WARNING, "ik_control: received SO_TRIGGER_EXPIRATION\n");
  795.                 #endif
  796.                 // copyin option parameter
  797.                 returnValue = sooptcopyin(sopt, &count, sizeof(count),
  798.                                         sopt->sopt_valsize);
  799.                 if (returnValue != 0) break;
  800.                 count = KFT_triggerDuration(count);
  801.                 // return current value
  802.                 returnValue = sooptcopyout(sopt, &count, sizeof(count));
  803.                 if (returnValue != 0) break;
  804.                 returnValue = EJUSTRETURN;
  805.                 break;
  806.             }        
  807.             case SO_TRIGGER_ADDRESS: {
  808.                 KFT_triggerKey_t value[101];
  809.                 int howMany;
  810.                 int s;
  811.                 int    funnel_state;    
  812.                 #if DEBUG_IPK
  813.                     log(LOG_WARNING, "ik_control: received SO_TRIGGER_ADDRESS\n");
  814.                 #endif
  815.                 // copyin option parameter
  816.                 returnValue = sooptcopyin(sopt, value, sizeof(KFT_triggerKey_t)*100,
  817.                                         sopt->sopt_valsize);
  818.                 if (returnValue != 0) break;
  819.                 howMany = sopt->sopt_valsize/sizeof(KFT_triggerKey_t);
  820.                 // grab the network funnel
  821.                     funnel_state = thread_funnel_set(network_flock, TRUE);
  822.                     s = splnet();
  823.                 KFT_triggerRemoveByKey(value, howMany);
  824.                 // restore previous priority level and thread funnel
  825.                     splx(s);
  826.                     thread_funnel_set(network_flock, funnel_state);
  827.                 // are there any more updates to send?
  828.                 KFT_triggerSendUpdates();
  829.                 returnValue = EJUSTRETURN;
  830.                 break;
  831.             }
  832.             case SO_TRIGGER_UPLOAD: {
  833.                 #if DEBUG_IPK
  834.                     log(LOG_WARNING, "ik_control: received SO_TRIGGER_UPLOAD\n");
  835.                 #endif
  836.                 // grab the network funnel and prevent other network threads from pre-empting us
  837.                     funnel_state = thread_funnel_set(network_flock, TRUE);
  838.                     s = splnet();
  839.                 count = KFT_triggerUpload();
  840.                 sooptcopyout(sopt, &count, sizeof(count));
  841.                 // restore previous priority level and thread funnel
  842.                     splx(s);
  843.                     thread_funnel_set(network_flock, funnel_state);    
  844.                 returnValue = EJUSTRETURN;
  845.                 break;
  846.             }
  847.             case SO_INTERFACE_UPLOAD: {
  848.                 #if DEBUG_IPK
  849.                     log(LOG_WARNING, "ik_control: received SO_INTERFACE_UPLOAD\n");
  850.                 #endif
  851.                 // grab the network funnel and prevent other network threads from pre-empting us
  852.                     funnel_state = thread_funnel_set(network_flock, TRUE);
  853.                     s = splnet();
  854.                 count = KFT_interfaceUpload();
  855.                 sooptcopyout(sopt, &count, sizeof(count));
  856.                 // restore previous priority level and thread funnel
  857.                     splx(s);
  858.                     thread_funnel_set(network_flock, funnel_state);    
  859.                 returnValue = EJUSTRETURN;
  860.                 break;
  861.             }
  862. #ifdef IPNetRouter
  863.             case SO_PORTMAP_UPLOAD: {
  864.                 #if DEBUG_IPK
  865.                     log(LOG_WARNING, "ik_control: received SO_PORTMAP_UPLOAD\n");
  866.                 #endif
  867.                 // grab the network funnel and prevent other network threads from pre-empting us
  868.                     funnel_state = thread_funnel_set(network_flock, TRUE);
  869.                     s = splnet();
  870.                 count = KFT_portMapUpload();
  871.                 sooptcopyout(sopt, &count, sizeof(count));
  872.                 // restore previous priority level and thread funnel
  873.                     splx(s);
  874.                     thread_funnel_set(network_flock, funnel_state);    
  875.                 returnValue = EJUSTRETURN;
  876.                 break;
  877.             }
  878.             case SO_NAT_UPLOAD: {
  879.                 #if DEBUG_IPK
  880.                     log(LOG_WARNING, "ik_control: received SO_NAT_UPLOAD\n");
  881.                 #endif
  882.                 // grab the network funnel and prevent other network threads from pre-empting us
  883.                     funnel_state = thread_funnel_set(network_flock, TRUE);
  884.                     s = splnet();
  885.                 count = KFT_natUpload();
  886.                 sooptcopyout(sopt, &count, sizeof(count));
  887.                 // restore previous priority level and thread funnel
  888.                     splx(s);
  889.                     thread_funnel_set(network_flock, funnel_state);    
  890.                 returnValue = EJUSTRETURN;
  891.                 break;
  892.             }
  893. #endif
  894.             case SO_IPK_MESSAGE: {
  895.                 // accept ipk_message as downstream data
  896.                 unsigned char buffer[kUpdateBufferSize];
  897.                 ipk_message_t* message;
  898.                 message = (ipk_message_t*)&buffer[0];
  899.                 #if DEBUG_IPK
  900.                     log(LOG_WARNING, "ik_control: received SO_IPK_MESSAGE\n");
  901.                 #endif
  902.     // Reference: copyin and copyout option parameters
  903.     //int    sooptcopyin __P((struct sockopt *sopt, void *buf, size_t len, size_t minlen));
  904.     //int    sooptcopyout __P((struct sockopt *sopt, void *buf, size_t len));
  905.                 // copyin option parameter
  906.                 returnValue = sooptcopyin(sopt, &buffer[0], kUpdateBufferSize, sizeof(ipk_message_t));
  907.                 if (returnValue != 0) break;
  908.                 // pass along to KFT for processing
  909.                 KFT_receiveMessage(message);
  910.                 returnValue = EJUSTRETURN;
  911.                 break;
  912.             }
  913.             default: {
  914.                 #if DEBUG_IPK
  915.                     log(LOG_WARNING, "ik_control: default unrecognized sopt->sopt_name=%x pass it on\n", sopt->sopt_name);
  916.                 #endif
  917.                 returnValue = 0;
  918.                 break;
  919.             }
  920.         }    // end switch
  921.     } while (FALSE);
  922.     #if 0
  923.         log(LOG_WARNING, "ik_control returnValue: %d\n", returnValue);
  924.     #endif    
  925.     return returnValue;
  926. }
  927.  
  928.  
  929. // ---------------------------------------------------------------------------------
  930. //    Ñ ik_connect
  931. // ---------------------------------------------------------------------------------
  932. //    intercept soconnect
  933. int
  934. ik_connect(struct socket *so, struct sockaddr *nam)
  935. {
  936.     ipk_connect(so);
  937.     return 0;
  938. }
  939.  
  940. // ---------------------------------------------------------------------------------
  941. //    Ñ ik_disconnect
  942. // ---------------------------------------------------------------------------------
  943. //    intercept sodisconnect
  944. int
  945. ik_disconnect(struct socket *so, register struct kextcb *kp)
  946. {
  947.     ipk_disconnect(so);
  948.     return 0;
  949. }
  950.  
  951. // ---------------------------------------------------------------------------------
  952. //    Ñ ik_close
  953. // ---------------------------------------------------------------------------------
  954. //    intercept soclose
  955. int
  956. ik_close(struct socket *so, register struct kextcb *kp)
  957. {
  958.     // socket is being closed:
  959.     //     disconnect, turn off monitoring, and detach from dlil if no more references.
  960.     // - Any open sockets will be closed by the kernel when the process quits,
  961.     //   so this is our big chance to clean up properly regardless of how the
  962.     //   companion application died.
  963.     ipk_disconnect(so);
  964.     return 0;
  965. }
  966.  
  967.  
  968. //
  969. // We have a control (PF_NKE) socket expressing interest.
  970. //
  971. // ---------------------------------------------------------------------------------
  972. //    Ñ ipk_connect
  973. // ---------------------------------------------------------------------------------
  974. //    Register connection between controller socket and our NKE
  975. //    Called via PF_NKE, ik_control (set_SO) and also soconnect (standard UDP)
  976. int ipk_connect(register struct socket *cso)
  977. {
  978.     int returnValue = 0;
  979.     int controlIndex;
  980.     int s;
  981.     int funnel_state;
  982. #if DEBUG_IPK
  983.             log(LOG_WARNING, "ipk_connect\n");
  984. #endif
  985.     // grab the network funnel and prevent other network threads from pre-empting us
  986.     funnel_state = thread_funnel_set(network_flock, TRUE);
  987.     s = splnet();
  988.  
  989.     do {
  990.         // check if this controller socket is already connected
  991.         controlIndex = ik_controlIndexForSocket(cso);
  992.         if (controlIndex) {    // found it
  993.             returnValue = EISCONN;
  994.             break;
  995.         }
  996.         // reserve socket buffer space if needed
  997.         if (cso->so_snd.sb_hiwat == 0 || cso->so_rcv.sb_hiwat == 0) {
  998.             returnValue = soreserve(cso, IPK_sendspace, IPK_recvspace);
  999.             if (returnValue != 0) break;
  1000.         }
  1001.         // find slot for connection instance
  1002.         controlIndex = ik_emptyControlIndex();
  1003.         if (!controlIndex) {
  1004.             returnValue = EBUSY;
  1005.             break;        // all connection slots full
  1006.         }
  1007.         // register we have a connection
  1008.         PROJECT_control[controlIndex].ctl = cso;
  1009.         returnValue = EJUSTRETURN;
  1010.     } while (FALSE);
  1011.  
  1012.     // restore previous priority level and thread funnel
  1013.     splx(s);
  1014.     thread_funnel_set(network_flock, funnel_state);    
  1015.     return returnValue;
  1016. }
  1017.  
  1018.  
  1019. // ---------------------------------------------------------------------------------
  1020. //    Ñ ipk_disconnect
  1021. // ---------------------------------------------------------------------------------
  1022. void ipk_disconnect(register struct socket *cso)
  1023. {
  1024.     int controlIndex;
  1025.     int s;
  1026.     int funnel_state;
  1027.  
  1028.     #if DEBUG_IPK
  1029.         log(LOG_WARNING, "ipk_disconnect\n");
  1030.     #endif
  1031.     // grab the network funnel and prevent other network threads from pre-empting us
  1032.     funnel_state = thread_funnel_set(network_flock, TRUE);
  1033.     s = splnet();
  1034.     
  1035.     // check if this controller socket is connected and remove it
  1036.     controlIndex = ik_controlIndexForSocket(cso);
  1037.     if (controlIndex) {    // found it
  1038.         // remove reference to dlil attach instance and clear control instance
  1039.         ik_detachController(controlIndex);
  1040.     }
  1041.     
  1042.     // restore previous priority level and thread funnel
  1043.     splx(s);
  1044.     thread_funnel_set(network_flock, funnel_state);    
  1045. }
  1046.  
  1047. int ipk_get()
  1048. {
  1049.     return(0);
  1050. }
  1051.  
  1052. int ipk_read()
  1053. {
  1054.     return(0);
  1055. }
  1056.  
  1057. int ipk_put()
  1058. {
  1059.     return(0);
  1060. }
  1061.  
  1062. int ipk_write()
  1063. {
  1064.     return(0);
  1065. }
  1066.  
  1067. //
  1068. // dlil protocol filter functions our NKE will intercept
  1069. //
  1070. // ---------------------------------------------------------------------------------
  1071. //    Ñ ipk_filter_pr_input
  1072. // ---------------------------------------------------------------------------------
  1073. //  protocol filter NKE intercept input datagram
  1074. int ipk_filter_pr_input(caddr_t    cookie, 
  1075.                struct mbuf    **m, 
  1076.                char        **frame_header, 
  1077.                struct ifnet **ifp)
  1078. {
  1079.     int returnValue = 0;
  1080.     struct mbuf *dg;    // mbuf chain for datagram
  1081.     attach_t* myAttach;
  1082.     // get access to our attach instance
  1083.     myAttach = (attach_t*)cookie;
  1084.     // examine the mbuf chain to determine the data length
  1085.         // for more information on mbufs, see TCP/IP Illustrated Volume 2,
  1086.         // "The Implementation" by Wright and Stevens
  1087.     dg = *m;    // first mbuf chain
  1088.     if (dg) {
  1089.         if (dg->m_flags & M_PKTHDR) {
  1090.             // count receive traffic
  1091.             myAttach->receiveCount += dg->m_pkthdr.len;
  1092.                 // dlil filters execute at splnet so we should be safe here
  1093.                 // need to set splnet to access receiveCount from other contexts
  1094.             // IP filtering
  1095.             if (0) {
  1096.                 KFT_packetData_t packet;
  1097.                 bzero(&packet, sizeof(packet));
  1098.                 packet.ipOffset = 0;
  1099.                 packet.direction = 1;
  1100.                 packet.myAttach = myAttach;
  1101.                 returnValue = KFT_filterPacket(&packet);
  1102.             }
  1103.         }
  1104.     }
  1105.     return returnValue;
  1106. }
  1107.  
  1108. // ---------------------------------------------------------------------------------
  1109. //    Ñ ipk_filter_pr_output
  1110. // ---------------------------------------------------------------------------------
  1111. //  protocol filter NKE intercept output datagram
  1112. int ipk_filter_pr_output(caddr_t        cookie, 
  1113.                 struct mbuf        **m, 
  1114.                 struct ifnet    **ifp, 
  1115.                 struct sockaddr **dest,
  1116.                 char            *dest_linkaddr, 
  1117.                 char        *frame_type)
  1118. {
  1119.     int returnValue = 0;
  1120.     struct mbuf *dg;    // mbuf chain for datagram
  1121.     attach_t* myAttach;
  1122.     // get access to our attach instance
  1123.     myAttach = (attach_t*)cookie;
  1124.     // examine the mbuf chain to determine the data length
  1125.     dg = *m;    // first mbuf chain
  1126.     if (dg) {
  1127.         if (dg->m_flags & M_PKTHDR) {
  1128.             // count send traffic
  1129.             myAttach->sendCount += dg->m_pkthdr.len;
  1130.                 // dlil filters execute at splnet so we should be safe here
  1131.                 // need to set splnet to access sendCount from other contexts
  1132.             // IP filtering
  1133.             if (0) {
  1134.                 KFT_packetData_t packet;
  1135.                 bzero(&packet, sizeof(packet));
  1136.                 packet.ipOffset = 0;
  1137.                 packet.direction = 0;
  1138.                 packet.myAttach = myAttach;
  1139.                 returnValue = KFT_filterPacket(&packet);
  1140.             }
  1141.         }
  1142.     }
  1143.     return returnValue;
  1144. }
  1145.  
  1146. //
  1147. // dlil interface filter functions our NKE will intercept
  1148. // Notice dlil will call us for each packet with m->m_nextpkt == NULL
  1149. // ---------------------------------------------------------------------------------
  1150. //    Ñ ipk_filter_if_input
  1151. // ---------------------------------------------------------------------------------
  1152. //  interface filter NKE intercept input datagram
  1153. int    ipk_filter_if_input(caddr_t         cookie,
  1154.                struct ifnet    **ifnet_ptr,
  1155.                struct mbuf     **mbuf_ptr,
  1156.                char           **frame_ptr)
  1157. {
  1158.     int returnValue = 0;
  1159.     ifnet_t ifnet_ref;
  1160.     mbuf_t m;    // mbuf chain for datagram
  1161.     attach_t* myAttach;
  1162.     u_char interfaceType = 0;
  1163.     u_char headerLength = 0;
  1164.     // get access to our attach instance
  1165.     myAttach = (attach_t*)cookie;
  1166.     // hardware info
  1167.     if (ifnet_ref = *ifnet_ptr) {
  1168.         interfaceType = ifnet_ref->if_type;
  1169.         headerLength = ifnet_ref->if_hdrlen;
  1170.     }
  1171.     // examine the mbuf chain to process IP datagrams
  1172.         // for more information on mbufs, see TCP/IP Illustrated Volume 2,
  1173.         // "The Implementation" by Wright and Stevens
  1174.     do {
  1175.         if ((m = *mbuf_ptr) == NULL) break;
  1176.         if (m->m_flags & M_PKTHDR) {
  1177.             // add to receive count
  1178.             myAttach->receiveCount += m->m_pkthdr.len;
  1179.                 // dlil filters execute at splnet so we should be safe here
  1180.                 // need to set splnet to access receiveCount from other contexts            
  1181.             // IP filtering
  1182.             if (PROJECT_timerRefCount) {
  1183.                 KFT_packetData_t packet;
  1184.                 bzero(&packet, sizeof(packet));
  1185.                 // passed in
  1186.                 packet.ifnet_ref = ifnet_ref;
  1187.                 packet.mbuf_ptr = mbuf_ptr;
  1188.                 packet.frame_ptr = frame_ptr;
  1189.                 packet.myAttach = myAttach;        // cookie
  1190.                 // link layer info
  1191.                 packet.ifType = interfaceType;
  1192.                 packet.ifHeaderLen = headerLength;
  1193.                 // check frame header for IP
  1194.                 if (interfaceType == IFT_ETHER) {
  1195.                     u_int16_t* dp16;
  1196.                     if (*frame_ptr) {    // defensive
  1197.                         dp16 = (u_int16_t*)(*frame_ptr);
  1198.                         if (dp16[6] != 0x0800) packet.bridgeNonIP = 1;
  1199.                     }
  1200.                 }
  1201.                 // packet  info
  1202.                 packet.ipOffset = 0;
  1203.                 packet.direction = 1;
  1204.                 // pass to filter
  1205.                 returnValue = KFT_filterPacket(&packet);
  1206.             }
  1207.         }
  1208.     } while (FALSE);
  1209.     return returnValue;
  1210. }
  1211.  
  1212.  
  1213. // ---------------------------------------------------------------------------------
  1214. //    Ñ ipk_filter_if_output
  1215. // ---------------------------------------------------------------------------------
  1216. //  interface filter NKE intercept output datagram
  1217. int    ipk_filter_if_output(caddr_t      cookie,
  1218.                 struct ifnet **ifnet_ptr,
  1219.                 struct mbuf  **mbuf_ptr)
  1220. {
  1221.     int returnValue = 0;
  1222.     ifnet_t ifnet_ref;
  1223.     mbuf_t m;
  1224.     attach_t* myAttach;
  1225.     u_char interfaceType = 0;
  1226.     u_char headerLength = 0;
  1227.     // get access to our attach instance
  1228.     myAttach = (attach_t*)cookie;
  1229.     // hardware info
  1230.     if (ifnet_ref = *ifnet_ptr) {    // defensive
  1231.         interfaceType = ifnet_ref->if_type;
  1232.         headerLength = ifnet_ref->if_hdrlen;
  1233.     }
  1234.     // examine the mbuf chain to process IP datagragms
  1235.     do {
  1236.         if ((m = *mbuf_ptr) == NULL) break;
  1237.         if (m->m_flags & M_PKTHDR) {
  1238.             // add to receive count
  1239.             myAttach->sendCount += (m->m_pkthdr.len - headerLength);
  1240.                 // dlil filters execute at splnet so we should be safe here
  1241.                 // need to set splnet to access sendCount from other contexts
  1242.             if (interfaceType == IFT_PPP) {
  1243.                 // fix header to work around PPP bug
  1244.                 if ((m->m_data[headerLength-2] & 0xF0) == 0x40) headerLength -= 2;
  1245.             }
  1246.             // IP filtering
  1247.             if (PROJECT_timerRefCount) {
  1248.                 KFT_packetData_t packet;
  1249.                 bzero(&packet, sizeof(packet));
  1250.                 // passed in
  1251.                 packet.ifnet_ref = ifnet_ref;
  1252.                 packet.mbuf_ptr = mbuf_ptr;
  1253.                 packet.frame_ptr = 0;
  1254.                 packet.myAttach = myAttach;
  1255.                 // link layer info
  1256.                 packet.ifType = interfaceType;
  1257.                 packet.ifHeaderLen = headerLength;
  1258.                 // check frame header for IP
  1259.                 if (interfaceType == IFT_ETHER) {
  1260.                     u_int16_t* dp16;
  1261.                     dp16 = (u_int16_t*)m->m_data;
  1262.                     if (dp16[6] != 0x0800) packet.bridgeNonIP = 1;
  1263.                 }
  1264.                 // packet info
  1265.                 packet.ipOffset = headerLength;        // output packets preceeded by frame header
  1266.                 packet.direction = 0;
  1267.                 // pass to filter
  1268.                 returnValue = KFT_filterPacket(&packet);
  1269.             }
  1270.         }
  1271.     } while (FALSE);
  1272.     return returnValue;
  1273. }
  1274.  
  1275.  
  1276. // ---------------------------------------------------------------------------------
  1277. //    Ñ ipk_timeout
  1278. // ---------------------------------------------------------------------------------
  1279. //    one second timer used for monitoring
  1280. //    reschedules itself to be called each second when timerRefCount > 0
  1281. void ipk_timeout(void *cookie)
  1282. {
  1283.     extern int hz;    // number of clock ticks that occur in one second
  1284.     int s;
  1285.     int    funnel_state;
  1286.  
  1287.     // grab the network funnel and prevent other network threads from pre-empting us
  1288.     funnel_state = thread_funnel_set(network_flock, TRUE);
  1289.     s = splnet();
  1290.  
  1291.     KFT_filterPeriodical();
  1292.     // reschedule ourself if anyone needs us
  1293.         // timeout(void (*func)(), void *cookie, int ticks);
  1294.     if (PROJECT_timerRefCount > 0) {
  1295.         ipk_timerPending = TRUE;
  1296.         timeout(ipk_timeout, (void *)0, hz);
  1297.     }
  1298.     else {
  1299.         ipk_timerPending = FALSE;
  1300.         #if DEBUG_IPK
  1301.             log(LOG_WARNING, "ipk_timeout: stop timer\n");
  1302.         #endif
  1303.     }
  1304.     
  1305.     // restore previous priority level and thread funnel
  1306.     splx(s);
  1307.     thread_funnel_set(network_flock, funnel_state);
  1308. }
  1309.  
  1310.  
  1311. // ---------------------------------------------------------------------------------
  1312. //    Ñ PROJECT_sendMessageToAll
  1313. // ---------------------------------------------------------------------------------
  1314. //     send message to each active controller
  1315. void PROJECT_sendMessageToAll(ipk_message_t *message)
  1316. {
  1317.     int i;
  1318.     for (i=1;i<=kMaxControl;i++) {
  1319.         if (PROJECT_control[i].ctl) {
  1320.             // increment NKE sends since last request so we don't
  1321.             // keep flooding input queue when no one is listening.
  1322.             PROJECT_control[i].nkeSends += 1;
  1323.             if (PROJECT_control[i].nkeSends < 250) {        // max messages allowed in 2.5 seconds
  1324.                 PROJECT_sendMessage(PROJECT_control[i].ctl, message);
  1325.             }
  1326.         }
  1327.     }
  1328. }
  1329.  
  1330. // ---------------------------------------------------------------------------------
  1331. //    Ñ PROJECT_sendMessage
  1332. // ---------------------------------------------------------------------------------
  1333. //     send message to controlling socket
  1334. void PROJECT_sendMessage(struct socket *ctl, ipk_message_t *message)
  1335. {
  1336.     struct mbuf *m;
  1337.     int s;
  1338.     int    funnel_state;
  1339.     
  1340.     // grab the network funnel and prevent other network threads from pre-empting us
  1341.     funnel_state = thread_funnel_set(network_flock, TRUE);
  1342.     s = splnet();
  1343.  
  1344.     do {
  1345.         char *p;    
  1346.         if (!ctl) break;    // defensive
  1347.         // make sure we have room
  1348.         if (sbspace(&ctl->so_rcv) < message->length) break;
  1349.         // get an mbuf to hold message
  1350.             // just discard if we can't get a buffer (M_NOWAIT)
  1351.             // since we're at splnet and holding the network funnel
  1352.         MGETHDR(m, M_NOWAIT, MT_DATA);
  1353.         if (m == NULL) break;
  1354.         // get a cluster to handle messages longer than 100 bytes
  1355.         if (message->length >= 100) {
  1356.             MCLGET(m, M_NOWAIT);
  1357.             // check if we got it
  1358.             if (!(m->m_flags & M_EXT)) {
  1359.                 m_freem(m);
  1360.                 break;
  1361.             }
  1362.         }
  1363.         // align mbuf data to long word boundary
  1364.         p = m->m_data;
  1365.         p = (char *)(((int)p+3)&(~0x3));    
  1366.         m->m_data = (caddr_t)p;
  1367.         // copy message to our mbuf and set data length
  1368.         bcopy(message, mtod(m, caddr_t), message->length);
  1369.         m->m_len = message->length;
  1370.         // append our mbuf to socket receive queue
  1371.         //sbappend(&ctl->so_rcv, m);
  1372.         sbappendrecord(&ctl->so_rcv, m);
  1373.         // wake any process waiting for read on this socket
  1374.         sorwakeup(ctl);
  1375.         // the mbuf we allocated should be released when the socket is read
  1376.     } while (FALSE);
  1377.     
  1378.     // restore previous priority level and thread funnel
  1379.     splx(s);
  1380.     thread_funnel_set(network_flock, funnel_state);
  1381. }
  1382.  
  1383. // ---------------------------------------------------------------------------------
  1384. //    Ñ ik_attachCount
  1385. // ---------------------------------------------------------------------------------
  1386. // how many attachments does this controller reference
  1387. static int ik_attachCount(int controlIndex)
  1388. {
  1389.     int count, i;
  1390.     count = 0;
  1391.     // valid controlIndex?
  1392.     if ((controlIndex > 0) && (controlIndex <= kMaxControl)) {
  1393.         // for each attach instance
  1394.         for (i=1; i<=kMaxAttach; i++) {
  1395.             // does this controller reference it
  1396.             if (PROJECT_control[controlIndex].attachMap[i]) count += 1;
  1397.         }
  1398.     }
  1399.     return count;    
  1400. }
  1401.  
  1402. // ---------------------------------------------------------------------------------
  1403. //    Ñ ik_controlCount
  1404. // ---------------------------------------------------------------------------------
  1405. // how many controllers reference this attachment
  1406. static int ik_controlCount(int attachIndex)
  1407. {
  1408.     int count, i;
  1409.     count = 0;
  1410.     // valid attachIndex?
  1411.     if ((attachIndex > 0) && (attachIndex <= kMaxAttach)) {
  1412.         // for each control instance
  1413.         for (i=1; i<=kMaxControl; i++) {
  1414.             // does it reference this attach instance
  1415.             if (PROJECT_control[i].attachMap[attachIndex]) count += 1;
  1416.         }
  1417.     }
  1418.     return count;
  1419. }
  1420.  
  1421. // ---------------------------------------------------------------------------------
  1422. //    Ñ ik_controlIndexForSocket
  1423. // ---------------------------------------------------------------------------------
  1424. //    Find controller instance with corresponding socket if any and pass back it's index.
  1425. //    Returns 0 for not found
  1426. static int ik_controlIndexForSocket(struct socket *so)
  1427. {
  1428.     int returnValue = 0;        // controller not connected ENOTCONN
  1429.     int i;
  1430.     
  1431.     for (i=1; i<=kMaxControl; i++) {
  1432.         if (PROJECT_control[i].ctl == so) {
  1433.             returnValue = i;
  1434.             break;
  1435.         }
  1436.     }
  1437.     return returnValue;
  1438. }
  1439.  
  1440.  
  1441. // ---------------------------------------------------------------------------------
  1442. //    Ñ ik_emptyControlIndex
  1443. // ---------------------------------------------------------------------------------
  1444. //    Find an empty controller instance (available slot)
  1445. //    Returns 0 for not found
  1446. static int ik_emptyControlIndex()
  1447. {
  1448.     int returnValue = 0;        // all slots in use EBUSY
  1449.     int i;
  1450.     
  1451.     for (i=1; i<=kMaxControl; i++) {
  1452.         if (PROJECT_control[i].ctl == 0) {
  1453.             returnValue = i;
  1454.             break;
  1455.         }
  1456.     }
  1457.     return returnValue;
  1458. }
  1459.  
  1460. // ---------------------------------------------------------------------------------
  1461. //    Ñ ik_attachIndexForName
  1462. // ---------------------------------------------------------------------------------
  1463. //    Find attach instance with corresponding bsdName.
  1464. //    Return 0 for not found.
  1465. static int ik_attachIndexForName(char *inName)
  1466. {
  1467.     int returnValue = 0;    // no such entry ENOENT
  1468.     int i;
  1469.     int len;
  1470.     
  1471.     len = strlen(inName);
  1472.     for (i=1; i<=kMaxAttach; i++) {
  1473.         if ( memcmp(inName, &PROJECT_attach[i].kftInterfaceEntry.bsdName[0], len) == 0 ) {
  1474.             returnValue = i;
  1475.             break;
  1476.         }
  1477.     }
  1478.     return returnValue;
  1479. }
  1480.  
  1481. // ---------------------------------------------------------------------------------
  1482. //    Ñ ik_emptyAttachIndex
  1483. // ---------------------------------------------------------------------------------
  1484. //    Find an empty attach instance (available slot)
  1485. //    Return 0 for not found
  1486. static int ik_emptyAttachIndex()
  1487. {
  1488.     int returnValue = 0;    // all slots in use EBUSY
  1489.     int i;
  1490.     
  1491.     for (i=1; i<=kMaxAttach; i++) {
  1492.         if (PROJECT_attach[i].filterID == 0) {
  1493.             returnValue = i;
  1494.             break;
  1495.         }
  1496.     }
  1497.     return returnValue;
  1498. }
  1499.  
  1500.  
  1501. // ---------------------------------------------------------------------------------
  1502. //    Ñ ik_findIFNet
  1503. // ---------------------------------------------------------------------------------
  1504. static int ik_findIFNet(char *inName, ifnet_t *ifnet_ref)
  1505. //     return 0 if ifnet was found, otherwise unix error
  1506. //
  1507. //    For insertering our NKE below IP as an interface filter, we use the ifnet
  1508. //    global variable which points to the list of ifnet structures and scan the
  1509. //    list to find the desired ifnet structure with matching interface name.
  1510. {
  1511.     int returnValue = ENOENT;
  1512.     extern    struct ifnethead ifnet;
  1513.     struct ifnet *ifp;
  1514.     int len, unit, i;
  1515.     short match;
  1516.     
  1517.     do {
  1518.         if (!inName) break;            // defensive - name is null
  1519.         len = strlen(inName) - 1;
  1520.         unit = inName[len] - '0';    // get unit from end of name of the form "en0"
  1521.         
  1522.         // walk the ifnet list
  1523.         for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) {
  1524.             // testing: list interfaces 
  1525.                 //log(LOG_WARNING, "ik_findIFNet interface name: %s unit: %d\n",
  1526.                 //    ifp->if_name, ifp->if_unit);            
  1527.             // check name length
  1528.             if (len != strlen(ifp->if_name)) continue;
  1529.             // compare base name
  1530.             match = 1;
  1531.             for (i=0; i<len; i++) {
  1532.                 if (inName[i] != ifp->if_name[i]) {
  1533.                     match = 0;
  1534.                     break;
  1535.                 }
  1536.             }
  1537.             if (!match) continue;
  1538.             // names match, check unit
  1539.             if (unit != ifp->if_unit) continue;
  1540.             // we found a match
  1541.             *ifnet_ref = ifp;
  1542.             returnValue = 0;
  1543.             break;
  1544.         }
  1545.     } while (FALSE);
  1546.     return returnValue;
  1547. }
  1548.  
  1549. // ---------------------------------------------------------------------------------
  1550. //    Ñ ik_detachController
  1551. // ---------------------------------------------------------------------------------
  1552. //    Detach controller and remove any dlil interface attachments
  1553. //    that are no longer referenced.  Finally, clear the control instance.
  1554. //
  1555. //    return 0 for success or unix error code
  1556. static int ik_detachController(int controlIndex)
  1557. {
  1558.     int returnValue=0;
  1559.     int attachIndex;
  1560.     int result;
  1561.     do {
  1562.         if (!controlIndex) break;    // no control instance, we're done
  1563.         // make sure delay table is empty before detaching from any interfaces
  1564.         KFT_delayAge(0);                
  1565.         // if controller was monitoring, turn it off
  1566.         // - user might quit app without stopping or closing monitor window
  1567.         if (PROJECT_control[controlIndex].monitorOn) {
  1568.             PROJECT_control[controlIndex].monitorOn = 0;
  1569.             // bump timer ref count
  1570.             //PROJECT_timerRefCount -= 1;
  1571.             //if (PROJECT_timerRefCount < 0) PROJECT_timerRefCount = 0;
  1572.             result = OSAddAtomic(-1, (SInt32*)&PROJECT_timerRefCount);
  1573.             if (result <= 0) PROJECT_timerRefCount = 0;    // defensive
  1574.         }
  1575.         // get corresponding attach instances
  1576.         for (attachIndex=1;attachIndex<=kMaxAttach;attachIndex++) {
  1577.             if (PROJECT_control[controlIndex].attachMap[attachIndex]) {
  1578.                 // remove our reference to attach instance
  1579.                 PROJECT_control[controlIndex].attachMap[attachIndex] = 0;            
  1580.                 // are there any more references?
  1581.                 if (ik_controlCount(attachIndex) == 0) {
  1582.                     // no more references to this attach instance
  1583.                     returnValue = ik_detachIndex(attachIndex);
  1584.                 }
  1585.             }    // end found attach instance
  1586.         }    // end for each attach instance
  1587.         // clear control instance
  1588.         bzero(&PROJECT_control[controlIndex], sizeof(control_t));
  1589.     } while (FALSE);
  1590.     return returnValue;
  1591. }
  1592.  
  1593. // ---------------------------------------------------------------------------------
  1594. //    Ñ ik_detachIndex
  1595. // ---------------------------------------------------------------------------------
  1596. // detach our NKE for corresponding attach instance
  1597. // return 0 for success or unix error code
  1598. static int ik_detachIndex(int attachIndex)
  1599. {
  1600.     int returnValue = 0;
  1601.     u_long filterID;
  1602.     char logBuffer[80];
  1603.  
  1604.     // disable promisc mode if we enabled it
  1605.     if (PROJECT_attach[attachIndex].promiscOn) {
  1606.         ifnet_t ifnet_ref;
  1607.         // get ifnet_ref for corresponding interface
  1608.         returnValue = ik_findIFNet(PROJECT_attach[attachIndex].kftInterfaceEntry.bsdName, &ifnet_ref);
  1609.         if (returnValue == 0) {    
  1610.             // disable promiscuous mode
  1611.             int s, ret ;
  1612.             s = splimp();
  1613.             ret = ifpromisc(ifnet_ref, 0);
  1614.             splx(s);
  1615.             strcpy(&logBuffer[0], "\nik_detachIndex set promiscOn=0 for: ");
  1616.             strcat(&logBuffer[0], PROJECT_attach[attachIndex].kftInterfaceEntry.bsdName);
  1617.             KFT_logText(logBuffer,NULL);
  1618.         }
  1619.     }
  1620.  
  1621.     // detach our NKE from this interface and clear instance
  1622.     filterID = PROJECT_attach[attachIndex].filterID;
  1623.     if (filterID) returnValue = dlil_detach_filter(filterID);
  1624.     bzero(&PROJECT_attach[attachIndex], sizeof(attach_t));
  1625.     
  1626.     return returnValue;
  1627. }
  1628.  
  1629. // ---------------------------------------------------------------------------------
  1630. //    Ñ PROJECT_modifyReadyPacket
  1631. // ---------------------------------------------------------------------------------
  1632. // Tiger: prepare packet to be modified by finalizing and setting appropriate mbuf flags, return 0
  1633. // Panther: return 1 if outbound hardware TCP checksum is enabled so calculation should be skipped
  1634. // (no easy way to "finalize" in Panther)
  1635. int PROJECT_modifyReadyPacket(KFT_packetData_t* packet)
  1636. {
  1637.     int returnValue = 0;
  1638.     mbuf_t mbuf_ref;
  1639. #if TIGER
  1640.     if (packet->modifyReady == 0) {
  1641.         mbuf_ref = *(packet->mbuf_ptr);
  1642.         if (packet->direction == kDirectionInbound) {
  1643.             mbuf_inbound_modified(mbuf_ref);
  1644.         }
  1645.         else {
  1646.             mbuf_outbound_finalize(mbuf_ref, AF_INET, packet->ipOffset);
  1647.             #if 1
  1648.                 mbuf_csum_request_flags_t request;
  1649.                 u_int32_t value;
  1650.                 mbuf_get_csum_requested(mbuf_ref, &request, &value);
  1651.                 // work around bug in 10.4.2
  1652.                 if (request & 0x1000) returnValue = 1;
  1653.                 if (request & MBUF_CSUM_REQ_TCP) returnValue = 1;
  1654.                 //KFT_logText("csum_requested ", &request);
  1655.             #endif
  1656.         }
  1657.         // remember what we did
  1658.         packet->modifyReady = 1;
  1659.     }
  1660. #else
  1661.     mbuf_ref = *(packet->mbuf_ptr);
  1662.     if (packet->direction == kDirectionInbound) {
  1663.         // invalidate HW generated checksum flags
  1664.         mbuf_ref->m_pkthdr.csum_data = 0;
  1665.         mbuf_ref->m_pkthdr.csum_flags = 0;
  1666.         //if ((mbuf_ref->m_pkthdr.csum_flags & CSUM_TCP_SUM16) &&
  1667.         //    (mbuf_ref->m_pkthdr.csum_flags & CSUM_DATA_VALID)) returnValue = 1;
  1668.     }
  1669.     else {
  1670.         // Notice for outgoing packets the tcp checksum may not include the TCP header yet
  1671.         if (mbuf_ref->m_pkthdr.csum_flags & CSUM_TCP_SUM16) returnValue = 1;
  1672.     }
  1673. #endif
  1674.     return returnValue;
  1675. }
  1676.