aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/interceptor/interceptor.h
blob: 054daf1955adc7f3c8b85129653937ba98460ebc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
/* Netfilter Driver for IPSec VPN Client
 *
 * Copyright(c)   2012 Samsung Electronics
 *
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

/*
 * interceptor.h
 *
 * Interceptor API specifies the Interceptor side interface between
 * the Interceptor and Engine components. This API contains functions
 * for Interceptor initialization, packet allocation, packet data access,
 * routing and packet sending.
 *
 */

#ifndef INTERCEPTOR_H
#define INTERCEPTOR_H

#include "sshinet.h"

/** The amount of space to reserve in packet header for the IPsec engine. */
#define SSH_INTERCEPTOR_UPPER_DATA_SIZE         192

/** The number of available extension selectors for platform-specific
    extensions. */
#define SSH_INTERCEPTOR_NUM_EXTENSION_SELECTORS 1

/** Size of interface system name. */
#define SSH_INTERCEPTOR_IFNAME_SIZE             64

/** Data type for the interceptor context. */
typedef struct SshInterceptorRec *SshInterceptor;

/** This type defines the type of a network interface interface.  The
    type is supposed to be sufficient to determine how to process the
    packets.  It is not expected to provide maximal detail to the
    user.  Regardless of the interface type, the higher-level code
    should not assume that incoming packets have been defragmented,
    nor will it assume that the interceptor will perform fragmentation
    for outgoing packets.  Thus, it will perform these functions
    itself.  It will not assume the underlying interceptor will do it.
    Routing will also be done by the higher level to determine which
    interface a packet should go out from. */
typedef enum {
  SSH_INTERCEPTOR_MEDIA_NONEXISTENT, /** The interface is not available */
  SSH_INTERCEPTOR_MEDIA_PLAIN,       /** Any interceptor w/o media headers*/
  SSH_INTERCEPTOR_MEDIA_ETHERNET,    /** Ethernet (rfc894) framing */
  SSH_INTERCEPTOR_MEDIA_FDDI,        /** FDDI (rfc1042/rfc1103) framing */
  SSH_INTERCEPTOR_MEDIA_TOKENRING,   /** Tokenring (rfc1042/rfc1469) framing */
  /** New types may be added here.  Look for one of the existing types
     to find all places in code that should be updated. */
  SSH_INTERCEPTOR_NUM_MEDIAS   /** Must be the last entry! */
} SshInterceptorMedia;

/** Protocol identifiers.  These identify recognized protocols (packet
    formats) in a portable manner.  This enumeration includes media
    types, but also all recognized higher-level protocols. */
typedef enum
{
  SSH_PROTOCOL_IP4,             /** IPv4 frame */
  SSH_PROTOCOL_IP6,             /** IPv6 frame */
  SSH_PROTOCOL_IPX,             /** IPX frame */
  SSH_PROTOCOL_ETHERNET,        /** Ethernet frame */
  SSH_PROTOCOL_FDDI,            /** FDDI frame */
  SSH_PROTOCOL_TOKENRING,       /** Token Ring frame */
  SSH_PROTOCOL_ARP,             /** ARP frame */
  SSH_PROTOCOL_OTHER,           /** some other type frame */
  SSH_PROTOCOL_NUM_PROTOCOLS    /** must be the last entry! */
} SshInterceptorProtocol;

/** Data type for an interface number. This type must be atleast as big as
    the system interface index. */
typedef SshUInt32 SshInterceptorIfnum;

/** Maximum value of interface number.
    All valid interface numbers must be smaller than this value. */
#define SSH_INTERCEPTOR_MAX_IFNUM ((SshInterceptorIfnum) 0xffffffff)

/** Reserved value for invalid interface number. */
#define SSH_INTERCEPTOR_INVALID_IFNUM SSH_INTERCEPTOR_MAX_IFNUM

/** Data structure for representing an address for a network interface. */
typedef struct SshInterfaceAddressRec
{
  /** Protocol for which the address is. */
  SshInterceptorProtocol protocol;

  /** The address itself. */
  union
  {
    /** IPv4 and IPv6. */
    struct
    {
      SshIpAddrStruct ip;
      SshIpAddrStruct mask;
      SshIpAddrStruct broadcast;
    } ip;

    /** IPX */
    struct
    {
      SshUInt32 net;
      unsigned char host[6];
    } ns;
  } addr;
} *SshInterfaceAddress, SshInterfaceAddressStruct;

/** Flags for the media direction information. */

/** Do not fragment before sending from engine. */
#define SSH_INTERCEPTOR_MEDIA_INFO_NO_FRAGMENT                  0x0001

/** Accessor for mtu member in SshInterceptorMediaDirectionInfo. */
#ifdef WITH_IPV6
#define SSH_INTERCEPTOR_MEDIA_INFO_MTU(info, is_ipv6) \
  ((is_ipv6) ? (info)->mtu_ipv6 : (info)->mtu_ipv4)
#else /* WITH_IPV6 */
#define SSH_INTERCEPTOR_MEDIA_INFO_MTU(info, is_ipv6) \
  ((info)->mtu_ipv4)
#endif /* WITH_IPV6 */

/** Media direction information.  This information is used when engine
    is sending packets to the interceptor. */
typedef struct SshInterceptorMediaDirectionInfoRec
{
  SshInterceptorMedia media;    /* media type */
  SshUInt32 flags;              /* flags */
  size_t mtu_ipv4;              /* mtu for the direction (ipv4) */
#ifdef WITH_IPV6
  size_t mtu_ipv6;              /* mtu for the direction (ipv6) */
#endif /* WITH_IPV6 */
} *SshInterceptorMediaDirectionInfo, SshInterceptorMediaDirectionInfoStruct;

/** Flag values for flags in SshInterceptorInterface */
/* Interface type */
#define SSH_INTERFACE_FLAG_VIP         0x0001
#define SSH_INTERFACE_FLAG_POINTOPOINT 0x0002
#define SSH_INTERFACE_FLAG_BROADCAST   0x0004
/* Interface link status */
#define SSH_INTERFACE_FLAG_LINK_DOWN   0x0100

/** Data structure for providing information about a network
    interface. */
typedef struct
{
  SshInterceptorMediaDirectionInfoStruct to_protocol;
  SshInterceptorMediaDirectionInfoStruct to_adapter;
  char name[SSH_INTERCEPTOR_IFNAME_SIZE]; /** system name for the interface */
  SshInterceptorIfnum ifnum;    /** Interface number */
  SshUInt32 num_addrs;          /** Number of addresses for the interface. */
  SshInterfaceAddress addrs;    /** mallocated array of address structures. */
  unsigned char media_addr[16]; /** MAC address, medium size and format */
  size_t media_addr_len;        /** Length of the MAC address. */

  SshUInt32 flags;              /** Flags for the interface. */

  /** Context pointer for owner/user for this SshInterceptorInterface.
      Can be used for e.g. storing interface-specific
      NAT-configuration. */
  void *ctx_user;
} SshInterceptorInterface;

/*  Packet flag bits. */
#define SSH_PACKET_FROMPROTOCOL  0x00000001U /** Packet from the protocol. */
#define SSH_PACKET_FROMADAPTER   0x00000002U /** Packet from the adapter. */
#define SSH_PACKET_IP4HDRCKSUMOK 0x00000004U /** IPv4 header cksum checked. */
#define SSH_PACKET_FORWARDED     0x00000008U /** Packet was forwarded. */
#define SSH_PACKET_HWCKSUM       0x00000010U /** TCP/UDP cksum done by NIC. */
#define SSH_PACKET_MEDIABCAST    0x00000020U /** Packet was media broadcast. */
#define SSH_PACKET_UNMODIFIED    0x00000200U /** Unmodified packet. */

/*  This flag specifies that the engine is allowed to fragment the packet if
    the packet is too large to fit into interafce MTU. Some operating
    system handle the fragmentation after us and therefore this flag
    may be set for some outbound data packets. The packet is guaranteed
    to have been originated from local stack and stack has indicated
    that this packet can be fragmented. */
#define SSH_PACKET_FRAGMENTATION_ALLOWED  0x00000400U

/*  Flag bits with mask 0x00000fff are reserved for interceptor. */
/*  Flag bits with mask 0xfffff000 are reserved for IPSEC engine. */

/** Macro to access upper-level data in the packet header. */
#define SSH_INTERCEPTOR_PACKET_DATA(packet, type) \
  ((type)(&(packet)->upper_data))

/** Data structure for a packet.  These data structures can only be
    allocated by the interceptor; higher-level code must never
    directly allocate these (the interceptor implementation may
    actually use a larger structure containing this public
    structure). */
typedef struct SshInterceptorPacketRec
{
  /** Flags for the packet.  The SSH_PACKET_* bitmasks are used.  Code
      above the interceptor is not allowed to modify flags 0x001-0x800;
      they may be used internally by the interceptor to pass
      information from packet_cb/ssh_interceptor_packet_alloc to
      ssh_interceptor_send/ssh_interceptor_packet_free.  During
      certain times, such when applying asynchronous IPSEC
      transformations, this field may be changed concurrently by
      another thread (or interrupt) even when another thread is
      processing the packet. Care should be taken with locking in
      those situations. */
  SshUInt32 flags;

  /** Number of the interface that this packet arrived from */
  SshInterceptorIfnum ifnum_in;

  /** Number of the interface that this packet going out */
  SshInterceptorIfnum ifnum_out;

  /** Format of the packet (protocol identifier). */
  SshInterceptorProtocol protocol;

  /** Path MTU stored for this packet, which must be respected at
      media send (if interface MTU is smaller than this value, then
      the media send routine must send ICMP PMTU message and discard
      the packet). If 0, means use the interface MTU only. */
  SshUInt32 pmtu;

#if (SSH_INTERCEPTOR_NUM_EXTENSION_SELECTORS > 0)
  /** Platform-dependent extension selectors for things like user id,
      virtual network identifier, etc. */
  SshUInt32 extension[SSH_INTERCEPTOR_NUM_EXTENSION_SELECTORS];
#endif /* (SSH_INTERCEPTOR_NUM_EXTENSION_SELECTORS > 0) */

#ifdef SSH_IPSEC_IP_ONLY_INTERCEPTOR
  /** Route key selector that was used in the route lookup */
  SshUInt16 route_selector;
#endif /* SSH_IPSEC_IP_ONLY_INTERCEPTOR */

  /** Buffer that can be used by higher level software to store its
      data (such as cached media addresses).  This field can only be
      accessed using the SSH_INTERCEPTOR_PACKET_DATA macro. */
  union {
    /** Contents of this union are private (they are there to
	guarantee proper alignment for any data structure stored
	here). */
    long force_alignment_l; int force_alignment_i; short force_alignment_s;
    void *force_alignment_v;
    SshUInt16 force_alignment_i16; SshUInt32 force_alignment_i32;
    SshUInt64 force_alignment_i64;
    char force_size_dont_use_this_directly[SSH_INTERCEPTOR_UPPER_DATA_SIZE];
    /* Should have double here if floating point was allowed. */
  } upper_data;

  /** Next pointer on freelist.  This can also be used by higher-level
      code to put the packet on a list. */
  struct SshInterceptorPacketRec *next;
} *SshInterceptorPacket, SshInterceptorPacketStruct;

/** Error codes for route add / remove functions. */
typedef enum {
  SSH_INTERCEPTOR_ROUTE_ERROR_OK = 0,
  SSH_INTERCEPTOR_ROUTE_ERROR_NONEXISTENT = 1,
  SSH_INTERCEPTOR_ROUTE_ERROR_OUT_OF_MEMORY = 2,
  SSH_INTERCEPTOR_ROUTE_ERROR_ALREADY_EXISTS = 3,
  SSH_INTERCEPTOR_ROUTE_ERROR_UNDEFINED = 255
} SshInterceptorRouteError;

/** Flag values for the route add / remove functions. */

/** Ignore non-existent routes when attempting to remove the route. */
#define SSH_INTERCEPTOR_ROUTE_FLAG_IGNORE_NONEXISTENT   0x0001

/** Data structure for routing key, used in route lookups and routing table
    manipulation.

    The route lookup is performed for the destination address, using other
    fields in the routing key to enforce routing policies. It is a fatal
    error to call ssh_interceptor_route using a SshInterceptorRouteKey
    which does not have the destination address set.

    Use the provided macros for setting fields in SshInterceptorRouteKey.

    Note that on platforms that do not support policy routing, the route lookup
    uses only the destination address. On other platforms other fields of the
    SshInterceptorRouteKey may be used in the route lookup. */
typedef struct SshInterceptorRouteKeyRec
{
  /** Destination address, mandatory */
  SshIpAddrStruct dst;
  /** Source address, optional */
  SshIpAddrStruct src;
  /** IP protocol identifier, optional */
  SshUInt32 ipproto;
  /** Interface number, optional.
      Note that this field specifies either the inbound interface number
      or the outbound interface number, depending on the value of the
      'selector' field. */
  SshUInt32 ifnum;
  /** Network layer fields */
  union
  {
    /** IPv4 TOS, optional */
    struct
    {
      SshUInt8 tos;
    } ip4;
    /** IPv6 priority and flow label, optional */
    struct
    {
      SshUInt8 priority;
      SshUInt32 flow;
    } ip6;
    /** For encoding / decoding */
    unsigned char raw[5];
  } nh;
  /** Transport layer fields */
  union
  {
    /** TCP / UDP ports, optional */
    struct
    {
      SshUInt16 dst_port;
      SshUInt16 src_port;
    } tcp;
    /** ICMP type and code, optional */
    struct
    {
      SshUInt8 type;
      SshUInt8 code;
    } icmp;
    /** ESP / AH spi, optional */
    struct
    {
      SshUInt32 spi;
    } ipsec;
    /** For encoding / decoding */
    unsigned char raw[4];
  } th;
#if (SSH_INTERCEPTOR_NUM_EXTENSION_SELECTORS > 0)
  /** Platform-dependent extension selectors, optional */
  SshUInt32 extension[SSH_INTERCEPTOR_NUM_EXTENSION_SELECTORS];
#endif /* (SSH_INTERCEPTOR_NUM_EXTENSION_SELECTORS > 0) */
  /** Bitmap of selectors that are to be used in the route lookup.
      Use the provided macros to add selectors to the routing key,
      do not access this field directly. The highest 3 bits of
      'selector' are reserved for flags defined below. */
  SshUInt16 selector;
} *SshInterceptorRouteKey, SshInterceptorRouteKeyStruct;

/*  Selector values for 'selector' bitmap */

/** Source address */
#define SSH_INTERCEPTOR_ROUTE_KEY_SRC                    0x0001
/** IP protocol identifier */
#define SSH_INTERCEPTOR_ROUTE_KEY_IPPROTO                0x0002
/** Inbound interface number */
#define SSH_INTERCEPTOR_ROUTE_KEY_IN_IFNUM               0x0004
/** Outbound interface number */
#define SSH_INTERCEPTOR_ROUTE_KEY_OUT_IFNUM              0x0008
/** IPv4 type of service */
#define SSH_INTERCEPTOR_ROUTE_KEY_IP4_TOS                0x0010
/** Platform-dependent Extension selectors */
#define SSH_INTERCEPTOR_ROUTE_KEY_EXTENSION              0x1000

/*  Flag values for 'selector' bitmap */

/** Packets going to this destination are transformed by the engine and the
    resulting packet may be larger than the path MTU reported to the IP stack
    by the engine. */
#define SSH_INTERCEPTOR_ROUTE_KEY_FLAG_TRANSFORM_APPLIED 0x2000
/** Source address belongs to one of the local interfaces. */
#define SSH_INTERCEPTOR_ROUTE_KEY_FLAG_LOCAL_SRC         0x4000

/** A callback function of this type will be called when the
    interceptor is first opened, and from then on whenever there is a
    change in the interface list (e.g., a new interface goes up or
    down or the address of an interface changes).  This function will
    be given a list of the interfaces.  The supplied array will only
    be valid for the duration of this call; the implementation of this
    function is supposed to copy the information if it is going to
    need it later.  Note that this function may be called
    asynchronously, concurrently with any other functions.  */
typedef void (*SshInterceptorInterfacesCB)(SshUInt32 num_interfaces,
                                           SshInterceptorInterface *ifs,
                                           void *context);

/** Callback functions of this type are called whenever a packet is
    received from the network or from a protocol.  This function must
    eventually free the packet, either by calling
    ssh_interceptor_packet_free on the packet or by passing it to the
    ssh_interceptor_send function.  Note that this function may be
    called asynchronously, concurrently with any other functions.

    When a packet is passed to this callback, the `pp->flags' field
    may contain arbitrary flags in the bits reserved for the
    interceptor (mask 0x00000fff).  This callback is not allowed to
    modify any of those bits; they must be passed intact to
    ssh_interceptor_send or ssh_interceptor_packet_free.  Any other
    bits (mask 0xfffff000) will be zero when the packet is sent to
    this callback; those bits may be used freely by this callback.
    They are not used by the interceptor. */
typedef void (*SshInterceptorPacketCB)(SshInterceptorPacket pp, void *context);

/** A callback function of this type is used to notify code above the
    interceptor that routing information has changed, and any cached
    routing data should be thrown away and refreshed by a new route
    lookup. */
typedef void (*SshInterceptorRouteChangeCB)(void *context);

/** Opens the packet interceptor.  This must be called before using
    any other interceptor functions.  This registers the callbacks
    that the interceptor will use to notify the higher levels of
    received packets or changes in the interface list.  The interface
    callback will be called once either during this call or soon after
    this has returned.

    The `machine_context' argument is intended to be meaningful only
    to machine-specific code.  It is passed through from the
    machine-specific main program.  One example of its possible uses
    is to identify a virtual router in systems that implement multiple
    virtual routers in a single software environment.  Most
    implementations will ignore this argument.

    The `packet_cb' callback will be called whenever a packet is
    received from either a network adapter or a protocol stack.  The
    first calls may arrive already before this function has returned.

    The `interfaces_cb' callback will be called once soon after
    opening the interceptor (possibly before this call returns).  From
    then on, it will be called whenever there is a change in the
    interface list (e.g., the IP address of an interface is changed,
    or a PPP interface goes up or down).

    The `route_change_cb' callback should be called whenever there is
    a change in routing information.  Implementing this callback is
    optional but beneficial in e.g. router environments (the
    information is not easily available on all systems).

    The `context' argument is passed to the callbacks.

    This function returns TRUE if opening the interceptor was
    successful.  The interceptor object is returned in the
    `interceptor_return' argument.  Most systems will only allow a
    single interceptor to be opened; however, some systems may support
    multiple interceptors identified by the `machine_context'
    argument.  This returns FALSE if an error occurs (e.g., no
    interceptor kernel module is loaded on this system, or the
    interceptor is already open).

    Care must be taken regarding concurrency control in systems that have
    multithreaded IP stacks.  In particular:
     - packet_cb and interfaces_cb may get called before this function
       returns.  It is, however, guaranteed that `*interceptor_return'
       has been set before the first call to either of them.
     - the interceptor cannot be closed while there are calls or packets
       out.  The ssh_interceptor_stop function must be used.
     In such systems, additional concurrency may be introduced by timeouts
     and actions from the policy manager connection. */
Boolean ssh_interceptor_open(void *machine_context,
                             SshInterceptorPacketCB packet_cb,
                             SshInterceptorInterfacesCB interfaces_cb,
                             SshInterceptorRouteChangeCB route_change_cb,
                             void *context,
                             SshInterceptor *interceptor_return);

/** Sends a packet to the network or to the protocol stacks.  This
    will eventually free the packet by calling
    ssh_interceptor_packet_free.  The `media_header_len' argument
    specifies how many bytes from the start of the packet are media
    (link-level) headers.  It will be 0 if the interceptor operates
    directly at protocol level. If the configure define
    INTERCEPTOR_IP_ALIGNS_PACKETS is set, this function must ensure
    that the IP header of the packet is aligned to a word boundary.

    This function relies on 'pp->ifnum_out' being an 'ifnum' which has
    previously been reported via a SshInterceptorInterfacesCB. It does
    not have to be valid at that precise point in time. If 'pp->ifnum_out'
    is an ifnum which may have been previously reported to the
    SshInterceptorInterfacesCB, then ssh_interceptor_send() MUST check
    that it is valid, or otherwise discard the packet.  Also,
    pp->protocol (and the corresponding encapsulation) may be
    incorrect for the interface denoted by 'pp->ifnum_out'. The packet
    should be dropped also in this case.

    This function can be called concurrently from multiple threads,
    but only for one packet at a time.  It is ok to call this even
    before ssh_interceptor_open has actually returned (from a
    `packet_cb' or `interface_cb' callback). */

void ssh_interceptor_send(SshInterceptor interceptor,
                          SshInterceptorPacket pp,
                          size_t media_header_len);

/** Enables or disables packet interception. */
void ssh_interceptor_enable_interception(SshInterceptor interceptor,
					 Boolean enable);

/** Stops the packet interceptor.  After this call has returned, no
    new calls to the packet and interfaces callbacks will be made.
    The interceptor keeps track of how many threads are processing
    packet, interface, or have pending route callbacks, and this
    function returns TRUE if there are no callbacks/pending calls to
    those functions.  This returns FALSE if threads are still
    executing in those callbacks or routing callbacks are pending.

    After calling this function, the higher-level code should wait for
    packet processing to continue, free all packet structures received
    from that interceptor, and then call ssh_interceptor_close.  It is
    not an error to call this multiple times (the latter calls are
    ignored).

    It is forbidden to hold ANY locks when calling
    ssh_interceptor_stop(). */

Boolean ssh_interceptor_stop(SshInterceptor interceptor);

/** Closes the packet interceptor.  This function can only be called when
     - ssh_interceptor_stop has been called
     - all packet and interface callbacks from this interceptor have
       returned.
     - all ssh_interceptor_route completions have been called
     - all packets received from the packet callbacks from this interceptor
       have been freed.

   It is illegal to call any packet interceptor functions (other than
   ssh_interceptor_open) after this call.  This function cannot be
   called from an interceptor callback.

   This function can be called from one thread only for any particular
   interceptor.  If multiple interceptors are supported, then this may be
   called for different interceptors asynchronously. */
void ssh_interceptor_close(SshInterceptor interceptor);

/** Completion function for route lookup.  This function is called when the
    route lookup is complete.
     reachable    FALSE if the destination cannot be reached, TRUE otherwise
     next_hop_gw  IP address of next hop gw or destination
     ifnum        network interface to which to send the packet
     mtu          path mtu, or 0 if not known (= should use link mtu)
     context      context argument supplied to route request.

    This function may get called concurrently from multiple threads. */
typedef void (*SshInterceptorRouteCompletion)(Boolean reachable,
                                              SshIpAddr next_hop_gw,
                                              SshInterceptorIfnum ifnum,
                                              size_t mtu,
                                              void *context);

/** Looks up routing information for the routing key specified
    by `key'.  Calls the callback function either during this
    call or some time later.  The purpose of the callback function is
    to allow this function to perform asynchronous operations, such as
    forwarding the routing request to a user-level process.  This
    function will not be very efficient on some systems, and calling
    this on a per-packet basis should be avoided if possible.
    This function expects that 'key' is valid only for the duration
    of the call, and will take a local copy of it, if necessary.

    Note that if this function is implemented by forwarding the
    request to a user-level process, care must be taken to never lose
    replies.  The completion function must *always* be called.  For
    example, if the policy manager interface is used to pass the
    requests to the policy manager process, and the interface is
    closed, the completion function must still be called for all
    requests.  Code may be needed to keep track of which requests are
    waiting for replies from the user-level process.

    This function can be called concurrently from multiple threads.
    While legal, new calls to this function after calling
    ssh_interceptor_stop should be avoided, because it is not possible
    to call ssh_interceptor_close until all route lookup completions
    have been called. */
void ssh_interceptor_route(SshInterceptor interceptor,
                           SshInterceptorRouteKey key,
                           SshInterceptorRouteCompletion completion,
                           void *context);

/** Allocates a packet of at least the given size.  Packets can only
    be allocated using this function (either internally by the
    interceptor or by other code by calling this function).
    Typically, this takes a packet header from a free list, stores a
    pointer to a platform-specific packet object, and returns the
    packet header.  This should be re-entrant and support concurrent
    operations if the IPSEC engine is re-entrant on the target
    platform.  Other functions in this interface should be re-entrant
    for different packet objects, but only one operation will be in
    progress at any given time for a single packet object.  This
    returns NULL if no more packets can be allocated.  On systems that
    support concurrency, this can be called from multiple threads
    concurrently.

    This sets initial values for the mandatory fields of the packet
    that always need to be initialized.  However, any of these fields
    can be modified later. */
SshInterceptorPacket ssh_interceptor_packet_alloc(SshInterceptor interceptor,
                                                 SshUInt32 flags,
                                                 SshInterceptorProtocol proto,
                                                 SshInterceptorIfnum ifnum_in,
                                                 SshInterceptorIfnum ifnum_out,
                                                 size_t total_len);


/** Frees the packet.

    All packets allocated by ssh_interceptor_packet_alloc must
    eventually be freed using this function by either calling this
    explicitly or by passing the packet to the ssh_interceptor_send
    function.  Typically, this calls a suitable function to
    free/release the platform-specific packet object, and puts the
    packet header on a free list.  This function should be re-entrant,
    so if a free list is used, it should be protected by a lock in
    systems that implement concurrency in the IPSEC Engine.  Multiple
    threads may call this function concurrently for different packets,
    but not for the same packet. */
void ssh_interceptor_packet_free(SshInterceptorPacket pp);

/** Returns the total length of the packet in bytes.  Multiple threads may
    call this function concurrently, but not for the same packet. */
size_t ssh_interceptor_packet_len(SshInterceptorPacket pp);


/** Copies data into the packet. Space for the new data must already
    have been allocated. It is a fatal error to attempt to copy beyond
    the allocated packet. Multiple threads may call this function
    concurrently, but not for the same packet. Returns TRUE if
    successfull and FALSE otherwise. If error occurs then the pp is
    already freed by this function, and the caller must not refer to
    it anymore.

    There is a generic version of this function inside the engine, in
    case interceptor does not want to implement this. If interceptor
    implements this function it must define the
    INTERCEPTOR_HAS_PACKET_COPYIN pre-processor symbol. */
Boolean ssh_interceptor_packet_copyin(SshInterceptorPacket pp, size_t offset,
                                      const unsigned char *buf, size_t len);

/** Copies data out from the packet.  Space for the new data must
    already have been allocated.  It is a fatal error to attempt to
    copy beyond the allocated packet. Multiple threads may call this
    function concurrently, but not for the same packet.

    There is a generic version of this function inside the engine, in
    case interceptor does not want to implement this. If interceptor
    implements this function it must define the
    INTERCEPTOR_HAS_PACKET_COPYOUT pre-processor symbol. */
void ssh_interceptor_packet_copyout(SshInterceptorPacket pp, size_t offset,
                                    unsigned char *buf, size_t len);


/** These two routines provide way to export and import
    interceptor-specific internal packet data as an opaque binary data
    block.

    If the export routine returns FALSE, the packet `pp' is
    invalidated. If it returnes TRUE, but *data_ret is NULL, then no
    internal data was exported. If *data_ret is non-NULL, then
    *len_return contains the length of *data_ret in bytes. The caller
    must free the *data_ret value using ssh_free.

    The import routine returns TRUE if the data was imported
    successfully, otherwise it returns FALSE and the packet `pp' is
    invalidated. It is a fatal error to call import routine on the
    same packet more than once.

    Notice: If the interceptor does not define these routines, then
    the engine provides dummy versions.

    Notice: This routine overlaps a bit with
    ssh_interceptor_packet_alloc_and_copy_ext_data, as it could be
    implemented as:

        new_pp = ssh_interceptor_packet_alloc(...);
        ssh_interceptor_packet_copy(pp, 0, ..., new_pp, 0);
        ssh_interceptor_packet_export_internal_data(pp, &data, &len);
        ssh_interceptor_packet_import_internal_data(new_pp, data, len);
        ssh_free(data);

    The main purpose of these routines is to allow some per-packet
    interceptor-specific data to be transported to the usermode
    engine. Under the kernel IPSec Engine, these routines are not
    actually used at all. */
Boolean ssh_interceptor_packet_export_internal_data(SshInterceptorPacket pp,
                                                    unsigned char **data_ret,
                                                    size_t *len_return);

Boolean ssh_interceptor_packet_import_internal_data(SshInterceptorPacket pp,
                                                    const unsigned char *data,
                                                    size_t len);

void ssh_interceptor_packet_discard_internal_data(unsigned char *data,
						  size_t data_len);


/** Copy data from one packet to another. Start from the
    `source_offset' and copy `bytes_to_copy' bytes to
    `destination_offset' in the destination packet. If the destination
    packet cannot be written then return FALSE, and the destination
    packet has been freed by this function. The source packet is not
    freed even in case of error. If data copying was successfull then
    return TRUE.

    This function can also be implemented so that it will simply
    increment the reference counts in the source packet and share the
    actual data without copying it at all. There is a generic version
    of this function inside the engine, in case interceptor does not
    want to implement this. If interceptor implements this function it
    must define INTERCEPTOR_HAS_PACKET_COPY pre-processor symbol. */
Boolean ssh_interceptor_packet_copy(SshInterceptorPacket source_pp,
                                    size_t source_offset,
                                    size_t bytes_to_copy,
                                    SshInterceptorPacket destination_pp,
                                    size_t destination_offset);

#ifdef DEBUG_LIGHT
#define KERNEL_INTERCEPTOR_USE_FUNCTIONS
#endif /* DEBUG_LIGHT */

#ifdef INTERCEPTOR_HAS_PLATFORM_INCLUDE
#include "platform_interceptor.h"
#endif /* INTERCEPTOR_HAS_PLATFORM_INCLUDE */

#endif /* INTERCEPTOR_H */