home *** CD-ROM | disk | FTP | other *** search
/ sustworks.com / 2014.06.sustworks.com.tar / sustworks.com / open_source_IPNetMonitor_NKE.dmg / IPNetMonitor_NKE.c < prev    next >
Text File  |  2005-03-09  |  49KB  |  1,396 lines

  1. //
  2. //  IPNetMonitor_NKE.c
  3. //  Mac OS X Interface Filter NKE
  4. //
  5. //  Created by psichel [PAS] on Wed Mar 27 2002.
  6. //  Based on SharedIP and TCPLogger provided as Open Source sample code
  7. //    from Apple Computer.
  8. //
  9. //    See IPNetMonitor_NKE.h for high level design overview.
  10. //    You can send comments or suggestions to psichel@sustworks.com
  11. //    The companion IPNetMonitorX 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 IPK_DEBUG 0
  32. #if IPK_DEBUG
  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 "IPNetMonitor_NKE.h"
  60. #include <libkern/OSTypes.h>
  61. #include <string.h>
  62. int     memcmp(const void *, const void *, size_t);
  63.  
  64. // macro to convert kernel to external socket
  65. //#define sotoextcb(so) (struct kextcb *)(so->so_ext)
  66.  
  67. //extern void kprintf(const char *, ...);
  68.  
  69. //
  70. //    Forward function declarations
  71. //        Use unix style names (words separated by "_") for intercepts and callbacks
  72. //        Use Mac style names for internal functions (initial caps)
  73. //        Use ipk_ or ik_ prefix to avoid kernel name space conflicts
  74. //        ipk_ for PF_NKE and DLIL filter functions, ik_ for socket functions
  75. //
  76. //    PF_NKE socket functions
  77. static int ipk_connect();
  78. static int ipk_read();
  79. static int ipk_write();
  80. static int ipk_get();
  81. static int ipk_put();
  82. static void ipk_disconnect();
  83.  
  84. // socket interface functions our NKE will intercept
  85. static int ik_close();
  86. static int ik_connect();
  87. static int ik_control();
  88. static int ik_disconnect();
  89.  
  90. // dlil protocol filter functions our NKE can intercept
  91. static int ipk_filter_dl_input();
  92. static int ipk_filter_dl_output();
  93.  
  94. // dlil interface filter functions our NKE can intercept
  95. static int ipk_filter_if_input();
  96. static int ipk_filter_if_output();
  97.  
  98. // timer callbacks
  99. static void ipk_timeout(void *cookie);
  100. static void ipk_periodical();
  101. // send message to controlling socket
  102. void PROJECT_sendMessage(struct socket *ctl, ipk_message_t *message);
  103.  
  104. // internal support functions
  105. static int ik_attachCount(int controlIndex);
  106. static int ik_controlCount(int attachIndex);
  107. static int ik_controlIndexForSocket(struct socket *so);
  108. static int ik_emptyControlIndex();
  109. static int ik_attachIndexForTag(u_long dl_tag);
  110. static int ik_attachIndexForName(char *inName);
  111. static int ik_emptyAttachIndex();
  112. static int ik_findIFNet(char *inName, struct ifnet **ifnet_ptr);
  113. static int ik_detachController(int controlIndex);
  114.  
  115. //
  116. // Global structures and data storage
  117. //
  118. // Dispatch vector for IPNetMonitor_NKE socket intercepts
  119. struct sockif IKsockif = {
  120.     NULL,        // soabort
  121.     NULL,        // soaccept
  122.     NULL,        // sobind
  123.     ik_close,        // soclose
  124.     ik_connect,        // soconnect
  125.     NULL,        // soconnect2
  126.     ik_control,    // soset/getopt
  127.     NULL,        // socreate
  128.     ik_disconnect,        // sodisconnect
  129.     NULL,        // sofree
  130.     NULL,        // sogetopt
  131.     NULL,        // sohasoutofband
  132.     NULL,        // solisten
  133.     NULL,        // soreceive
  134.     NULL,        // sorflush
  135.     NULL,        // sosend
  136.     NULL,        // sosetopt
  137.     NULL,        // soshutdown
  138.     NULL,        // socantrcvmore
  139.     NULL,        // socantsendmore
  140.     NULL,        // soisconnected
  141.     NULL,        // soisconnecting
  142.     NULL,        // soisdisconnected
  143.     NULL,        // soisdisconnecting
  144.     NULL,        // sonewconn1
  145.     NULL,        // soqinsque
  146.     NULL,        // soqremque
  147.     NULL,        // soreserve
  148.     NULL,        // sowakeup
  149. };
  150.  
  151. // Dispatch vector for IPNetMonitor_NKE socket buffer functions
  152. struct sockutil IKsockutil = {
  153.     NULL,    // sb_lock
  154.     NULL,    // sbappend
  155.     NULL,    // sbappendaddr
  156.     NULL,    // sbappendcontrol
  157.     NULL,    // sbappendrecord
  158.     NULL,    // sbcompress
  159.     NULL,    // sbdrop
  160.     NULL,    // sbdroprecord
  161.     NULL,    // sbflush
  162.     NULL,    // sbinsertoob
  163.     NULL,    // sbrelease
  164.     NULL,    // sbreserve
  165.     NULL,    // sbwait
  166. };
  167.  
  168. // Dispatch vector for PF_NKE socket control functions
  169. struct NFDescriptor IPNetMonitor_NKE = {
  170.     {NULL, NULL},
  171.     {NULL, NULL},
  172.     IPNetMonitor_NKE_Handle,
  173.     NFD_PROG|NFD_VISIBLE,    // Ask for me by name
  174. //    NFD_GLOBAL|NFS_VISIBLE,    // only if we want global filtering
  175.     ipk_connect,
  176.     ipk_disconnect,
  177.     ipk_read,
  178.     ipk_write,
  179.     ipk_get,
  180.     ipk_put,
  181.     &IKsockif, &IKsockutil
  182. };
  183.  
  184. // I include code for both DLIL protocol and DLIL interface filters.
  185. // I tried using a protocol filter first and discovered it did not
  186. // see traffic from the classic networking stack.  When using an
  187. // interface filter, we need to sort the traffic for different
  188. // protocols ourselves (IP vs AppleTalk...).
  189.  
  190. // Dispatch vector for DLIL protocol filter intercepts
  191. struct dlil_pr_flt_str IKprotocol_filter = {
  192.     NULL, // caddr_t cookie
  193.     ipk_filter_dl_input, // filter_dl_input
  194.     ipk_filter_dl_output, // filter_dl_output
  195.     NULL, // filter_dl_event
  196.     NULL, // filter_dl_ioctl
  197.     NULL, // filter_detach
  198. };
  199.  
  200. // Dispatch vector for DLIL interface filter intercepts
  201. struct dlil_if_flt_str IKinterface_filter = {
  202.     NULL, // caddr_t cookie
  203.     ipk_filter_if_input, // filter_if_input
  204.     NULL, // filter_if_event
  205.     ipk_filter_if_output, // filter_if_output
  206.     NULL, // filter_if_ioctl
  207.     NULL, // filter_if_free
  208.     NULL, // filter_detach
  209. };
  210.  
  211. int32_t PROJECT_timerRefCount;
  212.     // ipk_timeout reschedules itself when PROJECT_timerRefCount>0
  213. int32_t PROJECT_timerPending;
  214.  
  215.  
  216. //
  217. // Module wide variables (not exported)
  218. //
  219. // socket highwater mark for flow control
  220. //    make these big enough to hold our report data without starving kernel memory
  221. static int IPK_recvspace = 8192;
  222. static int IPK_sendspace = 8192;
  223.  
  224. static int ipk_initted = 0;
  225.  
  226.  
  227. //
  228. // Setup per instance structures and storage
  229. //
  230.  
  231. // maximum number of controllers and DLIL attachments use index values 1..n
  232. // 0 is reserved for "not found"
  233. //#define kMaxControl    8
  234. //#define kMaxAttach 8
  235.  
  236. // Array of controller instances
  237. control_t PROJECT_control[kMaxControl+1];
  238.  
  239. // Global Array of DLIL attach instances
  240. attach_t PROJECT_attach[kMaxAttach+1];
  241.  
  242.  
  243. //
  244. // Load and unload kernel extension
  245. //
  246. // ---------------------------------------------------------------------------------
  247. //    Ñ IPNetMonitor_NKE_start
  248. // ---------------------------------------------------------------------------------
  249. kern_return_t IPNetMonitor_NKE_start (kmod_info_t * ki, void * d)
  250. {
  251.     int returnValue = KERN_SUCCESS;
  252.     struct protosw *pp;
  253.     int s;
  254.     int    funnel_state;
  255.     int i;
  256.     
  257.     printf("IPNetMonitor_NKE has loaded!\n");
  258.  
  259.     // grab the network funnel and prevent other network threads from pre-empting us
  260.     funnel_state = thread_funnel_set(network_flock, TRUE);
  261.     s = splnet();
  262.  
  263.     do {
  264.         // already initialized?
  265.         if (ipk_initted) break;
  266.         
  267.         // initialize global storage
  268.         PROJECT_timerRefCount = 0;
  269.         PROJECT_timerPending = 0;
  270.         
  271.         // initialize our instance storage
  272.         for (i=0; i<=kMaxControl; i++) {
  273.             bzero(&PROJECT_control[i], sizeof(control_t));
  274.         }
  275.         for (i=0; i<=kMaxAttach; i++) {
  276.             bzero(&PROJECT_attach[i], sizeof(attach_t));
  277.         }
  278.         
  279.         // find the protosw we want to sidle up to
  280.             // we will use UDP for the control connection to our NKE
  281.         pp = pffindproto(AF_INET, IPPROTO_UDP, SOCK_DGRAM);
  282.         if (pp == NULL) {
  283.             returnValue = EPFNOSUPPORT;
  284.             break;
  285.         }
  286.         
  287.         // register our NKE
  288.         returnValue = register_sockfilter(&IPNetMonitor_NKE, NULL, pp, NFF_AFTER);
  289.         if (!returnValue) {
  290.             ipk_initted = 1;
  291.             returnValue = KERN_SUCCESS;
  292.         }
  293. #if IPK_DEBUG
  294.         log(LOG_WARNING, "IPNetMonitor_NKE init: %d\n", returnValue);
  295. #endif
  296.  
  297.     } while (FALSE);
  298.  
  299.     // restore previous priority level and thread funnel
  300.     splx(s);
  301.     thread_funnel_set(network_flock, funnel_state);
  302.  
  303.     return returnValue;
  304. }
  305.  
  306.  
  307. // ---------------------------------------------------------------------------------
  308. //    Ñ IPNetMonitor_NKE_stop
  309. // ---------------------------------------------------------------------------------
  310. kern_return_t IPNetMonitor_NKE_stop (kmod_info_t * ki, void * d) {
  311.     int returnValue = KERN_SUCCESS;
  312.     struct protosw *pp;
  313.     int s;
  314.     int    funnel_state;
  315.     int i;
  316.     u_long filterID;
  317.  
  318.     funnel_state = thread_funnel_set(network_flock, TRUE);
  319.     s = splnet();
  320.     do {
  321.         // if not initted
  322.         if (!ipk_initted) break;
  323.         
  324.         // unlink controllers and remove any DLIL attach instances
  325.         for (i=1; i<=kMaxControl; i++) {
  326.             if (PROJECT_control[i].ctl != 0) {
  327.                 ik_detachController(i);
  328.                 // tell any clients the socket has gone away
  329.                 // not sure how to do this, so just fail for now
  330.                 returnValue = KERN_FAILURE;    // fail until all sockets are disconnected
  331.                 break;
  332.             }
  333.         }
  334.         if (returnValue) break;
  335.         
  336.         // remove any remaining attach instances (defensive)
  337.         for (i=1; i<=kMaxAttach; i++) {
  338.             if (filterID = PROJECT_attach[i].filterID != 0) {
  339.                 returnValue = dlil_detach_filter(PROJECT_attach[i].filterID);
  340.                 bzero(&PROJECT_attach[i], sizeof(attach_t));
  341.                 #if IPK_DEBUG
  342.                     log(LOG_WARNING, "IPNetMonitor_NKE_stop: detach protocol filter: %d\n",filterID);
  343.                 #endif
  344.             }
  345.         }
  346.         
  347.         // need to cancel any pending kernel callbacks (timeout)
  348.             // fortunately we don't normally unload and can warn the user
  349.             // not to unload while any tools are running
  350.         // force timer ref count to zero
  351.         if (PROJECT_timerRefCount || PROJECT_timerPending) {
  352.             untimeout(ipk_timeout, (void *)0);
  353.             PROJECT_timerRefCount = 0;
  354.         }
  355.         
  356.         // unplug our socket filter
  357.         pp = pffindproto(AF_INET, IPPROTO_UDP, SOCK_DGRAM);
  358.         if (pp == NULL) {
  359.             returnValue = EPFNOSUPPORT;
  360.             break;
  361.         }
  362.         returnValue = unregister_sockfilter(&IPNetMonitor_NKE, pp, 0);
  363.         if (!returnValue) {
  364.             ipk_initted = 0;    // don't allow multiples
  365.             returnValue = KERN_SUCCESS;
  366.         }
  367. #if IPK_DEBUG
  368.         log(LOG_WARNING, "IPNetMonitor_NKE_stop terminate: %d\n", returnValue);
  369. #endif
  370.     } while (FALSE);
  371.  
  372.     splx(s);
  373.     thread_funnel_set(network_flock, funnel_state);
  374.     
  375.     if (returnValue == 0) printf("IPNetMonitor_NKE has unloaded!\n");
  376.  
  377.     return returnValue;
  378. }
  379.  
  380.  
  381. // ---------------------------------------------------------------------------------
  382. //    Ñ ik_control
  383. // ---------------------------------------------------------------------------------
  384. // intercept socket options (soset and soget)
  385. static int ik_control(struct socket *so, struct sockopt *sopt, struct kextcb *kp)
  386. {
  387.     int returnValue = 0;    // continue normall processing (pass it on)
  388.     int result;
  389.     int controlIndex=0;
  390.     int attachIndex=0;
  391.  
  392.     int s;
  393.     int    funnel_state;
  394.  
  395.     do {
  396.         // find our controller instance
  397.         controlIndex = ik_controlIndexForSocket(so);
  398.         if (!controlIndex) {
  399.             // not yet connected, try to connect
  400.             returnValue = ipk_connect(so);
  401.             if (returnValue != EJUSTRETURN) break;
  402.             controlIndex = ik_controlIndexForSocket(so);
  403.             if (!controlIndex) {
  404.                 returnValue = ENOTCONN;
  405.                 break;
  406.             }
  407.         }
  408.     
  409.         switch(sopt->sopt_name) {
  410.             case SO_ATTACH_LINK:
  411.                 // grab the network funnel and prevent other network threads from pre-empting us
  412.                 funnel_state = thread_funnel_set(network_flock, TRUE);
  413.                 s = splnet();
  414.                 do {
  415.                                     // attach a controller socket to an IP interface (data link)
  416.                                     struct sopt_attachParam attachParam;
  417.                                     u_long dl_tag;
  418.                                     u_long filterID;
  419.                                     struct ifnet *ifnet_ptr;
  420.             // Reference: copyin and copyout option parameters
  421.             //int    sooptcopyin __P((struct sockopt *sopt, void *buf, size_t len, size_t minlen));
  422.             //int    sooptcopyout __P((struct sockopt *sopt, void *buf, size_t len));
  423.                                     #if IPK_DEBUG
  424.                                             log(LOG_WARNING, "ik_control: received SO_ATTACH_LINK\n");
  425.                                     #endif
  426.                                     // copyin option parameter
  427.                                     returnValue = sooptcopyin(sopt, &attachParam, sizeof (struct sopt_attachParam),
  428.                                                                                     sizeof (attachParam));
  429.                                     if (returnValue) break;
  430.             
  431.                                     // get ifnet_ptr for corresponding interface
  432.                                     returnValue = ik_findIFNet(attachParam.bsdName, &ifnet_ptr);
  433.                                     if (returnValue) break;
  434.                                     // get DLIL attachID we're interested in
  435.                                     returnValue = dlil_find_dltag(ifnet_ptr->if_family, ifnet_ptr->if_unit, PF_INET, &dl_tag);
  436.                                     if (returnValue) break;
  437.                                     
  438.                                     // look for existing DLIL attach instance
  439.                                     attachIndex = ik_attachIndexForTag(dl_tag);
  440.                                     if (attachIndex) {
  441.                                         // found existing DLIL attach
  442.                                         // associate this controller with DLIL attach
  443.                                         PROJECT_control[controlIndex].attachMap[attachIndex] = 1;
  444.                                         returnValue = EJUSTRETURN;
  445.                                         break;            
  446.                                     }
  447.                                     // defensive, look for existing DLIL attach by bsdName
  448.                                     attachIndex = ik_attachIndexForName(attachParam.bsdName);
  449.                                     if (attachIndex) {
  450.                                         // found existing DLIL attach
  451.                                         // associate this controller with DLIL attach
  452.                                         PROJECT_control[controlIndex].attachMap[attachIndex] = 1;
  453.                                         returnValue = EJUSTRETURN;
  454.                                         break;            
  455.                                     }                                    
  456.                                     // did not find previous attachment
  457.                                     // create a new DLIL attach instance for requested interface
  458.                                             // find slot for attach instance
  459.                                     attachIndex = ik_emptyAttachIndex();
  460.                                     if (!attachIndex) {
  461.                                         returnValue = EBUSY;
  462.                                         break;
  463.                                     }
  464.                                             // set dlil dispatch cookie to point to this attach instance
  465.                                     IKprotocol_filter.cookie = (caddr_t)&PROJECT_attach[attachIndex];
  466.                                     IKinterface_filter.cookie = (caddr_t)&PROJECT_attach[attachIndex];
  467.                                             // attach our NKE as a protocol filter using dl_tag or
  468.                                             // an interface filter using ifnet_ptr
  469.                                     if (attachParam.protocolFilter) {
  470.                                         returnValue = dlil_attach_protocol_filter(dl_tag, &IKprotocol_filter,
  471.                                                 &filterID, DLIL_LAST_FILTER);
  472.                                         if (returnValue) break;            
  473.                                         #if IPK_DEBUG
  474.                                         log(LOG_WARNING, "ik_control: protocol filter on %s\n", attachParam.bsdName);
  475.                                         #endif
  476.                                     }
  477.                                     else {
  478.                                         returnValue = dlil_attach_interface_filter(ifnet_ptr, &IKinterface_filter,
  479.                                                 &filterID, DLIL_LAST_FILTER);
  480.                                         if (returnValue) break;
  481.                                         #if IPK_DEBUG
  482.                                         log(LOG_WARNING, "ik_control: interface filter on %s\n", attachParam.bsdName);
  483.                                         #endif
  484.                                     }
  485.             
  486.                                     // initialize attach instance and remember dlil attach info
  487.                                     {
  488.                                         int len;
  489.                                         bzero(&PROJECT_attach[attachIndex], sizeof(attach_t));
  490.                                         PROJECT_attach[attachIndex].attachID = dl_tag;
  491.                                         PROJECT_attach[attachIndex].filterID = filterID;
  492.                                         // default to filter on
  493.                                         PROJECT_attach[attachIndex].kftInterfaceEntry.filterOn = 1;
  494.                                         // remember interface name as CString
  495.                                         len = strlen(attachParam.bsdName);
  496.                                         memcpy(&PROJECT_attach[attachIndex].kftInterfaceEntry.bsdName[0],
  497.                                                         &attachParam.bsdName[0], len+1);
  498.                                         // associate this controller with DLIL attach
  499.                                         PROJECT_control[controlIndex].attachMap[attachIndex] = 1;
  500.                                         #if IPK_DEBUG
  501.                                                 log(LOG_WARNING, "ik_control control instance: %d attach instance: %d attach filterID: %d\n",
  502.                                                         controlIndex, attachIndex, filterID);
  503.                                         #endif
  504.                                     }
  505.                                     // Everything worked, Yay!
  506.                                     returnValue = EJUSTRETURN;                    
  507.                 } while (FALSE);
  508.                 // restore previous priority level and thread funnel
  509.                 splx(s);
  510.                 thread_funnel_set(network_flock, funnel_state);    
  511.                 break;
  512.             case SO_DETACH_LINK:
  513.                 // grab the network funnel and prevent other network threads from pre-empting us
  514.                 funnel_state = thread_funnel_set(network_flock, TRUE);
  515.                 s = splnet();
  516.                 do {
  517.                     // detach specified interface from controller socket
  518.                     struct sopt_attachParam attachParam;
  519.                     u_long dl_tag;
  520.                     u_long filterID;
  521.                     struct ifnet *ifnet_ptr;
  522.                     #if IPK_DEBUG
  523.                         log(LOG_WARNING, "ik_control: received SO_DETACH_LINK\n");
  524.                     #endif
  525.                     // if name is nil, detach controller and any dlil attachments
  526.                     if (sopt->sopt_valsize == 0) {
  527.                         #if IPK_DEBUG
  528.                             log(LOG_WARNING, "ik_control detach all interfaces\n");
  529.                         #endif
  530.                         returnValue = ik_detachController(controlIndex);
  531.                         if (returnValue) break;
  532.                         returnValue = EJUSTRETURN;
  533.                         break;
  534.                     }
  535.                     // copyin option parameter
  536.                     returnValue = sooptcopyin(sopt, &attachParam, sizeof(struct sopt_attachParam),
  537.                                             sopt->sopt_valsize);
  538.                     if (returnValue) break;
  539.                     // make sure delay table is empty before detaching from any interfaces
  540.                     //KFT_delayAge(0);                
  541.                     // get ifnet_ptr for corresponding interface
  542.                     returnValue = ik_findIFNet(attachParam.bsdName, &ifnet_ptr);
  543.                     if (returnValue) break;
  544.                     // get DLIL attachID we're interested in
  545.                     returnValue = dlil_find_dltag(ifnet_ptr->if_family, ifnet_ptr->if_unit, PF_INET, &dl_tag);
  546.                     if (returnValue) break;
  547.                     // look for existing DLIL attach instance
  548.                     attachIndex = ik_attachIndexForTag(dl_tag);
  549.                     // defensive, look for existing DLIL attach by bsdName
  550.                     if (!attachIndex) attachIndex = ik_attachIndexForName(attachParam.bsdName);
  551.                     if (attachIndex) {
  552.                         // found existing DLIL attach
  553.                         // dis-associate this controller with DLIL attach
  554.                         PROJECT_control[controlIndex].attachMap[attachIndex] = 0;
  555.                         // are there any more references?
  556.                         if (ik_controlCount(attachIndex) == 0) {
  557.                             // no more references to this attach instance
  558.                             // detach our NKE from this interface and clear instance
  559.                             filterID = PROJECT_attach[attachIndex].filterID;
  560.                             returnValue = dlil_detach_filter(filterID);
  561.                             bzero(&PROJECT_attach[attachIndex], sizeof(attach_t));
  562.                             #if IPK_DEBUG
  563.                                 log(LOG_WARNING, "ik_control control instance: %d attach instance: %d detach filterID: %d\n",
  564.                                     controlIndex, attachIndex, filterID);
  565.                             #endif
  566.                         }
  567.                     }
  568.                     else {
  569.                         returnValue = ENOENT;
  570.                         break;
  571.                     }
  572.                     returnValue = EJUSTRETURN;
  573.                 } while (FALSE);
  574.                 // restore previous priority level and thread funnel
  575.                 splx(s);
  576.                 thread_funnel_set(network_flock, funnel_state);
  577.                 break;
  578.             case SO_MONITOR_ON:
  579.                 do {
  580.                     #if IPK_DEBUG
  581.                         log(LOG_WARNING, "ik_control: received SO_MONITOR_ON\n");
  582.                     #endif
  583.                     // reset nkeSends to tell NKE we want more
  584.                     PROJECT_control[controlIndex].nkeSends = 0;
  585.                     // check for attachment to an interface
  586.                     if (ik_attachCount(controlIndex) == 0) {
  587.                         returnValue = ENOENT;
  588.                         break;
  589.                     }
  590.                     // if monitoring is not already on
  591.                     if (PROJECT_control[controlIndex].monitorOn == 0) {
  592.                         PROJECT_control[controlIndex].monitorOn = 1;
  593.                         // start 1-second timer to send interface stats upstream
  594.                         //PROJECT_timerRefCount += 1;
  595.                         result = OSAddAtomic(1, (SInt32*)&PROJECT_timerRefCount);
  596.                         result = OSAddAtomic(1, (SInt32*)&PROJECT_timerPending);
  597.                         if (result == 0) {    // timer is not running
  598.                             #if IPK_DEBUG
  599.                                 log(LOG_WARNING, "ik_control: start timer\n");
  600.                             #endif
  601.                             ipk_timeout((void *)0);
  602.                         }
  603.                     }
  604.                     returnValue = EJUSTRETURN;
  605.                 } while (FALSE);
  606.                 break;
  607.             case SO_MONITOR_OFF:
  608.                 do {
  609.                     #if IPK_DEBUG
  610.                         log(LOG_WARNING, "ik_control: received SO_MONITOR_OFF\n");
  611.                     #endif
  612.                     PROJECT_control[controlIndex].monitorOn = 0;
  613.                     // bump timer ref count
  614.                     //PROJECT_timerRefCount -= 1;
  615.                     result = OSAddAtomic(-1, (SInt32*)&PROJECT_timerRefCount);
  616.                     if (result <= 0) PROJECT_timerRefCount = 0;    // defensive
  617.                     // report current connection table
  618.                     {
  619.                         // grab the network funnel and prevent other network threads from pre-empting us
  620.                         funnel_state = thread_funnel_set(network_flock, TRUE);
  621.                         s = splnet();
  622.                         
  623.                         //KFT_connectionReport();
  624.                         // restore previous priority level and thread funnel
  625.                         splx(s);
  626.                         thread_funnel_set(network_flock, funnel_state);                    
  627.                     }
  628.                     returnValue = EJUSTRETURN;
  629.                 } while (FALSE);
  630.                 break;
  631.             default: {
  632.                 #if IPK_DEBUG
  633.                     log(LOG_WARNING, "ik_control: default unrecognized sopt->sopt_name=%x pass it on\n", sopt->sopt_name);
  634.                 #endif
  635.                 returnValue = 0;
  636.                 break;
  637.             }
  638.         }    // end switch
  639.     } while (FALSE);
  640.     #if 0
  641.         log(LOG_WARNING, "ik_control returnValue: %d\n", returnValue);
  642.     #endif    
  643.     return returnValue;
  644. }
  645.  
  646.  
  647. // ---------------------------------------------------------------------------------
  648. //    Ñ ik_connect
  649. // ---------------------------------------------------------------------------------
  650. //    intercept soconnect
  651. static int ik_connect(struct socket *so, struct sockaddr *nam)
  652. {
  653.     ipk_connect(so);
  654.     return 0;
  655. }
  656.  
  657. // ---------------------------------------------------------------------------------
  658. //    Ñ ik_disconnect
  659. // ---------------------------------------------------------------------------------
  660. //    intercept sodisconnect
  661. static int ik_disconnect(struct socket *so, register struct kextcb *kp)
  662. {
  663.     ipk_disconnect(so);
  664.     return 0;
  665. }
  666.  
  667. // ---------------------------------------------------------------------------------
  668. //    Ñ ik_close
  669. // ---------------------------------------------------------------------------------
  670. //    intercept soclose
  671. static int ik_close(struct socket *so, register struct kextcb *kp)
  672. {
  673.     // socket is being closed:
  674.     //     disconnect, turn off monitoring, and detach from dlil if no more references.
  675.     // - Any open sockets will be closed by the kernel when the process quits,
  676.     //   so this is our big chance to clean up properly regardless of how the
  677.     //   companion application died.
  678.     ipk_disconnect(so);
  679.     return 0;
  680. }
  681.  
  682.  
  683. //
  684. // We have a control (PF_NKE) socket expressing interest.
  685. //
  686. // ---------------------------------------------------------------------------------
  687. //    Ñ ipk_connect
  688. // ---------------------------------------------------------------------------------
  689. //    Register connection between controller socket and our NKE
  690. //    Called via PF_NKE, ik_control (set_SO) and also soconnect (standard UDP)
  691. static int ipk_connect(register struct socket *cso)
  692. {
  693.     int returnValue = 0;
  694.     int controlIndex;
  695.     int s;
  696.     int funnel_state;
  697. #if IPK_DEBUG
  698.             log(LOG_WARNING, "ipk_connect\n");
  699. #endif
  700.     // grab the network funnel and prevent other network threads from pre-empting us
  701.     funnel_state = thread_funnel_set(network_flock, TRUE);
  702.     s = splnet();
  703.  
  704.     do {
  705.         // check if this controller socket is already connected
  706.         controlIndex = ik_controlIndexForSocket(cso);
  707.         if (controlIndex) {    // found it
  708.             returnValue = EISCONN;
  709.             break;
  710.         }
  711.         // reserve socket buffer space if needed
  712.         if (cso->so_snd.sb_hiwat == 0 || cso->so_rcv.sb_hiwat == 0) {
  713.             returnValue = soreserve(cso, IPK_sendspace, IPK_recvspace);
  714.             if (returnValue) break;
  715.         }
  716.         // find slot for connection instance
  717.         controlIndex = ik_emptyControlIndex();
  718.         if (!controlIndex) {
  719.             returnValue = EBUSY;
  720.             break;        // all connection slots full
  721.         }
  722.         // register we have a connection
  723.         PROJECT_control[controlIndex].ctl = cso;
  724.         returnValue = EJUSTRETURN;
  725.     } while (FALSE);
  726.  
  727.     // restore previous priority level and thread funnel
  728.     splx(s);
  729.     thread_funnel_set(network_flock, funnel_state);    
  730.     return returnValue;
  731. }
  732.  
  733.  
  734. // ---------------------------------------------------------------------------------
  735. //    Ñ ipk_disconnect
  736. // ---------------------------------------------------------------------------------
  737. static void ipk_disconnect(register struct socket *cso)
  738. {
  739.     int controlIndex;
  740.     int s;
  741.     int funnel_state;
  742.  
  743.     #if IPK_DEBUG
  744.         log(LOG_WARNING, "ipk_disconnect\n");
  745.     #endif
  746.     // grab the network funnel and prevent other network threads from pre-empting us
  747.     funnel_state = thread_funnel_set(network_flock, TRUE);
  748.     s = splnet();
  749.     
  750.     // check if this controller socket is connected and remove it
  751.     controlIndex = ik_controlIndexForSocket(cso);
  752.     if (controlIndex) {    // found it
  753.         // remove reference to dlil attach instance and clear control instance
  754.         ik_detachController(controlIndex);
  755.     }
  756.     
  757.     // restore previous priority level and thread funnel
  758.     splx(s);
  759.     thread_funnel_set(network_flock, funnel_state);    
  760. }
  761.  
  762. static int ipk_get()
  763. {
  764.     return(0);
  765. }
  766.  
  767. static int ipk_read()
  768. {
  769.     return(0);
  770. }
  771.  
  772. static int ipk_put()
  773. {
  774.     return(0);
  775. }
  776.  
  777. static int ipk_write()
  778. {
  779.     return(0);
  780. }
  781.  
  782. //
  783. // dlil protocol filter functions our NKE will intercept
  784. //
  785. // ---------------------------------------------------------------------------------
  786. //    Ñ ipk_filter_dl_input
  787. // ---------------------------------------------------------------------------------
  788. //  protocol filter NKE intercept input datagram
  789. static int ipk_filter_dl_input(caddr_t    cookie, 
  790.                struct mbuf    **m, 
  791.                char        **frame_header, 
  792.                struct ifnet **ifp)
  793. {
  794.     int returnValue = 0;
  795.     struct mbuf *dg;    // mbuf chain for datagram
  796.     attach_t* myAttach;
  797.     // get access to our attach instance
  798.     myAttach = (attach_t*)cookie;
  799.     // examine the mbuf chain to determine the data length
  800.         // for more information on mbufs, see TCP/IP Illustrated Volume 2,
  801.         // "The Implementation" by Wright and Stevens
  802.     dg = *m;    // first mbuf chain
  803.     if (dg) {
  804.         if (dg->m_flags & M_PKTHDR) {
  805.             // count receive traffic
  806.             myAttach->receiveCount += dg->m_pkthdr.len;
  807.                 // dlil filters execute at splnet so we should be safe here
  808.                 // need to set splnet to access receiveCount from other contexts
  809.             // IP filtering
  810.             #if 0
  811.             if (0) {
  812.                 KFT_packetData_t packet;
  813.                 bzero(&packet, sizeof(packet));
  814.                 packet.ipOffset = 0;
  815.                 packet.direction = 1;
  816.                 packet.myAttach = myAttach;
  817.                 returnValue = KFT_filterPacket(&packet);
  818.             }
  819.             #endif
  820.         }
  821.     }
  822.     return returnValue;
  823. }
  824.  
  825. // ---------------------------------------------------------------------------------
  826. //    Ñ ipk_filter_dl_output
  827. // ---------------------------------------------------------------------------------
  828. //  protocol filter NKE intercept output datagram
  829. static int ipk_filter_dl_output(caddr_t        cookie, 
  830.                 struct mbuf        **m, 
  831.                 struct ifnet    **ifp, 
  832.                 struct sockaddr **dest,
  833.                 char            *dest_linkaddr, 
  834.                 char        *frame_type)
  835. {
  836.     int returnValue = 0;
  837.     struct mbuf *dg;    // mbuf chain for datagram
  838.     attach_t* myAttach;
  839.     // get access to our attach instance
  840.     myAttach = (attach_t*)cookie;
  841.     // examine the mbuf chain to determine the data length
  842.     dg = *m;    // first mbuf chain
  843.     if (dg) {
  844.         if (dg->m_flags & M_PKTHDR) {
  845.             // count send traffic
  846.             myAttach->sendCount += dg->m_pkthdr.len;
  847.                 // dlil filters execute at splnet so we should be safe here
  848.                 // need to set splnet to access sendCount from other contexts
  849.             // IP filtering
  850.             #if 0
  851.             if (0) {
  852.                 KFT_packetData_t packet;
  853.                 bzero(&packet, sizeof(packet));
  854.                 packet.ipOffset = 0;
  855.                 packet.direction = 0;
  856.                 packet.myAttach = myAttach;
  857.                 returnValue = KFT_filterPacket(&packet);
  858.             }
  859.             #endif
  860.         }
  861.     }
  862.     return returnValue;
  863. }
  864.  
  865. //
  866. // dlil interface filter functions our NKE will intercept
  867. // Notice dlil will call us for each packet with m->m_nextpkt == NULL
  868. // ---------------------------------------------------------------------------------
  869. //    Ñ ipk_filter_if_input
  870. // ---------------------------------------------------------------------------------
  871. //  interface filter NKE intercept input datagram
  872. static int ipk_filter_if_input(caddr_t         cookie,
  873.                struct ifnet    **ifnet_ptr,
  874.                struct mbuf     **mbuf_ptr,
  875.                char           **frame_ptr)
  876. {
  877.     int returnValue = 0;
  878.     struct mbuf *m;    // mbuf chain for datagram
  879.     attach_t* myAttach;
  880.     u_char interfaceType = 0;
  881.     u_char headerLength = 0;
  882.     // get access to our attach instance
  883.     myAttach = (attach_t*)cookie;
  884.     // hardware info
  885.     if (*ifnet_ptr) {    // defensive
  886.         interfaceType = (*ifnet_ptr)->if_type;
  887.         headerLength = (*ifnet_ptr)->if_hdrlen;
  888.     }
  889.     // examine the mbuf chain to process IP datagrams
  890.         // for more information on mbufs, see TCP/IP Illustrated Volume 2,
  891.         // "The Implementation" by Wright and Stevens
  892.     do {
  893.         if ((m = *mbuf_ptr) == NULL) break;
  894.         if (m->m_flags & M_PKTHDR) {
  895.             // add to receive count
  896.             myAttach->receiveCount += m->m_pkthdr.len;
  897.                 // dlil filters execute at splnet so we should be safe here
  898.                 // need to set splnet to access receiveCount from other contexts            
  899. #if 0
  900.             // check frame header for IP
  901.             if ((interfaceType == IFT_ETHER) && (headerLength == 14)) {
  902.                 u_int16_t* dp16;
  903.                 if (*frame_ptr) {    // defensive
  904.                     dp16 = (u_int16_t*)(*frame_ptr);
  905.                     if (dp16[6] != 0x0800) {
  906.                         #if 0
  907.                             log(LOG_WARNING, "ipk_filter_if_input non IP frame header\n");
  908.                         #endif
  909.                         break;
  910.                     }
  911.                 }
  912.             }
  913.             // IP filtering
  914.             if (PROJECT_timerRefCount) {
  915.                 KFT_packetData_t packet;
  916.                 bzero(&packet, sizeof(packet));
  917.                 // passed in
  918.                 packet.ifnet_ptr = ifnet_ptr;
  919.                 packet.mbuf_ptr = mbuf_ptr;
  920.                 packet.frame_ptr = frame_ptr;
  921.                 packet.myAttach = myAttach;        // cookie
  922.                 // interface info
  923.                 packet.ifType = interfaceType;
  924.                 packet.ifHeaderLen = headerLength;
  925.                 // packet  info
  926.                 packet.ipOffset = 0;
  927.                 packet.direction = 1;
  928.                 // pass to filter
  929.                 returnValue = KFT_filterPacket(&packet);
  930.             }
  931. #endif
  932.         }
  933.     } while (FALSE);
  934.     return returnValue;
  935. }
  936.  
  937.  
  938. // ---------------------------------------------------------------------------------
  939. //    Ñ ipk_filter_if_output
  940. // ---------------------------------------------------------------------------------
  941. //  interface filter NKE intercept output datagram
  942. static int ipk_filter_if_output(caddr_t      cookie,
  943.                 struct ifnet **ifnet_ptr,
  944.                 struct mbuf  **mbuf_ptr)
  945. {
  946.     int returnValue = 0;
  947.     struct mbuf *m;
  948.     attach_t* myAttach;
  949.     u_char interfaceType = 0;
  950.     u_char headerLength = 0;
  951.     // get access to our attach instance
  952.     myAttach = (attach_t*)cookie;
  953.     // hardware info
  954.     if (*ifnet_ptr) {    // defensive
  955.         interfaceType = (*ifnet_ptr)->if_type;
  956.         headerLength = (*ifnet_ptr)->if_hdrlen;
  957.     }
  958.     // examine the mbuf chain to process IP datagragms
  959.     do {
  960.         if ((m = *mbuf_ptr) == NULL) break;
  961.         if (m->m_flags & M_PKTHDR) {
  962.             // add to receive count
  963.             myAttach->sendCount += (m->m_pkthdr.len - headerLength);
  964.                 // dlil filters execute at splnet so we should be safe here
  965.                 // need to set splnet to access sendCount from other contexts
  966. #if 0
  967.             // check frame header for IP
  968.             if ((interfaceType == IFT_ETHER) && (headerLength == 14)) {
  969.                 u_int16_t* dp16;
  970.                 dp16 = (u_int16_t*)m->m_data;
  971.                 if (dp16[6] != 0x0800) {
  972.                     #if 0
  973.                         log(LOG_WARNING, "ipk_filter_if_output non IP frame header\n");
  974.                     #endif
  975.                     break;
  976.                 }
  977.             }
  978.             if (interfaceType == IFT_PPP) {
  979.                 // fix header to work around PPP bug
  980.                 if ((m->m_data[headerLength-2] & 0xF0) == 0x40) headerLength -= 2;
  981.             }
  982.             // IP filtering
  983.             if (PROJECT_timerRefCount) {
  984.                 KFT_packetData_t packet;
  985.                 bzero(&packet, sizeof(packet));
  986.                 // passed in
  987.                 packet.ifnet_ptr = ifnet_ptr;
  988.                 packet.mbuf_ptr = mbuf_ptr;
  989.                 packet.frame_ptr = 0;
  990.                 packet.myAttach = myAttach;
  991.                 // interface info
  992.                 packet.ifType = interfaceType;
  993.                 packet.ifHeaderLen = headerLength;
  994.                 // packet info
  995.                 packet.ipOffset = headerLength;        // output packets preceeded by frame header
  996.                 packet.direction = 0;
  997.                 // pass to filter
  998.                 returnValue = KFT_filterPacket(&packet);
  999.             }
  1000. #endif
  1001.         }
  1002.     } while (FALSE);
  1003.     return returnValue;
  1004. }
  1005.  
  1006.  
  1007. // ---------------------------------------------------------------------------------
  1008. //    Ñ ipk_timeout
  1009. // ---------------------------------------------------------------------------------
  1010. //    one second timer used for monitoring
  1011. //    reschedules itself to be called each second when timerRefCount > 0
  1012. static void ipk_timeout(void *cookie)
  1013. {
  1014.     extern int hz;    // number of clock ticks that occur in one second
  1015.     int s;
  1016.     int    funnel_state;
  1017.  
  1018.     // grab the network funnel and prevent other network threads from pre-empting us
  1019.     funnel_state = thread_funnel_set(network_flock, TRUE);
  1020.     s = splnet();
  1021.  
  1022.     ipk_periodical();
  1023.     // reschedule ourself if anyone needs us
  1024.         // timeout(void (*func)(), void *cookie, int ticks);
  1025.     if (PROJECT_timerRefCount > 0) {
  1026.         PROJECT_timerPending = TRUE;
  1027.         timeout(ipk_timeout, (void *)0, hz);
  1028.     }
  1029.     else {
  1030.         PROJECT_timerPending = FALSE;
  1031.         #if IPK_DEBUG
  1032.             log(LOG_WARNING, "ipk_timeout: stop timer\n");
  1033.         #endif
  1034.     }
  1035.     
  1036.     // restore previous priority level and thread funnel
  1037.     splx(s);
  1038.     thread_funnel_set(network_flock, funnel_state);
  1039. }
  1040.  
  1041.  
  1042. // ---------------------------------------------------------------------------------
  1043. //    Ñ ipk_periodical
  1044. // ---------------------------------------------------------------------------------
  1045. //    periodic processing
  1046. static void ipk_periodical()
  1047. {
  1048.     int i, j;
  1049.     // grab stats for each attach instance
  1050.     for (i=1; i<=kMaxAttach; i++) {
  1051.         if (PROJECT_attach[i].attachID) {
  1052.             // copy current value
  1053.             PROJECT_attach[i].sendStamp = PROJECT_attach[i].sendCount;
  1054.             PROJECT_attach[i].receiveStamp = PROJECT_attach[i].receiveCount;
  1055.             // reset counter
  1056.             PROJECT_attach[i].sendCount = 0;
  1057.             PROJECT_attach[i].receiveCount = 0;
  1058.         }
  1059.     }    
  1060.  
  1061.     // send corresponding stats upstream for each monitoring control instance
  1062.     for (i=1; i<=kMaxControl; i++) {
  1063.         if (PROJECT_control[i].monitorOn) {
  1064.             // increment NKE sends since last request so we don't
  1065.             // flood input queue when no one is listening.
  1066.             PROJECT_control[i].nkeSends += 1;
  1067.             if (PROJECT_control[i].nkeSends < 15) {        // 15 seconds of data max
  1068.                 // build message to send monitor stats
  1069.                 ipk_monitorStats_t    monitorStats;
  1070.                 monitorStats.length = sizeof(ipk_monitorStats_t);
  1071.                 monitorStats.type = kMonitorStats;
  1072.                 for (j=1; j<=kMaxAttach; j++) {
  1073.                     if (PROJECT_control[i].attachMap[j]) {
  1074.                         monitorStats.sendCount = PROJECT_attach[j].sendStamp;
  1075.                         monitorStats.receiveCount = PROJECT_attach[j].receiveStamp;
  1076.                         break;
  1077.                     }
  1078.                 }
  1079.                 // send it
  1080.                 PROJECT_sendMessage(PROJECT_control[i].ctl, (ipk_message_t*)&monitorStats);
  1081.             }
  1082.         }
  1083.     }
  1084. }
  1085.  
  1086.  
  1087.  
  1088. // ---------------------------------------------------------------------------------
  1089. //    Ñ PROJECT_sendMessageToAll
  1090. // ---------------------------------------------------------------------------------
  1091. //     send message to each active controller
  1092. void PROJECT_sendMessageToAll(ipk_message_t *message)
  1093. {
  1094.     int i;
  1095.     for (i=1;i<=kMaxControl;i++) {
  1096.         if (PROJECT_control[i].ctl) {
  1097.             // increment NKE sends since last request so we don't
  1098.             // keep flooding input queue when no one is listening.
  1099.             PROJECT_control[i].nkeSends += 1;
  1100.             if (PROJECT_control[i].nkeSends < 250) {        // max messages allowed in 2.5 seconds
  1101.                 PROJECT_sendMessage(PROJECT_control[i].ctl, message);
  1102.             }
  1103.         }
  1104.     }
  1105. }
  1106.  
  1107. // ---------------------------------------------------------------------------------
  1108. //    Ñ PROJECT_sendMessage
  1109. // ---------------------------------------------------------------------------------
  1110. //     send message to controlling socket
  1111. void PROJECT_sendMessage(struct socket *ctl, ipk_message_t *message)
  1112. {
  1113.     struct mbuf *m;
  1114.     int s;
  1115.     int    funnel_state;
  1116.     
  1117.     // grab the network funnel and prevent other network threads from pre-empting us
  1118.     funnel_state = thread_funnel_set(network_flock, TRUE);
  1119.     s = splnet();
  1120.  
  1121.     do {
  1122.         char *p;    
  1123.         if (!ctl) break;    // defensive
  1124.         // make sure we have room
  1125.         if (sbspace(&ctl->so_rcv) < message->length) break;
  1126.         // get an mbuf to hold message
  1127.             // just discard if we can't get a buffer (M_NOWAIT)
  1128.             // since we're at splnet and holding the network funnel
  1129.         MGETHDR(m, M_NOWAIT, MT_DATA);
  1130.         if (m == NULL) break;
  1131.         // get a cluster to handle messages longer than 100 bytes
  1132.         if (message->length >= 100) {
  1133.             MCLGET(m, M_NOWAIT);
  1134.             // check if we got it
  1135.             if (!(m->m_flags & M_EXT)) {
  1136.                 m_freem(m);
  1137.                 break;
  1138.             }
  1139.         }
  1140.         // align mbuf data to long word boundary
  1141.         p = m->m_data;
  1142.         p = (char *)(((int)p+3)&(~0x3));    
  1143.         m->m_data = (caddr_t)p;
  1144.         // copy message to our mbuf and set data length
  1145.         bcopy(message, mtod(m, caddr_t), message->length);
  1146.         m->m_len = message->length;
  1147.         // append our mbuf to socket receive queue
  1148.         //sbappend(&ctl->so_rcv, m);
  1149.         sbappendrecord(&ctl->so_rcv, m);
  1150.         // wake any process waiting for read on this socket
  1151.         sorwakeup(ctl);
  1152.         // the mbuf we allocated should be released when the socket is read
  1153.     } while (FALSE);
  1154.     
  1155.     // restore previous priority level and thread funnel
  1156.     splx(s);
  1157.     thread_funnel_set(network_flock, funnel_state);
  1158. }
  1159.  
  1160. // ---------------------------------------------------------------------------------
  1161. //    Ñ ik_attachCount
  1162. // ---------------------------------------------------------------------------------
  1163. // how many attachments does this controller reference
  1164. static int ik_attachCount(int controlIndex)
  1165. {
  1166.     int count, i;
  1167.     count = 0;
  1168.     // valid controlIndex?
  1169.     if ((controlIndex > 0) && (controlIndex <= kMaxControl)) {
  1170.         // for each attach instance
  1171.         for (i=1; i<=kMaxAttach; i++) {
  1172.             // does this controller reference it
  1173.             if (PROJECT_control[controlIndex].attachMap[i]) count += 1;
  1174.         }
  1175.     }
  1176.     return count;    
  1177. }
  1178.  
  1179. // ---------------------------------------------------------------------------------
  1180. //    Ñ ik_controlCount
  1181. // ---------------------------------------------------------------------------------
  1182. // how many controllers reference this attachment
  1183. static int ik_controlCount(int attachIndex)
  1184. {
  1185.     int count, i;
  1186.     count = 0;
  1187.     // valid attachIndex?
  1188.     if ((attachIndex > 0) && (attachIndex <= kMaxAttach)) {
  1189.         // for each control instance
  1190.         for (i=1; i<=kMaxControl; i++) {
  1191.             // does it reference this attach instance
  1192.             if (PROJECT_control[i].attachMap[attachIndex]) count += 1;
  1193.         }
  1194.     }
  1195.     return count;
  1196. }
  1197.  
  1198. // ---------------------------------------------------------------------------------
  1199. //    Ñ ik_controlIndexForSocket
  1200. // ---------------------------------------------------------------------------------
  1201. //    Find controller instance with corresponding socket if any and pass back it's index.
  1202. //    Returns 0 for not found
  1203. static int ik_controlIndexForSocket(struct socket *so)
  1204. {
  1205.     int returnValue = 0;        // controller not connected ENOTCONN
  1206.     int i;
  1207.     
  1208.     for (i=1; i<=kMaxControl; i++) {
  1209.         if (PROJECT_control[i].ctl == so) {
  1210.             returnValue = i;
  1211.             break;
  1212.         }
  1213.     }
  1214.     return returnValue;
  1215. }
  1216.  
  1217.  
  1218. // ---------------------------------------------------------------------------------
  1219. //    Ñ ik_emptyControlIndex
  1220. // ---------------------------------------------------------------------------------
  1221. //    Find an empty controller instance (available slot)
  1222. //    Returns 0 for not found
  1223. static int ik_emptyControlIndex()
  1224. {
  1225.     int returnValue = 0;        // all slots in use EBUSY
  1226.     int i;
  1227.     
  1228.     for (i=1; i<=kMaxControl; i++) {
  1229.         if (PROJECT_control[i].ctl == 0) {
  1230.             returnValue = i;
  1231.             break;
  1232.         }
  1233.     }
  1234.     return returnValue;
  1235. }
  1236.  
  1237. // ---------------------------------------------------------------------------------
  1238. //    Ñ ik_attachIndexForTag
  1239. // ---------------------------------------------------------------------------------
  1240. //    Find attach instance with corresponding dl_tag if any and pass back it's index.
  1241. //    Return 0 for not found.
  1242. static int ik_attachIndexForTag(u_long dl_tag)
  1243. {
  1244.     int returnValue = 0;    // no such entry ENOENT
  1245.     int i;
  1246.     
  1247.     for (i=1; i<=kMaxAttach; i++) {
  1248.         if (PROJECT_attach[i].attachID == dl_tag) {
  1249.             returnValue = i;
  1250.             break;
  1251.         }
  1252.     }
  1253.     return returnValue;
  1254. }
  1255.  
  1256. // ---------------------------------------------------------------------------------
  1257. //    Ñ ik_attachIndexForName
  1258. // ---------------------------------------------------------------------------------
  1259. //    Find attach instance with corresponding bsdName.
  1260. //    Return 0 for not found.
  1261. static int ik_attachIndexForName(char *inName)
  1262. {
  1263.     int returnValue = 0;    // no such entry ENOENT
  1264.     int i;
  1265.     int len;
  1266.     
  1267.     len = strlen(inName);
  1268.     for (i=1; i<=kMaxAttach; i++) {
  1269.         if ( memcmp(inName, &PROJECT_attach[i].kftInterfaceEntry.bsdName[0], len) == 0 ) {
  1270.             returnValue = i;
  1271.             break;
  1272.         }
  1273.     }
  1274.     return returnValue;
  1275. }
  1276.  
  1277. // ---------------------------------------------------------------------------------
  1278. //    Ñ ik_emptyAttachIndex
  1279. // ---------------------------------------------------------------------------------
  1280. //    Find an empty attach instance (available slot)
  1281. //    Return 0 for not found
  1282. static int ik_emptyAttachIndex()
  1283. {
  1284.     int returnValue = 0;    // all slots in use EBUSY
  1285.     int i;
  1286.     
  1287.     for (i=1; i<=kMaxAttach; i++) {
  1288.         if (PROJECT_attach[i].attachID == 0) {
  1289.             returnValue = i;
  1290.             break;
  1291.         }
  1292.     }
  1293.     return returnValue;
  1294. }
  1295.  
  1296.  
  1297. // ---------------------------------------------------------------------------------
  1298. //    Ñ ik_findIFNet
  1299. // ---------------------------------------------------------------------------------
  1300. static int ik_findIFNet(char *inName, struct ifnet **ifnet_ptr)
  1301. //     return 0 if ifnet was found, otherwise unix error
  1302. //
  1303. //    For insertering our NKE below IP as an interface filter, we use the ifnet
  1304. //    global variable which points to the list of ifnet structures and scan the
  1305. //    list to find the desired ifnet structure with matching interface name.
  1306. {
  1307.     int returnValue = ENOENT;
  1308.     extern    struct ifnethead ifnet;
  1309.     struct ifnet *ifp;
  1310.     int len, unit, i;
  1311.     short match;
  1312.     
  1313.     do {
  1314.         if (!inName) break;            // defensive - name is null
  1315.         len = strlen(inName) - 1;
  1316.         unit = inName[len] - '0';    // get unit from end of name of the form "en0"
  1317.         
  1318.         // walk the ifnet list
  1319.         for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) {
  1320.             // testing: list interfaces 
  1321.                 //log(LOG_WARNING, "ik_findIFNet interface name: %s unit: %d\n",
  1322.                 //    ifp->if_name, ifp->if_unit);            
  1323.             // check name length
  1324.             if (len != strlen(ifp->if_name)) continue;
  1325.             // compare base name
  1326.             match = 1;
  1327.             for (i=0; i<len; i++) {
  1328.                 if (inName[i] != ifp->if_name[i]) {
  1329.                     match = 0;
  1330.                     break;
  1331.                 }
  1332.             }
  1333.             if (!match) continue;
  1334.             // names match, check unit
  1335.             if (unit != ifp->if_unit) continue;
  1336.             // we found a match
  1337.             *ifnet_ptr = ifp;
  1338.             returnValue = 0;
  1339.             break;
  1340.         }
  1341.     } while (FALSE);
  1342.     return returnValue;
  1343. }
  1344.  
  1345. // ---------------------------------------------------------------------------------
  1346. //    Ñ ik_detachController
  1347. // ---------------------------------------------------------------------------------
  1348. //    detach controller and remove any dlil interface attachments
  1349. //    that are no longer referenced.  Finally, clear the control instance.
  1350. //
  1351. //    return 0 for success or unix error code
  1352. static int ik_detachController(int controlIndex)
  1353. {
  1354.     int returnValue=0;
  1355.     int attachIndex;
  1356.     u_long filterID;
  1357.     int result;
  1358.     do {
  1359.         if (!controlIndex) break;    // no control instance, we're done
  1360.         // make sure delay table is empty before detaching from any interfaces
  1361.         //KFT_delayAge(0);                
  1362.         // if controller was monitoring, turn it off
  1363.         // - user might quit app without stopping or closing monitor window
  1364.         if (PROJECT_control[controlIndex].monitorOn) {
  1365.             PROJECT_control[controlIndex].monitorOn = 0;
  1366.             // bump timer ref count
  1367.             //PROJECT_timerRefCount -= 1;
  1368.             //if (PROJECT_timerRefCount < 0) PROJECT_timerRefCount = 0;
  1369.             result = OSAddAtomic(-1, (SInt32*)&PROJECT_timerRefCount);
  1370.             if (result <= 0) PROJECT_timerRefCount = 0;    // defensive
  1371.         }
  1372.         // get corresponding attach instances
  1373.         for (attachIndex=1;attachIndex<=kMaxAttach;attachIndex++) {
  1374.             if (PROJECT_control[controlIndex].attachMap[attachIndex]) {
  1375.                 // remove our reference to attach instance
  1376.                 PROJECT_control[controlIndex].attachMap[attachIndex] = 0;            
  1377.                 // are there any more references?
  1378.                 if (ik_controlCount(attachIndex) == 0) {
  1379.                     // no more references to this attach instance
  1380.                     // detach our NKE from this interface and clear instance
  1381.                     filterID = PROJECT_attach[attachIndex].filterID;
  1382.                     returnValue = dlil_detach_filter(filterID);
  1383.                     bzero(&PROJECT_attach[attachIndex], sizeof(attach_t));
  1384.                     #if IPK_DEBUG
  1385.                         log(LOG_WARNING, "ik_detachController control instance: %d attach instance: %d detach filterID: %d\n",
  1386.                             controlIndex, attachIndex, filterID);
  1387.                     #endif
  1388.                 }
  1389.             }    // end found attach instance
  1390.         }    // end for each attach instance
  1391.         // clear control instance
  1392.         bzero(&PROJECT_control[controlIndex], sizeof(control_t));
  1393.     } while (FALSE);
  1394.     return returnValue;
  1395. }
  1396.