1433d6423SLionel Sambuc #include <minix/drivers.h>
2433d6423SLionel Sambuc #include <minix/ioctl.h>
3433d6423SLionel Sambuc #include <sys/ioc_fbd.h>
4433d6423SLionel Sambuc
5433d6423SLionel Sambuc #include "action.h"
6433d6423SLionel Sambuc #include "rule.h"
7433d6423SLionel Sambuc
8433d6423SLionel Sambuc static struct fbd_rule rules[MAX_RULES];
9433d6423SLionel Sambuc static struct fbd_rule *matches[MAX_RULES];
10433d6423SLionel Sambuc static int nr_matches;
11433d6423SLionel Sambuc
12433d6423SLionel Sambuc /*===========================================================================*
13433d6423SLionel Sambuc * rule_ctl *
14433d6423SLionel Sambuc *===========================================================================*/
rule_ctl(unsigned long request,endpoint_t endpt,cp_grant_id_t grant)15*63ce03dbSDavid van Moolenbroek int rule_ctl(unsigned long request, endpoint_t endpt, cp_grant_id_t grant)
16433d6423SLionel Sambuc {
17433d6423SLionel Sambuc /* Handle an I/O control request regarding rules. */
18433d6423SLionel Sambuc fbd_rulenum_t i;
19433d6423SLionel Sambuc int r;
20433d6423SLionel Sambuc
21433d6423SLionel Sambuc /* Note that any of the safecopy calls may fail if the ioctl is
22433d6423SLionel Sambuc * improperly defined in userland; never panic if they fail!
23433d6423SLionel Sambuc */
24433d6423SLionel Sambuc switch (request) {
25433d6423SLionel Sambuc case FBDCADDRULE:
26433d6423SLionel Sambuc /* Find a free rule slot. */
27433d6423SLionel Sambuc for (i = 1; i <= MAX_RULES; i++)
28433d6423SLionel Sambuc if (rules[i-1].num == 0)
29433d6423SLionel Sambuc break;
30433d6423SLionel Sambuc
31433d6423SLionel Sambuc if (i == MAX_RULES+1)
32433d6423SLionel Sambuc return ENOMEM;
33433d6423SLionel Sambuc
34433d6423SLionel Sambuc /* Copy in the rule. */
35433d6423SLionel Sambuc if ((r = sys_safecopyfrom(endpt, grant, 0,
36433d6423SLionel Sambuc (vir_bytes) &rules[i-1], sizeof(rules[0]))) != OK)
37433d6423SLionel Sambuc return r;
38433d6423SLionel Sambuc
39433d6423SLionel Sambuc /* Mark the rule as active, and return its number. */
40433d6423SLionel Sambuc rules[i-1].num = i;
41433d6423SLionel Sambuc
42433d6423SLionel Sambuc return i;
43433d6423SLionel Sambuc
44433d6423SLionel Sambuc case FBDCDELRULE:
45433d6423SLionel Sambuc /* Copy in the given rule number. */
46433d6423SLionel Sambuc if ((r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &i,
47433d6423SLionel Sambuc sizeof(i))) != OK)
48433d6423SLionel Sambuc return r;
49433d6423SLionel Sambuc
50433d6423SLionel Sambuc /* Fail if the given rule number is not valid or in use.
51433d6423SLionel Sambuc * Allow the caller to determine the maximum rule number.
52433d6423SLionel Sambuc */
53433d6423SLionel Sambuc if (i <= 0 || i > MAX_RULES) return EINVAL;
54433d6423SLionel Sambuc
55433d6423SLionel Sambuc if (rules[i-1].num != i) return ENOENT;
56433d6423SLionel Sambuc
57433d6423SLionel Sambuc /* Mark the rule as not active. */
58433d6423SLionel Sambuc rules[i-1].num = 0;
59433d6423SLionel Sambuc
60433d6423SLionel Sambuc return OK;
61433d6423SLionel Sambuc
62433d6423SLionel Sambuc case FBDCGETRULE:
63433d6423SLionel Sambuc /* Copy in just the rule number from the given structure. */
64433d6423SLionel Sambuc if ((r = sys_safecopyfrom(endpt, grant,
65433d6423SLionel Sambuc offsetof(struct fbd_rule, num), (vir_bytes) &i,
66433d6423SLionel Sambuc sizeof(i))) != OK)
67433d6423SLionel Sambuc return r;
68433d6423SLionel Sambuc
69433d6423SLionel Sambuc /* Fail if the given rule number is not valid or in use.
70433d6423SLionel Sambuc * Allow the caller to determine the maximum rule number.
71433d6423SLionel Sambuc */
72433d6423SLionel Sambuc if (i <= 0 || i > MAX_RULES) return EINVAL;
73433d6423SLionel Sambuc
74433d6423SLionel Sambuc if (rules[i-1].num != i) return ENOENT;
75433d6423SLionel Sambuc
76433d6423SLionel Sambuc /* Copy out the entire rule as is. */
77433d6423SLionel Sambuc return sys_safecopyto(endpt, grant, 0, (vir_bytes) &rules[i-1],
78433d6423SLionel Sambuc sizeof(rules[0]));
79433d6423SLionel Sambuc
80433d6423SLionel Sambuc default:
81433d6423SLionel Sambuc return EINVAL;
82433d6423SLionel Sambuc }
83433d6423SLionel Sambuc }
84433d6423SLionel Sambuc
85433d6423SLionel Sambuc /*===========================================================================*
86433d6423SLionel Sambuc * rule_match *
87433d6423SLionel Sambuc *===========================================================================*/
rule_match(struct fbd_rule * rule,u64_t pos,size_t size,int flag)88433d6423SLionel Sambuc static int rule_match(struct fbd_rule *rule, u64_t pos, size_t size, int flag)
89433d6423SLionel Sambuc {
90433d6423SLionel Sambuc /* Check whether the given rule matches the given parameters. As side
91433d6423SLionel Sambuc * effect, update counters in the rule as appropriate.
92433d6423SLionel Sambuc */
93433d6423SLionel Sambuc
94433d6423SLionel Sambuc /* Ranges must overlap (start < pos+size && end > pos). */
95433d6423SLionel Sambuc if (rule->start >= pos + size ||
96433d6423SLionel Sambuc (rule->end != 0 && rule->end <= pos))
97433d6423SLionel Sambuc return FALSE;
98433d6423SLionel Sambuc
99433d6423SLionel Sambuc /* Flags must match. */
100433d6423SLionel Sambuc if (!(rule->flags & flag)) return FALSE;
101433d6423SLionel Sambuc
102433d6423SLionel Sambuc /* This is a match, but is it supposed to trigger yet? */
103433d6423SLionel Sambuc if (rule->skip > 0) {
104433d6423SLionel Sambuc rule->skip--;
105433d6423SLionel Sambuc
106433d6423SLionel Sambuc return FALSE;
107433d6423SLionel Sambuc }
108433d6423SLionel Sambuc
109433d6423SLionel Sambuc return TRUE;
110433d6423SLionel Sambuc }
111433d6423SLionel Sambuc
112433d6423SLionel Sambuc /*===========================================================================*
113433d6423SLionel Sambuc * rule_find *
114433d6423SLionel Sambuc *===========================================================================*/
rule_find(u64_t pos,size_t size,int flag)115433d6423SLionel Sambuc int rule_find(u64_t pos, size_t size, int flag)
116433d6423SLionel Sambuc {
117433d6423SLionel Sambuc /* Find all matching rules, and return a hook mask. */
118433d6423SLionel Sambuc struct fbd_rule *rule;
119433d6423SLionel Sambuc int i, hooks;
120433d6423SLionel Sambuc
121433d6423SLionel Sambuc nr_matches = 0;
122433d6423SLionel Sambuc hooks = 0;
123433d6423SLionel Sambuc
124433d6423SLionel Sambuc for (i = 0; i < MAX_RULES; i++) {
125433d6423SLionel Sambuc rule = &rules[i];
126433d6423SLionel Sambuc
127433d6423SLionel Sambuc if (rule->num == 0) continue;
128433d6423SLionel Sambuc
129433d6423SLionel Sambuc if (!rule_match(rule, pos, size, flag))
130433d6423SLionel Sambuc continue;
131433d6423SLionel Sambuc
132433d6423SLionel Sambuc matches[nr_matches++] = rule;
133433d6423SLionel Sambuc
134433d6423SLionel Sambuc /* If the rule has a limited lifetime, update it now. */
135433d6423SLionel Sambuc if (rule->count > 0) {
136433d6423SLionel Sambuc rule->count--;
137433d6423SLionel Sambuc
138433d6423SLionel Sambuc /* Disable the rule from future matching. */
139433d6423SLionel Sambuc if (rule->count == 0)
140433d6423SLionel Sambuc rule->num = 0;
141433d6423SLionel Sambuc }
142433d6423SLionel Sambuc
143433d6423SLionel Sambuc hooks |= action_mask(rule);
144433d6423SLionel Sambuc }
145433d6423SLionel Sambuc
146433d6423SLionel Sambuc return hooks;
147433d6423SLionel Sambuc }
148433d6423SLionel Sambuc
149433d6423SLionel Sambuc /*===========================================================================*
150433d6423SLionel Sambuc * rule_pre_hook *
151433d6423SLionel Sambuc *===========================================================================*/
rule_pre_hook(iovec_t * iov,unsigned * count,size_t * size,u64_t * pos)152433d6423SLionel Sambuc void rule_pre_hook(iovec_t *iov, unsigned *count, size_t *size,
153433d6423SLionel Sambuc u64_t *pos)
154433d6423SLionel Sambuc {
155433d6423SLionel Sambuc int i;
156433d6423SLionel Sambuc
157433d6423SLionel Sambuc for (i = 0; i < nr_matches; i++)
158433d6423SLionel Sambuc if (action_mask(matches[i]) & PRE_HOOK)
159433d6423SLionel Sambuc action_pre_hook(matches[i], iov, count, size, pos);
160433d6423SLionel Sambuc }
161433d6423SLionel Sambuc
162433d6423SLionel Sambuc /*===========================================================================*
163433d6423SLionel Sambuc * rule_io_hook *
164433d6423SLionel Sambuc *===========================================================================*/
rule_io_hook(char * buf,size_t size,u64_t pos,int flag)165433d6423SLionel Sambuc void rule_io_hook(char *buf, size_t size, u64_t pos, int flag)
166433d6423SLionel Sambuc {
167433d6423SLionel Sambuc int i;
168433d6423SLionel Sambuc
169433d6423SLionel Sambuc for (i = 0; i < nr_matches; i++)
170433d6423SLionel Sambuc if (action_mask(matches[i]) & IO_HOOK)
171433d6423SLionel Sambuc action_io_hook(matches[i], buf, size, pos, flag);
172433d6423SLionel Sambuc }
173433d6423SLionel Sambuc
174433d6423SLionel Sambuc /*===========================================================================*
175433d6423SLionel Sambuc * rule_post_hook *
176433d6423SLionel Sambuc *===========================================================================*/
rule_post_hook(size_t osize,int * result)177433d6423SLionel Sambuc void rule_post_hook(size_t osize, int *result)
178433d6423SLionel Sambuc {
179433d6423SLionel Sambuc int i;
180433d6423SLionel Sambuc
181433d6423SLionel Sambuc for (i = 0; i < nr_matches; i++)
182433d6423SLionel Sambuc if (action_mask(matches[i]) & POST_HOOK)
183433d6423SLionel Sambuc action_post_hook(matches[i], osize, result);
184433d6423SLionel Sambuc }
185