net: Audit drivers to identify those needing IFF_TX_SKB_SHARING cleared

After the last patch, We are left in a state in which only drivers calling
ether_setup have IFF_TX_SKB_SHARING set (we assume that drivers touching real
hardware call ether_setup for their net_devices and don't hold any state in
their skbs.  There are a handful of drivers that violate this assumption of
course, and need to be fixed up.  This patch identifies those drivers, and marks
them as not being able to support the safe transmission of skbs by clearning the
IFF_TX_SKB_SHARING flag in priv_flags

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
CC: Karsten Keil <isdn@linux-pingi.de>
CC: "David S. Miller" <davem@davemloft.net>
CC: Jay Vosburgh <fubar@us.ibm.com>
CC: Andy Gospodarek <andy@greyhouse.net>
CC: Patrick McHardy <kaber@trash.net>
CC: Krzysztof Halasa <khc@pm.waw.pl>
CC: "John W. Linville" <linville@tuxdriver.com>
CC: Greg Kroah-Hartman <gregkh@suse.de>
CC: Marcel Holtmann <marcel@holtmann.org>
CC: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
static int airo_set_encodeext(struct net_device *dev,
			   struct iw_request_info *info,
			    union iwreq_data *wrqu,
			    char *extra)
{
	struct airo_info *local = dev->ml_priv;
	struct iw_point *encoding = &wrqu->encoding;
	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
	int perm = ( encoding->flags & IW_ENCODE_TEMP ? 0 : 1 );
	__le16 currentAuthType = local->config.authType;
	int idx, key_len, alg = ext->alg, set_key = 1, rc;
	wep_key_t key;

	if (!local->wep_capable)
		return -EOPNOTSUPP;

	readConfigRid(local, 1);

	/* Determine and validate the key index */
	idx = encoding->flags & IW_ENCODE_INDEX;
	if (idx) {
		if (!valid_index(local, idx - 1))
			return -EINVAL;
		idx--;
	} else {
		idx = get_wep_tx_idx(local);
		if (idx < 0)
			idx = 0;
	}

	if (encoding->flags & IW_ENCODE_DISABLED)
		alg = IW_ENCODE_ALG_NONE;

	if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
		/* Only set transmit key index here, actual
		 * key is set below if needed.
		 */
		rc = set_wep_tx_idx(local, idx, perm, 1);
		if (rc < 0) {
			airo_print_err(local->dev->name, "failed to set "
			               "WEP transmit index to %d: %d.",
			               idx, rc);
			return rc;
		}
		set_key = ext->key_len > 0 ? 1 : 0;
	}

	if (set_key) {
		/* Set the requested key first */
		memset(key.key, 0, MAX_KEY_SIZE);
		switch (alg) {
		case IW_ENCODE_ALG_NONE:
			key.len = 0;
			break;
		case IW_ENCODE_ALG_WEP:
			if (ext->key_len > MIN_KEY_SIZE) {
				key.len = MAX_KEY_SIZE;
			} else if (ext->key_len > 0) {
				key.len = MIN_KEY_SIZE;
			} else {
				return -EINVAL;
			}
			key_len = min (ext->key_len, key.len);
			memcpy(key.key, ext->key, key_len);
			break;
		default:
			return -EINVAL;
		}
		if (key.len == 0) {
			rc = set_wep_tx_idx(local, idx, perm, 1);
			if (rc < 0) {
				airo_print_err(local->dev->name,
					       "failed to set WEP transmit index to %d: %d.",
					       idx, rc);
				return rc;
			}
		} else {
			rc = set_wep_key(local, idx, key.key, key.len, perm, 1);
			if (rc < 0) {
				airo_print_err(local->dev->name,
					       "failed to set WEP key at index %d: %d.",
					       idx, rc);
				return rc;
			}
		}
	}

	/* Read the flags */
	if(encoding->flags & IW_ENCODE_DISABLED)
		local->config.authType = AUTH_OPEN;	// disable encryption
	if(encoding->flags & IW_ENCODE_RESTRICTED)
		local->config.authType = AUTH_SHAREDKEY;	// Only Both
	if(encoding->flags & IW_ENCODE_OPEN)
		local->config.authType = AUTH_ENCRYPT;	// Only Wep
	/* Commit the changes to flags if needed */
	if (local->config.authType != currentAuthType)
		set_bit (FLAG_COMMIT, &local->flags);

	return -EINPROGRESS;
}

static int airo_set_encodeext(struct net_device *dev,
			   struct iw_request_info *info,
			    union iwreq_data *wrqu,
			    char *extra)
{
	struct airo_info *local = dev->ml_priv;
	struct iw_point *encoding = &wrqu->encoding;
	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
	int perm = ( encoding->flags & IW_ENCODE_TEMP ? 0 : 1 );
	__le16 currentAuthType = local->config.authType;
	int idx, key_len, alg = ext->alg, set_key = 1, rc;
	wep_key_t key;

	if (!local->wep_capable)
		return -EOPNOTSUPP;

	readConfigRid(local, 1);

	/* Determine and validate the key index */
	idx = encoding->flags & IW_ENCODE_INDEX;
	if (idx) {
		if (!valid_index(local, idx - 1))
			return -EINVAL;
		idx--;
	} else {
		idx = get_wep_tx_idx(local);
		if (idx < 0)
			idx = 0;
	}

	if (encoding->flags & IW_ENCODE_DISABLED)
		alg = IW_ENCODE_ALG_NONE;

	if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
		/* Only set transmit key index here, actual
		 * key is set below if needed.
		 */
		rc = set_wep_tx_idx(local, idx, perm, 1);
		if (rc < 0) {
			airo_print_err(local->dev->name, "failed to set "
			               "WEP transmit index to %d: %d.",
			               idx, rc);
			return rc;
		}
		set_key = ext->key_len > 0 ? 1 : 0;
	}

	if (set_key) {
		/* Set the requested key first */
		memset(key.key, 0, MAX_KEY_SIZE);
		switch (alg) {
		case IW_ENCODE_ALG_NONE:
			key.len = 0;
			break;
		case IW_ENCODE_ALG_WEP:
			if (ext->key_len > MIN_KEY_SIZE) {
				key.len = MAX_KEY_SIZE;
			} else if (ext->key_len > 0) {
				key.len = MIN_KEY_SIZE;
			} else {
				return -EINVAL;
			}
			key_len = min (ext->key_len, key.len);
			memcpy(key.key, ext->key, key_len);
			break;
		default:
			return -EINVAL;
		}
		if (key.len == 0) {
			rc = set_wep_tx_idx(local, idx, perm, 1);
			if (rc < 0) {
				airo_print_err(local->dev->name,
					       "failed to set WEP transmit index to %d: %d.",
					       idx, rc);
				return rc;
			}
		} else {
			rc = set_wep_key(local, idx, key.key, key.len, perm, 1);
			if (rc < 0) {
				airo_print_err(local->dev->name,
					       "failed to set WEP key at index %d: %d.",
					       idx, rc);
				return rc;
			}
		}
	}

	/* Read the flags */
	if(encoding->flags & IW_ENCODE_DISABLED)
		local->config.authType = AUTH_OPEN;	// disable encryption
	if(encoding->flags & IW_ENCODE_RESTRICTED)
		local->config.authType = AUTH_SHAREDKEY;	// Only Both
	if(encoding->flags & IW_ENCODE_OPEN)
		local->config.authType = AUTH_ENCRYPT;	// Only Wep
	/* Commit the changes to flags if needed */
	if (local->config.authType != currentAuthType)
		set_bit (FLAG_COMMIT, &local->flags);

	return -EINPROGRESS;
}
