Merge tag 'dt-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
[cascardo/linux.git] / drivers / staging / ozwpan / ozproto.c
1 /* -----------------------------------------------------------------------------
2  * Copyright (c) 2011 Ozmo Inc
3  * Released under the GNU General Public License Version 2 (GPLv2).
4  * -----------------------------------------------------------------------------
5  */
6
7 #include <linux/module.h>
8 #include <linux/timer.h>
9 #include <linux/sched.h>
10 #include <linux/netdevice.h>
11 #include <linux/errno.h>
12 #include <linux/ieee80211.h>
13 #include "ozdbg.h"
14 #include "ozprotocol.h"
15 #include "ozeltbuf.h"
16 #include "ozpd.h"
17 #include "ozproto.h"
18 #include "ozusbsvc.h"
19
20 #include "ozappif.h"
21 #include <asm/unaligned.h>
22 #include <linux/uaccess.h>
23 #include <net/psnap.h>
24
25 #define OZ_CF_CONN_SUCCESS      1
26 #define OZ_CF_CONN_FAILURE      2
27
28 #define OZ_DO_STOP              1
29 #define OZ_DO_SLEEP             2
30
31 #define OZ_MAX_TIMER_POOL_SIZE  16
32
33 struct oz_binding {
34         struct packet_type ptype;
35         char name[OZ_MAX_BINDING_LEN];
36         struct list_head link;
37 };
38
39 /*
40  * Static external variables.
41  */
42 static DEFINE_SPINLOCK(g_polling_lock);
43 static LIST_HEAD(g_pd_list);
44 static LIST_HEAD(g_binding);
45 static DEFINE_SPINLOCK(g_binding_lock);
46 static struct sk_buff_head g_rx_queue;
47 static u8 g_session_id;
48 static u16 g_apps = 0x1;
49 static int g_processing_rx;
50
51 /*
52  * Context: softirq-serialized
53  */
54 static u8 oz_get_new_session_id(u8 exclude)
55 {
56         if (++g_session_id == 0)
57                 g_session_id = 1;
58         if (g_session_id == exclude) {
59                 if (++g_session_id == 0)
60                         g_session_id = 1;
61         }
62         return g_session_id;
63 }
64
65 /*
66  * Context: softirq-serialized
67  */
68 static void oz_send_conn_rsp(struct oz_pd *pd, u8 status)
69 {
70         struct sk_buff *skb;
71         struct net_device *dev = pd->net_dev;
72         struct oz_hdr *oz_hdr;
73         struct oz_elt *elt;
74         struct oz_elt_connect_rsp *body;
75
76         int sz = sizeof(struct oz_hdr) + sizeof(struct oz_elt) +
77                         sizeof(struct oz_elt_connect_rsp);
78         skb = alloc_skb(sz + OZ_ALLOCATED_SPACE(dev), GFP_ATOMIC);
79         if (skb == NULL)
80                 return;
81         skb_reserve(skb, LL_RESERVED_SPACE(dev));
82         skb_reset_network_header(skb);
83         oz_hdr = (struct oz_hdr *)skb_put(skb, sz);
84         elt = (struct oz_elt *)(oz_hdr+1);
85         body = (struct oz_elt_connect_rsp *)(elt+1);
86         skb->dev = dev;
87         skb->protocol = htons(OZ_ETHERTYPE);
88         /* Fill in device header */
89         if (dev_hard_header(skb, dev, OZ_ETHERTYPE, pd->mac_addr,
90                         dev->dev_addr, skb->len) < 0) {
91                 kfree_skb(skb);
92                 return;
93         }
94         oz_hdr->control = (OZ_PROTOCOL_VERSION<<OZ_VERSION_SHIFT);
95         oz_hdr->last_pkt_num = 0;
96         put_unaligned(0, &oz_hdr->pkt_num);
97         elt->type = OZ_ELT_CONNECT_RSP;
98         elt->length = sizeof(struct oz_elt_connect_rsp);
99         memset(body, 0, sizeof(struct oz_elt_connect_rsp));
100         body->status = status;
101         if (status == 0) {
102                 body->mode = pd->mode;
103                 body->session_id = pd->session_id;
104                 put_unaligned(cpu_to_le16(pd->total_apps), &body->apps);
105         }
106         oz_dbg(ON, "TX: OZ_ELT_CONNECT_RSP %d", status);
107         dev_queue_xmit(skb);
108         return;
109 }
110
111 /*
112  * Context: softirq-serialized
113  */
114 static void pd_set_keepalive(struct oz_pd *pd, u8 kalive)
115 {
116         unsigned long keep_alive = kalive & OZ_KALIVE_VALUE_MASK;
117
118         switch (kalive & OZ_KALIVE_TYPE_MASK) {
119         case OZ_KALIVE_SPECIAL:
120                 pd->keep_alive = keep_alive * 1000*60*60*24*20;
121                 break;
122         case OZ_KALIVE_SECS:
123                 pd->keep_alive = keep_alive*1000;
124                 break;
125         case OZ_KALIVE_MINS:
126                 pd->keep_alive = keep_alive*1000*60;
127                 break;
128         case OZ_KALIVE_HOURS:
129                 pd->keep_alive = keep_alive*1000*60*60;
130                 break;
131         default:
132                 pd->keep_alive = 0;
133         }
134         oz_dbg(ON, "Keepalive = %lu mSec\n", pd->keep_alive);
135 }
136
137 /*
138  * Context: softirq-serialized
139  */
140 static void pd_set_presleep(struct oz_pd *pd, u8 presleep, u8 start_timer)
141 {
142         if (presleep)
143                 pd->presleep = presleep*100;
144         else
145                 pd->presleep = OZ_PRESLEEP_TOUT;
146         if (start_timer) {
147                 spin_unlock(&g_polling_lock);
148                 oz_timer_add(pd, OZ_TIMER_TOUT, pd->presleep);
149                 spin_lock(&g_polling_lock);
150         }
151         oz_dbg(ON, "Presleep time = %lu mSec\n", pd->presleep);
152 }
153
154 /*
155  * Context: softirq-serialized
156  */
157 static struct oz_pd *oz_connect_req(struct oz_pd *cur_pd, struct oz_elt *elt,
158                         const u8 *pd_addr, struct net_device *net_dev)
159 {
160         struct oz_pd *pd;
161         struct oz_elt_connect_req *body =
162                         (struct oz_elt_connect_req *)(elt+1);
163         u8 rsp_status = OZ_STATUS_SUCCESS;
164         u8 stop_needed = 0;
165         u16 new_apps = g_apps;
166         struct net_device *old_net_dev = NULL;
167         struct oz_pd *free_pd = NULL;
168
169         if (cur_pd) {
170                 pd = cur_pd;
171                 spin_lock_bh(&g_polling_lock);
172         } else {
173                 struct oz_pd *pd2 = NULL;
174                 struct list_head *e;
175                 pd = oz_pd_alloc(pd_addr);
176                 if (pd == NULL)
177                         return NULL;
178                 getnstimeofday(&pd->last_rx_timestamp);
179                 spin_lock_bh(&g_polling_lock);
180                 list_for_each(e, &g_pd_list) {
181                         pd2 = container_of(e, struct oz_pd, link);
182                         if (memcmp(pd2->mac_addr, pd_addr, ETH_ALEN) == 0) {
183                                 free_pd = pd;
184                                 pd = pd2;
185                                 break;
186                         }
187                 }
188                 if (pd != pd2)
189                         list_add_tail(&pd->link, &g_pd_list);
190         }
191         if (pd == NULL) {
192                 spin_unlock_bh(&g_polling_lock);
193                 return NULL;
194         }
195         if (pd->net_dev != net_dev) {
196                 old_net_dev = pd->net_dev;
197                 dev_hold(net_dev);
198                 pd->net_dev = net_dev;
199         }
200         oz_dbg(ON, "Host vendor: %d\n", body->host_vendor);
201         pd->max_tx_size = OZ_MAX_TX_SIZE;
202         pd->mode = body->mode;
203         pd->pd_info = body->pd_info;
204         if (pd->mode & OZ_F_ISOC_NO_ELTS) {
205                 pd->ms_per_isoc = body->ms_per_isoc;
206                 if (!pd->ms_per_isoc)
207                         pd->ms_per_isoc = 4;
208
209                 switch (body->ms_isoc_latency & OZ_LATENCY_MASK) {
210                 case OZ_ONE_MS_LATENCY:
211                         pd->isoc_latency = (body->ms_isoc_latency &
212                                         ~OZ_LATENCY_MASK) / pd->ms_per_isoc;
213                         break;
214                 case OZ_TEN_MS_LATENCY:
215                         pd->isoc_latency = ((body->ms_isoc_latency &
216                                 ~OZ_LATENCY_MASK) * 10) / pd->ms_per_isoc;
217                         break;
218                 default:
219                         pd->isoc_latency = OZ_MAX_TX_QUEUE_ISOC;
220                 }
221         }
222         if (body->max_len_div16)
223                 pd->max_tx_size = ((u16)body->max_len_div16)<<4;
224         oz_dbg(ON, "Max frame:%u Ms per isoc:%u\n",
225                pd->max_tx_size, pd->ms_per_isoc);
226         pd->max_stream_buffering = 3*1024;
227         pd->pulse_period = OZ_QUANTUM;
228         pd_set_presleep(pd, body->presleep, 0);
229         pd_set_keepalive(pd, body->keep_alive);
230
231         new_apps &= le16_to_cpu(get_unaligned(&body->apps));
232         if ((new_apps & 0x1) && (body->session_id)) {
233                 if (pd->session_id) {
234                         if (pd->session_id != body->session_id) {
235                                 rsp_status = OZ_STATUS_SESSION_MISMATCH;
236                                 goto done;
237                         }
238                 } else {
239                         new_apps &= ~0x1;  /* Resume not permitted */
240                         pd->session_id =
241                                 oz_get_new_session_id(body->session_id);
242                 }
243         } else {
244                 if (pd->session_id && !body->session_id) {
245                         rsp_status = OZ_STATUS_SESSION_TEARDOWN;
246                         stop_needed = 1;
247                 } else {
248                         new_apps &= ~0x1;  /* Resume not permitted */
249                         pd->session_id =
250                                 oz_get_new_session_id(body->session_id);
251                 }
252         }
253 done:
254         if (rsp_status == OZ_STATUS_SUCCESS) {
255                 u16 start_apps = new_apps & ~pd->total_apps & ~0x1;
256                 u16 stop_apps = pd->total_apps & ~new_apps & ~0x1;
257                 u16 resume_apps = new_apps & pd->paused_apps  & ~0x1;
258                 spin_unlock_bh(&g_polling_lock);
259                 oz_pd_set_state(pd, OZ_PD_S_CONNECTED);
260                 oz_dbg(ON, "new_apps=0x%x total_apps=0x%x paused_apps=0x%x\n",
261                        new_apps, pd->total_apps, pd->paused_apps);
262                 if (start_apps) {
263                         if (oz_services_start(pd, start_apps, 0))
264                                 rsp_status = OZ_STATUS_TOO_MANY_PDS;
265                 }
266                 if (resume_apps)
267                         if (oz_services_start(pd, resume_apps, 1))
268                                 rsp_status = OZ_STATUS_TOO_MANY_PDS;
269                 if (stop_apps)
270                         oz_services_stop(pd, stop_apps, 0);
271                 oz_pd_request_heartbeat(pd);
272         } else {
273                 spin_unlock_bh(&g_polling_lock);
274         }
275         oz_send_conn_rsp(pd, rsp_status);
276         if (rsp_status != OZ_STATUS_SUCCESS) {
277                 if (stop_needed)
278                         oz_pd_stop(pd);
279                 oz_pd_put(pd);
280                 pd = NULL;
281         }
282         if (old_net_dev)
283                 dev_put(old_net_dev);
284         if (free_pd)
285                 oz_pd_destroy(free_pd);
286         return pd;
287 }
288
289 /*
290  * Context: softirq-serialized
291  */
292 static void oz_add_farewell(struct oz_pd *pd, u8 ep_num, u8 index,
293                         const u8 *report, u8 len)
294 {
295         struct oz_farewell *f;
296         struct oz_farewell *f2;
297         int found = 0;
298
299         f = kmalloc(sizeof(struct oz_farewell) + len, GFP_ATOMIC);
300         if (!f)
301                 return;
302         f->ep_num = ep_num;
303         f->index = index;
304         f->len = len;
305         memcpy(f->report, report, len);
306         oz_dbg(ON, "RX: Adding farewell report\n");
307         spin_lock(&g_polling_lock);
308         list_for_each_entry(f2, &pd->farewell_list, link) {
309                 if ((f2->ep_num == ep_num) && (f2->index == index)) {
310                         found = 1;
311                         list_del(&f2->link);
312                         break;
313                 }
314         }
315         list_add_tail(&f->link, &pd->farewell_list);
316         spin_unlock(&g_polling_lock);
317         if (found)
318                 kfree(f2);
319 }
320
321 /*
322  * Context: softirq-serialized
323  */
324 static void oz_rx_frame(struct sk_buff *skb)
325 {
326         u8 *mac_hdr;
327         u8 *src_addr;
328         struct oz_elt *elt;
329         int length;
330         struct oz_pd *pd = NULL;
331         struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb);
332         struct timespec current_time;
333         int dup = 0;
334         u32 pkt_num;
335
336         oz_dbg(RX_FRAMES, "RX frame PN=0x%x LPN=0x%x control=0x%x\n",
337                oz_hdr->pkt_num, oz_hdr->last_pkt_num, oz_hdr->control);
338         mac_hdr = skb_mac_header(skb);
339         src_addr = &mac_hdr[ETH_ALEN];
340         length = skb->len;
341
342         /* Check the version field */
343         if (oz_get_prot_ver(oz_hdr->control) != OZ_PROTOCOL_VERSION) {
344                 oz_dbg(ON, "Incorrect protocol version: %d\n",
345                        oz_get_prot_ver(oz_hdr->control));
346                 goto done;
347         }
348
349         pkt_num = le32_to_cpu(get_unaligned(&oz_hdr->pkt_num));
350
351         pd = oz_pd_find(src_addr);
352         if (pd) {
353                 if (!(pd->state & OZ_PD_S_CONNECTED))
354                         oz_pd_set_state(pd, OZ_PD_S_CONNECTED);
355                 getnstimeofday(&current_time);
356                 if ((current_time.tv_sec != pd->last_rx_timestamp.tv_sec) ||
357                         (pd->presleep < MSEC_PER_SEC))  {
358                         oz_timer_add(pd, OZ_TIMER_TOUT, pd->presleep);
359                         pd->last_rx_timestamp = current_time;
360                 }
361                 if (pkt_num != pd->last_rx_pkt_num) {
362                         pd->last_rx_pkt_num = pkt_num;
363                 } else {
364                         dup = 1;
365                         oz_dbg(ON, "Duplicate frame\n");
366                 }
367         }
368
369         if (pd && !dup && ((pd->mode & OZ_MODE_MASK) == OZ_MODE_TRIGGERED)) {
370                 oz_dbg(RX_FRAMES, "Received TRIGGER Frame\n");
371                 pd->last_sent_frame = &pd->tx_queue;
372                 if (oz_hdr->control & OZ_F_ACK) {
373                         /* Retire completed frames */
374                         oz_retire_tx_frames(pd, oz_hdr->last_pkt_num);
375                 }
376                 if ((oz_hdr->control & OZ_F_ACK_REQUESTED) &&
377                                 (pd->state == OZ_PD_S_CONNECTED)) {
378                         int backlog = pd->nb_queued_frames;
379                         pd->trigger_pkt_num = pkt_num;
380                         /* Send queued frames */
381                         oz_send_queued_frames(pd, backlog);
382                 }
383         }
384
385         length -= sizeof(struct oz_hdr);
386         elt = (struct oz_elt *)((u8 *)oz_hdr + sizeof(struct oz_hdr));
387
388         while (length >= sizeof(struct oz_elt)) {
389                 length -= sizeof(struct oz_elt) + elt->length;
390                 if (length < 0)
391                         break;
392                 switch (elt->type) {
393                 case OZ_ELT_CONNECT_REQ:
394                         oz_dbg(ON, "RX: OZ_ELT_CONNECT_REQ\n");
395                         pd = oz_connect_req(pd, elt, src_addr, skb->dev);
396                         break;
397                 case OZ_ELT_DISCONNECT:
398                         oz_dbg(ON, "RX: OZ_ELT_DISCONNECT\n");
399                         if (pd)
400                                 oz_pd_sleep(pd);
401                         break;
402                 case OZ_ELT_UPDATE_PARAM_REQ: {
403                                 struct oz_elt_update_param *body =
404                                         (struct oz_elt_update_param *)(elt + 1);
405                                 oz_dbg(ON, "RX: OZ_ELT_UPDATE_PARAM_REQ\n");
406                                 if (pd && (pd->state & OZ_PD_S_CONNECTED)) {
407                                         spin_lock(&g_polling_lock);
408                                         pd_set_keepalive(pd, body->keepalive);
409                                         pd_set_presleep(pd, body->presleep, 1);
410                                         spin_unlock(&g_polling_lock);
411                                 }
412                         }
413                         break;
414                 case OZ_ELT_FAREWELL_REQ: {
415                                 struct oz_elt_farewell *body =
416                                         (struct oz_elt_farewell *)(elt + 1);
417                                 oz_dbg(ON, "RX: OZ_ELT_FAREWELL_REQ\n");
418                                 oz_add_farewell(pd, body->ep_num,
419                                         body->index, body->report,
420                                         elt->length + 1 - sizeof(*body));
421                         }
422                         break;
423                 case OZ_ELT_APP_DATA:
424                         if (pd && (pd->state & OZ_PD_S_CONNECTED)) {
425                                 struct oz_app_hdr *app_hdr =
426                                         (struct oz_app_hdr *)(elt+1);
427                                 if (dup)
428                                         break;
429                                 oz_handle_app_elt(pd, app_hdr->app_id, elt);
430                         }
431                         break;
432                 default:
433                         oz_dbg(ON, "RX: Unknown elt %02x\n", elt->type);
434                 }
435                 elt = oz_next_elt(elt);
436         }
437 done:
438         if (pd)
439                 oz_pd_put(pd);
440         consume_skb(skb);
441 }
442
443 /*
444  * Context: process
445  */
446 void oz_protocol_term(void)
447 {
448         struct oz_binding *b, *t;
449
450         /* Walk the list of bindings and remove each one.
451          */
452         spin_lock_bh(&g_binding_lock);
453         list_for_each_entry_safe(b, t, &g_binding, link) {
454                 list_del(&b->link);
455                 spin_unlock_bh(&g_binding_lock);
456                 dev_remove_pack(&b->ptype);
457                 if (b->ptype.dev)
458                         dev_put(b->ptype.dev);
459                 kfree(b);
460                 spin_lock_bh(&g_binding_lock);
461         }
462         spin_unlock_bh(&g_binding_lock);
463         /* Walk the list of PDs and stop each one. This causes the PD to be
464          * removed from the list so we can just pull each one from the head
465          * of the list.
466          */
467         spin_lock_bh(&g_polling_lock);
468         while (!list_empty(&g_pd_list)) {
469                 struct oz_pd *pd =
470                         list_first_entry(&g_pd_list, struct oz_pd, link);
471                 oz_pd_get(pd);
472                 spin_unlock_bh(&g_polling_lock);
473                 oz_pd_stop(pd);
474                 oz_pd_put(pd);
475                 spin_lock_bh(&g_polling_lock);
476         }
477         spin_unlock_bh(&g_polling_lock);
478         oz_dbg(ON, "Protocol stopped\n");
479 }
480
481 /*
482  * Context: softirq
483  */
484 void oz_pd_heartbeat_handler(unsigned long data)
485 {
486         struct oz_pd *pd = (struct oz_pd *)data;
487         u16 apps = 0;
488
489         spin_lock_bh(&g_polling_lock);
490         if (pd->state & OZ_PD_S_CONNECTED)
491                 apps = pd->total_apps;
492         spin_unlock_bh(&g_polling_lock);
493         if (apps)
494                 oz_pd_heartbeat(pd, apps);
495         oz_pd_put(pd);
496 }
497
498 /*
499  * Context: softirq
500  */
501 void oz_pd_timeout_handler(unsigned long data)
502 {
503         int type;
504         struct oz_pd *pd = (struct oz_pd *)data;
505
506         spin_lock_bh(&g_polling_lock);
507         type = pd->timeout_type;
508         spin_unlock_bh(&g_polling_lock);
509         switch (type) {
510         case OZ_TIMER_TOUT:
511                 oz_pd_sleep(pd);
512                 break;
513         case OZ_TIMER_STOP:
514                 oz_pd_stop(pd);
515                 break;
516         }
517         oz_pd_put(pd);
518 }
519
520 /*
521  * Context: Interrupt
522  */
523 enum hrtimer_restart oz_pd_heartbeat_event(struct hrtimer *timer)
524 {
525         struct oz_pd *pd;
526
527         pd = container_of(timer, struct oz_pd, heartbeat);
528         hrtimer_forward_now(timer, ktime_set(pd->pulse_period /
529         MSEC_PER_SEC, (pd->pulse_period % MSEC_PER_SEC) * NSEC_PER_MSEC));
530         oz_pd_get(pd);
531         tasklet_schedule(&pd->heartbeat_tasklet);
532         return HRTIMER_RESTART;
533 }
534
535 /*
536  * Context: Interrupt
537  */
538 enum hrtimer_restart oz_pd_timeout_event(struct hrtimer *timer)
539 {
540         struct oz_pd *pd;
541
542         pd = container_of(timer, struct oz_pd, timeout);
543         oz_pd_get(pd);
544         tasklet_schedule(&pd->timeout_tasklet);
545         return HRTIMER_NORESTART;
546 }
547
548 /*
549  * Context: softirq or process
550  */
551 void oz_timer_add(struct oz_pd *pd, int type, unsigned long due_time)
552 {
553         spin_lock_bh(&g_polling_lock);
554         switch (type) {
555         case OZ_TIMER_TOUT:
556         case OZ_TIMER_STOP:
557                 if (hrtimer_active(&pd->timeout)) {
558                         hrtimer_set_expires(&pd->timeout, ktime_set(due_time /
559                         MSEC_PER_SEC, (due_time % MSEC_PER_SEC) *
560                                                         NSEC_PER_MSEC));
561                         hrtimer_start_expires(&pd->timeout, HRTIMER_MODE_REL);
562                 } else {
563                         hrtimer_start(&pd->timeout, ktime_set(due_time /
564                         MSEC_PER_SEC, (due_time % MSEC_PER_SEC) *
565                                         NSEC_PER_MSEC), HRTIMER_MODE_REL);
566                 }
567                 pd->timeout_type = type;
568                 break;
569         case OZ_TIMER_HEARTBEAT:
570                 if (!hrtimer_active(&pd->heartbeat))
571                         hrtimer_start(&pd->heartbeat, ktime_set(due_time /
572                         MSEC_PER_SEC, (due_time % MSEC_PER_SEC) *
573                                         NSEC_PER_MSEC), HRTIMER_MODE_REL);
574                 break;
575         }
576         spin_unlock_bh(&g_polling_lock);
577 }
578
579 /*
580  * Context: softirq or process
581  */
582 void oz_pd_request_heartbeat(struct oz_pd *pd)
583 {
584         oz_timer_add(pd, OZ_TIMER_HEARTBEAT, pd->pulse_period > 0 ?
585                                         pd->pulse_period : OZ_QUANTUM);
586 }
587
588 /*
589  * Context: softirq or process
590  */
591 struct oz_pd *oz_pd_find(const u8 *mac_addr)
592 {
593         struct oz_pd *pd;
594         struct list_head *e;
595
596         spin_lock_bh(&g_polling_lock);
597         list_for_each(e, &g_pd_list) {
598                 pd = container_of(e, struct oz_pd, link);
599                 if (memcmp(pd->mac_addr, mac_addr, ETH_ALEN) == 0) {
600                         atomic_inc(&pd->ref_count);
601                         spin_unlock_bh(&g_polling_lock);
602                         return pd;
603                 }
604         }
605         spin_unlock_bh(&g_polling_lock);
606         return NULL;
607 }
608
609 /*
610  * Context: process
611  */
612 void oz_app_enable(int app_id, int enable)
613 {
614         if (app_id <= OZ_APPID_MAX) {
615                 spin_lock_bh(&g_polling_lock);
616                 if (enable)
617                         g_apps |= (1<<app_id);
618                 else
619                         g_apps &= ~(1<<app_id);
620                 spin_unlock_bh(&g_polling_lock);
621         }
622 }
623
624 /*
625  * Context: softirq
626  */
627 static int oz_pkt_recv(struct sk_buff *skb, struct net_device *dev,
628                 struct packet_type *pt, struct net_device *orig_dev)
629 {
630         skb = skb_share_check(skb, GFP_ATOMIC);
631         if (skb == NULL)
632                 return 0;
633         spin_lock_bh(&g_rx_queue.lock);
634         if (g_processing_rx) {
635                 /* We already hold the lock so use __ variant.
636                  */
637                 __skb_queue_head(&g_rx_queue, skb);
638                 spin_unlock_bh(&g_rx_queue.lock);
639         } else {
640                 g_processing_rx = 1;
641                 do {
642
643                         spin_unlock_bh(&g_rx_queue.lock);
644                         oz_rx_frame(skb);
645                         spin_lock_bh(&g_rx_queue.lock);
646                         if (skb_queue_empty(&g_rx_queue)) {
647                                 g_processing_rx = 0;
648                                 spin_unlock_bh(&g_rx_queue.lock);
649                                 break;
650                         }
651                         /* We already hold the lock so use __ variant.
652                          */
653                         skb = __skb_dequeue(&g_rx_queue);
654                 } while (1);
655         }
656         return 0;
657 }
658
659 /*
660  * Context: process
661  */
662 void oz_binding_add(const char *net_dev)
663 {
664         struct oz_binding *binding;
665
666         binding = kmalloc(sizeof(struct oz_binding), GFP_KERNEL);
667         if (binding) {
668                 binding->ptype.type = __constant_htons(OZ_ETHERTYPE);
669                 binding->ptype.func = oz_pkt_recv;
670                 memcpy(binding->name, net_dev, OZ_MAX_BINDING_LEN);
671                 if (net_dev && *net_dev) {
672                         oz_dbg(ON, "Adding binding: %s\n", net_dev);
673                         binding->ptype.dev =
674                                 dev_get_by_name(&init_net, net_dev);
675                         if (binding->ptype.dev == NULL) {
676                                 oz_dbg(ON, "Netdev %s not found\n", net_dev);
677                                 kfree(binding);
678                                 binding = NULL;
679                         }
680                 } else {
681                         oz_dbg(ON, "Binding to all netcards\n");
682                         binding->ptype.dev = NULL;
683                 }
684                 if (binding) {
685                         dev_add_pack(&binding->ptype);
686                         spin_lock_bh(&g_binding_lock);
687                         list_add_tail(&binding->link, &g_binding);
688                         spin_unlock_bh(&g_binding_lock);
689                 }
690         }
691 }
692
693 /*
694  * Context: process
695  */
696 static void pd_stop_all_for_device(struct net_device *net_dev)
697 {
698         struct list_head h;
699         struct oz_pd *pd;
700         struct oz_pd *n;
701
702         INIT_LIST_HEAD(&h);
703         spin_lock_bh(&g_polling_lock);
704         list_for_each_entry_safe(pd, n, &g_pd_list, link) {
705                 if (pd->net_dev == net_dev) {
706                         list_move(&pd->link, &h);
707                         oz_pd_get(pd);
708                 }
709         }
710         spin_unlock_bh(&g_polling_lock);
711         while (!list_empty(&h)) {
712                 pd = list_first_entry(&h, struct oz_pd, link);
713                 oz_pd_stop(pd);
714                 oz_pd_put(pd);
715         }
716 }
717
718 /*
719  * Context: process
720  */
721 void oz_binding_remove(const char *net_dev)
722 {
723         struct oz_binding *binding;
724         int found = 0;
725
726         oz_dbg(ON, "Removing binding: %s\n", net_dev);
727         spin_lock_bh(&g_binding_lock);
728         list_for_each_entry(binding, &g_binding, link) {
729                 if (strncmp(binding->name, net_dev, OZ_MAX_BINDING_LEN) == 0) {
730                         oz_dbg(ON, "Binding '%s' found\n", net_dev);
731                         found = 1;
732                         break;
733                 }
734         }
735         spin_unlock_bh(&g_binding_lock);
736         if (found) {
737                 dev_remove_pack(&binding->ptype);
738                 if (binding->ptype.dev) {
739                         dev_put(binding->ptype.dev);
740                         pd_stop_all_for_device(binding->ptype.dev);
741                 }
742                 list_del(&binding->link);
743                 kfree(binding);
744         }
745 }
746
747 /*
748  * Context: process
749  */
750 static char *oz_get_next_device_name(char *s, char *dname, int max_size)
751 {
752         while (*s == ',')
753                 s++;
754         while (*s && (*s != ',') && max_size > 1) {
755                 *dname++ = *s++;
756                 max_size--;
757         }
758         *dname = 0;
759         return s;
760 }
761
762 /*
763  * Context: process
764  */
765 int oz_protocol_init(char *devs)
766 {
767         skb_queue_head_init(&g_rx_queue);
768         if (devs && (devs[0] == '*')) {
769                 oz_binding_add(NULL);
770         } else {
771                 char d[32];
772                 while (*devs) {
773                         devs = oz_get_next_device_name(devs, d, sizeof(d));
774                         if (d[0])
775                                 oz_binding_add(d);
776                 }
777         }
778         return 0;
779 }
780
781 /*
782  * Context: process
783  */
784 int oz_get_pd_list(struct oz_mac_addr *addr, int max_count)
785 {
786         struct oz_pd *pd;
787         struct list_head *e;
788         int count = 0;
789
790         spin_lock_bh(&g_polling_lock);
791         list_for_each(e, &g_pd_list) {
792                 if (count >= max_count)
793                         break;
794                 pd = container_of(e, struct oz_pd, link);
795                 memcpy(&addr[count++], pd->mac_addr, ETH_ALEN);
796         }
797         spin_unlock_bh(&g_polling_lock);
798         return count;
799 }
800
801 void oz_polling_lock_bh(void)
802 {
803         spin_lock_bh(&g_polling_lock);
804 }
805
806 void oz_polling_unlock_bh(void)
807 {
808         spin_unlock_bh(&g_polling_lock);
809 }