#ifndef KPI_SOCKETFILTER_H
#define KPI_SOCKETFILTER_H


#include <sys/kernel_types.h>
#include <sys/kpi_socket.h>
#include <HYS/sys/kpi_socketfilter.h>

#include <netinet/in.h>//hys

/*sf_ioctl_func

typedef errno_t (*sf_ioctl_func)(
    void *cookie,
    socket_t so, 
    u_int32_t request,
    const char*argp);  
Parameters
cookie
Cookie value specified when the filter attach was called.
so
The socket the filter is attached to.
request
The ioctl name.
argp
A pointer to the ioctl parameter.
Return Value
Return: 0 - The caller will continue with normal processing of this ioctl. Anything Else - The caller will stop processing and return this error. 
Discussion 
sf_ioctl_func is called before performing an ioctl on a socket.*/
typedef errno_t (*sf_ioctl_func)(
    void *cookie,
    socket_t so, 
    u_int32_t request,
    const char*argp);  

/*sf_listen_func

typedef errno_t (*sf_listen_func)(
    void *cookie,
    socket_t so);  
Parameters
cookie
Cookie value specified when the filter attach was called.
so
The socket the filter is attached to.
Return Value
Return: 0 - The caller will continue with normal processing of listen. Anything Else - The caller will stop processing and return this error. 
Discussion 
sf_listen_func is called before performing listen on a socket.*/
typedef errno_t (*sf_listen_func)(
    void *cookie,
    socket_t so);  

/*sf_getoption_func

typedef errno_t (*sf_getoption_func)(
    void *cookie,
    socket_t so, 
    sockopt_t opt);  
Parameters
cookie
Cookie value specified when the filter attach was called.
so
The socket the filter is attached to.
opt
The socket option to get.
Return Value
Return: 0 - The caller will continue with normal processing of the getsockopt. Anything Else - The caller will stop processing and return this error. 
Discussion 
sf_getoption_func is called before performing getsockopt on a socket.*/
typedef errno_t (*sf_getoption_func)(
    void *cookie,
    socket_t so, 
    sockopt_t opt);  

/*sf_setoption_func

typedef errno_t (*sf_setoption_func)(
    void *cookie,
    socket_t so, 
    sockopt_t opt);  
Parameters
cookie
Cookie value specified when the filter attach was called.
so
The socket the filter is attached to.
opt
The socket option to set.
Return Value
Return: 0 - The caller will continue with normal processing of the setsockopt. Anything Else - The caller will stop processing and return this error. 
Discussion 
sf_setoption_func is called before performing setsockopt on a socket.*/

typedef errno_t (*sf_setoption_func)(
    void *cookie,
    socket_t so, 
    sockopt_t opt);  


/*sf_bind_func

typedef errno_t (*sf_bind_func)(
    void *cookie,
    socket_t so, 
    const struct sockaddr *to);  
Parameters
cookie
Cookie value specified when the filter attach was called.
so
The socket the filter is attached to.
to
The local address of the socket will be bound to.
Return Value
Return: 0 - The caller will continue with normal processing of the bind. Anything Else - The caller will rejecting the bind. 
Discussion 
sf_bind_func is called before performing a bind operation on a socket.*/
typedef errno_t (*sf_bind_func)(
    void *cookie,
    socket_t so, 
    const struct sockaddr *to);  


/*sf_connect_in_func

typedef errno_t (*sf_connect_in_func)(
    void *cookie,
    socket_t so, 
    const struct sockaddr *from);  
Parameters
cookie
Cookie value specified when the filter attach was called.
so
The socket the filter is attached to.
from
The address the incoming connection is from.
Return Value
Return: 0 - The caller will continue with normal processing of the connection. Anything Else - The caller will rejecting the incoming connection. 
Discussion 
sf_connect_in_func is called to filter inbound connections. A protocol will call this before accepting an incoming connection and placing it on the queue of completed connections. Warning: This filter is on the data path. Do not spend excesive time. Do not wait for data on another socket. */
typedef errno_t (*sf_connect_in_func)(
    void *cookie,
    socket_t so, 
    const struct sockaddr *from);  

/*sf_connect_out_func

typedef errno_t (*sf_connect_out_func)(
    void *cookie,
    socket_t so, 
    const struct sockaddr *to);  
Parameters
cookie
Cookie value specified when the filter attach was called.
so
The socket the filter is attached to.
to
The remote address of the outbound connection.
Return Value
Return: 0 - The caller will continue with normal processing of the connection. Anything Else - The caller will rejecting the outbound connection. 
Discussion 
sf_connect_out_func is called to filter outbound connections. A protocol will call this before initiating an outbound connection.*/
typedef errno_t (*sf_connect_out_func)(
    void *cookie,
    socket_t so, 
    const struct sockaddr *to);  

/*sf_data_out_func

typedef errno_t (*sf_data_out_func)(
    void *cookie,
    socket_t so, 
    const struct sockaddr *to,
    mbuf_t *data, 
    mbuf_t *control,
    sflt_data_flag_t flags);  
Parameters
cookie
Cookie value specified when the filter attach was called.
so
The socket the filter is attached to.
to
The address the data is going to, may be NULL if the socket is connected.
data
The data being sent. Control data may appear in the mbuf chain; be sure to check the mbuf types to find control data.
control
Control data being passed separately from the data.
flags
Flags to indicate if this is out of band data or a record.
Return Value
Return: 0 - The caller will continue with normal processing of the data. EJUSTRETURN - The caller will stop processing the data, the data will not be freed. Anything Else - The caller will free the data and stop processing. 
Discussion 
sf_data_out_func is called to filter outbound data. If your filter intercepts data for later reinjection, it must queue all outbound data to preserve the order of the data when reinjecting. Use sock_inject_data_out to later reinject this data.*/
typedef errno_t (*sf_data_out_func)(
    void *cookie,
    socket_t so, 
    const struct sockaddr *to,
    mbuf_t *data, 
    mbuf_t *control,
    sflt_data_flag_t flags);  

/*sf_data_in_func

typedef errno_t (*sf_data_in_func)(
    void *cookie,
    socket_t so, 
    const struct sockaddr *from,
    mbuf_t *data, 
    mbuf_t *control,
    sflt_data_flag_t flags);  
Parameters
cookie
Cookie value specified when the filter attach was called.
so
The socket the filter is attached to.
from
The addres the data is from, may be NULL if the socket is connected.
data
The data being received. Control data may appear in the mbuf chain; be sure to check the mbuf types to find control data.
control
Control data being passed separately from the data.
flags
Flags to indicate if this is out of band data or a record.
Return Value
Return: 0 - The caller will continue with normal processing of the data. EJUSTRETURN - The caller will stop processing the data, the data will not be freed. Anything Else - The caller will free the data and stop processing. 
Discussion 
sf_data_in_func is called to filter incoming data. If your filter intercepts data for later reinjection, it must queue all incoming data to preserve the order of the data. Use sock_inject_data_in to later reinject this data if you return EJUSTRETURN. Warning: This filter is on the data path. Do not spend excesive time. Do not wait for data on another socket.*/
typedef errno_t (*sf_data_in_func)(
    void *cookie,
    socket_t so, 
    const struct sockaddr *from,
    mbuf_t *data, 
    mbuf_t *control,
    sflt_data_flag_t flags);  

/*sf_getsockname_func

typedef int (*sf_getsockname_func)(
    void *cookie,
    socket_t so, 
    struct sockaddr **sa);  
Parameters
cookie
Cookie value specified when the filter attach was called.
so
The socket the filter is attached to.
sa
A pointer to a socket address pointer.
Return Value
If you return a non-zero value, processing will stop. If you return EJUSTRETURN, no further filters will be called but a result of zero will be returned to the caller of getsockname. 
Discussion 
sf_getsockname_func is called to allow a filter to to intercept the getsockname function. When called, sa will point to a pointer to a socket address that was malloced in zone M_SONAME. If you want to replace this address, either modify the currenty copy or allocate a new one and free the old one.*/

typedef int (*sf_getsockname_func)(
    void *cookie,
    socket_t so, 
    struct sockaddr **sa);  


/*sf_getpeername_func

typedef int (*sf_getpeername_func)(
    void *cookie,
    socket_t so, 
    struct sockaddr **sa);  
Parameters
cookie
Cookie value specified when the filter attach was called.
so
The socket the filter is attached to.
sa
A pointer to a socket address pointer.
Return Value
If you return a non-zero value, processing will stop. If you return EJUSTRETURN, no further filters will be called but a result of zero will be returned to the caller of getpeername. 
Discussion 
sf_getpeername_func is called to allow a filter to to intercept the getpeername function. When called, sa will point to a pointer to a socket address that was malloced in zone M_SONAME. If you want to replace this address, either modify the currenty copy or allocate a new one and free the old one.*/
typedef int (*sf_getpeername_func)(
    void *cookie,
    socket_t so, 
    struct sockaddr **sa);  

/*sf_notify_func

typedef void (*sf_notify_func)(
    void *cookie,
    socket_t so, 
    sflt_event_t event,
    void *param);  
Parameters
cookie
Cookie value specified when the filter attach was called.
so
The socket the filter is attached to.
event
The type of event that has occurred.
param
Additional information about the event.
Discussion 
sf_notify_func is called to notify the filter of various state changes and other events occuring on the socket.*/
typedef void (*sf_notify_func)(
    void *cookie,
    socket_t so, 
    sflt_event_t event,
    void *param);  

/*sf_detach_func

typedef void (*sf_detach_func)(
    void *cookie,
    socket_t so);  
Parameters
cookie
Cookie value specified when the filter attach was called.
so
The socket the filter is attached to.
Return Value
If you return a non-zero value, your filter will not be attached to this socket. 
Discussion 
sf_detach_func is called to notify the filter it has been detached from a socket. If the filter allocated any memory for this attachment, it should be freed. This function will be called when the socket is disposed of.*/
typedef void (*sf_detach_func)(
    void *cookie,
    socket_t so);  

/*sf_attach_func

typedef errno_t (*sf_attach_func)(
    void **cookie,
    socket_t so);  
Parameters
cookie
Used to allow the socket filter to set the cookie for this attachment.
so
The socket the filter is being attached to.
Return Value

If you return a non-zero value, your filter will not be attached to this socket. 
Discussion 

sf_attach_func is called to notify the filter it has been attached to a socket. The filter may allocate memory for this attachment and use the cookie to track it. This filter is called in one of two cases: 
You've installed a global filter and a new socket was created. 2) Your non-global socket filter is being attached using the SO_NKE socket option*/

typedef errno_t (*sf_attach_func)(
    void **cookie,
    socket_t so);  

/*sf_unregistered_func

typedef void (*sf_unregistered_func)(
    sflt_handle handle);  
Parameters
handle
The socket filter handle used to identify this filter.
Discussion 
sf_unregistered_func is called to notify the filter it has been unregistered. This is the last function the stack will call and this function will only be called once all other function calls in to your filter have completed. Once this function has been called, your kext may safely unload.*/
typedef void (*sf_unregistered_func)(
    sflt_handle handle);  

/*sflt_filter

struct sflt_filter { 
    sflt_handle sf_handle; 
    int sf_flags; 
    char*sf_name;  
    sf_unregistered_func sf_unregistered; 
    sf_attach_func sf_attach; 
    sf_detach_func sf_detach;  
    sf_notify_func sf_notify; 
    sf_getpeername_func sf_getpeername; 
    sf_getsockname_func sf_getsockname; 
    sf_data_in_func sf_data_in; 
    sf_data_out_func sf_data_out; 
    sf_connect_in_func sf_connect_in; 
    sf_connect_out_func sf_connect_out; 
    sf_bind_func sf_bind; 
    sf_setoption_func sf_setoption; 
    sf_getoption_func sf_getoption; 
    sf_listen_func sf_listen; 
    sf_ioctl_func sf_ioctl; 
};  
Fields
sf_handle
A value used to find socket filters by applications. An application can use this value to specify that this filter should be attached when using the SO_NKE socket option.
sf_flags
Indicate whether this filter should be attached to all new sockets or just those that request the filter be attached using the SO_NKE socket option.
sf_name
A name used for debug purposes.
sf_unregistered
Your function for being notified when your filter has been unregistered.
sf_attach
Your function for handling attaches to sockets.
sf_detach
Your function for handling detaches from sockets.
sf_notify
Your function for handling events. May be null.
sf_data_in
Your function for handling incoming data. May be null.
sf_data_out
Your function for handling outgoing data. May be null.
sf_connect_in
Your function for handling inbound connections. May be null.
sf_connect_in
Your function for handling outbound connections. May be null.
sf_bind
Your function for handling binds. May be null.
sf_setoption
Your function for handling setsockopt. May be null.
sf_getoption
Your function for handling getsockopt. May be null.
sf_listen
Your function for handling listen. May be null.
sf_ioctl
Your function for handling ioctls. May be null.
Discussion 
This structure is used to define a socket filter.*/
struct sflt_filter { 
    sflt_handle sf_handle; 
    int sf_flags; 
    char*sf_name;  
    sf_unregistered_func sf_unregistered; 
    sf_attach_func sf_attach; 
    sf_detach_func sf_detach;  
    sf_notify_func sf_notify; 
    sf_getpeername_func sf_getpeername; 
    sf_getsockname_func sf_getsockname; 
    sf_data_in_func sf_data_in; 
    sf_data_out_func sf_data_out; 
    sf_connect_in_func sf_connect_in; 
    sf_connect_out_func sf_connect_out; 
    sf_bind_func sf_bind; 
    sf_setoption_func sf_setoption; 
    sf_getoption_func sf_getoption; 
    sf_listen_func sf_listen; 
    sf_ioctl_func sf_ioctl; 
};  

/*sflt_event_t

Events notify a filter of state changes and other various events related to the socket. These events can not be prevented or intercepted, only observed. 
enum { 
    sock_evt_connecting = 1, 
    sock_evt_connected = 2, 
    sock_evt_disconnecting = 3, 
    sock_evt_disconnected = 4, 
    sock_evt_flush_read = 5, 
    sock_evt_shutdown = 6, // param points to an integer specifying how (read, write, or both) see man 2 shutdown 
    sock_evt_cantrecvmore = 7, 
    sock_evt_cantsendmore = 8, 
    sock_evt_closing = 9 
};  
Constants
sock_evt_connected
Indicates this socket has moved to the connected state.
sock_evt_disconnected
Indicates this socket has moved to the disconnected state.
sock_evt_flush_read
The read socket buffer has been flushed.
sock_evt_shutdown
The read and or write side(s) of the connection have been shutdown. The param will point to an integer that indicates the direction that has been shutdown. See 'man 2 shutdown' for more information.
sock_evt_cantrecvmore
Indicates the socket can not receive more data.
sock_evt_cantsendmore
Indicates the socket can not send more data.
sock_evt_closing
Indicates the socket is closing.*/
enum { 
    sock_evt_connecting = 1, 
    sock_evt_connected = 2, 
    sock_evt_disconnecting = 3, 
    sock_evt_disconnected = 4, 
    sock_evt_flush_read = 5, 
    sock_evt_shutdown = 6, // param points to an integer specifying how (read, write, or both) see man 2 shutdown 
    sock_evt_cantrecvmore = 7, 
    sock_evt_cantsendmore = 8, 
    sock_evt_closing = 9 
};  


/*sflt_flags

Constants defining mbuf flags. Only the flags listed below can be set or retreieved. 
enum { 
    SFLT_GLOBAL = 0x01, 
    SFLT_PROG = 0x02 
};  
Constants
SFLT_GLOBAL
Indicates this socket filter should be attached to all new sockets when they're created.
SFLT_PROG
Indicates this socket filter should be attached only when request by the application using the SO_NKE socket option*/
enum { 
    SFLT_GLOBAL = 0x01, 
    SFLT_PROG = 0x02 
};  


/*sflt_data_flag_t

Inbound and outbound data filters may handle many different types of incoming and outgoing data. These flags help distinguish between normal data, out-of-band data, and records. 
enum { 
    sock_data_filt_flag_oob = 1, 
    sock_data_filt_flag_record = 2 
};  
Constants
sock_data_filt_flag_oob
Indicates this data is out-of-band data.
sock_data_filt_flag_record
Indicates this data is a record. This flag is only ever seen on inbound data.*/
enum { 
    sock_data_filt_flag_oob = 1,
    sock_data_filt_flag_record = 2
};

/*sock_inject_data_in

errno_t sock_inject_data_in(
    socket_t so,
    const struct sockaddr*from, 
    mbuf_t data,
    mbuf_t control,
    sflt_data_flag_t flags);  
Parameters
so
The socket to inject the data on.
from
The address the data is from, only necessary on un-connected sockets. A copy of the address will be made, caller is responsible for freeing the address after calling this function.
data
The data and possibly control mbufs.
control
The separate control mbufs.
flags
Flags indicating the type of data.
Return Value

0 on success otherwise the errno error. If the function returns an error, the caller is responsible for freeing the mbuf. 
Discussion 

Inject data in to the receive buffer of the socket as if it had come from the network.*/
errno_t sock_inject_data_in(
    socket_t so,
    const struct sockaddr*from,
    mbuf_t data,
    mbuf_t control,
    sflt_data_flag_t flags);

/*sock_inject_data_out

errno_t sock_inject_data_out(
    socket_t so,
    const struct sockaddr*to, 
    mbuf_t data,
    mbuf_t control,
    sflt_data_flag_t flags);  
Parameters
so
The socket to inject the data on.
to
The address the data should be sent to, only necessary on un-connected sockets. The caller is responsible for freeing the to address after sock_inject_data_out returns.
data
The data and possibly control mbufs.
control
The separate control mbufs.
flags
Flags indicating the type of data.
Return Value

0 on success otherwise the errno error. The data and control values are always freed regardless of return value. 
Discussion 

Inject data in to the send buffer of the socket as if it had come from the client.*/
 errno_t sock_inject_data_out(
    socket_t so,
    const struct sockaddr *to,
    mbuf_t data,
    mbuf_t control,
    sflt_data_flag_t flags); 

/*sflt_register

errno_t sflt_register(
    const struct sflt_filter *filter,
    int domain, 
    int type,
    int protocol);  
Parameters
filter
A structure describing the filter.
domain
The protocol domain these filters will be attached to.
type
The socket type these filters will be attached to.
protocol
The protocol these filters will be attached to.
Return Value

0 on success otherwise the errno error. 
Discussion 

Registers a socket filter. See 'man 2 socket' for a desciption of domain, type, and protocol.*/
errno_t sflt_register(
    const struct sflt_filter *filter,
    int domain, 
    int type,
    int protocol);  

/*sflt_unregister

errno_t sflt_unregister(
    sflt_handle handle);  
Parameters
handle
The sf_handle of the socket filter to unregister.
Return Value

0 on success otherwise the errno error. 
Discussion 

Unregisters a socket filter. This will not detach the socket filter from all sockets it may be attached to at the time, it will just prevent the socket filter from being attached to any new sockets.*/
errno_t sflt_unregister(
    sflt_handle handle);  

#endif