home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.sustworks.com 2018
/
ftp.sustworks.com.zip
/
ftp.sustworks.com
/
open_source_IPNetSentry_NKE.dmg
/
IPNetSentry_NKE.c
< prev
next >
Wrap
C/C++ Source or Header
|
2005-08-08
|
55KB
|
1,676 lines
//
// IPNetSentry_NKE.c
// Mac OS X Interface Filter NKE
//
// Created by psichel [PAS] on Teus Nov 12 2002.
// Based on SharedIP and TCPLogger provided as Open Source sample code
// from Apple Computer.
//
// See IPNetSentry_NKE.h for high level design overview.
// You can send comments or suggestions to psichel@sustworks.com
// The companion IPNetSentryX controller application is available from
// http://www.sustworks.com
//
// ---------------------------------------------------------------------------------
// Portions Copyright (c) 1999-2002 Apple Computer, Inc. All Rights Reserved.
//
// This file contains Original Code and/or Modifications of Original Code as defined
// in and that are subject to the Apple Public Source License Version 1.2 (the 'License').
// You may not use this file except in compliance with the License.
// Please obtain a copy of the License at http://www.apple.com/publicsource
// and read it before using this file.
//
// The Original Code and all software distributed under the License are distributed
// on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
// AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION,
// ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
// ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the specific
// language governing rights and limitations under the License."
// ---------------------------------------------------------------------------------
#define DEBUG_IPK 0
#if DEBUG_IPK
#include <sys/syslog.h>
#endif
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/socket.h>
#include <sys/protosw.h>
#include <sys/socketvar.h>
#include <sys/fcntl.h>
#include <sys/malloc.h>
#include <sys/queue.h>
#include <sys/domain.h>
#include <sys/mbuf.h>
#include <net/route.h>
#include <net/if.h>
#include <net/if_types.h>
#include <net/if_dl.h>
#include <net/ndrv.h>
#include <net/kext_net.h>
#include <net/dlil.h>
#include <netinet/in.h> // Needed for (*&^%$#@ arpcom in if_arp.h
#include <net/ethernet.h>
#include <net/if_arp.h>
#include <machine/spl.h>
#include <kern/thread.h>
#include <libkern/OSAtomic.h>
#include PS_NKE_INCLUDE
#include "IPTypes.h"
#include "kft.h"
#include "kftDelay.h"
#include "kftTrigger.h"
#include "kftConnectionTable.h"
#if IPNetRouter
#include "kftPortMapTable.h"
#include "kftNatTable.h"
#endif
#include "FilterTypes.h"
// macro to convert kernel to external socket
//#define sotoextcb(so) (struct kextcb *)(so->so_ext)
//extern void kprintf(const char *, ...);
//
// Forward function declarations
// Use unix style names (words separated by "_") for intercepts and callbacks
// Use Mac style names for internal functions (initial caps)
// Use ipk_ or ik_ prefix to avoid kernel name space conflicts
// ipk_ for PF_NKE and DLIL filter functions, ik_ for socket functions
//
// PF_NKE socket functions
int ipk_connect();
int ipk_read();
int ipk_write();
int ipk_get();
int ipk_put();
void ipk_disconnect();
// socket interface functions our NKE will intercept
int ik_close();
int ik_connect();
int ik_control();
int ik_disconnect();
// dlil protocol filter functions our NKE can intercept
int ipk_filter_pr_input();
int ipk_filter_pr_output();
// dlil interface filter functions our NKE can intercept
int ipk_filter_if_input();
int ipk_filter_if_output();
// timer callbacks
void ipk_timeout(void *cookie);
// send message to controlling socket
void PROJECT_sendMessage(struct socket *ctl, ipk_message_t *message);
// internal support functions
static int ik_attachCount(int controlIndex);
static int ik_controlCount(int attachIndex);
static int ik_controlIndexForSocket(struct socket *so);
static int ik_emptyControlIndex();
static int ik_attachIndexForName(char *inName);
static int ik_emptyAttachIndex();
static int ik_findIFNet(char *inName, ifnet_t *ifnet_ref);
static int ik_detachController(int controlIndex);
static int ik_detachIndex(int attachIndex);
//
// Global structures and data storage
//
// Dispatch vector for IPNetRouter_NKE/IPNetSentry_NKE socket intercepts
struct sockif IKsockif = {
NULL, // soabort
NULL, // soaccept
NULL, // sobind
ik_close, // soclose
ik_connect, // soconnect
NULL, // soconnect2
ik_control, // soset/getopt
NULL, // socreate
ik_disconnect, // sodisconnect
NULL, // sofree
NULL, // sogetopt
NULL, // sohasoutofband
NULL, // solisten
NULL, // soreceive
NULL, // sorflush
NULL, // sosend
NULL, // sosetopt
NULL, // soshutdown
NULL, // socantrcvmore
NULL, // socantsendmore
NULL, // soisconnected
NULL, // soisconnecting
NULL, // soisdisconnected
NULL, // soisdisconnecting
NULL, // sonewconn1
NULL, // soqinsque
NULL, // soqremque
NULL, // soreserve
NULL, // sowakeup
};
// Dispatch vector for IPNetRouter_NKE/IPNetSentry socket buffer functions
struct sockutil IKsockutil = {
NULL, // sb_lock
NULL, // sbappend
NULL, // sbappendaddr
NULL, // sbappendcontrol
NULL, // sbappendrecord
NULL, // sbcompress
NULL, // sbdrop
NULL, // sbdroprecord
NULL, // sbflush
NULL, // sbinsertoob
NULL, // sbrelease
NULL, // sbreserve
NULL, // sbwait
};
// Dispatch vector for PF_NKE socket control functions
struct NFDescriptor IPNetSentry_NKE = {
{NULL, NULL},
{NULL, NULL},
IPNetSentry_NKE_Handle,
NFD_PROG|NFD_VISIBLE, // Ask for me by name
// NFD_GLOBAL|NFS_VISIBLE, // only if we want global filtering
ipk_connect,
ipk_disconnect,
ipk_read,
ipk_write,
ipk_get,
ipk_put,
&IKsockif, &IKsockutil
};
// I include code for both DLIL protocol and DLIL interface filters.
// I tried using a protocol filter first and discovered it did not
// see traffic from the classic networking stack. When using an
// interface filter, we need to sort the traffic for different
// protocols ourselves (IP vs AppleTalk...).
// Dispatch vector for DLIL protocol filter intercepts
struct dlil_pr_flt_str IKprotocol_filter = {
NULL, // caddr_t cookie
ipk_filter_pr_input, // filter_dl_input
ipk_filter_pr_output, // filter_dl_output
NULL, // filter_dl_event
NULL, // filter_dl_ioctl
NULL, // filter_detach
};
// Dispatch vector for DLIL interface filter intercepts
struct dlil_if_flt_str IKinterface_filter = {
NULL, // caddr_t cookie
ipk_filter_if_input, // filter_if_input
NULL, // filter_if_event
ipk_filter_if_output, // filter_if_output
NULL, // filter_if_ioctl
NULL, // filter_if_free
NULL, // filter_detach
};
// max size of drop Response
#define KFT_dropResponseMax 1000
// drop Connection response
u_int8_t PROJECT_dropResponseBuffer[KFT_dropResponseMax];
int PROJECT_dropResponseLength;
// time of day info
sopt_timeParam_t PROJECT_timeOfDay;
// flags
u_int32_t PROJECT_flags;
// timer Ref Count (firewall enabled)
int32_t PROJECT_timerRefCount;
// ipk_timeout reschedules itself when PROJECT_timerRefCount>0
int PROJECT_doRateLimit; // packet matched a rate limit rule
// index of failover requested 0=none, 1=default, 2=alternate gateway
int PROJECT_failoverRequest;
// reserve bandwidth info
KFT_reserveInfo_t PROJECT_rReserveInfo;
KFT_reserveInfo_t PROJECT_sReserveInfo;
//
// Module wide variables (not exported)
//
// socket highwater mark for flow control
// make these big enough to hold our report data without starving kernel memory
static int IPK_recvspace = 8192;
static int IPK_sendspace = 8192;
static int32_t ipk_timerPending;
static int ipk_initted = 0;
//
// Setup per instance structures and storage
//
// maximum number of controllers and DLIL attachments use index values 1..n
// 0 is reserved for "not found"
//#define kMaxControl 8
//#define kMaxAttach 8
// Array of controller instances
static control_t PROJECT_control[kMaxControl+1];
// Global Array of DLIL attach instances
attach_t PROJECT_attach[kMaxAttach+1];
#pragma mark -- Load and unload kernel extension
//
// Load and unload kernel extension
//
// ---------------------------------------------------------------------------------
// Ñ IPNetSentry_NKE_start
// ---------------------------------------------------------------------------------
kern_return_t IPNetSentry_NKE_start (kmod_info_t * ki, void * d)
{
int returnValue = KERN_SUCCESS;
struct protosw *pp;
int s;
int funnel_state;
int i;
#if IPNetRouter
printf("IPNetRouter_NKE has loaded!\n");
#else
printf("IPNetSentry_NKE has loaded!\n");
#endif
// grab the network funnel and prevent other network threads from pre-empting us
funnel_state = thread_funnel_set(network_flock, TRUE);
s = splnet();
do {
// already initialized?
if (ipk_initted) break;
// initialize global storage
PROJECT_timerRefCount = 0;
ipk_timerPending = 0;
PROJECT_timeOfDay.timeStamp = 0;
PROJECT_flags = 0;
PROJECT_dropResponseLength = 0;
// initialize our instance storage
for (i=0; i<=kMaxControl; i++) {
bzero(&PROJECT_control[i], sizeof(control_t));
}
for (i=0; i<=kMaxAttach; i++) {
bzero(&PROJECT_attach[i], sizeof(attach_t));
}
// setup KFT structures
KFT_init();
// find the protosw we want to sidle up to
// we will use UDP for the control connection to our NKE
pp = pffindproto(AF_INET, IPPROTO_UDP, SOCK_DGRAM);
if (pp == NULL) {
returnValue = EPFNOSUPPORT;
break;
}
// register our NKE
returnValue = register_sockfilter(&IPNetSentry_NKE, NULL, pp, NFF_AFTER);
if (returnValue == 0) {
ipk_initted = 1;
returnValue = KERN_SUCCESS;
}
} while (FALSE);
// restore previous priority level and thread funnel
splx(s);
thread_funnel_set(network_flock, funnel_state);
return returnValue;
}
// ---------------------------------------------------------------------------------
// Ñ IPNetSentry_NKE_stop
// ---------------------------------------------------------------------------------
kern_return_t IPNetSentry_NKE_stop (kmod_info_t * ki, void * d) {
int returnValue = KERN_SUCCESS;
struct protosw *pp;
int s;
int funnel_state;
int i;
u_long filterID;
funnel_state = thread_funnel_set(network_flock, TRUE);
s = splnet();
do {
// if not initted
if (!ipk_initted) break;
// unlink controllers and remove any DLIL attach instances
for (i=1; i<=kMaxControl; i++) {
if (PROJECT_control[i].ctl != 0) {
ik_detachController(i);
// tell any clients the socket has gone away
// not sure how to do this, so just fail for now
returnValue = KERN_FAILURE; // fail until all sockets are disconnected
break;
}
}
if (returnValue != 0) break;
// remove any remaining attach instances (defensive)
for (i=1; i<=kMaxAttach; i++) {
if (filterID = PROJECT_attach[i].filterID != 0) {
ik_detachIndex(i);
#if DEBUG_IPK
log(LOG_WARNING, "NKE_stop: detach protocol filter: %d\n",filterID);
#endif
}
}
// release KFT structures
KFT_terminate();
// need to cancel any pending kernel callbacks (timeout)
// fortunately we don't normally unload and can warn the user
// not to unload while any tools are running
// force timer ref count to zero
if (PROJECT_timerRefCount || ipk_timerPending) {
untimeout(ipk_timeout, (void *)0);
PROJECT_timerRefCount = 0;
}
// unplug our socket filter
pp = pffindproto(AF_INET, IPPROTO_UDP, SOCK_DGRAM);
if (pp == NULL) {
returnValue = EPFNOSUPPORT;
break;
}
returnValue = unregister_sockfilter(&IPNetSentry_NKE, pp, 0);
if (returnValue == 0) {
ipk_initted = 0; // don't allow multiples
returnValue = KERN_SUCCESS;
}
} while (FALSE);
splx(s);
thread_funnel_set(network_flock, funnel_state);
if (returnValue == 0) printf("IPNetSentry_NKE has unloaded!\n");
return returnValue;
}
// ---------------------------------------------------------------------------------
// Ñ ik_control
// ---------------------------------------------------------------------------------
// intercept socket options (soset and soget)
int ik_control(struct socket *so, struct sockopt *sopt, struct kextcb *kp)
{
int returnValue = 0; // continue normall processing (pass it on)
int result;
int controlIndex=0;
int attachIndex=0;
unsigned long count; // copy out a single u_long
int s;
int funnel_state;
do {
// find our controller instance
controlIndex = ik_controlIndexForSocket(so);
if (!controlIndex) {
// not yet connected, try to connect
returnValue = ipk_connect(so);
if (returnValue != EJUSTRETURN) break;
controlIndex = ik_controlIndexForSocket(so);
if (!controlIndex) {
returnValue = ENOTCONN;
break;
}
}
switch(sopt->sopt_name) {
case SO_ATTACH_LINK:
// grab the network funnel and prevent other network threads from pre-empting us
funnel_state = thread_funnel_set(network_flock, TRUE);
s = splnet();
do {
// attach a controller socket to an IP interface (data link)
struct sopt_attachParam attachParam;
u_long filterID;
ifnet_t ifnet_ref;
// Reference: copyin and copyout option parameters
//int sooptcopyin __P((struct sockopt *sopt, void *buf, size_t len, size_t minlen));
//int sooptcopyout __P((struct sockopt *sopt, void *buf, size_t len));
#if DEBUG_IPK
log(LOG_WARNING, "ik_control: received SO_ATTACH_LINK\n");
#endif
// copyin option parameter
returnValue = sooptcopyin(sopt, &attachParam, sizeof (struct sopt_attachParam),
sizeof (attachParam));
if (returnValue != 0) break;
// look for existing DLIL attach by bsdName
attachIndex = ik_attachIndexForName(attachParam.bsdName);
if (attachIndex) {
// found existing DLIL attach
// associate this controller with DLIL attach
PROJECT_control[controlIndex].attachMap[attachIndex] = 1;
returnValue = EJUSTRETURN;
break;
}
// did not find previous attachment
// create a new DLIL attach instance for requested interface
// find slot for attach instance
attachIndex = ik_emptyAttachIndex();
if (!attachIndex) {
returnValue = EBUSY;
break;
}
// set dlil dispatch cookie to point to this attach instance
IKprotocol_filter.cookie = (caddr_t)&PROJECT_attach[attachIndex];
IKinterface_filter.cookie = (caddr_t)&PROJECT_attach[attachIndex];
// get ifnet_ref for corresponding interface
returnValue = ik_findIFNet(attachParam.bsdName, &ifnet_ref);
if (returnValue != 0) break;
// attach our NKE as a protocol filter using dl_tag or
// an interface filter using ifnet_ref
if (attachParam.protocolFilter) {
// get DLIL tag for protocol interface pair we're interested in
u_long dl_tag;
returnValue = dlil_find_dltag(ifnet_ref->if_family, ifnet_ref->if_unit, PF_INET, &dl_tag);
if (returnValue != 0) break;
// attach our NKE as a protocol filter
returnValue = dlil_attach_protocol_filter(dl_tag, &IKprotocol_filter,
&filterID, DLIL_LAST_FILTER);
if (returnValue != 0) break;
#if DEBUG_IPK
log(LOG_WARNING, "ik_control: protocol filter on %s\n", attachParam.bsdName);
#endif
}
else {
returnValue = dlil_attach_interface_filter(ifnet_ref, &IKinterface_filter,
&filterID, DLIL_LAST_FILTER);
if (returnValue != 0) break;
#if DEBUG_IPK
log(LOG_WARNING, "ik_control: interface filter on %s\n", attachParam.bsdName);
#endif
}
// initialize attach instance and remember dlil attach info
{
int len;
bzero(&PROJECT_attach[attachIndex], sizeof(attach_t));
PROJECT_attach[attachIndex].filterID = filterID;
PROJECT_attach[attachIndex].ifnet_ref = ifnet_ref;
PROJECT_attach[attachIndex].attachIndex = attachIndex;
// default to filter on
PROJECT_attach[attachIndex].kftInterfaceEntry.filterOn = 1;
// remember interface name as CString
len = strlen(attachParam.bsdName);
memcpy(&PROJECT_attach[attachIndex].kftInterfaceEntry.bsdName[0],
&attachParam.bsdName[0], len+1);
// associate this controller with DLIL attach
PROJECT_control[controlIndex].attachMap[attachIndex] = 1;
#if DEBUG_IPK
log(LOG_WARNING, "ik_control control instance: %d attach instance: %d attach filterID: %d\n",
controlIndex, attachIndex, filterID);
#endif
}
// Everything worked, Yay!
returnValue = EJUSTRETURN;
} while (FALSE);
// restore previous priority level and thread funnel
splx(s);
thread_funnel_set(network_flock, funnel_state);
break;
case SO_DETACH_LINK:
// grab the network funnel and prevent other network threads from pre-empting us
funnel_state = thread_funnel_set(network_flock, TRUE);
s = splnet();
do {
// detach specified interface from controller socket
struct sopt_attachParam attachParam;
#if DEBUG_IPK
log(LOG_WARNING, "ik_control: received SO_DETACH_LINK\n");
#endif
// make sure delay table is empty before detaching from any interfaces
KFT_delayAge(0);
// if name is nil, detach controller and any dlil attachments
if (sopt->sopt_valsize == 0) {
#if DEBUG_IPK
log(LOG_WARNING, "ik_control detach all interfaces\n");
#endif
returnValue = ik_detachController(controlIndex);
if (returnValue != 0) break;
returnValue = EJUSTRETURN;
break;
}
// copyin option parameter
returnValue = sooptcopyin(sopt, &attachParam, sizeof(struct sopt_attachParam),
sopt->sopt_valsize);
if (returnValue != 0) break;
// look for existing DLIL attach by bsdName
attachIndex = ik_attachIndexForName(attachParam.bsdName);
if (attachIndex) {
// found existing DLIL attach
// dis-associate this controller with DLIL attach
PROJECT_control[controlIndex].attachMap[attachIndex] = 0;
// are there any more references?
if (ik_controlCount(attachIndex) == 0) {
#if DEBUG_IPK
u_long filterID = PROJECT_attach[attachIndex].filterID;
#endif
// no more references to this attach instance
// detach our NKE from this interface
returnValue = ik_detachIndex(attachIndex);
#if DEBUG_IPK
log(LOG_WARNING, "ik_control control instance: %d attach instance: %d detach filterID: %d\n",
controlIndex, attachIndex, filterID);
#endif
}
}
else {
returnValue = ENOENT;
break;
}
returnValue = EJUSTRETURN;
} while (FALSE);
// restore previous priority level and thread funnel
splx(s);
thread_funnel_set(network_flock, funnel_state);
break;
case SO_MONITOR_ON:
do {
#if DEBUG_IPK
log(LOG_WARNING, "ik_control: received SO_MONITOR_ON\n");
#endif
// reset nkeSends to tell NKE we want more
PROJECT_control[controlIndex].nkeSends = 0;
// check for attachment to an interface
if (ik_attachCount(controlIndex) == 0) {
returnValue = ENOENT;
break;
}
// if monitoring is not already on
if (PROJECT_control[controlIndex].monitorOn == 0) {
PROJECT_control[controlIndex].monitorOn = 1;
// start 1-second timer to send interface stats upstream
//PROJECT_timerRefCount += 1;
result = OSAddAtomic(1, (SInt32*)&PROJECT_timerRefCount);
result = OSAddAtomic(1, (SInt32*)&ipk_timerPending);
if (result == 0) { // timer is not running
#if DEBUG_IPK
log(LOG_WARNING, "ik_control: start timer\n");
#endif
ipk_timeout((void *)0);
}
}
returnValue = EJUSTRETURN;
} while (FALSE);
break;
case SO_MONITOR_OFF:
do {
#if DEBUG_IPK
log(LOG_WARNING, "ik_control: received SO_MONITOR_OFF\n");
#endif
PROJECT_control[controlIndex].monitorOn = 0;
// bump timer ref count
//PROJECT_timerRefCount -= 1;
result = OSAddAtomic(-1, (SInt32*)&PROJECT_timerRefCount);
if (result <= 0) PROJECT_timerRefCount = 0; // defensive
// report current connection table
{
// grab the network funnel and prevent other network threads from pre-empting us
funnel_state = thread_funnel_set(network_flock, TRUE);
s = splnet();
KFT_connectionReport();
// restore previous priority level and thread funnel
splx(s);
thread_funnel_set(network_flock, funnel_state);
}
returnValue = EJUSTRETURN;
} while (FALSE);
break;
case SO_FILTER_DOWNLOAD:
// grab the network funnel and prevent other network threads from pre-empting us
funnel_state = thread_funnel_set(network_flock, TRUE);
s = splnet();
do {
#if DEBUG_IPK
log(LOG_WARNING, "ik_control: received SO_FILTER_DOWNLOAD\n");
#endif
// copyin option parameter
returnValue = sooptcopyin(sopt, kft_filterTableD.bytes,
kft_filterTableD.bufferLength, sopt->sopt_valsize);
if (returnValue != 0) break;
#if DEBUG_IPK
log(LOG_WARNING, "ik_control: sooptcopyin OK\n");
#endif
kft_filterTableD.length = sopt->sopt_valsize;
if (kft_filterTableD.length >= kft_filterTableD.bufferLength) {
kft_filterTableD.length = kft_filterTableD.bufferLength;
#if DEBUG_IPK
log(LOG_WARNING, "SO_FILTER_DOWNLOAD buffer space exceeded.\n");
#endif
returnValue = EMSGSIZE;
break;
}
kft_filterTableD.offset = kft_filterTableD.length/sizeof(KFT_filterEntry_t);
returnValue = EJUSTRETURN;
} while (FALSE);
// restore previous priority level and thread funnel
splx(s);
thread_funnel_set(network_flock, funnel_state);
break;
case SO_FILTER_UPLOAD: {
#if DEBUG_IPK
log(LOG_WARNING, "ik_control: received SO_FILTER_UPLOAD\n");
#endif
returnValue = sooptcopyout(sopt, kft_filterTableD.bytes, kft_filterTableD.length);
if (returnValue != 0) break;
#if DEBUG_IPK
log(LOG_WARNING, "ik_control: sooptcopyout OK %d\n",outBuf.length);
#endif
returnValue = EJUSTRETURN;
break;
}
case SO_KFT_RESET: {
#if DEBUG_IPK
log(LOG_WARNING, "ik_control: received SO_KFT_RESET\n");
#endif
// grab the network funnel and prevent other network threads from pre-empting us
funnel_state = thread_funnel_set(network_flock, TRUE);
s = splnet();
// reset selected state before downloading
KFT_reset();
// restore previous priority level and thread funnel
splx(s);
thread_funnel_set(network_flock, funnel_state);
returnValue = EJUSTRETURN;
break;
}
case SO_FILTER_COUNT: {
#if DEBUG_IPK
log(LOG_WARNING, "ik_control: received SO_FILTER_COUNT\n");
#endif
count = KFT_filterCount();
returnValue = sooptcopyout(sopt, &count, sizeof(count));
if (returnValue != 0) break;
returnValue = EJUSTRETURN;
break;
}
case SO_TRIGGER_COUNT: {
#if DEBUG_IPK
log(LOG_WARNING, "ik_control: received SO_TRIGGER_COUNT\n");
#endif
count = KFT_triggerCount();
returnValue = sooptcopyout(sopt, &count, sizeof(count));
if (returnValue != 0) break;
returnValue = EJUSTRETURN;
break;
}
case SO_INTERFACE_COUNT: {
#if DEBUG_IPK
log(LOG_WARNING, "ik_control: received SO_INTERFACE_COUNT\n");
#endif
count = ik_attachCount(controlIndex);
returnValue = sooptcopyout(sopt, &count, sizeof(count));
if (returnValue != 0) break;
returnValue = EJUSTRETURN;
break;
}
#ifdef IPNetRouter
case SO_PORTMAP_COUNT: {
#if DEBUG_IPK
log(LOG_WARNING, "ik_control: received SO_PORTMAP_COUNT\n");
#endif
count = KFT_portMapCount();
returnValue = sooptcopyout(sopt, &count, sizeof(count));
if (returnValue != 0) break;
returnValue = EJUSTRETURN;
break;
}
#endif
case SO_SET_TIME: {
// set time of day info for NKE
#if DEBUG_IPK
log(LOG_WARNING, "ik_control: received SO_SET_TIME\n");
#endif
// copyin option parameter
returnValue = sooptcopyin(sopt, &PROJECT_timeOfDay, sizeof (struct sopt_timeParam),
sopt->sopt_valsize);
if (returnValue != 0) break;
returnValue = EJUSTRETURN;
break;
}
case SO_SET_FLAGS: {
// set global NKE flags
sopt_flagsParam_t flagsParam;
// copyin option parameter
returnValue = sooptcopyin(sopt, &flagsParam, sizeof(struct sopt_flagsParam), sopt->sopt_valsize);
if (returnValue != 0) break;
PROJECT_flags &= ~flagsParam.mask; // clear bits we're going to modify
PROJECT_flags |= flagsParam.flags; // set bits to effect change
returnValue = EJUSTRETURN;
break;
}
case SO_GET_FLAGS: {
// get global NKE flags
sopt_flagsParam_t flagsParam;
flagsParam.flags = PROJECT_flags;
flagsParam.mask = 0xFFFFFFFF;
// return current value
returnValue = sooptcopyout(sopt, &flagsParam, sizeof(flagsParam));
if (returnValue != 0) break;
returnValue = EJUSTRETURN;
break;
}
case SO_DROP_RESPONSE: {
#if DEBUG_IPK
log(LOG_WARNING, "ik_control: received SO_DROP_RESPONSE\n");
#endif
// copyin option parameter
// leave room for link header, ip header, tcp header
returnValue = sooptcopyin(sopt, &PROJECT_dropResponseBuffer[60], KFT_dropResponseMax-60, sopt->sopt_valsize);
PROJECT_dropResponseLength = sopt->sopt_valsize;
if (returnValue != 0) break;
#if DEBUG_IPK
log(LOG_WARNING, "ik_control: sooptcopyin OK %d\n",PROJECT_dropResponseLength);
#endif
returnValue = EJUSTRETURN;
break;
}
case SO_TRIGGER_DURATION: {
#if DEBUG_IPK
log(LOG_WARNING, "ik_control: received SO_TRIGGER_EXPIRATION\n");
#endif
// copyin option parameter
returnValue = sooptcopyin(sopt, &count, sizeof(count),
sopt->sopt_valsize);
if (returnValue != 0) break;
count = KFT_triggerDuration(count);
// return current value
returnValue = sooptcopyout(sopt, &count, sizeof(count));
if (returnValue != 0) break;
returnValue = EJUSTRETURN;
break;
}
case SO_TRIGGER_ADDRESS: {
KFT_triggerKey_t value[101];
int howMany;
int s;
int funnel_state;
#if DEBUG_IPK
log(LOG_WARNING, "ik_control: received SO_TRIGGER_ADDRESS\n");
#endif
// copyin option parameter
returnValue = sooptcopyin(sopt, value, sizeof(KFT_triggerKey_t)*100,
sopt->sopt_valsize);
if (returnValue != 0) break;
howMany = sopt->sopt_valsize/sizeof(KFT_triggerKey_t);
// grab the network funnel
funnel_state = thread_funnel_set(network_flock, TRUE);
s = splnet();
KFT_triggerRemoveByKey(value, howMany);
// restore previous priority level and thread funnel
splx(s);
thread_funnel_set(network_flock, funnel_state);
// are there any more updates to send?
KFT_triggerSendUpdates();
returnValue = EJUSTRETURN;
break;
}
case SO_TRIGGER_UPLOAD: {
#if DEBUG_IPK
log(LOG_WARNING, "ik_control: received SO_TRIGGER_UPLOAD\n");
#endif
// grab the network funnel and prevent other network threads from pre-empting us
funnel_state = thread_funnel_set(network_flock, TRUE);
s = splnet();
count = KFT_triggerUpload();
sooptcopyout(sopt, &count, sizeof(count));
// restore previous priority level and thread funnel
splx(s);
thread_funnel_set(network_flock, funnel_state);
returnValue = EJUSTRETURN;
break;
}
case SO_INTERFACE_UPLOAD: {
#if DEBUG_IPK
log(LOG_WARNING, "ik_control: received SO_INTERFACE_UPLOAD\n");
#endif
// grab the network funnel and prevent other network threads from pre-empting us
funnel_state = thread_funnel_set(network_flock, TRUE);
s = splnet();
count = KFT_interfaceUpload();
sooptcopyout(sopt, &count, sizeof(count));
// restore previous priority level and thread funnel
splx(s);
thread_funnel_set(network_flock, funnel_state);
returnValue = EJUSTRETURN;
break;
}
#ifdef IPNetRouter
case SO_PORTMAP_UPLOAD: {
#if DEBUG_IPK
log(LOG_WARNING, "ik_control: received SO_PORTMAP_UPLOAD\n");
#endif
// grab the network funnel and prevent other network threads from pre-empting us
funnel_state = thread_funnel_set(network_flock, TRUE);
s = splnet();
count = KFT_portMapUpload();
sooptcopyout(sopt, &count, sizeof(count));
// restore previous priority level and thread funnel
splx(s);
thread_funnel_set(network_flock, funnel_state);
returnValue = EJUSTRETURN;
break;
}
case SO_NAT_UPLOAD: {
#if DEBUG_IPK
log(LOG_WARNING, "ik_control: received SO_NAT_UPLOAD\n");
#endif
// grab the network funnel and prevent other network threads from pre-empting us
funnel_state = thread_funnel_set(network_flock, TRUE);
s = splnet();
count = KFT_natUpload();
sooptcopyout(sopt, &count, sizeof(count));
// restore previous priority level and thread funnel
splx(s);
thread_funnel_set(network_flock, funnel_state);
returnValue = EJUSTRETURN;
break;
}
#endif
case SO_IPK_MESSAGE: {
// accept ipk_message as downstream data
unsigned char buffer[kUpdateBufferSize];
ipk_message_t* message;
message = (ipk_message_t*)&buffer[0];
#if DEBUG_IPK
log(LOG_WARNING, "ik_control: received SO_IPK_MESSAGE\n");
#endif
// Reference: copyin and copyout option parameters
//int sooptcopyin __P((struct sockopt *sopt, void *buf, size_t len, size_t minlen));
//int sooptcopyout __P((struct sockopt *sopt, void *buf, size_t len));
// copyin option parameter
returnValue = sooptcopyin(sopt, &buffer[0], kUpdateBufferSize, sizeof(ipk_message_t));
if (returnValue != 0) break;
// pass along to KFT for processing
KFT_receiveMessage(message);
returnValue = EJUSTRETURN;
break;
}
default: {
#if DEBUG_IPK
log(LOG_WARNING, "ik_control: default unrecognized sopt->sopt_name=%x pass it on\n", sopt->sopt_name);
#endif
returnValue = 0;
break;
}
} // end switch
} while (FALSE);
#if 0
log(LOG_WARNING, "ik_control returnValue: %d\n", returnValue);
#endif
return returnValue;
}
// ---------------------------------------------------------------------------------
// Ñ ik_connect
// ---------------------------------------------------------------------------------
// intercept soconnect
int
ik_connect(struct socket *so, struct sockaddr *nam)
{
ipk_connect(so);
return 0;
}
// ---------------------------------------------------------------------------------
// Ñ ik_disconnect
// ---------------------------------------------------------------------------------
// intercept sodisconnect
int
ik_disconnect(struct socket *so, register struct kextcb *kp)
{
ipk_disconnect(so);
return 0;
}
// ---------------------------------------------------------------------------------
// Ñ ik_close
// ---------------------------------------------------------------------------------
// intercept soclose
int
ik_close(struct socket *so, register struct kextcb *kp)
{
// socket is being closed:
// disconnect, turn off monitoring, and detach from dlil if no more references.
// - Any open sockets will be closed by the kernel when the process quits,
// so this is our big chance to clean up properly regardless of how the
// companion application died.
ipk_disconnect(so);
return 0;
}
//
// We have a control (PF_NKE) socket expressing interest.
//
// ---------------------------------------------------------------------------------
// Ñ ipk_connect
// ---------------------------------------------------------------------------------
// Register connection between controller socket and our NKE
// Called via PF_NKE, ik_control (set_SO) and also soconnect (standard UDP)
int ipk_connect(register struct socket *cso)
{
int returnValue = 0;
int controlIndex;
int s;
int funnel_state;
#if DEBUG_IPK
log(LOG_WARNING, "ipk_connect\n");
#endif
// grab the network funnel and prevent other network threads from pre-empting us
funnel_state = thread_funnel_set(network_flock, TRUE);
s = splnet();
do {
// check if this controller socket is already connected
controlIndex = ik_controlIndexForSocket(cso);
if (controlIndex) { // found it
returnValue = EISCONN;
break;
}
// reserve socket buffer space if needed
if (cso->so_snd.sb_hiwat == 0 || cso->so_rcv.sb_hiwat == 0) {
returnValue = soreserve(cso, IPK_sendspace, IPK_recvspace);
if (returnValue != 0) break;
}
// find slot for connection instance
controlIndex = ik_emptyControlIndex();
if (!controlIndex) {
returnValue = EBUSY;
break; // all connection slots full
}
// register we have a connection
PROJECT_control[controlIndex].ctl = cso;
returnValue = EJUSTRETURN;
} while (FALSE);
// restore previous priority level and thread funnel
splx(s);
thread_funnel_set(network_flock, funnel_state);
return returnValue;
}
// ---------------------------------------------------------------------------------
// Ñ ipk_disconnect
// ---------------------------------------------------------------------------------
void ipk_disconnect(register struct socket *cso)
{
int controlIndex;
int s;
int funnel_state;
#if DEBUG_IPK
log(LOG_WARNING, "ipk_disconnect\n");
#endif
// grab the network funnel and prevent other network threads from pre-empting us
funnel_state = thread_funnel_set(network_flock, TRUE);
s = splnet();
// check if this controller socket is connected and remove it
controlIndex = ik_controlIndexForSocket(cso);
if (controlIndex) { // found it
// remove reference to dlil attach instance and clear control instance
ik_detachController(controlIndex);
}
// restore previous priority level and thread funnel
splx(s);
thread_funnel_set(network_flock, funnel_state);
}
int ipk_get()
{
return(0);
}
int ipk_read()
{
return(0);
}
int ipk_put()
{
return(0);
}
int ipk_write()
{
return(0);
}
//
// dlil protocol filter functions our NKE will intercept
//
// ---------------------------------------------------------------------------------
// Ñ ipk_filter_pr_input
// ---------------------------------------------------------------------------------
// protocol filter NKE intercept input datagram
int ipk_filter_pr_input(caddr_t cookie,
struct mbuf **m,
char **frame_header,
struct ifnet **ifp)
{
int returnValue = 0;
struct mbuf *dg; // mbuf chain for datagram
attach_t* myAttach;
// get access to our attach instance
myAttach = (attach_t*)cookie;
// examine the mbuf chain to determine the data length
// for more information on mbufs, see TCP/IP Illustrated Volume 2,
// "The Implementation" by Wright and Stevens
dg = *m; // first mbuf chain
if (dg) {
if (dg->m_flags & M_PKTHDR) {
// count receive traffic
myAttach->receiveCount += dg->m_pkthdr.len;
// dlil filters execute at splnet so we should be safe here
// need to set splnet to access receiveCount from other contexts
// IP filtering
if (0) {
KFT_packetData_t packet;
bzero(&packet, sizeof(packet));
packet.ipOffset = 0;
packet.direction = 1;
packet.myAttach = myAttach;
returnValue = KFT_filterPacket(&packet);
}
}
}
return returnValue;
}
// ---------------------------------------------------------------------------------
// Ñ ipk_filter_pr_output
// ---------------------------------------------------------------------------------
// protocol filter NKE intercept output datagram
int ipk_filter_pr_output(caddr_t cookie,
struct mbuf **m,
struct ifnet **ifp,
struct sockaddr **dest,
char *dest_linkaddr,
char *frame_type)
{
int returnValue = 0;
struct mbuf *dg; // mbuf chain for datagram
attach_t* myAttach;
// get access to our attach instance
myAttach = (attach_t*)cookie;
// examine the mbuf chain to determine the data length
dg = *m; // first mbuf chain
if (dg) {
if (dg->m_flags & M_PKTHDR) {
// count send traffic
myAttach->sendCount += dg->m_pkthdr.len;
// dlil filters execute at splnet so we should be safe here
// need to set splnet to access sendCount from other contexts
// IP filtering
if (0) {
KFT_packetData_t packet;
bzero(&packet, sizeof(packet));
packet.ipOffset = 0;
packet.direction = 0;
packet.myAttach = myAttach;
returnValue = KFT_filterPacket(&packet);
}
}
}
return returnValue;
}
//
// dlil interface filter functions our NKE will intercept
// Notice dlil will call us for each packet with m->m_nextpkt == NULL
// ---------------------------------------------------------------------------------
// Ñ ipk_filter_if_input
// ---------------------------------------------------------------------------------
// interface filter NKE intercept input datagram
int ipk_filter_if_input(caddr_t cookie,
struct ifnet **ifnet_ptr,
struct mbuf **mbuf_ptr,
char **frame_ptr)
{
int returnValue = 0;
ifnet_t ifnet_ref;
mbuf_t m; // mbuf chain for datagram
attach_t* myAttach;
u_char interfaceType = 0;
u_char headerLength = 0;
// get access to our attach instance
myAttach = (attach_t*)cookie;
// hardware info
if (ifnet_ref = *ifnet_ptr) {
interfaceType = ifnet_ref->if_type;
headerLength = ifnet_ref->if_hdrlen;
}
// examine the mbuf chain to process IP datagrams
// for more information on mbufs, see TCP/IP Illustrated Volume 2,
// "The Implementation" by Wright and Stevens
do {
if ((m = *mbuf_ptr) == NULL) break;
if (m->m_flags & M_PKTHDR) {
// add to receive count
myAttach->receiveCount += m->m_pkthdr.len;
// dlil filters execute at splnet so we should be safe here
// need to set splnet to access receiveCount from other contexts
// IP filtering
if (PROJECT_timerRefCount) {
KFT_packetData_t packet;
bzero(&packet, sizeof(packet));
// passed in
packet.ifnet_ref = ifnet_ref;
packet.mbuf_ptr = mbuf_ptr;
packet.frame_ptr = frame_ptr;
packet.myAttach = myAttach; // cookie
// link layer info
packet.ifType = interfaceType;
packet.ifHeaderLen = headerLength;
// check frame header for IP
if (interfaceType == IFT_ETHER) {
u_int16_t* dp16;
if (*frame_ptr) { // defensive
dp16 = (u_int16_t*)(*frame_ptr);
if (dp16[6] != 0x0800) packet.bridgeNonIP = 1;
}
}
// packet info
packet.ipOffset = 0;
packet.direction = 1;
// pass to filter
returnValue = KFT_filterPacket(&packet);
}
}
} while (FALSE);
return returnValue;
}
// ---------------------------------------------------------------------------------
// Ñ ipk_filter_if_output
// ---------------------------------------------------------------------------------
// interface filter NKE intercept output datagram
int ipk_filter_if_output(caddr_t cookie,
struct ifnet **ifnet_ptr,
struct mbuf **mbuf_ptr)
{
int returnValue = 0;
ifnet_t ifnet_ref;
mbuf_t m;
attach_t* myAttach;
u_char interfaceType = 0;
u_char headerLength = 0;
// get access to our attach instance
myAttach = (attach_t*)cookie;
// hardware info
if (ifnet_ref = *ifnet_ptr) { // defensive
interfaceType = ifnet_ref->if_type;
headerLength = ifnet_ref->if_hdrlen;
}
// examine the mbuf chain to process IP datagragms
do {
if ((m = *mbuf_ptr) == NULL) break;
if (m->m_flags & M_PKTHDR) {
// add to receive count
myAttach->sendCount += (m->m_pkthdr.len - headerLength);
// dlil filters execute at splnet so we should be safe here
// need to set splnet to access sendCount from other contexts
if (interfaceType == IFT_PPP) {
// fix header to work around PPP bug
if ((m->m_data[headerLength-2] & 0xF0) == 0x40) headerLength -= 2;
}
// IP filtering
if (PROJECT_timerRefCount) {
KFT_packetData_t packet;
bzero(&packet, sizeof(packet));
// passed in
packet.ifnet_ref = ifnet_ref;
packet.mbuf_ptr = mbuf_ptr;
packet.frame_ptr = 0;
packet.myAttach = myAttach;
// link layer info
packet.ifType = interfaceType;
packet.ifHeaderLen = headerLength;
// check frame header for IP
if (interfaceType == IFT_ETHER) {
u_int16_t* dp16;
dp16 = (u_int16_t*)m->m_data;
if (dp16[6] != 0x0800) packet.bridgeNonIP = 1;
}
// packet info
packet.ipOffset = headerLength; // output packets preceeded by frame header
packet.direction = 0;
// pass to filter
returnValue = KFT_filterPacket(&packet);
}
}
} while (FALSE);
return returnValue;
}
// ---------------------------------------------------------------------------------
// Ñ ipk_timeout
// ---------------------------------------------------------------------------------
// one second timer used for monitoring
// reschedules itself to be called each second when timerRefCount > 0
void ipk_timeout(void *cookie)
{
extern int hz; // number of clock ticks that occur in one second
int s;
int funnel_state;
// grab the network funnel and prevent other network threads from pre-empting us
funnel_state = thread_funnel_set(network_flock, TRUE);
s = splnet();
KFT_filterPeriodical();
// reschedule ourself if anyone needs us
// timeout(void (*func)(), void *cookie, int ticks);
if (PROJECT_timerRefCount > 0) {
ipk_timerPending = TRUE;
timeout(ipk_timeout, (void *)0, hz);
}
else {
ipk_timerPending = FALSE;
#if DEBUG_IPK
log(LOG_WARNING, "ipk_timeout: stop timer\n");
#endif
}
// restore previous priority level and thread funnel
splx(s);
thread_funnel_set(network_flock, funnel_state);
}
// ---------------------------------------------------------------------------------
// Ñ PROJECT_sendMessageToAll
// ---------------------------------------------------------------------------------
// send message to each active controller
void PROJECT_sendMessageToAll(ipk_message_t *message)
{
int i;
for (i=1;i<=kMaxControl;i++) {
if (PROJECT_control[i].ctl) {
// increment NKE sends since last request so we don't
// keep flooding input queue when no one is listening.
PROJECT_control[i].nkeSends += 1;
if (PROJECT_control[i].nkeSends < 250) { // max messages allowed in 2.5 seconds
PROJECT_sendMessage(PROJECT_control[i].ctl, message);
}
}
}
}
// ---------------------------------------------------------------------------------
// Ñ PROJECT_sendMessage
// ---------------------------------------------------------------------------------
// send message to controlling socket
void PROJECT_sendMessage(struct socket *ctl, ipk_message_t *message)
{
struct mbuf *m;
int s;
int funnel_state;
// grab the network funnel and prevent other network threads from pre-empting us
funnel_state = thread_funnel_set(network_flock, TRUE);
s = splnet();
do {
char *p;
if (!ctl) break; // defensive
// make sure we have room
if (sbspace(&ctl->so_rcv) < message->length) break;
// get an mbuf to hold message
// just discard if we can't get a buffer (M_NOWAIT)
// since we're at splnet and holding the network funnel
MGETHDR(m, M_NOWAIT, MT_DATA);
if (m == NULL) break;
// get a cluster to handle messages longer than 100 bytes
if (message->length >= 100) {
MCLGET(m, M_NOWAIT);
// check if we got it
if (!(m->m_flags & M_EXT)) {
m_freem(m);
break;
}
}
// align mbuf data to long word boundary
p = m->m_data;
p = (char *)(((int)p+3)&(~0x3));
m->m_data = (caddr_t)p;
// copy message to our mbuf and set data length
bcopy(message, mtod(m, caddr_t), message->length);
m->m_len = message->length;
// append our mbuf to socket receive queue
//sbappend(&ctl->so_rcv, m);
sbappendrecord(&ctl->so_rcv, m);
// wake any process waiting for read on this socket
sorwakeup(ctl);
// the mbuf we allocated should be released when the socket is read
} while (FALSE);
// restore previous priority level and thread funnel
splx(s);
thread_funnel_set(network_flock, funnel_state);
}
// ---------------------------------------------------------------------------------
// Ñ ik_attachCount
// ---------------------------------------------------------------------------------
// how many attachments does this controller reference
static int ik_attachCount(int controlIndex)
{
int count, i;
count = 0;
// valid controlIndex?
if ((controlIndex > 0) && (controlIndex <= kMaxControl)) {
// for each attach instance
for (i=1; i<=kMaxAttach; i++) {
// does this controller reference it
if (PROJECT_control[controlIndex].attachMap[i]) count += 1;
}
}
return count;
}
// ---------------------------------------------------------------------------------
// Ñ ik_controlCount
// ---------------------------------------------------------------------------------
// how many controllers reference this attachment
static int ik_controlCount(int attachIndex)
{
int count, i;
count = 0;
// valid attachIndex?
if ((attachIndex > 0) && (attachIndex <= kMaxAttach)) {
// for each control instance
for (i=1; i<=kMaxControl; i++) {
// does it reference this attach instance
if (PROJECT_control[i].attachMap[attachIndex]) count += 1;
}
}
return count;
}
// ---------------------------------------------------------------------------------
// Ñ ik_controlIndexForSocket
// ---------------------------------------------------------------------------------
// Find controller instance with corresponding socket if any and pass back it's index.
// Returns 0 for not found
static int ik_controlIndexForSocket(struct socket *so)
{
int returnValue = 0; // controller not connected ENOTCONN
int i;
for (i=1; i<=kMaxControl; i++) {
if (PROJECT_control[i].ctl == so) {
returnValue = i;
break;
}
}
return returnValue;
}
// ---------------------------------------------------------------------------------
// Ñ ik_emptyControlIndex
// ---------------------------------------------------------------------------------
// Find an empty controller instance (available slot)
// Returns 0 for not found
static int ik_emptyControlIndex()
{
int returnValue = 0; // all slots in use EBUSY
int i;
for (i=1; i<=kMaxControl; i++) {
if (PROJECT_control[i].ctl == 0) {
returnValue = i;
break;
}
}
return returnValue;
}
// ---------------------------------------------------------------------------------
// Ñ ik_attachIndexForName
// ---------------------------------------------------------------------------------
// Find attach instance with corresponding bsdName.
// Return 0 for not found.
static int ik_attachIndexForName(char *inName)
{
int returnValue = 0; // no such entry ENOENT
int i;
int len;
len = strlen(inName);
for (i=1; i<=kMaxAttach; i++) {
if ( memcmp(inName, &PROJECT_attach[i].kftInterfaceEntry.bsdName[0], len) == 0 ) {
returnValue = i;
break;
}
}
return returnValue;
}
// ---------------------------------------------------------------------------------
// Ñ ik_emptyAttachIndex
// ---------------------------------------------------------------------------------
// Find an empty attach instance (available slot)
// Return 0 for not found
static int ik_emptyAttachIndex()
{
int returnValue = 0; // all slots in use EBUSY
int i;
for (i=1; i<=kMaxAttach; i++) {
if (PROJECT_attach[i].filterID == 0) {
returnValue = i;
break;
}
}
return returnValue;
}
// ---------------------------------------------------------------------------------
// Ñ ik_findIFNet
// ---------------------------------------------------------------------------------
static int ik_findIFNet(char *inName, ifnet_t *ifnet_ref)
// return 0 if ifnet was found, otherwise unix error
//
// For insertering our NKE below IP as an interface filter, we use the ifnet
// global variable which points to the list of ifnet structures and scan the
// list to find the desired ifnet structure with matching interface name.
{
int returnValue = ENOENT;
extern struct ifnethead ifnet;
struct ifnet *ifp;
int len, unit, i;
short match;
do {
if (!inName) break; // defensive - name is null
len = strlen(inName) - 1;
unit = inName[len] - '0'; // get unit from end of name of the form "en0"
// walk the ifnet list
for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) {
// testing: list interfaces
//log(LOG_WARNING, "ik_findIFNet interface name: %s unit: %d\n",
// ifp->if_name, ifp->if_unit);
// check name length
if (len != strlen(ifp->if_name)) continue;
// compare base name
match = 1;
for (i=0; i<len; i++) {
if (inName[i] != ifp->if_name[i]) {
match = 0;
break;
}
}
if (!match) continue;
// names match, check unit
if (unit != ifp->if_unit) continue;
// we found a match
*ifnet_ref = ifp;
returnValue = 0;
break;
}
} while (FALSE);
return returnValue;
}
// ---------------------------------------------------------------------------------
// Ñ ik_detachController
// ---------------------------------------------------------------------------------
// Detach controller and remove any dlil interface attachments
// that are no longer referenced. Finally, clear the control instance.
//
// return 0 for success or unix error code
static int ik_detachController(int controlIndex)
{
int returnValue=0;
int attachIndex;
int result;
do {
if (!controlIndex) break; // no control instance, we're done
// make sure delay table is empty before detaching from any interfaces
KFT_delayAge(0);
// if controller was monitoring, turn it off
// - user might quit app without stopping or closing monitor window
if (PROJECT_control[controlIndex].monitorOn) {
PROJECT_control[controlIndex].monitorOn = 0;
// bump timer ref count
//PROJECT_timerRefCount -= 1;
//if (PROJECT_timerRefCount < 0) PROJECT_timerRefCount = 0;
result = OSAddAtomic(-1, (SInt32*)&PROJECT_timerRefCount);
if (result <= 0) PROJECT_timerRefCount = 0; // defensive
}
// get corresponding attach instances
for (attachIndex=1;attachIndex<=kMaxAttach;attachIndex++) {
if (PROJECT_control[controlIndex].attachMap[attachIndex]) {
// remove our reference to attach instance
PROJECT_control[controlIndex].attachMap[attachIndex] = 0;
// are there any more references?
if (ik_controlCount(attachIndex) == 0) {
// no more references to this attach instance
returnValue = ik_detachIndex(attachIndex);
}
} // end found attach instance
} // end for each attach instance
// clear control instance
bzero(&PROJECT_control[controlIndex], sizeof(control_t));
} while (FALSE);
return returnValue;
}
// ---------------------------------------------------------------------------------
// Ñ ik_detachIndex
// ---------------------------------------------------------------------------------
// detach our NKE for corresponding attach instance
// return 0 for success or unix error code
static int ik_detachIndex(int attachIndex)
{
int returnValue = 0;
u_long filterID;
char logBuffer[80];
// disable promisc mode if we enabled it
if (PROJECT_attach[attachIndex].promiscOn) {
ifnet_t ifnet_ref;
// get ifnet_ref for corresponding interface
returnValue = ik_findIFNet(PROJECT_attach[attachIndex].kftInterfaceEntry.bsdName, &ifnet_ref);
if (returnValue == 0) {
// disable promiscuous mode
int s, ret ;
s = splimp();
ret = ifpromisc(ifnet_ref, 0);
splx(s);
strcpy(&logBuffer[0], "\nik_detachIndex set promiscOn=0 for: ");
strcat(&logBuffer[0], PROJECT_attach[attachIndex].kftInterfaceEntry.bsdName);
KFT_logText(logBuffer,NULL);
}
}
// detach our NKE from this interface and clear instance
filterID = PROJECT_attach[attachIndex].filterID;
if (filterID) returnValue = dlil_detach_filter(filterID);
bzero(&PROJECT_attach[attachIndex], sizeof(attach_t));
return returnValue;
}
// ---------------------------------------------------------------------------------
// Ñ PROJECT_modifyReadyPacket
// ---------------------------------------------------------------------------------
// Tiger: prepare packet to be modified by finalizing and setting appropriate mbuf flags, return 0
// Panther: return 1 if outbound hardware TCP checksum is enabled so calculation should be skipped
// (no easy way to "finalize" in Panther)
int PROJECT_modifyReadyPacket(KFT_packetData_t* packet)
{
int returnValue = 0;
mbuf_t mbuf_ref;
#if TIGER
if (packet->modifyReady == 0) {
mbuf_ref = *(packet->mbuf_ptr);
if (packet->direction == kDirectionInbound) {
mbuf_inbound_modified(mbuf_ref);
}
else {
mbuf_outbound_finalize(mbuf_ref, AF_INET, packet->ipOffset);
#if 1
mbuf_csum_request_flags_t request;
u_int32_t value;
mbuf_get_csum_requested(mbuf_ref, &request, &value);
// work around bug in 10.4.2
if (request & 0x1000) returnValue = 1;
if (request & MBUF_CSUM_REQ_TCP) returnValue = 1;
//KFT_logText("csum_requested ", &request);
#endif
}
// remember what we did
packet->modifyReady = 1;
}
#else
mbuf_ref = *(packet->mbuf_ptr);
if (packet->direction == kDirectionInbound) {
// invalidate HW generated checksum flags
mbuf_ref->m_pkthdr.csum_data = 0;
mbuf_ref->m_pkthdr.csum_flags = 0;
//if ((mbuf_ref->m_pkthdr.csum_flags & CSUM_TCP_SUM16) &&
// (mbuf_ref->m_pkthdr.csum_flags & CSUM_DATA_VALID)) returnValue = 1;
}
else {
// Notice for outgoing packets the tcp checksum may not include the TCP header yet
if (mbuf_ref->m_pkthdr.csum_flags & CSUM_TCP_SUM16) returnValue = 1;
}
#endif
return returnValue;
}