diff options
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index a363ca17bfc5..2d3541c5e058 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -70,6 +70,88 @@ static int get_rdev_dev_by_ifindex(struct net *netns, struct nlattr **attrs, | |||
70 | return 0; | 70 | return 0; |
71 | } | 71 | } |
72 | 72 | ||
73 | static struct cfg80211_registered_device * | ||
74 | __cfg80211_rdev_from_info(struct genl_info *info) | ||
75 | { | ||
76 | int ifindex; | ||
77 | struct cfg80211_registered_device *bywiphyidx = NULL, *byifidx = NULL; | ||
78 | struct net_device *dev; | ||
79 | int err = -EINVAL; | ||
80 | |||
81 | assert_cfg80211_lock(); | ||
82 | |||
83 | if (info->attrs[NL80211_ATTR_WIPHY]) { | ||
84 | bywiphyidx = cfg80211_rdev_by_wiphy_idx( | ||
85 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY])); | ||
86 | err = -ENODEV; | ||
87 | } | ||
88 | |||
89 | if (info->attrs[NL80211_ATTR_IFINDEX]) { | ||
90 | ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]); | ||
91 | dev = dev_get_by_index(genl_info_net(info), ifindex); | ||
92 | if (dev) { | ||
93 | if (dev->ieee80211_ptr) | ||
94 | byifidx = | ||
95 | wiphy_to_dev(dev->ieee80211_ptr->wiphy); | ||
96 | dev_put(dev); | ||
97 | } | ||
98 | err = -ENODEV; | ||
99 | } | ||
100 | |||
101 | if (bywiphyidx && byifidx) { | ||
102 | if (bywiphyidx != byifidx) | ||
103 | return ERR_PTR(-EINVAL); | ||
104 | else | ||
105 | return bywiphyidx; /* == byifidx */ | ||
106 | } | ||
107 | if (bywiphyidx) | ||
108 | return bywiphyidx; | ||
109 | |||
110 | if (byifidx) | ||
111 | return byifidx; | ||
112 | |||
113 | return ERR_PTR(err); | ||
114 | } | ||
115 | |||
116 | /* | ||
117 | * This function returns a pointer to the driver | ||
118 | * that the genl_info item that is passed refers to. | ||
119 | * If successful, it returns non-NULL and also locks | ||
120 | * the driver's mutex! | ||
121 | * | ||
122 | * This means that you need to call cfg80211_unlock_rdev() | ||
123 | * before being allowed to acquire &cfg80211_mutex! | ||
124 | * | ||
125 | * This is necessary because we need to lock the global | ||
126 | * mutex to get an item off the list safely, and then | ||
127 | * we lock the rdev mutex so it doesn't go away under us. | ||
128 | * | ||
129 | * We don't want to keep cfg80211_mutex locked | ||
130 | * for all the time in order to allow requests on | ||
131 | * other interfaces to go through at the same time. | ||
132 | * | ||
133 | * The result of this can be a PTR_ERR and hence must | ||
134 | * be checked with IS_ERR() for errors. | ||
135 | */ | ||
136 | static struct cfg80211_registered_device * | ||
137 | cfg80211_get_dev_from_info(struct genl_info *info) | ||
138 | { | ||
139 | struct cfg80211_registered_device *rdev; | ||
140 | |||
141 | mutex_lock(&cfg80211_mutex); | ||
142 | rdev = __cfg80211_rdev_from_info(info); | ||
143 | |||
144 | /* if it is not an error we grab the lock on | ||
145 | * it to assure it won't be going away while | ||
146 | * we operate on it */ | ||
147 | if (!IS_ERR(rdev)) | ||
148 | mutex_lock(&rdev->mtx); | ||
149 | |||
150 | mutex_unlock(&cfg80211_mutex); | ||
151 | |||
152 | return rdev; | ||
153 | } | ||
154 | |||
73 | /* policy for the attributes */ | 155 | /* policy for the attributes */ |
74 | static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | 156 | static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { |
75 | [NL80211_ATTR_WIPHY] = { .type = NLA_U32 }, | 157 | [NL80211_ATTR_WIPHY] = { .type = NLA_U32 }, |