]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - net/wireless/wext.c
net/compat/wext: send different messages to compat tasks
[net-next-2.6.git] / net / wireless / wext.c
index ee35e6422f1ff926b1eb683741314223c4f12ca3..3fe3c2c0ce118dfbff57e4de11c48697f9c667ec 100644 (file)
@@ -417,6 +417,21 @@ static const int event_type_size[] = {
        IW_EV_QUAL_LEN,                 /* IW_HEADER_TYPE_QUAL */
 };
 
+#ifdef CONFIG_COMPAT
+static const int compat_event_type_size[] = {
+       IW_EV_COMPAT_LCP_LEN,           /* IW_HEADER_TYPE_NULL */
+       0,
+       IW_EV_COMPAT_CHAR_LEN,          /* IW_HEADER_TYPE_CHAR */
+       0,
+       IW_EV_COMPAT_UINT_LEN,          /* IW_HEADER_TYPE_UINT */
+       IW_EV_COMPAT_FREQ_LEN,          /* IW_HEADER_TYPE_FREQ */
+       IW_EV_COMPAT_ADDR_LEN,          /* IW_HEADER_TYPE_ADDR */
+       0,
+       IW_EV_COMPAT_POINT_LEN,         /* Without variable payload */
+       IW_EV_COMPAT_PARAM_LEN,         /* IW_HEADER_TYPE_PARAM */
+       IW_EV_COMPAT_QUAL_LEN,          /* IW_HEADER_TYPE_QUAL */
+};
+#endif
 
 /************************ COMMON SUBROUTINES ************************/
 /*
@@ -1348,6 +1363,22 @@ void wireless_send_event(struct net_device *     dev,
        struct sk_buff *skb;
        struct nlmsghdr *nlh;
        struct nlattr *nla;
+#ifdef CONFIG_COMPAT
+       struct __compat_iw_event *compat_event;
+       struct compat_iw_point compat_wrqu;
+       struct sk_buff *compskb;
+#endif
+
+       /*
+        * Nothing in the kernel sends scan events with data, be safe.
+        * This is necessary because we cannot fix up scan event data
+        * for compat, due to being contained in 'extra', but normally
+        * applications are required to retrieve the scan data anyway
+        * and no data is included in the event, this codifies that
+        * practice.
+        */
+       if (WARN_ON(cmd == SIOCGIWSCAN && extra))
+               extra = NULL;
 
        /* Get the description of the Event */
        if (cmd <= SIOCIWLAST) {
@@ -1446,7 +1477,54 @@ void wireless_send_event(struct net_device *     dev,
                memcpy(((char *) event) + hdr_len, extra, extra_len);
 
        nlmsg_end(skb, nlh);
+#ifdef CONFIG_COMPAT
+       hdr_len = compat_event_type_size[descr->header_type];
+       event_len = hdr_len + extra_len;
 
+       compskb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
+       if (!compskb) {
+               kfree_skb(skb);
+               return;
+       }
+
+       /* Send via the RtNetlink event channel */
+       nlh = rtnetlink_ifinfo_prep(dev, compskb);
+       if (WARN_ON(!nlh)) {
+               kfree_skb(skb);
+               kfree_skb(compskb);
+               return;
+       }
+
+       /* Add the wireless events in the netlink packet */
+       nla = nla_reserve(compskb, IFLA_WIRELESS, event_len);
+       if (!nla) {
+               kfree_skb(skb);
+               kfree_skb(compskb);
+               return;
+       }
+       compat_event = nla_data(nla);
+
+       compat_event->len = event_len;
+       compat_event->cmd = cmd;
+       if (descr->header_type == IW_HEADER_TYPE_POINT) {
+               compat_wrqu.length = wrqu->data.length;
+               compat_wrqu.flags = wrqu->data.flags;
+               memcpy(&compat_event->pointer,
+                       ((char *) &compat_wrqu) + IW_EV_COMPAT_POINT_OFF,
+                       hdr_len - IW_EV_COMPAT_LCP_LEN);
+               if (extra_len)
+                       memcpy(((char *) compat_event) + hdr_len,
+                               extra, extra_len);
+       } else {
+               /* extra_len must be zero, so no if (extra) needed */
+               memcpy(&compat_event->pointer, wrqu,
+                       hdr_len - IW_EV_COMPAT_LCP_LEN);
+       }
+
+       nlmsg_end(compskb, nlh);
+
+       skb_shinfo(skb)->frag_list = compskb;
+#endif
        skb_queue_tail(&dev_net(dev)->wext_nlevents, skb);
        schedule_work(&wireless_nlevent_work);
 }