1 #include <minix/drivers.h>
2 #include <minix/ioctl.h>
3 #include <sys/ioc_fbd.h>
4
5 #include "action.h"
6 #include "rule.h"
7
8 static struct fbd_rule rules[MAX_RULES];
9 static struct fbd_rule *matches[MAX_RULES];
10 static int nr_matches;
11
12 /*===========================================================================*
13 * rule_ctl *
14 *===========================================================================*/
rule_ctl(unsigned long request,endpoint_t endpt,cp_grant_id_t grant)15 int rule_ctl(unsigned long request, endpoint_t endpt, cp_grant_id_t grant)
16 {
17 /* Handle an I/O control request regarding rules. */
18 fbd_rulenum_t i;
19 int r;
20
21 /* Note that any of the safecopy calls may fail if the ioctl is
22 * improperly defined in userland; never panic if they fail!
23 */
24 switch (request) {
25 case FBDCADDRULE:
26 /* Find a free rule slot. */
27 for (i = 1; i <= MAX_RULES; i++)
28 if (rules[i-1].num == 0)
29 break;
30
31 if (i == MAX_RULES+1)
32 return ENOMEM;
33
34 /* Copy in the rule. */
35 if ((r = sys_safecopyfrom(endpt, grant, 0,
36 (vir_bytes) &rules[i-1], sizeof(rules[0]))) != OK)
37 return r;
38
39 /* Mark the rule as active, and return its number. */
40 rules[i-1].num = i;
41
42 return i;
43
44 case FBDCDELRULE:
45 /* Copy in the given rule number. */
46 if ((r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &i,
47 sizeof(i))) != OK)
48 return r;
49
50 /* Fail if the given rule number is not valid or in use.
51 * Allow the caller to determine the maximum rule number.
52 */
53 if (i <= 0 || i > MAX_RULES) return EINVAL;
54
55 if (rules[i-1].num != i) return ENOENT;
56
57 /* Mark the rule as not active. */
58 rules[i-1].num = 0;
59
60 return OK;
61
62 case FBDCGETRULE:
63 /* Copy in just the rule number from the given structure. */
64 if ((r = sys_safecopyfrom(endpt, grant,
65 offsetof(struct fbd_rule, num), (vir_bytes) &i,
66 sizeof(i))) != OK)
67 return r;
68
69 /* Fail if the given rule number is not valid or in use.
70 * Allow the caller to determine the maximum rule number.
71 */
72 if (i <= 0 || i > MAX_RULES) return EINVAL;
73
74 if (rules[i-1].num != i) return ENOENT;
75
76 /* Copy out the entire rule as is. */
77 return sys_safecopyto(endpt, grant, 0, (vir_bytes) &rules[i-1],
78 sizeof(rules[0]));
79
80 default:
81 return EINVAL;
82 }
83 }
84
85 /*===========================================================================*
86 * rule_match *
87 *===========================================================================*/
rule_match(struct fbd_rule * rule,u64_t pos,size_t size,int flag)88 static int rule_match(struct fbd_rule *rule, u64_t pos, size_t size, int flag)
89 {
90 /* Check whether the given rule matches the given parameters. As side
91 * effect, update counters in the rule as appropriate.
92 */
93
94 /* Ranges must overlap (start < pos+size && end > pos). */
95 if (rule->start >= pos + size ||
96 (rule->end != 0 && rule->end <= pos))
97 return FALSE;
98
99 /* Flags must match. */
100 if (!(rule->flags & flag)) return FALSE;
101
102 /* This is a match, but is it supposed to trigger yet? */
103 if (rule->skip > 0) {
104 rule->skip--;
105
106 return FALSE;
107 }
108
109 return TRUE;
110 }
111
112 /*===========================================================================*
113 * rule_find *
114 *===========================================================================*/
rule_find(u64_t pos,size_t size,int flag)115 int rule_find(u64_t pos, size_t size, int flag)
116 {
117 /* Find all matching rules, and return a hook mask. */
118 struct fbd_rule *rule;
119 int i, hooks;
120
121 nr_matches = 0;
122 hooks = 0;
123
124 for (i = 0; i < MAX_RULES; i++) {
125 rule = &rules[i];
126
127 if (rule->num == 0) continue;
128
129 if (!rule_match(rule, pos, size, flag))
130 continue;
131
132 matches[nr_matches++] = rule;
133
134 /* If the rule has a limited lifetime, update it now. */
135 if (rule->count > 0) {
136 rule->count--;
137
138 /* Disable the rule from future matching. */
139 if (rule->count == 0)
140 rule->num = 0;
141 }
142
143 hooks |= action_mask(rule);
144 }
145
146 return hooks;
147 }
148
149 /*===========================================================================*
150 * rule_pre_hook *
151 *===========================================================================*/
rule_pre_hook(iovec_t * iov,unsigned * count,size_t * size,u64_t * pos)152 void rule_pre_hook(iovec_t *iov, unsigned *count, size_t *size,
153 u64_t *pos)
154 {
155 int i;
156
157 for (i = 0; i < nr_matches; i++)
158 if (action_mask(matches[i]) & PRE_HOOK)
159 action_pre_hook(matches[i], iov, count, size, pos);
160 }
161
162 /*===========================================================================*
163 * rule_io_hook *
164 *===========================================================================*/
rule_io_hook(char * buf,size_t size,u64_t pos,int flag)165 void rule_io_hook(char *buf, size_t size, u64_t pos, int flag)
166 {
167 int i;
168
169 for (i = 0; i < nr_matches; i++)
170 if (action_mask(matches[i]) & IO_HOOK)
171 action_io_hook(matches[i], buf, size, pos, flag);
172 }
173
174 /*===========================================================================*
175 * rule_post_hook *
176 *===========================================================================*/
rule_post_hook(size_t osize,int * result)177 void rule_post_hook(size_t osize, int *result)
178 {
179 int i;
180
181 for (i = 0; i < nr_matches; i++)
182 if (action_mask(matches[i]) & POST_HOOK)
183 action_post_hook(matches[i], osize, result);
184 }
185