File: | ozproto.c |
Location: | line 929, column 10 |
Description: | Dereference of null pointer (loaded from variable 'devs') |
1 | /* ----------------------------------------------------------------------------- |
2 | * Copyright (c) 2011 Ozmo Inc |
3 | * Released under the GNU General Public License Version 2 (GPLv2). |
4 | * ----------------------------------------------------------------------------- |
5 | */ |
6 | #include <linux1/init.h> |
7 | #include <linux1/module.h> |
8 | #include <linux1/timer.h> |
9 | #include <linux1/sched.h> |
10 | #include <linux1/netdevice.h> |
11 | #include <linux1/errno.h> |
12 | #include <linux1/ieee80211.h> |
13 | #include "ozconfig.h" |
14 | #include "ozprotocol.h" |
15 | #include "ozeltbuf.h" |
16 | #include "ozpd.h" |
17 | #include "ozproto.h" |
18 | #include "ozusbsvc.h" |
19 | #include "oztrace.h" |
20 | #include "ozappif.h" |
21 | #include "ozevent.h" |
22 | #include <asm/unaligned.h> |
23 | #include <linux1/uaccess.h> |
24 | #include <net/psnap.h> |
25 | /*------------------------------------------------------------------------------ |
26 | */ |
27 | #define OZ_CF_CONN_SUCCESS1 1 |
28 | #define OZ_CF_CONN_FAILURE2 2 |
29 | |
30 | #define OZ_DO_STOP1 1 |
31 | #define OZ_DO_SLEEP2 2 |
32 | |
33 | /* States of the timer. |
34 | */ |
35 | #define OZ_TIMER_IDLE0 0 |
36 | #define OZ_TIMER_SET1 1 |
37 | #define OZ_TIMER_IN_HANDLER2 2 |
38 | |
39 | #define OZ_MAX_TIMER_POOL_SIZE16 16 |
40 | |
41 | /*------------------------------------------------------------------------------ |
42 | */ |
43 | struct oz_binding { |
44 | struct packet_type ptype; |
45 | char name[OZ_MAX_BINDING_LEN32]; |
46 | struct oz_binding *next; |
47 | }; |
48 | |
49 | struct oz_timer { |
50 | struct list_head link; |
51 | struct oz_pd *pd; |
52 | unsigned long due_time; |
53 | int type; |
54 | }; |
55 | /*------------------------------------------------------------------------------ |
56 | * Static external variables. |
57 | */ |
58 | static DEFINE_SPINLOCK(g_polling_lock)spinlock_t g_polling_lock = (spinlock_t ) { { .rlock = { .raw_lock = { { 0 } }, } } }; |
59 | static LIST_HEAD(g_pd_list)struct list_head g_pd_list = { &(g_pd_list), &(g_pd_list ) }; |
60 | static struct oz_binding *g_binding ; |
61 | static DEFINE_SPINLOCK(g_binding_lock)spinlock_t g_binding_lock = (spinlock_t ) { { .rlock = { .raw_lock = { { 0 } }, } } }; |
62 | static struct sk_buff_head g_rx_queue; |
63 | static u8 g_session_id; |
64 | static u16 g_apps = 0x1; |
65 | static int g_processing_rx; |
66 | static struct timer_list g_timer; |
67 | static struct oz_timer *g_cur_timer; |
68 | static struct list_head *g_timer_pool; |
69 | static int g_timer_pool_count; |
70 | static int g_timer_state = OZ_TIMER_IDLE0; |
71 | static LIST_HEAD(g_timer_list)struct list_head g_timer_list = { &(g_timer_list), &( g_timer_list) }; |
72 | /*------------------------------------------------------------------------------ |
73 | */ |
74 | static void oz_protocol_timer_start(void); |
75 | /*------------------------------------------------------------------------------ |
76 | * Context: softirq-serialized |
77 | */ |
78 | static u8 oz_get_new_session_id(u8 exclude) |
79 | { |
80 | if (++g_session_id == 0) |
81 | g_session_id = 1; |
82 | if (g_session_id == exclude) { |
83 | if (++g_session_id == 0) |
84 | g_session_id = 1; |
85 | } |
86 | return g_session_id; |
87 | } |
88 | /*------------------------------------------------------------------------------ |
89 | * Context: softirq-serialized |
90 | */ |
91 | static void oz_send_conn_rsp(struct oz_pd *pd, u8 status) |
92 | { |
93 | struct sk_buff *skb; |
94 | struct net_device *dev = pd->net_dev; |
95 | struct oz_hdr *oz_hdr; |
96 | struct oz_elt *elt; |
97 | struct oz_elt_connect_rsp *body; |
98 | int sz = sizeof(struct oz_hdr) + sizeof(struct oz_elt) + |
99 | sizeof(struct oz_elt_connect_rsp); |
100 | skb = alloc_skb(sz + OZ_ALLOCATED_SPACE(dev)(((((dev)->hard_header_len+(dev)->needed_headroom)& ~(16 - 1)) + 16)+(dev)->needed_tailroom), GFP_ATOMIC((( gfp_t)0x20u))); |
101 | if (skb == NULL((void *)0)) |
102 | return; |
103 | skb_reserve(skb, LL_RESERVED_SPACE(dev)((((dev)->hard_header_len+(dev)->needed_headroom)&~ (16 - 1)) + 16)); |
104 | skb_reset_network_header(skb); |
105 | oz_hdr = (struct oz_hdr *)skb_put(skb, sz); |
106 | elt = (struct oz_elt *)(oz_hdr+1); |
107 | body = (struct oz_elt_connect_rsp *)(elt+1); |
108 | skb->dev = dev; |
109 | skb->protocol = htons(OZ_ETHERTYPE)(( __be16)(__builtin_constant_p((__u16)((0x892e))) ? ((__u16) ( (((__u16)((0x892e)) & (__u16)0x00ffU) << 8) | ((( __u16)((0x892e)) & (__u16)0xff00U) >> 8))) : __fswab16 ((0x892e)))); |
110 | /* Fill in device header */ |
111 | if (dev_hard_header(skb, dev, OZ_ETHERTYPE0x892e, pd->mac_addr, |
112 | dev->dev_addr, skb->len) < 0) { |
113 | kfree_skb(skb); |
114 | return; |
115 | } |
116 | oz_hdr->control = (OZ_PROTOCOL_VERSION0x1<<OZ_VERSION_SHIFT2); |
117 | oz_hdr->last_pkt_num = 0; |
118 | put_unaligned(0, &oz_hdr->pkt_num)({ void *__gu_p = (&oz_hdr->pkt_num); switch (sizeof(* (&oz_hdr->pkt_num))) { case 1: *(u8 *)__gu_p = ( u8)(0 ); break; case 2: put_unaligned_le16(( u16)(0), __gu_p); break ; case 4: put_unaligned_le32(( u32)(0), __gu_p); break; case 8 : put_unaligned_le64(( u64)(0), __gu_p); break; default: __bad_unaligned_access_size (); break; } (void)0; }); |
119 | oz_event_log(OZ_EVT_CONNECT_RSP, 0, 0, NULL, 0)do { if ((1<<(11)) & g_evt_mask) oz_event_log2(11, 0 , 0, ((void *)0), 0); } while (0); |
120 | elt->type = OZ_ELT_CONNECT_RSP0x07; |
121 | elt->length = sizeof(struct oz_elt_connect_rsp); |
122 | memset(body, 0, sizeof(struct oz_elt_connect_rsp)); |
123 | body->status = status; |
124 | if (status == 0) { |
125 | body->mode = pd->mode; |
126 | body->session_id = pd->session_id; |
127 | put_unaligned(cpu_to_le16(pd->total_apps), &body->apps)({ void *__gu_p = (&body->apps); switch (sizeof(*(& body->apps))) { case 1: *(u8 *)__gu_p = ( u8)((( __le16)(__u16 )(pd->total_apps))); break; case 2: put_unaligned_le16(( u16 )((( __le16)(__u16)(pd->total_apps))), __gu_p); break; case 4: put_unaligned_le32(( u32)((( __le16)(__u16)(pd->total_apps ))), __gu_p); break; case 8: put_unaligned_le64(( u64)((( __le16 )(__u16)(pd->total_apps))), __gu_p); break; default: __bad_unaligned_access_size (); break; } (void)0; }); |
128 | } |
129 | oz_trace("TX: OZ_ELT_CONNECT_RSP %d", status); |
130 | dev_queue_xmit(skb); |
131 | return; |
132 | } |
133 | /*------------------------------------------------------------------------------ |
134 | * Context: softirq-serialized |
135 | */ |
136 | static void pd_set_keepalive(struct oz_pd *pd, u8 kalive) |
137 | { |
138 | unsigned long keep_alive = kalive & OZ_KALIVE_VALUE_MASK0x3f; |
139 | |
140 | switch (kalive & OZ_KALIVE_TYPE_MASK0xc0) { |
141 | case OZ_KALIVE_SPECIAL0x00: |
142 | pd->keep_alive_j = |
143 | oz_ms_to_jiffies(keep_alive * 1000*60*60*24*20)msecs_to_jiffies(keep_alive * 1000*60*60*24*20); |
144 | break; |
145 | case OZ_KALIVE_SECS0x40: |
146 | pd->keep_alive_j = oz_ms_to_jiffies(keep_alive*1000)msecs_to_jiffies(keep_alive*1000); |
147 | break; |
148 | case OZ_KALIVE_MINS0x80: |
149 | pd->keep_alive_j = oz_ms_to_jiffies(keep_alive*1000*60)msecs_to_jiffies(keep_alive*1000*60); |
150 | break; |
151 | case OZ_KALIVE_HOURS0xc0: |
152 | pd->keep_alive_j = oz_ms_to_jiffies(keep_alive*1000*60*60)msecs_to_jiffies(keep_alive*1000*60*60); |
153 | break; |
154 | default: |
155 | pd->keep_alive_j = 0; |
156 | } |
157 | oz_trace("Keepalive = %lu jiffies\n", pd->keep_alive_j); |
158 | } |
159 | /*------------------------------------------------------------------------------ |
160 | * Context: softirq-serialized |
161 | */ |
162 | static void pd_set_presleep(struct oz_pd *pd, u8 presleep) |
163 | { |
164 | if (presleep) |
165 | pd->presleep_j = oz_ms_to_jiffies(presleep*100)msecs_to_jiffies(presleep*100); |
166 | else |
167 | pd->presleep_j = OZ_PRESLEEP_TOUT_J(11*1000); |
168 | oz_trace("Presleep time = %lu jiffies\n", pd->presleep_j); |
169 | } |
170 | /*------------------------------------------------------------------------------ |
171 | * Context: softirq-serialized |
172 | */ |
173 | static struct oz_pd *oz_connect_req(struct oz_pd *cur_pd, struct oz_elt *elt, |
174 | u8 *pd_addr, struct net_device *net_dev) |
175 | { |
176 | struct oz_pd *pd; |
177 | struct oz_elt_connect_req *body = |
178 | (struct oz_elt_connect_req *)(elt+1); |
179 | u8 rsp_status = OZ_STATUS_SUCCESS0; |
180 | u8 stop_needed = 0; |
181 | u16 new_apps = g_apps; |
182 | struct net_device *old_net_dev = NULL((void *)0); |
183 | struct oz_pd *free_pd = NULL((void *)0); |
184 | if (cur_pd) { |
185 | pd = cur_pd; |
186 | spin_lock_bh(&g_polling_lock); |
187 | } else { |
188 | struct oz_pd *pd2 = NULL((void *)0); |
189 | struct list_head *e; |
190 | pd = oz_pd_alloc(pd_addr); |
191 | if (pd == NULL((void *)0)) |
192 | return NULL((void *)0); |
193 | pd->last_rx_time_j = jiffies; |
194 | spin_lock_bh(&g_polling_lock); |
195 | list_for_each(e, &g_pd_list)for (e = (&g_pd_list)->next; e != (&g_pd_list); e = e->next) { |
196 | pd2 = container_of(e, struct oz_pd, link)({ const typeof( ((struct oz_pd *)0)->link ) *__mptr = (e) ; (struct oz_pd *)( (char *)__mptr - __builtin_offsetof(struct oz_pd,link) );}); |
197 | if (memcmp(pd2->mac_addr, pd_addr, ETH_ALEN6) == 0) { |
198 | free_pd = pd; |
199 | pd = pd2; |
200 | break; |
201 | } |
202 | } |
203 | if (pd != pd2) |
204 | list_add_tail(&pd->link, &g_pd_list); |
205 | } |
206 | if (pd == NULL((void *)0)) { |
207 | spin_unlock_bh(&g_polling_lock); |
208 | return NULL((void *)0); |
209 | } |
210 | if (pd->net_dev != net_dev) { |
211 | old_net_dev = pd->net_dev; |
212 | dev_hold(net_dev); |
213 | pd->net_dev = net_dev; |
214 | } |
215 | oz_trace("Host vendor: %d\n", body->host_vendor); |
216 | pd->max_tx_size = OZ_MAX_TX_SIZE1514; |
217 | pd->mode = body->mode; |
218 | pd->pd_info = body->pd_info; |
219 | if (pd->mode & OZ_F_ISOC_NO_ELTS0x40) { |
220 | pd->ms_per_isoc = body->ms_per_isoc; |
221 | if (!pd->ms_per_isoc) |
222 | pd->ms_per_isoc = 4; |
223 | |
224 | switch (body->ms_isoc_latency & OZ_LATENCY_MASK0xc0) { |
225 | case OZ_ONE_MS_LATENCY0x40: |
226 | pd->isoc_latency = (body->ms_isoc_latency & |
227 | ~OZ_LATENCY_MASK0xc0) / pd->ms_per_isoc; |
228 | break; |
229 | case OZ_TEN_MS_LATENCY0x80: |
230 | pd->isoc_latency = ((body->ms_isoc_latency & |
231 | ~OZ_LATENCY_MASK0xc0) * 10) / pd->ms_per_isoc; |
232 | break; |
233 | default: |
234 | pd->isoc_latency = OZ_MAX_TX_QUEUE_ISOC32; |
235 | } |
236 | } |
237 | if (body->max_len_div16) |
238 | pd->max_tx_size = ((u16)body->max_len_div16)<<4; |
239 | oz_trace("Max frame:%u Ms per isoc:%u\n", |
240 | pd->max_tx_size, pd->ms_per_isoc); |
241 | pd->max_stream_buffering = 3*1024; |
242 | pd->timeout_time_j = jiffies + OZ_CONNECTION_TOUT_J(2*1000); |
243 | pd->pulse_period_j = OZ_QUANTUM_J(msecs_to_jiffies(8)); |
244 | pd_set_presleep(pd, body->presleep); |
245 | pd_set_keepalive(pd, body->keep_alive); |
246 | |
247 | new_apps &= le16_to_cpu(get_unaligned(&body->apps))(( __u16)(__le16)((( typeof(*(&body->apps)))({ __builtin_choose_expr (sizeof(*(&body->apps)) == 1, *(&body->apps), __builtin_choose_expr (sizeof(*(&body->apps)) == 2, get_unaligned_le16((& body->apps)), __builtin_choose_expr(sizeof(*(&body-> apps)) == 4, get_unaligned_le32((&body->apps)), __builtin_choose_expr (sizeof(*(&body->apps)) == 8, get_unaligned_le64((& body->apps)), __bad_unaligned_access_size())))); })))); |
248 | if ((new_apps & 0x1) && (body->session_id)) { |
249 | if (pd->session_id) { |
250 | if (pd->session_id != body->session_id) { |
251 | rsp_status = OZ_STATUS_SESSION_MISMATCH5; |
252 | goto done; |
253 | } |
254 | } else { |
255 | new_apps &= ~0x1; /* Resume not permitted */ |
256 | pd->session_id = |
257 | oz_get_new_session_id(body->session_id); |
258 | } |
259 | } else { |
260 | if (pd->session_id && !body->session_id) { |
261 | rsp_status = OZ_STATUS_SESSION_TEARDOWN6; |
262 | stop_needed = 1; |
263 | } else { |
264 | new_apps &= ~0x1; /* Resume not permitted */ |
265 | pd->session_id = |
266 | oz_get_new_session_id(body->session_id); |
267 | } |
268 | } |
269 | done: |
270 | if (rsp_status == OZ_STATUS_SUCCESS0) { |
271 | u16 start_apps = new_apps & ~pd->total_apps & ~0x1; |
272 | u16 stop_apps = pd->total_apps & ~new_apps & ~0x1; |
273 | u16 resume_apps = new_apps & pd->paused_apps & ~0x1; |
274 | spin_unlock_bh(&g_polling_lock); |
275 | oz_pd_set_state(pd, OZ_PD_S_CONNECTED0x2); |
276 | oz_timer_delete(pd, OZ_TIMER_STOP3); |
277 | oz_trace("new_apps=0x%x total_apps=0x%x paused_apps=0x%x\n", |
278 | new_apps, pd->total_apps, pd->paused_apps); |
279 | if (start_apps) { |
280 | if (oz_services_start(pd, start_apps, 0)) |
281 | rsp_status = OZ_STATUS_TOO_MANY_PDS2; |
282 | } |
283 | if (resume_apps) |
284 | if (oz_services_start(pd, resume_apps, 1)) |
285 | rsp_status = OZ_STATUS_TOO_MANY_PDS2; |
286 | if (stop_apps) |
287 | oz_services_stop(pd, stop_apps, 0); |
288 | oz_pd_request_heartbeat(pd); |
289 | } else { |
290 | spin_unlock_bh(&g_polling_lock); |
291 | } |
292 | oz_send_conn_rsp(pd, rsp_status); |
293 | if (rsp_status != OZ_STATUS_SUCCESS0) { |
294 | if (stop_needed) |
295 | oz_pd_stop(pd); |
296 | oz_pd_put(pd); |
297 | pd = NULL((void *)0); |
298 | } |
299 | if (old_net_dev) |
300 | dev_put(old_net_dev); |
301 | if (free_pd) |
302 | oz_pd_destroy(free_pd); |
303 | return pd; |
304 | } |
305 | /*------------------------------------------------------------------------------ |
306 | * Context: softirq-serialized |
307 | */ |
308 | static void oz_add_farewell(struct oz_pd *pd, u8 ep_num, u8 index, |
309 | u8 *report, u8 len) |
310 | { |
311 | struct oz_farewell *f; |
312 | struct oz_farewell *f2; |
313 | int found = 0; |
314 | f = kmalloc(sizeof(struct oz_farewell) + len - 1, GFP_ATOMIC((( gfp_t)0x20u))); |
315 | if (!f) |
316 | return; |
317 | f->ep_num = ep_num; |
318 | f->index = index; |
319 | memcpy(f->report, report, len)({ size_t __len = (len); void *__ret; if (__builtin_constant_p (len) && __len >= 64) __ret = __memcpy((f->report ), (report), __len); else __ret = __builtin_memcpy((f->report ), (report), __len); __ret; }); |
320 | oz_trace("RX: Adding farewell report\n"); |
321 | spin_lock(&g_polling_lock); |
322 | list_for_each_entry(f2, &pd->farewell_list, link)for (f2 = ({ const typeof( ((typeof(*f2) *)0)->link ) *__mptr = ((&pd->farewell_list)->next); (typeof(*f2) *)( ( char *)__mptr - __builtin_offsetof(typeof(*f2),link) );}); & f2->link != (&pd->farewell_list); f2 = ({ const typeof ( ((typeof(*f2) *)0)->link ) *__mptr = (f2->link.next); (typeof(*f2) *)( (char *)__mptr - __builtin_offsetof(typeof( *f2),link) );})) { |
323 | if ((f2->ep_num == ep_num) && (f2->index == index)) { |
324 | found = 1; |
325 | list_del(&f2->link); |
326 | break; |
327 | } |
328 | } |
329 | list_add_tail(&f->link, &pd->farewell_list); |
330 | spin_unlock(&g_polling_lock); |
331 | if (found) |
332 | kfree(f2); |
333 | } |
334 | /*------------------------------------------------------------------------------ |
335 | * Context: softirq-serialized |
336 | */ |
337 | static void oz_rx_frame(struct sk_buff *skb) |
338 | { |
339 | u8 *mac_hdr; |
340 | u8 *src_addr; |
341 | struct oz_elt *elt; |
342 | int length; |
343 | struct oz_pd *pd = NULL((void *)0); |
344 | struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb); |
345 | int dup = 0; |
346 | u32 pkt_num; |
347 | |
348 | oz_event_log(OZ_EVT_RX_PROCESS, 0,do { if ((1<<(1)) & g_evt_mask) oz_event_log2(1, 0, (((u16)oz_hdr->control)<<8)|oz_hdr->last_pkt_num , ((void *)0), oz_hdr->pkt_num); } while (0) |
349 | (((u16)oz_hdr->control)<<8)|oz_hdr->last_pkt_num,do { if ((1<<(1)) & g_evt_mask) oz_event_log2(1, 0, (((u16)oz_hdr->control)<<8)|oz_hdr->last_pkt_num , ((void *)0), oz_hdr->pkt_num); } while (0) |
350 | NULL, oz_hdr->pkt_num)do { if ((1<<(1)) & g_evt_mask) oz_event_log2(1, 0, (((u16)oz_hdr->control)<<8)|oz_hdr->last_pkt_num , ((void *)0), oz_hdr->pkt_num); } while (0); |
351 | oz_trace2(OZ_TRACE_RX_FRAMES, |
352 | "RX frame PN=0x%x LPN=0x%x control=0x%x\n", |
353 | oz_hdr->pkt_num, oz_hdr->last_pkt_num, oz_hdr->control); |
354 | mac_hdr = skb_mac_header(skb); |
355 | src_addr = &mac_hdr[ETH_ALEN6] ; |
356 | length = skb->len; |
357 | |
358 | /* Check the version field */ |
359 | if (oz_get_prot_ver(oz_hdr->control)(((oz_hdr->control) & 0xc) >> 2) != OZ_PROTOCOL_VERSION0x1) { |
360 | oz_trace("Incorrect protocol version: %d\n", |
361 | oz_get_prot_ver(oz_hdr->control)); |
362 | goto done; |
363 | } |
364 | |
365 | pkt_num = le32_to_cpu(get_unaligned(&oz_hdr->pkt_num))(( __u32)(__le32)((( typeof(*(&oz_hdr->pkt_num)))({ __builtin_choose_expr (sizeof(*(&oz_hdr->pkt_num)) == 1, *(&oz_hdr->pkt_num ), __builtin_choose_expr(sizeof(*(&oz_hdr->pkt_num)) == 2, get_unaligned_le16((&oz_hdr->pkt_num)), __builtin_choose_expr (sizeof(*(&oz_hdr->pkt_num)) == 4, get_unaligned_le32( (&oz_hdr->pkt_num)), __builtin_choose_expr(sizeof(*(& oz_hdr->pkt_num)) == 8, get_unaligned_le64((&oz_hdr-> pkt_num)), __bad_unaligned_access_size())))); })))); |
366 | |
367 | pd = oz_pd_find(src_addr); |
368 | if (pd) { |
369 | pd->last_rx_time_j = jiffies; |
370 | oz_timer_add(pd, OZ_TIMER_TOUT1, |
371 | pd->last_rx_time_j + pd->presleep_j, 1); |
372 | if (pkt_num != pd->last_rx_pkt_num) { |
373 | pd->last_rx_pkt_num = pkt_num; |
374 | } else { |
375 | dup = 1; |
376 | oz_trace("Duplicate frame\n"); |
377 | } |
378 | } |
379 | |
380 | if (pd && !dup && ((pd->mode & OZ_MODE_MASK0xf) == OZ_MODE_TRIGGERED0x1)) { |
381 | oz_trace2(OZ_TRACE_RX_FRAMES, "Received TRIGGER Frame\n"); |
382 | pd->last_sent_frame = &pd->tx_queue; |
383 | if (oz_hdr->control & OZ_F_ACK0x10) { |
384 | /* Retire completed frames */ |
385 | oz_retire_tx_frames(pd, oz_hdr->last_pkt_num); |
386 | } |
387 | if ((oz_hdr->control & OZ_F_ACK_REQUESTED0x80) && |
388 | (pd->state == OZ_PD_S_CONNECTED0x2)) { |
389 | int backlog = pd->nb_queued_frames; |
390 | pd->trigger_pkt_num = pkt_num; |
391 | /* Send queued frames */ |
392 | oz_send_queued_frames(pd, backlog); |
393 | } |
394 | } |
395 | |
396 | length -= sizeof(struct oz_hdr); |
397 | elt = (struct oz_elt *)((u8 *)oz_hdr + sizeof(struct oz_hdr)); |
398 | |
399 | while (length >= sizeof(struct oz_elt)) { |
400 | length -= sizeof(struct oz_elt) + elt->length; |
401 | if (length < 0) |
402 | break; |
403 | switch (elt->type) { |
404 | case OZ_ELT_CONNECT_REQ0x06: |
405 | oz_event_log(OZ_EVT_CONNECT_REQ, 0, 0, NULL, 0)do { if ((1<<(10)) & g_evt_mask) oz_event_log2(10, 0 , 0, ((void *)0), 0); } while (0); |
406 | oz_trace("RX: OZ_ELT_CONNECT_REQ\n"); |
407 | pd = oz_connect_req(pd, elt, src_addr, skb->dev); |
408 | break; |
409 | case OZ_ELT_DISCONNECT0x08: |
410 | oz_trace("RX: OZ_ELT_DISCONNECT\n"); |
411 | if (pd) |
412 | oz_pd_sleep(pd); |
413 | break; |
414 | case OZ_ELT_UPDATE_PARAM_REQ0x11: { |
415 | struct oz_elt_update_param *body = |
416 | (struct oz_elt_update_param *)(elt + 1); |
417 | oz_trace("RX: OZ_ELT_UPDATE_PARAM_REQ\n"); |
418 | if (pd && (pd->state & OZ_PD_S_CONNECTED0x2)) { |
419 | spin_lock(&g_polling_lock); |
420 | pd_set_keepalive(pd, body->keepalive); |
421 | pd_set_presleep(pd, body->presleep); |
422 | spin_unlock(&g_polling_lock); |
423 | } |
424 | } |
425 | break; |
426 | case OZ_ELT_FAREWELL_REQ0x12: { |
427 | struct oz_elt_farewell *body = |
428 | (struct oz_elt_farewell *)(elt + 1); |
429 | oz_trace("RX: OZ_ELT_FAREWELL_REQ\n"); |
430 | oz_add_farewell(pd, body->ep_num, |
431 | body->index, body->report, |
432 | elt->length + 1 - sizeof(*body)); |
433 | } |
434 | break; |
435 | case OZ_ELT_APP_DATA0x31: |
436 | if (pd && (pd->state & OZ_PD_S_CONNECTED0x2)) { |
437 | struct oz_app_hdr *app_hdr = |
438 | (struct oz_app_hdr *)(elt+1); |
439 | if (dup) |
440 | break; |
441 | oz_handle_app_elt(pd, app_hdr->app_id, elt); |
442 | } |
443 | break; |
444 | default: |
445 | oz_trace("RX: Unknown elt %02x\n", elt->type); |
446 | } |
447 | elt = oz_next_elt(elt)(struct oz_elt *)((u8 *)((elt) + 1) + (elt)->length); |
448 | } |
449 | done: |
450 | if (pd) |
451 | oz_pd_put(pd); |
452 | consume_skb(skb); |
453 | } |
454 | /*------------------------------------------------------------------------------ |
455 | * Context: process |
456 | */ |
457 | void oz_protocol_term(void) |
458 | { |
459 | struct list_head *chain = NULL((void *)0); |
460 | del_timer_sync(&g_timer); |
461 | /* Walk the list of bindings and remove each one. |
462 | */ |
463 | spin_lock_bh(&g_binding_lock); |
464 | while (g_binding) { |
465 | struct oz_binding *b = g_binding; |
466 | g_binding = b->next; |
467 | spin_unlock_bh(&g_binding_lock); |
468 | dev_remove_pack(&b->ptype); |
469 | if (b->ptype.dev) |
470 | dev_put(b->ptype.dev); |
471 | kfree(b); |
472 | spin_lock_bh(&g_binding_lock); |
473 | } |
474 | spin_unlock_bh(&g_binding_lock); |
475 | /* Walk the list of PDs and stop each one. This causes the PD to be |
476 | * removed from the list so we can just pull each one from the head |
477 | * of the list. |
478 | */ |
479 | spin_lock_bh(&g_polling_lock); |
480 | while (!list_empty(&g_pd_list)) { |
481 | struct oz_pd *pd = |
482 | list_first_entry(&g_pd_list, struct oz_pd, link)({ const typeof( ((struct oz_pd *)0)->link ) *__mptr = ((& g_pd_list)->next); (struct oz_pd *)( (char *)__mptr - __builtin_offsetof (struct oz_pd,link) );}); |
483 | oz_pd_get(pd); |
484 | spin_unlock_bh(&g_polling_lock); |
485 | oz_pd_stop(pd); |
486 | oz_pd_put(pd); |
487 | spin_lock_bh(&g_polling_lock); |
488 | } |
489 | chain = g_timer_pool; |
490 | g_timer_pool = NULL((void *)0); |
491 | spin_unlock_bh(&g_polling_lock); |
492 | while (chain) { |
493 | struct oz_timer *t = container_of(chain, struct oz_timer, link)({ const typeof( ((struct oz_timer *)0)->link ) *__mptr = ( chain); (struct oz_timer *)( (char *)__mptr - __builtin_offsetof (struct oz_timer,link) );}); |
494 | chain = chain->next; |
495 | kfree(t); |
496 | } |
497 | oz_trace("Protocol stopped\n"); |
498 | } |
499 | /*------------------------------------------------------------------------------ |
500 | * Context: softirq |
501 | */ |
502 | static void oz_pd_handle_timer(struct oz_pd *pd, int type) |
503 | { |
504 | switch (type) { |
505 | case OZ_TIMER_TOUT1: |
506 | oz_pd_sleep(pd); |
507 | break; |
508 | case OZ_TIMER_STOP3: |
509 | oz_pd_stop(pd); |
510 | break; |
511 | case OZ_TIMER_HEARTBEAT2: { |
512 | u16 apps = 0; |
513 | spin_lock_bh(&g_polling_lock); |
514 | pd->heartbeat_requested = 0; |
515 | if (pd->state & OZ_PD_S_CONNECTED0x2) |
516 | apps = pd->total_apps; |
517 | spin_unlock_bh(&g_polling_lock); |
518 | if (apps) |
519 | oz_pd_heartbeat(pd, apps); |
520 | } |
521 | break; |
522 | } |
523 | } |
524 | /*------------------------------------------------------------------------------ |
525 | * Context: softirq |
526 | */ |
527 | static void oz_protocol_timer(unsigned long arg) |
528 | { |
529 | struct oz_timer *t; |
530 | struct oz_timer *t2; |
531 | struct oz_pd *pd; |
532 | spin_lock_bh(&g_polling_lock); |
533 | if (!g_cur_timer) { |
534 | /* This happens if we remove the current timer but can't stop |
535 | * the timer from firing. In this case just get out. |
536 | */ |
537 | oz_event_log(OZ_EVT_TIMER, 0, 0, NULL, 0)do { if ((1<<(17)) & g_evt_mask) oz_event_log2(17, 0 , 0, ((void *)0), 0); } while (0); |
538 | spin_unlock_bh(&g_polling_lock); |
539 | return; |
540 | } |
541 | g_timer_state = OZ_TIMER_IN_HANDLER2; |
542 | t = g_cur_timer; |
543 | g_cur_timer = NULL((void *)0); |
544 | list_del(&t->link); |
545 | spin_unlock_bh(&g_polling_lock); |
546 | do { |
547 | pd = t->pd; |
548 | oz_event_log(OZ_EVT_TIMER, 0, t->type, NULL, 0)do { if ((1<<(17)) & g_evt_mask) oz_event_log2(17, 0 , t->type, ((void *)0), 0); } while (0); |
549 | oz_pd_handle_timer(pd, t->type); |
550 | spin_lock_bh(&g_polling_lock); |
551 | if (g_timer_pool_count < OZ_MAX_TIMER_POOL_SIZE16) { |
552 | t->link.next = g_timer_pool; |
553 | g_timer_pool = &t->link; |
554 | g_timer_pool_count++; |
555 | t = NULL((void *)0); |
556 | } |
557 | if (!list_empty(&g_timer_list)) { |
558 | t2 = container_of(g_timer_list.next,({ const typeof( ((struct oz_timer *)0)->link ) *__mptr = ( g_timer_list.next); (struct oz_timer *)( (char *)__mptr - __builtin_offsetof (struct oz_timer,link) );}) |
559 | struct oz_timer, link)({ const typeof( ((struct oz_timer *)0)->link ) *__mptr = ( g_timer_list.next); (struct oz_timer *)( (char *)__mptr - __builtin_offsetof (struct oz_timer,link) );}); |
560 | if (time_before_eq(t2->due_time, jiffies)(({ unsigned long __dummy; typeof(jiffies) __dummy2; (void)(& __dummy == &__dummy2); 1; }) && ({ unsigned long __dummy ; typeof(t2->due_time) __dummy2; (void)(&__dummy == & __dummy2); 1; }) && ((long)(jiffies) - (long)(t2-> due_time) >= 0))) |
561 | list_del(&t2->link); |
562 | else |
563 | t2 = NULL((void *)0); |
564 | } else { |
565 | t2 = NULL((void *)0); |
566 | } |
567 | spin_unlock_bh(&g_polling_lock); |
568 | oz_pd_put(pd); |
569 | kfree(t); |
570 | t = t2; |
571 | } while (t); |
572 | g_timer_state = OZ_TIMER_IDLE0; |
573 | oz_protocol_timer_start(); |
574 | } |
575 | /*------------------------------------------------------------------------------ |
576 | * Context: softirq |
577 | */ |
578 | static void oz_protocol_timer_start(void) |
579 | { |
580 | spin_lock_bh(&g_polling_lock); |
581 | if (!list_empty(&g_timer_list)) { |
582 | g_cur_timer = |
583 | container_of(g_timer_list.next, struct oz_timer, link)({ const typeof( ((struct oz_timer *)0)->link ) *__mptr = ( g_timer_list.next); (struct oz_timer *)( (char *)__mptr - __builtin_offsetof (struct oz_timer,link) );}); |
584 | if (g_timer_state == OZ_TIMER_SET1) { |
585 | oz_event_log(OZ_EVT_TIMER_CTRL, 3,do { if ((1<<(16)) & g_evt_mask) oz_event_log2(16, 3 , (u16)g_cur_timer->type, ((void *)0), (unsigned)g_cur_timer ->due_time); } while (0) |
586 | (u16)g_cur_timer->type, NULL,do { if ((1<<(16)) & g_evt_mask) oz_event_log2(16, 3 , (u16)g_cur_timer->type, ((void *)0), (unsigned)g_cur_timer ->due_time); } while (0) |
587 | (unsigned)g_cur_timer->due_time)do { if ((1<<(16)) & g_evt_mask) oz_event_log2(16, 3 , (u16)g_cur_timer->type, ((void *)0), (unsigned)g_cur_timer ->due_time); } while (0); |
588 | mod_timer(&g_timer, g_cur_timer->due_time); |
589 | } else { |
590 | oz_event_log(OZ_EVT_TIMER_CTRL, 4,do { if ((1<<(16)) & g_evt_mask) oz_event_log2(16, 4 , (u16)g_cur_timer->type, ((void *)0), (unsigned)g_cur_timer ->due_time); } while (0) |
591 | (u16)g_cur_timer->type, NULL,do { if ((1<<(16)) & g_evt_mask) oz_event_log2(16, 4 , (u16)g_cur_timer->type, ((void *)0), (unsigned)g_cur_timer ->due_time); } while (0) |
592 | (unsigned)g_cur_timer->due_time)do { if ((1<<(16)) & g_evt_mask) oz_event_log2(16, 4 , (u16)g_cur_timer->type, ((void *)0), (unsigned)g_cur_timer ->due_time); } while (0); |
593 | g_timer.expires = g_cur_timer->due_time; |
594 | g_timer.function = oz_protocol_timer; |
595 | g_timer.data = 0; |
596 | add_timer(&g_timer); |
597 | } |
598 | g_timer_state = OZ_TIMER_SET1; |
599 | } else { |
600 | oz_trace("No queued timers\n"); |
601 | } |
602 | spin_unlock_bh(&g_polling_lock); |
603 | } |
604 | /*------------------------------------------------------------------------------ |
605 | * Context: softirq or process |
606 | */ |
607 | void oz_timer_add(struct oz_pd *pd, int type, unsigned long due_time, |
608 | int remove) |
609 | { |
610 | struct list_head *e; |
611 | struct oz_timer *t = NULL((void *)0); |
612 | int restart_needed = 0; |
613 | oz_event_log(OZ_EVT_TIMER_CTRL, 1, (u16)type, NULL, (unsigned)due_time)do { if ((1<<(16)) & g_evt_mask) oz_event_log2(16, 1 , (u16)type, ((void *)0), (unsigned)due_time); } while (0); |
614 | spin_lock(&g_polling_lock); |
615 | if (remove) { |
616 | list_for_each(e, &g_timer_list)for (e = (&g_timer_list)->next; e != (&g_timer_list ); e = e->next) { |
617 | t = container_of(e, struct oz_timer, link)({ const typeof( ((struct oz_timer *)0)->link ) *__mptr = ( e); (struct oz_timer *)( (char *)__mptr - __builtin_offsetof( struct oz_timer,link) );}); |
618 | if ((t->pd == pd) && (t->type == type)) { |
619 | if (g_cur_timer == t) { |
620 | restart_needed = 1; |
621 | g_cur_timer = NULL((void *)0); |
622 | } |
623 | list_del(e); |
624 | break; |
625 | } |
626 | t = NULL((void *)0); |
627 | } |
628 | } |
629 | if (!t) { |
630 | if (g_timer_pool) { |
631 | t = container_of(g_timer_pool, struct oz_timer, link)({ const typeof( ((struct oz_timer *)0)->link ) *__mptr = ( g_timer_pool); (struct oz_timer *)( (char *)__mptr - __builtin_offsetof (struct oz_timer,link) );}); |
632 | g_timer_pool = g_timer_pool->next; |
633 | g_timer_pool_count--; |
634 | } else { |
635 | t = kmalloc(sizeof(struct oz_timer), GFP_ATOMIC((( gfp_t)0x20u))); |
636 | } |
637 | if (t) { |
638 | t->pd = pd; |
639 | t->type = type; |
640 | oz_pd_get(pd); |
641 | } |
642 | } |
643 | if (t) { |
644 | struct oz_timer *t2; |
645 | t->due_time = due_time; |
646 | list_for_each(e, &g_timer_list)for (e = (&g_timer_list)->next; e != (&g_timer_list ); e = e->next) { |
647 | t2 = container_of(e, struct oz_timer, link)({ const typeof( ((struct oz_timer *)0)->link ) *__mptr = ( e); (struct oz_timer *)( (char *)__mptr - __builtin_offsetof( struct oz_timer,link) );}); |
648 | if (time_before(due_time, t2->due_time)(({ unsigned long __dummy; typeof(t2->due_time) __dummy2; ( void)(&__dummy == &__dummy2); 1; }) && ({ unsigned long __dummy; typeof(due_time) __dummy2; (void)(&__dummy == &__dummy2); 1; }) && ((long)(due_time) - (long )(t2->due_time) < 0))) { |
649 | if (t2 == g_cur_timer) { |
650 | g_cur_timer = NULL((void *)0); |
651 | restart_needed = 1; |
652 | } |
653 | break; |
654 | } |
655 | } |
656 | list_add_tail(&t->link, e); |
657 | } |
658 | if (g_timer_state == OZ_TIMER_IDLE0) |
659 | restart_needed = 1; |
660 | else if (g_timer_state == OZ_TIMER_IN_HANDLER2) |
661 | restart_needed = 0; |
662 | spin_unlock(&g_polling_lock); |
663 | if (restart_needed) |
664 | oz_protocol_timer_start(); |
665 | } |
666 | /*------------------------------------------------------------------------------ |
667 | * Context: softirq or process |
668 | */ |
669 | void oz_timer_delete(struct oz_pd *pd, int type) |
670 | { |
671 | struct list_head *chain = NULL((void *)0); |
672 | struct oz_timer *t; |
673 | struct oz_timer *n; |
674 | int restart_needed = 0; |
675 | int release = 0; |
676 | oz_event_log(OZ_EVT_TIMER_CTRL, 2, (u16)type, NULL, 0)do { if ((1<<(16)) & g_evt_mask) oz_event_log2(16, 2 , (u16)type, ((void *)0), 0); } while (0); |
677 | spin_lock(&g_polling_lock); |
678 | list_for_each_entry_safe(t, n, &g_timer_list, link)for (t = ({ const typeof( ((typeof(*t) *)0)->link ) *__mptr = ((&g_timer_list)->next); (typeof(*t) *)( (char *)__mptr - __builtin_offsetof(typeof(*t),link) );}), n = ({ const typeof ( ((typeof(*t) *)0)->link ) *__mptr = (t->link.next); ( typeof(*t) *)( (char *)__mptr - __builtin_offsetof(typeof(*t) ,link) );}); &t->link != (&g_timer_list); t = n, n = ({ const typeof( ((typeof(*n) *)0)->link ) *__mptr = (n ->link.next); (typeof(*n) *)( (char *)__mptr - __builtin_offsetof (typeof(*n),link) );})) { |
679 | if ((t->pd == pd) && ((type == 0) || (t->type == type))) { |
680 | if (g_cur_timer == t) { |
681 | restart_needed = 1; |
682 | g_cur_timer = NULL((void *)0); |
683 | del_timer(&g_timer); |
684 | } |
685 | list_del(&t->link); |
686 | release++; |
687 | if (g_timer_pool_count < OZ_MAX_TIMER_POOL_SIZE16) { |
688 | t->link.next = g_timer_pool; |
689 | g_timer_pool = &t->link; |
690 | g_timer_pool_count++; |
691 | } else { |
692 | t->link.next = chain; |
693 | chain = &t->link; |
694 | } |
695 | if (type) |
696 | break; |
697 | } |
698 | } |
699 | if (g_timer_state == OZ_TIMER_IN_HANDLER2) |
700 | restart_needed = 0; |
701 | else if (restart_needed) |
702 | g_timer_state = OZ_TIMER_IDLE0; |
703 | spin_unlock(&g_polling_lock); |
704 | if (restart_needed) |
705 | oz_protocol_timer_start(); |
706 | while (release--) |
707 | oz_pd_put(pd); |
708 | while (chain) { |
709 | t = container_of(chain, struct oz_timer, link)({ const typeof( ((struct oz_timer *)0)->link ) *__mptr = ( chain); (struct oz_timer *)( (char *)__mptr - __builtin_offsetof (struct oz_timer,link) );}); |
710 | chain = chain->next; |
711 | kfree(t); |
712 | } |
713 | } |
714 | /*------------------------------------------------------------------------------ |
715 | * Context: softirq or process |
716 | */ |
717 | void oz_pd_request_heartbeat(struct oz_pd *pd) |
718 | { |
719 | unsigned long now = jiffies; |
720 | unsigned long t; |
721 | spin_lock(&g_polling_lock); |
722 | if (pd->heartbeat_requested) { |
723 | spin_unlock(&g_polling_lock); |
724 | return; |
725 | } |
726 | if (pd->pulse_period_j) |
727 | t = ((now / pd->pulse_period_j) + 1) * pd->pulse_period_j; |
728 | else |
729 | t = now + 1; |
730 | pd->heartbeat_requested = 1; |
731 | spin_unlock(&g_polling_lock); |
732 | oz_timer_add(pd, OZ_TIMER_HEARTBEAT2, t, 0); |
733 | } |
734 | /*------------------------------------------------------------------------------ |
735 | * Context: softirq or process |
736 | */ |
737 | struct oz_pd *oz_pd_find(u8 *mac_addr) |
738 | { |
739 | struct oz_pd *pd; |
740 | struct list_head *e; |
741 | spin_lock_bh(&g_polling_lock); |
742 | list_for_each(e, &g_pd_list)for (e = (&g_pd_list)->next; e != (&g_pd_list); e = e->next) { |
743 | pd = container_of(e, struct oz_pd, link)({ const typeof( ((struct oz_pd *)0)->link ) *__mptr = (e) ; (struct oz_pd *)( (char *)__mptr - __builtin_offsetof(struct oz_pd,link) );}); |
744 | if (memcmp(pd->mac_addr, mac_addr, ETH_ALEN6) == 0) { |
745 | atomic_inc(&pd->ref_count); |
746 | spin_unlock_bh(&g_polling_lock); |
747 | return pd; |
748 | } |
749 | } |
750 | spin_unlock_bh(&g_polling_lock); |
751 | return NULL((void *)0); |
752 | } |
753 | /*------------------------------------------------------------------------------ |
754 | * Context: process |
755 | */ |
756 | void oz_app_enable(int app_id, int enable) |
757 | { |
758 | if (app_id <= OZ_APPID_MAX0x4) { |
759 | spin_lock_bh(&g_polling_lock); |
760 | if (enable) |
761 | g_apps |= (1<<app_id); |
762 | else |
763 | g_apps &= ~(1<<app_id); |
764 | spin_unlock_bh(&g_polling_lock); |
765 | } |
766 | } |
767 | /*------------------------------------------------------------------------------ |
768 | * Context: softirq |
769 | */ |
770 | static int oz_pkt_recv(struct sk_buff *skb, struct net_device *dev, |
771 | struct packet_type *pt, struct net_device *orig_dev) |
772 | { |
773 | oz_event_log(OZ_EVT_RX_FRAME, 0, 0, NULL, 0)do { if ((1<<(0)) & g_evt_mask) oz_event_log2(0, 0, 0, ((void *)0), 0); } while (0); |
774 | skb = skb_share_check(skb, GFP_ATOMIC((( gfp_t)0x20u))); |
775 | if (skb == NULL((void *)0)) |
776 | return 0; |
777 | spin_lock_bh(&g_rx_queue.lock); |
778 | if (g_processing_rx) { |
779 | /* We already hold the lock so use __ variant. |
780 | */ |
781 | __skb_queue_head(&g_rx_queue, skb); |
782 | spin_unlock_bh(&g_rx_queue.lock); |
783 | } else { |
784 | g_processing_rx = 1; |
785 | do { |
786 | |
787 | spin_unlock_bh(&g_rx_queue.lock); |
788 | oz_rx_frame(skb); |
789 | spin_lock_bh(&g_rx_queue.lock); |
790 | if (skb_queue_empty(&g_rx_queue)) { |
791 | g_processing_rx = 0; |
792 | spin_unlock_bh(&g_rx_queue.lock); |
793 | break; |
794 | } |
795 | /* We already hold the lock so use __ variant. |
796 | */ |
797 | skb = __skb_dequeue(&g_rx_queue); |
798 | } while (1); |
799 | } |
800 | return 0; |
801 | } |
802 | /*------------------------------------------------------------------------------ |
803 | * Context: process |
804 | */ |
805 | void oz_binding_add(char *net_dev) |
806 | { |
807 | struct oz_binding *binding; |
808 | |
809 | binding = kmalloc(sizeof(struct oz_binding), GFP_KERNEL((( gfp_t)0x10u) | (( gfp_t)0x40u) | (( gfp_t)0x80u))); |
810 | if (binding) { |
811 | binding->ptype.type = __constant_htons(OZ_ETHERTYPE)(( __be16)((__u16)( (((__u16)((0x892e)) & (__u16)0x00ffU) << 8) | (((__u16)((0x892e)) & (__u16)0xff00U) >> 8)))); |
812 | binding->ptype.func = oz_pkt_recv; |
813 | memcpy(binding->name, net_dev, OZ_MAX_BINDING_LEN)({ size_t __len = (32); void *__ret; if (__builtin_constant_p (32) && __len >= 64) __ret = __memcpy((binding-> name), (net_dev), __len); else __ret = __builtin_memcpy((binding ->name), (net_dev), __len); __ret; }); |
814 | if (net_dev && *net_dev) { |
815 | oz_trace("Adding binding: %s\n", net_dev); |
816 | binding->ptype.dev = |
817 | dev_get_by_name(&init_net, net_dev); |
818 | if (binding->ptype.dev == NULL((void *)0)) { |
819 | oz_trace("Netdev %s not found\n", net_dev); |
820 | kfree(binding); |
821 | binding = NULL((void *)0); |
822 | } |
823 | } else { |
824 | oz_trace("Binding to all netcards\n"); |
825 | binding->ptype.dev = NULL((void *)0); |
826 | } |
827 | if (binding) { |
828 | dev_add_pack(&binding->ptype); |
829 | spin_lock_bh(&g_binding_lock); |
830 | binding->next = g_binding; |
831 | g_binding = binding; |
832 | spin_unlock_bh(&g_binding_lock); |
833 | } |
834 | } |
835 | } |
836 | /*------------------------------------------------------------------------------ |
837 | * Context: process |
838 | */ |
839 | static int compare_binding_name(char *s1, char *s2) |
840 | { |
841 | int i; |
842 | for (i = 0; i < OZ_MAX_BINDING_LEN32; i++) { |
843 | if (*s1 != *s2) |
844 | return 0; |
845 | if (!*s1++) |
846 | return 1; |
847 | s2++; |
848 | } |
849 | return 1; |
850 | } |
851 | /*------------------------------------------------------------------------------ |
852 | * Context: process |
853 | */ |
854 | static void pd_stop_all_for_device(struct net_device *net_dev) |
855 | { |
856 | struct list_head h; |
857 | struct oz_pd *pd; |
858 | struct oz_pd *n; |
859 | INIT_LIST_HEAD(&h); |
860 | spin_lock_bh(&g_polling_lock); |
861 | list_for_each_entry_safe(pd, n, &g_pd_list, link)for (pd = ({ const typeof( ((typeof(*pd) *)0)->link ) *__mptr = ((&g_pd_list)->next); (typeof(*pd) *)( (char *)__mptr - __builtin_offsetof(typeof(*pd),link) );}), n = ({ const typeof ( ((typeof(*pd) *)0)->link ) *__mptr = (pd->link.next); (typeof(*pd) *)( (char *)__mptr - __builtin_offsetof(typeof( *pd),link) );}); &pd->link != (&g_pd_list); pd = n , n = ({ const typeof( ((typeof(*n) *)0)->link ) *__mptr = (n->link.next); (typeof(*n) *)( (char *)__mptr - __builtin_offsetof (typeof(*n),link) );})) { |
862 | if (pd->net_dev == net_dev) { |
863 | list_move(&pd->link, &h); |
864 | oz_pd_get(pd); |
865 | } |
866 | } |
867 | spin_unlock_bh(&g_polling_lock); |
868 | while (!list_empty(&h)) { |
869 | pd = list_first_entry(&h, struct oz_pd, link)({ const typeof( ((struct oz_pd *)0)->link ) *__mptr = ((& h)->next); (struct oz_pd *)( (char *)__mptr - __builtin_offsetof (struct oz_pd,link) );}); |
870 | oz_pd_stop(pd); |
871 | oz_pd_put(pd); |
872 | } |
873 | } |
874 | /*------------------------------------------------------------------------------ |
875 | * Context: process |
876 | */ |
877 | void oz_binding_remove(char *net_dev) |
878 | { |
879 | struct oz_binding *binding = NULL((void *)0); |
880 | struct oz_binding **link; |
881 | oz_trace("Removing binding: %s\n", net_dev); |
882 | spin_lock_bh(&g_binding_lock); |
883 | binding = g_binding; |
884 | link = &g_binding; |
885 | while (binding) { |
886 | if (compare_binding_name(binding->name, net_dev)) { |
887 | oz_trace("Binding '%s' found\n", net_dev); |
888 | *link = binding->next; |
889 | break; |
890 | } else { |
891 | link = &binding; |
892 | binding = binding->next; |
893 | } |
894 | } |
895 | spin_unlock_bh(&g_binding_lock); |
896 | if (binding) { |
897 | dev_remove_pack(&binding->ptype); |
898 | if (binding->ptype.dev) { |
899 | dev_put(binding->ptype.dev); |
900 | pd_stop_all_for_device(binding->ptype.dev); |
901 | } |
902 | kfree(binding); |
903 | } |
904 | } |
905 | /*------------------------------------------------------------------------------ |
906 | * Context: process |
907 | */ |
908 | static char *oz_get_next_device_name(char *s, char *dname, int max_size) |
909 | { |
910 | while (*s == ',') |
911 | s++; |
912 | while (*s && (*s != ',') && max_size > 1) { |
913 | *dname++ = *s++; |
914 | max_size--; |
915 | } |
916 | *dname = 0; |
917 | return s; |
918 | } |
919 | /*------------------------------------------------------------------------------ |
920 | * Context: process |
921 | */ |
922 | int oz_protocol_init(char *devs) |
923 | { |
924 | skb_queue_head_init(&g_rx_queue); |
925 | if (devs && (devs[0] == '*')) { |
926 | oz_binding_add(NULL((void *)0)); |
927 | } else { |
928 | char d[32]; |
929 | while (*devs) { |
Dereference of null pointer (loaded from variable 'devs') | |
930 | devs = oz_get_next_device_name(devs, d, sizeof(d)); |
931 | if (d[0]) |
932 | oz_binding_add(d); |
933 | } |
934 | } |
935 | init_timer(&g_timer)init_timer_key(((&g_timer)), (0), ((void *)0), ((void *)0 )); |
936 | return 0; |
937 | } |
938 | /*------------------------------------------------------------------------------ |
939 | * Context: process |
940 | */ |
941 | int oz_get_pd_list(struct oz_mac_addr *addr, int max_count) |
942 | { |
943 | struct oz_pd *pd; |
944 | struct list_head *e; |
945 | int count = 0; |
946 | spin_lock_bh(&g_polling_lock); |
947 | list_for_each(e, &g_pd_list)for (e = (&g_pd_list)->next; e != (&g_pd_list); e = e->next) { |
948 | if (count >= max_count) |
949 | break; |
950 | pd = container_of(e, struct oz_pd, link)({ const typeof( ((struct oz_pd *)0)->link ) *__mptr = (e) ; (struct oz_pd *)( (char *)__mptr - __builtin_offsetof(struct oz_pd,link) );}); |
951 | memcpy(&addr[count++], pd->mac_addr, ETH_ALEN)({ size_t __len = (6); void *__ret; if (__builtin_constant_p( 6) && __len >= 64) __ret = __memcpy((&addr[count ++]), (pd->mac_addr), __len); else __ret = __builtin_memcpy ((&addr[count++]), (pd->mac_addr), __len); __ret; }); |
952 | } |
953 | spin_unlock_bh(&g_polling_lock); |
954 | return count; |
955 | } |
956 | /*------------------------------------------------------------------------------ |
957 | */ |
958 | void oz_polling_lock_bh(void) |
959 | { |
960 | spin_lock_bh(&g_polling_lock); |
961 | } |
962 | /*------------------------------------------------------------------------------ |
963 | */ |
964 | void oz_polling_unlock_bh(void) |
965 | { |
966 | spin_unlock_bh(&g_polling_lock); |
967 | } |