static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode) { /* Room for "event_msgs" + '\0' + bitvec */ s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; const s8 *str; struct wl_pkt_filter pkt_filter; struct wl_pkt_filter *pkt_filterp; s32 buf_len; s32 str_len; u32 mask_size; u32 pattern_size; s8 buf[256]; s32 err = 0; /* add a default packet filter pattern */ str = "pkt_filter_add"; str_len = strlen(str); strncpy(buf, str, str_len); buf[str_len] = '\0'; buf_len = str_len + 1; pkt_filterp = (struct wl_pkt_filter *)(buf + str_len + 1); /* Parse packet filter id. */ pkt_filter.id = htod32(100); /* Parse filter polarity. */ pkt_filter.negate_match = htod32(0); /* Parse filter type. */ pkt_filter.type = htod32(0); /* Parse pattern filter offset. */ pkt_filter.u.pattern.offset = htod32(0); /* Parse pattern filter mask. */ mask_size = htod32(wl_pattern_atoh("0xff", (char *)pkt_filterp->u.pattern. mask_and_pattern)); /* Parse pattern filter pattern. */ pattern_size = htod32(wl_pattern_atoh("0x00", (char *)&pkt_filterp->u.pattern.mask_and_pattern[mask_size])); if (mask_size != pattern_size) { WL_ERR(("Mask and pattern not the same size\n")); err = -EINVAL; goto dongle_filter_out; } pkt_filter.u.pattern.size_bytes = mask_size; buf_len += WL_PKT_FILTER_FIXED_LEN; buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size); /* Keep-alive attributes are set in local * variable (keep_alive_pkt), and * then memcpy'ed into buffer (keep_alive_pktp) since there is no * guarantee that the buffer is properly aligned. */ memcpy((char *)pkt_filterp, &pkt_filter, WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN); err = wldev_ioctl(ndev, WLC_SET_VAR, buf, buf_len, true); if (err) { if (err == -EOPNOTSUPP) { WL_INFO(("filter not supported\n")); } else { WL_ERR(("filter (%d)\n", err)); } goto dongle_filter_out; } /* set mode to allow pattern */ bcm_mkiovar("pkt_filter_mode", (char *)&filter_mode, 4, iovbuf, sizeof(iovbuf)); err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); if (err) { if (err == -EOPNOTSUPP) { WL_INFO(("filter_mode not supported\n")); } else { WL_ERR(("filter_mode (%d)\n", err)); } goto dongle_filter_out; } dongle_filter_out: return err; }
void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg) { const char *str; wl_pkt_filter_t pkt_filter; wl_pkt_filter_t *pkt_filterp; int buf_len; int str_len; int rc; uint32 mask_size; uint32 pattern_size; char *argv[8], * buf = 0; int i = 0; char *arg_save = 0, *arg_org = 0; #define BUF_SIZE 2048 if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) { DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); goto fail; } arg_org = arg_save; if (!(buf = MALLOC(dhd->osh, BUF_SIZE))) { DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); goto fail; } memcpy(arg_save, arg, strlen(arg) + 1); if (strlen(arg) > BUF_SIZE) { DHD_ERROR(("Not enough buffer %d < %d\n", (int)strlen(arg), (int)sizeof(buf))); goto fail; } argv[i] = bcmstrtok(&arg_save, " ", 0); while (argv[i++]) argv[i] = bcmstrtok(&arg_save, " ", 0); i = 0; if (NULL == argv[i]) { DHD_ERROR(("No args provided\n")); goto fail; } str = "pkt_filter_add"; str_len = strlen(str); strncpy(buf, str, str_len); buf[ str_len ] = '\0'; buf_len = str_len + 1; pkt_filterp = (wl_pkt_filter_t *) (buf + str_len + 1); /* Parse packet filter id. */ pkt_filter.id = htod32(strtoul(argv[i], NULL, 0)); if (NULL == argv[++i]) { DHD_ERROR(("Polarity not provided\n")); goto fail; } /* Parse filter polarity. */ pkt_filter.negate_match = htod32(strtoul(argv[i], NULL, 0)); if (NULL == argv[++i]) { DHD_ERROR(("Filter type not provided\n")); goto fail; } /* Parse filter type. */ pkt_filter.type = htod32(strtoul(argv[i], NULL, 0)); if (NULL == argv[++i]) { DHD_ERROR(("Offset not provided\n")); goto fail; } /* Parse pattern filter offset. */ pkt_filter.u.pattern.offset = htod32(strtoul(argv[i], NULL, 0)); if (NULL == argv[++i]) { DHD_ERROR(("Bitmask not provided\n")); goto fail; } /* Parse pattern filter mask. */ mask_size = htod32(wl_pattern_atoh(argv[i], (char *) pkt_filterp->u.pattern.mask_and_pattern)); if (NULL == argv[++i]) { DHD_ERROR(("Pattern not provided\n")); goto fail; } /* Parse pattern filter pattern. */ pattern_size = htod32(wl_pattern_atoh(argv[i], (char *) &pkt_filterp->u.pattern.mask_and_pattern[mask_size])); if (mask_size != pattern_size) { DHD_ERROR(("Mask and pattern not the same size\n")); goto fail; } pkt_filter.u.pattern.size_bytes = mask_size; buf_len += WL_PKT_FILTER_FIXED_LEN; buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size); /* Keep-alive attributes are set in local variable (keep_alive_pkt), and ** then memcpy'ed into buffer (keep_alive_pktp) since there is no ** guarantee that the buffer is properly aligned. */ memcpy((char *)pkt_filterp, &pkt_filter, WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN); rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); rc = rc >= 0 ? 0 : rc; if (rc) DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n", __FUNCTION__, arg, rc)); else DHD_TRACE(("%s: successfully added pktfilter %s\n", __FUNCTION__, arg)); fail: if (arg_org) MFREE(dhd->osh, arg_org, strlen(arg) + 1); if (buf) MFREE(dhd->osh, buf, BUF_SIZE); }