Package: broadcom-sta / 6.30.223.248-3

07-fix_procfs_handling.patch Patch series | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
Description: Fix kernel crash/system hang because of incorrect pointer
 argument use while retrieving cookie in procfs handling.
 .
 based on: http://ix.io/9DV
 tested on: kernel 3.14
Author: Mickael MASSON <mmasson.dev@gmail.com>
Bug-Debian: https://bugs.debian.org/770327

Index: broadcom-sta-6.30.223.248/amd64/src/wl/sys/wl_linux.c
===================================================================
--- broadcom-sta-6.30.223.248.orig/amd64/src/wl/sys/wl_linux.c	2014-12-07 17:23:06.437532026 +0400
+++ broadcom-sta-6.30.223.248/amd64/src/wl/sys/wl_linux.c	2014-12-07 17:23:06.433532026 +0400
@@ -3225,42 +3225,75 @@
 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
 static int
 wl_proc_read(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
+{
+	wl_info_t * wl = (wl_info_t *)data;
 #else
 static ssize_t
-wl_proc_read(struct file *filp, char __user *buffer, size_t length, loff_t *data)
-#endif
+wl_proc_read(struct file *filp, char __user *buffer, size_t length, loff_t *offp)
 {
-	wl_info_t * wl = (wl_info_t *)data;
-	int to_user;
-	int len;
+	wl_info_t * wl = PDE_DATA(file_inode(filp));
+#endif
+	int bcmerror, len;
+	int to_user = 0;
+	char tmp[8];
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
 	if (offset > 0) {
 		*eof = 1;
 		return 0;
 	}
+#else
+	if (*offp > 0) { /* for example, stop: cat /proc/brcm_monitor0 */
+		return 0; /* 0 <=> EOF */
+	}
 #endif
 
-	if (!length) {
-		WL_ERROR(("%s: Not enough return buf space\n", __FUNCTION__));
-		return 0;
-	}
 	WL_LOCK(wl);
-	wlc_ioctl(wl->wlc, WLC_GET_MONITOR, &to_user, sizeof(int), NULL);
-	len = sprintf(buffer, "%d\n", to_user);
-	WL_UNLOCK(wl);
-	return len;
+	bcmerror = wlc_ioctl(wl->wlc, WLC_GET_MONITOR, &to_user, sizeof(int), NULL);
+ 	WL_UNLOCK(wl);
+
+	if (bcmerror != BCME_OK) {
+		WL_ERROR(("%s: GET_MONITOR failed with %d\n", __FUNCTION__, bcmerror));
+		return -EIO;
+	}
+
+ 	len = snprintf(tmp, ARRAY_SIZE(tmp), "%d\n", to_user);
+	tmp[ARRAY_SIZE(tmp) - 1] = '\0';
+	if (len >= ARRAY_SIZE(tmp)) {
+		printk(KERN_ERR "%s:%d [%s()] output would be truncated (ret=%d)!", __FILE__, __LINE__, __FUNCTION__, len);
+		return -ERANGE;
+	}
+	else if (len < 0) {
+		printk(KERN_ERR "%s:%d [%s()] unable to convert value (ret=%d)!", __FILE__, __LINE__, __FUNCTION__, len);
+		return len;
+	}
+	if (length < len) {
+		printk(KERN_ERR "%s:%d [%s()] user buffer is too small (at least=%d ; user=%d)!", __FILE__, __LINE__, __FUNCTION__, len, (int)length);
+		return -EMSGSIZE;
+	}
+	if (copy_to_user(buffer, tmp, len) != 0) {
+		printk(KERN_ERR "%s:%d [%s()] unable to copy data!", __FILE__, __LINE__, __FUNCTION__);
+		return -EFAULT;
+	}
+	
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+	*offp += len;
+#endif
+
+ 	return len;
 }
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
 static int
 wl_proc_write(struct file *filp, const char *buff, unsigned long length, void *data)
+{
+	wl_info_t * wl = (wl_info_t *)data;
 #else
 static ssize_t
-wl_proc_write(struct file *filp, const char __user *buff, size_t length, loff_t *data)
-#endif
+wl_proc_write(struct file *filp, const char __user *buff, size_t length, loff_t *offp)
 {
-	wl_info_t * wl = (wl_info_t *)data;
+	wl_info_t * wl = PDE_DATA(file_inode(filp));
+#endif
 	int from_user = 0;
 	int bcmerror;
 
@@ -3271,7 +3304,11 @@
 	}
 	if (copy_from_user(&from_user, buff, 1)) {
 		WL_ERROR(("%s: copy from user failed\n", __FUNCTION__));
-		return -EIO;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
+ 		return -EIO;
+#else
+		return -EFAULT;
+#endif
 	}
 
 	if (from_user >= 0x30)
@@ -3281,10 +3318,15 @@
 	bcmerror = wlc_ioctl(wl->wlc, WLC_SET_MONITOR, &from_user, sizeof(int), NULL);
 	WL_UNLOCK(wl);
 
-	if (bcmerror < 0) {
+	if (bcmerror != BCME_OK) {
 		WL_ERROR(("%s: SET_MONITOR failed with %d\n", __FUNCTION__, bcmerror));
 		return -EIO;
 	}
+	
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) && 0 /* no need to update offset because this file should only trigger action... */
+	*offp += length;
+#endif
+
 	return length;
 }
 
@@ -3305,8 +3347,8 @@
 	if ((wl->proc_entry = create_proc_entry(tmp, 0644, NULL)) == NULL) {
 		WL_ERROR(("%s: create_proc_entry %s failed\n", __FUNCTION__, tmp));
 #else
-	if ((wl->proc_entry = proc_create(tmp, 0644, NULL, &wl_fops)) == NULL) {
-		WL_ERROR(("%s: proc_create %s failed\n", __FUNCTION__, tmp));
+	if ((wl->proc_entry = proc_create_data(tmp, 0644, NULL, &wl_fops, wl)) == NULL) {
+		WL_ERROR(("%s: proc_create_data %s failed\n", __FUNCTION__, tmp));
 #endif
 		ASSERT(0);
 		return -1;