1/*-
2 * Copyright (c) 2010-2011 The FreeBSD Foundation
3 * All rights reserved.
4 *
5 * This software was developed at the Centre for Advanced Internet
6 * Architectures, Swinburne University of Technology, Melbourne, Australia by
7 * Lawrence Stewart under sponsorship from the FreeBSD Foundation.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31/*
32 * This example Khelp module uses the helper hook points available in the TCP
33 * stack to calculate a per-connection count of inbound and outbound packets
34 * when the connection is in the established state. The code is verbosely
35 * documented in an attempt to explain how everything fits together.
36 */
37
38#include <sys/cdefs.h>
39__FBSDID("$FreeBSD: releng/10.2/share/examples/kld/khelp/h_example.c 218545 2011-02-11 07:26:17Z lstewart $");
40
41#include <sys/param.h>
42#include <sys/kernel.h>
43#include <sys/hhook.h>
44#include <sys/khelp.h>
45#include <sys/module.h>
46#include <sys/module_khelp.h>
47#include <sys/socket.h>
48#include <sys/socketvar.h>
49
50#include <netinet/tcp_var.h>
51
52#include <vm/uma.h>
53
54/*
55 * Function prototype for our helper hook (man 9 hhook) compatible hook
56 * function.
57 */
58static int example_hook(int hhook_type, int hhook_id, void *udata,
59    void *ctx_data, void *hdata, struct osd *hosd);
60
61/*
62 * Our per-connection persistent data storage struct.
63 */
64struct example {
65	uint32_t est_in_count;
66	uint32_t est_out_count;
67};
68
69/*
70 * Fill in the required bits of our module's struct helper (defined in
71 * <sys/module_khelp.h>).
72 *
73 * - Our helper will be storing persistent state for each TCP connection, so we
74 * request the use the Object Specific Data (OSD) feature from the framework by
75 * setting the HELPER_NEEDS_OSD flag.
76 *
77 * - Our helper is related to the TCP subsystem, so tell the Khelp framework
78 * this by setting an appropriate class for the module. When a new TCP
79 * connection is created, the Khelp framework takes care of associating helper
80 * modules of the appropriate class with the new connection.
81 */
82struct helper example_helper = {
83	.h_flags = HELPER_NEEDS_OSD,
84	.h_classes = HELPER_CLASS_TCP
85};
86
87/*
88 * Set which helper hook points our module wants to hook by creating an array of
89 * hookinfo structs (defined in <sys/hhook.h>). We hook the TCP established
90 * inbound/outbound hook points (TCP hhook points are defined in
91 * <netinet/tcp_var.h>) with our example_hook() function. We don't require a user
92 * data pointer to be passed to our hook function when called, so we set it to
93 * NULL.
94 */
95struct hookinfo example_hooks[] = {
96	{
97		.hook_type = HHOOK_TYPE_TCP,
98		.hook_id = HHOOK_TCP_EST_IN,
99		.hook_udata = NULL,
100		.hook_func = &example_hook
101	},
102	{
103		.hook_type = HHOOK_TYPE_TCP,
104		.hook_id = HHOOK_TCP_EST_OUT,
105		.hook_udata = NULL,
106		.hook_func = &example_hook
107	}
108};
109
110/*
111 * Very simple helper hook function. Here's a quick run through the arguments:
112 *
113 * - hhook_type and hhook_id are useful if you use a single function with many
114 * hook points and want to know which hook point called the function.
115 *
116 * - udata will be NULL, because we didn't elect to pass a pointer in either of
117 * the hookinfo structs we instantiated above in the example_hooks array.
118 *
119 * - ctx_data contains context specific data from the hook point call site. The
120 * data type passed is subsystem dependent. In the case of TCP, the hook points
121 * pass a pointer to a "struct tcp_hhook_data" (defined in <netinet/tcp_var.h>).
122 *
123 * - hdata is a pointer to the persistent per-object storage for our module. The
124 * pointer is allocated automagically by the Khelp framework when the connection
125 * is created, and comes from a dedicated UMA zone. It will never be NULL.
126 *
127 * - hosd can be used with the Khelp framework's khelp_get_osd() function to
128 * access data belonging to a different Khelp module.
129 */
130static int
131example_hook(int hhook_type, int hhook_id, void *udata, void *ctx_data,
132    void *hdata, struct osd *hosd)
133{
134	struct example *data;
135
136	data = hdata;
137
138	if (hhook_id == HHOOK_TCP_EST_IN)
139		data->est_in_count++;
140	else if (hhook_id == HHOOK_TCP_EST_OUT)
141		data->est_out_count++;
142
143	return (0);
144}
145
146/*
147 * We use a convenient macro which handles registering our module with the Khelp
148 * framework. Note that Khelp modules which set the HELPER_NEEDS_OSD flag (i.e.
149 * require persistent per-object storage) must use the KHELP_DECLARE_MOD_UMA()
150 * macro. If you don't require per-object storage, use the KHELP_DECLARE_MOD()
151 * macro instead.
152 */
153KHELP_DECLARE_MOD_UMA(example, &example_helper, example_hooks, 1,
154    sizeof(struct example), NULL, NULL);
155