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