1#include <net/if.h> 2#include <errno.h> 3#include <string.h> 4#include <stdio.h> 5 6#include <netlink/genl/genl.h> 7#include <netlink/genl/family.h> 8#include <netlink/genl/ctrl.h> 9#include <netlink/msg.h> 10#include <netlink/attr.h> 11 12#include <arpa/inet.h> 13 14#include "nl80211.h" 15#include "iw.h" 16 17SECTION(coalesce); 18 19static int handle_coalesce_enable(struct nl80211_state *state, struct nl_cb *cb, 20 struct nl_msg *msg, int argc, char **argv, 21 enum id_input id) 22{ 23 struct nlattr *nl_rules, *nl_rule = NULL, *nl_pats, *nl_pat; 24 unsigned char *pat, *mask; 25 size_t patlen; 26 int patnum = 0, pkt_offset, err = 1; 27 char *eptr, *value1, *value2, *sptr = NULL, *end, buf[16768]; 28 enum nl80211_coalesce_condition condition; 29 FILE *f = fopen(argv[0], "r"); 30 enum { 31 PS_DELAY, 32 PS_CONDITION, 33 PS_PATTERNS 34 } parse_state = PS_DELAY; 35 int rule_num = 0; 36 37 if (!f) 38 return 1; 39 40 nl_rules = nla_nest_start(msg, NL80211_ATTR_COALESCE_RULE); 41 if (!nl_rules) { 42 fclose(f); 43 return -ENOBUFS; 44 } 45 46 while (!feof(f)) { 47 char *eol; 48 49 if (!fgets(buf, sizeof(buf), f)) 50 break; 51 52 eol = strchr(buf + 5, '\r'); 53 if (eol) 54 *eol = 0; 55 eol = strchr(buf + 5, '\n'); 56 if (eol) 57 *eol = 0; 58 59 switch (parse_state) { 60 case PS_DELAY: 61 if (strncmp(buf, "delay=", 6) == 0) { 62 char *delay = buf + 6; 63 64 rule_num++; 65 nl_rule = nla_nest_start(msg, rule_num); 66 if (!nl_rule) 67 goto close; 68 69 NLA_PUT_U32(msg, NL80211_ATTR_COALESCE_RULE_DELAY, 70 strtoul(delay, &end, 10)); 71 if (*end != '\0') 72 goto close; 73 parse_state = PS_CONDITION; 74 } else { 75 goto close; 76 } 77 break; 78 case PS_CONDITION: 79 if (strncmp(buf, "condition=", 10) == 0) { 80 char *cond = buf + 10; 81 82 condition = strtoul(cond, &end, 10); 83 if (*end != '\0') 84 goto close; 85 NLA_PUT_U32(msg, NL80211_ATTR_COALESCE_RULE_CONDITION, 86 condition); 87 parse_state = PS_PATTERNS; 88 } else { 89 goto close; 90 } 91 break; 92 case PS_PATTERNS: 93 if (strncmp(buf, "patterns=", 9) == 0) { 94 char *cur_pat = buf + 9; 95 char *next_pat = strchr(buf + 9, ','); 96 97 if (next_pat) { 98 *next_pat = 0; 99 next_pat++; 100 } 101 102 nl_pats = nla_nest_start(msg, NL80211_ATTR_COALESCE_RULE_PKT_PATTERN); 103 while (1) { 104 value1 = strtok_r(cur_pat, "+", &sptr); 105 value2 = strtok_r(NULL, "+", &sptr); 106 107 if (!value2) { 108 pkt_offset = 0; 109 if (!value1) 110 goto close; 111 value2 = value1; 112 } else { 113 pkt_offset = strtoul(value1, &eptr, 10); 114 if (eptr != value1 + strlen(value1)) 115 goto close; 116 } 117 118 if (parse_hex_mask(value2, &pat, &patlen, &mask)) 119 goto close; 120 121 nl_pat = nla_nest_start(msg, ++patnum); 122 NLA_PUT(msg, NL80211_PKTPAT_MASK, 123 DIV_ROUND_UP(patlen, 8), mask); 124 NLA_PUT(msg, NL80211_PKTPAT_PATTERN, patlen, pat); 125 NLA_PUT_U32(msg, NL80211_PKTPAT_OFFSET, 126 pkt_offset); 127 nla_nest_end(msg, nl_pat); 128 free(mask); 129 free(pat); 130 131 if (!next_pat) 132 break; 133 cur_pat = next_pat; 134 next_pat = strchr(cur_pat, ','); 135 if (next_pat) { 136 *next_pat = 0; 137 next_pat++; 138 } 139 } 140 nla_nest_end(msg, nl_pats); 141 nla_nest_end(msg, nl_rule); 142 parse_state = PS_DELAY; 143 144 } else { 145 goto close; 146 } 147 break; 148 default: 149 if (buf[0] == '#') 150 continue; 151 goto close; 152 } 153 } 154 155 if (parse_state == PS_DELAY) 156 err = 0; 157 else 158 err = 1; 159 goto close; 160nla_put_failure: 161 err = -ENOBUFS; 162close: 163 fclose(f); 164 nla_nest_end(msg, nl_rules); 165 return err; 166} 167 168COMMAND(coalesce, enable, "<config-file>", 169 NL80211_CMD_SET_COALESCE, 0, CIB_PHY, handle_coalesce_enable, 170 "Enable coalesce with given configuration.\n" 171 "The configuration file contains coalesce rules:\n" 172 " delay=<delay>\n" 173 " condition=<condition>\n" 174 " patterns=<[offset1+]<pattern1>,<[offset2+]<pattern2>,...>\n" 175 " delay=<delay>\n" 176 " condition=<condition>\n" 177 " patterns=<[offset1+]<pattern1>,<[offset2+]<pattern2>,...>\n" 178 " ...\n" 179 "delay: maximum coalescing delay in msec.\n" 180 "condition: 1/0 i.e. 'not match'/'match' the patterns\n" 181 "patterns: each pattern is given as a bytestring with '-' in\n" 182 "places where any byte may be present, e.g. 00:11:22:-:44 will\n" 183 "match 00:11:22:33:44 and 00:11:22:33:ff:44 etc. Offset and\n" 184 "pattern should be separated by '+', e.g. 18+43:34:00:12 will\n" 185 "match '43:34:00:12' after 18 bytes of offset in Rx packet.\n"); 186 187static int 188handle_coalesce_disable(struct nl80211_state *state, struct nl_cb *cb, 189 struct nl_msg *msg, int argc, char **argv, 190 enum id_input id) 191{ 192 /* just a set w/o coalesce attribute */ 193 return 0; 194} 195COMMAND(coalesce, disable, "", NL80211_CMD_SET_COALESCE, 0, CIB_PHY, 196 handle_coalesce_disable, "Disable coalesce."); 197 198static int print_coalesce_handler(struct nl_msg *msg, void *arg) 199{ 200 struct nlattr *attrs[NL80211_ATTR_MAX + 1]; 201 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); 202 struct nlattr *pattern, *rule; 203 int rem_pattern, rem_rule; 204 enum nl80211_coalesce_condition condition; 205 int delay; 206 207 nla_parse(attrs, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), 208 genlmsg_attrlen(gnlh, 0), NULL); 209 210 if (!attrs[NL80211_ATTR_COALESCE_RULE]) { 211 printf("Coalesce is disabled.\n"); 212 return NL_SKIP; 213 } 214 215 printf("Coalesce is enabled:\n"); 216 217 nla_for_each_nested(rule, attrs[NL80211_ATTR_COALESCE_RULE], rem_rule) { 218 struct nlattr *ruleattr[NUM_NL80211_ATTR_COALESCE_RULE]; 219 220 nla_parse(ruleattr, NL80211_ATTR_COALESCE_RULE_MAX, 221 nla_data(rule), nla_len(rule), NULL); 222 223 delay = nla_get_u32(ruleattr[NL80211_ATTR_COALESCE_RULE_DELAY]); 224 condition = 225 nla_get_u32(ruleattr[NL80211_ATTR_COALESCE_RULE_CONDITION]); 226 227 printf("Rule - max coalescing delay: %dmsec condition:", delay); 228 if (condition) 229 printf("not match\n"); 230 else 231 printf("match\n"); 232 233 if (ruleattr[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN]) { 234 nla_for_each_nested(pattern, 235 ruleattr[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN], 236 rem_pattern) { 237 struct nlattr *patattr[NUM_NL80211_PKTPAT]; 238 int i, patlen, masklen, pkt_offset; 239 uint8_t *mask, *pat; 240 241 nla_parse(patattr, MAX_NL80211_PKTPAT, 242 nla_data(pattern), nla_len(pattern), 243 NULL); 244 if (!patattr[NL80211_PKTPAT_MASK] || 245 !patattr[NL80211_PKTPAT_PATTERN] || 246 !patattr[NL80211_PKTPAT_OFFSET]) { 247 printf(" * (invalid pattern specification)\n"); 248 continue; 249 } 250 masklen = nla_len(patattr[NL80211_PKTPAT_MASK]); 251 patlen = nla_len(patattr[NL80211_PKTPAT_PATTERN]); 252 pkt_offset = nla_get_u32(patattr[NL80211_PKTPAT_OFFSET]); 253 if (DIV_ROUND_UP(patlen, 8) != masklen) { 254 printf(" * (invalid pattern specification)\n"); 255 continue; 256 } 257 printf(" * packet offset: %d", pkt_offset); 258 printf(" pattern: "); 259 pat = nla_data(patattr[NL80211_PKTPAT_PATTERN]); 260 mask = nla_data(patattr[NL80211_PKTPAT_MASK]); 261 for (i = 0; i < patlen; i++) { 262 if (mask[i / 8] & (1 << (i % 8))) 263 printf("%.2x", pat[i]); 264 else 265 printf("--"); 266 if (i != patlen - 1) 267 printf(":"); 268 } 269 printf("\n"); 270 } 271 } 272 } 273 274 return NL_SKIP; 275} 276 277static int handle_coalesce_show(struct nl80211_state *state, struct nl_cb *cb, 278 struct nl_msg *msg, int argc, char **argv, 279 enum id_input id) 280{ 281 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, 282 print_coalesce_handler, NULL); 283 284 return 0; 285} 286COMMAND(coalesce, show, "", NL80211_CMD_GET_COALESCE, 0, CIB_PHY, handle_coalesce_show, 287 "Show coalesce status."); 288