cregit-Linux how code gets into the kernel

Release 4.11 net/irda/irlmp.c

Directory: net/irda
/*********************************************************************
 *
 * Filename:      irlmp.c
 * Version:       1.0
 * Description:   IrDA Link Management Protocol (LMP) layer
 * Status:        Stable.
 * Author:        Dag Brattli <dagb@cs.uit.no>
 * Created at:    Sun Aug 17 20:54:32 1997
 * Modified at:   Wed Jan  5 11:26:03 2000
 * Modified by:   Dag Brattli <dagb@cs.uit.no>
 *
 *     Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>,
 *     All Rights Reserved.
 *     Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
 *
 *     This program is free software; you can redistribute it and/or
 *     modify it under the terms of the GNU General Public License as
 *     published by the Free Software Foundation; either version 2 of
 *     the License, or (at your option) any later version.
 *
 *     Neither Dag Brattli nor University of Tromsø admit liability nor
 *     provide warranty for any of this software. This material is
 *     provided "AS-IS" and at no charge.
 *
 ********************************************************************/

#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/skbuff.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
#include <linux/kmod.h>
#include <linux/random.h>
#include <linux/seq_file.h>

#include <net/irda/irda.h>
#include <net/irda/timer.h>
#include <net/irda/qos.h>
#include <net/irda/irlap.h>
#include <net/irda/iriap.h>
#include <net/irda/irlmp.h>
#include <net/irda/irlmp_frame.h>

#include <asm/unaligned.h>

static __u8 irlmp_find_free_slsap(void);
static int irlmp_slsap_inuse(__u8 slsap_sel);

/* Master structure */

struct irlmp_cb *irlmp = NULL;

/* These can be altered by the sysctl interface */

int  sysctl_discovery         = 0;

int  sysctl_discovery_timeout = 3; 
/* 3 seconds by default */

int  sysctl_discovery_slots   = 6; 
/* 6 slots by default */

int  sysctl_lap_keepalive_time = LM_IDLE_TIMEOUT * 1000 / HZ;

char sysctl_devname[65];


static const char *irlmp_reasons[] = {
	"ERROR, NOT USED",
	"LM_USER_REQUEST",
	"LM_LAP_DISCONNECT",
	"LM_CONNECT_FAILURE",
	"LM_LAP_RESET",
	"LM_INIT_DISCONNECT",
	"ERROR, NOT USED",
	"UNKNOWN",
};


const char *irlmp_reason_str(LM_REASON reason) { reason = min_t(size_t, reason, ARRAY_SIZE(irlmp_reasons) - 1); return irlmp_reasons[reason]; }

Contributors

PersonTokensPropCommitsCommitProp
Dan Carpenter32100.00%1100.00%
Total32100.00%1100.00%

/* * Function irlmp_init (void) * * Create (allocate) the main IrLMP structure * */
int __init irlmp_init(void) { /* Initialize the irlmp structure. */ irlmp = kzalloc( sizeof(struct irlmp_cb), GFP_KERNEL); if (irlmp == NULL) return -ENOMEM; irlmp->magic = LMP_MAGIC; irlmp->clients = hashbin_new(HB_LOCK); irlmp->services = hashbin_new(HB_LOCK); irlmp->links = hashbin_new(HB_LOCK); irlmp->unconnected_lsaps = hashbin_new(HB_LOCK); irlmp->cachelog = hashbin_new(HB_NOLOCK); if ((irlmp->clients == NULL) || (irlmp->services == NULL) || (irlmp->links == NULL) || (irlmp->unconnected_lsaps == NULL) || (irlmp->cachelog == NULL)) { return -ENOMEM; } spin_lock_init(&irlmp->cachelog->hb_spinlock); irlmp->last_lsap_sel = 0x0f; /* Reserved 0x00-0x0f */ strcpy(sysctl_devname, "Linux"); init_timer(&irlmp->discovery_timer); /* Do discovery every 3 seconds, conditionally */ if (sysctl_discovery) irlmp_start_discovery_timer(irlmp, sysctl_discovery_timeout*HZ); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)10960.56%440.00%
Jean Tourrilhes6536.11%330.00%
Ross Burton42.22%110.00%
André Goddard Rosa10.56%110.00%
Panagiotis Issaris10.56%110.00%
Total180100.00%10100.00%

/* * Function irlmp_cleanup (void) * * Remove IrLMP layer * */
void irlmp_cleanup(void) { /* Check for main structure */ IRDA_ASSERT(irlmp != NULL, return;); IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return;); del_timer(&irlmp->discovery_timer); hashbin_delete(irlmp->links, (FREE_FUNC) kfree); hashbin_delete(irlmp->unconnected_lsaps, (FREE_FUNC) kfree); hashbin_delete(irlmp->clients, (FREE_FUNC) kfree); hashbin_delete(irlmp->services, (FREE_FUNC) kfree); hashbin_delete(irlmp->cachelog, (FREE_FUNC) kfree); /* De-allocate main structure */ kfree(irlmp); irlmp = NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)9898.00%266.67%
Jean Tourrilhes22.00%133.33%
Total100100.00%3100.00%

/* * Function irlmp_open_lsap (slsap, notify) * * Register with IrLMP and create a local LSAP, * returns handle to LSAP. */
struct lsap_cb *irlmp_open_lsap(__u8 slsap_sel, notify_t *notify, __u8 pid) { struct lsap_cb *self; IRDA_ASSERT(notify != NULL, return NULL;); IRDA_ASSERT(irlmp != NULL, return NULL;); IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return NULL;); IRDA_ASSERT(notify->instance != NULL, return NULL;); /* Does the client care which Source LSAP selector it gets? */ if (slsap_sel == LSAP_ANY) { slsap_sel = irlmp_find_free_slsap(); if (!slsap_sel) return NULL; } else if (irlmp_slsap_inuse(slsap_sel)) return NULL; /* Allocate new instance of a LSAP connection */ self = kzalloc(sizeof(struct lsap_cb), GFP_ATOMIC); if (self == NULL) return NULL; self->magic = LMP_LSAP_MAGIC; self->slsap_sel = slsap_sel; /* Fix connectionless LSAP's */ if (slsap_sel == LSAP_CONNLESS) { #ifdef CONFIG_IRDA_ULTRA self->dlsap_sel = LSAP_CONNLESS; self->pid = pid; #endif /* CONFIG_IRDA_ULTRA */ } else self->dlsap_sel = LSAP_ANY; /* self->connected = FALSE; -> already NULL via memset() */ init_timer(&self->watchdog_timer); self->notify = *notify; self->lsap_state = LSAP_DISCONNECTED; /* Insert into queue of unconnected LSAPs */ hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) self, (long) self, NULL); return self; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)18291.92%444.44%
Jean Tourrilhes115.56%333.33%
Linus Torvalds42.02%111.11%
Panagiotis Issaris10.51%111.11%
Total198100.00%9100.00%

EXPORT_SYMBOL(irlmp_open_lsap); /* * Function __irlmp_close_lsap (self) * * Remove an instance of LSAP */
static void __irlmp_close_lsap(struct lsap_cb *self) { IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;); /* * Set some of the variables to preset values */ self->magic = 0; del_timer(&self->watchdog_timer); /* Important! */ if (self->conn_skb) dev_kfree_skb(self->conn_skb); kfree(self); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)5796.61%266.67%
Jean Tourrilhes23.39%133.33%
Total59100.00%3100.00%

/* * Function irlmp_close_lsap (self) * * Close and remove LSAP * */
void irlmp_close_lsap(struct lsap_cb *self) { struct lap_cb *lap; struct lsap_cb *lsap = NULL; IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;); /* * Find out if we should remove this LSAP from a link or from the * list of unconnected lsaps (not associated with a link) */ lap = self->lap; if (lap) { IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return;); /* We might close a LSAP before it has completed the * connection setup. In those case, higher layers won't * send a proper disconnect request. Harmless, except * that we will forget to close LAP... - Jean II */ if(self->lsap_state != LSAP_DISCONNECTED) { self->lsap_state = LSAP_DISCONNECTED; irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL); } /* Now, remove from the link */ lsap = hashbin_remove(lap->lsaps, (long) self, NULL); #ifdef CONFIG_IRDA_CACHE_LAST_LSAP lap->cache.valid = FALSE; #endif } self->lap = NULL; /* Check if we found the LSAP! If not then try the unconnected lsaps */ if (!lsap) { lsap = hashbin_remove(irlmp->unconnected_lsaps, (long) self, NULL); } if (!lsap) { pr_debug("%s(), Looks like somebody has removed me already!\n", __func__); return; } __irlmp_close_lsap(self); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)10765.24%220.00%
Jean Tourrilhes4929.88%550.00%
Linus Torvalds63.66%110.00%
Harvey Harrison10.61%110.00%
Joe Perches10.61%110.00%
Total164100.00%10100.00%

EXPORT_SYMBOL(irlmp_close_lsap); /* * Function irlmp_register_irlap (saddr, notify) * * Register IrLAP layer with IrLMP. There is possible to have multiple * instances of the IrLAP layer, each connected to different IrDA ports * */
void irlmp_register_link(struct irlap_cb *irlap, __u32 saddr, notify_t *notify) { struct lap_cb *lap; IRDA_ASSERT(irlmp != NULL, return;); IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return;); IRDA_ASSERT(notify != NULL, return;); /* * Allocate new instance of a LSAP connection */ lap = kzalloc(sizeof(struct lap_cb), GFP_KERNEL); if (lap == NULL) return; lap->irlap = irlap; lap->magic = LMP_LAP_MAGIC; lap->saddr = saddr; lap->daddr = DEV_ADDR_ANY; #ifdef CONFIG_IRDA_CACHE_LAST_LSAP lap->cache.valid = FALSE; #endif lap->lsaps = hashbin_new(HB_LOCK); if (lap->lsaps == NULL) { net_warn_ratelimited("%s(), unable to kmalloc lsaps\n", __func__); kfree(lap); return; } lap->lap_state = LAP_STANDBY; init_timer(&lap->idle_timer); /* * Insert into queue of LMP links */ hashbin_insert(irlmp->links, (irda_queue_t *) lap, lap->saddr, NULL); /* * We set only this variable so IrLAP can tell us on which link the * different events happened on */ irda_notify_init(notify); notify->instance = lap; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)12670.39%433.33%
Jean Tourrilhes4625.70%325.00%
Linus Torvalds31.68%18.33%
Martin Dalecki10.56%18.33%
Harvey Harrison10.56%18.33%
Joe Perches10.56%18.33%
Panagiotis Issaris10.56%18.33%
Total179100.00%12100.00%

/* * Function irlmp_unregister_irlap (saddr) * * IrLAP layer has been removed! * */
void irlmp_unregister_link(__u32 saddr) { struct lap_cb *link; /* We must remove ourselves from the hashbin *first*. This ensure * that no more LSAPs will be open on this link and no discovery * will be triggered anymore. Jean II */ link = hashbin_remove(irlmp->links, saddr, NULL); if (link) { IRDA_ASSERT(link->magic == LMP_LAP_MAGIC, return;); /* Kill all the LSAPs on this link. Jean II */ link->reason = LAP_DISC_INDICATION; link->daddr = DEV_ADDR_ANY; irlmp_do_lap_event(link, LM_LAP_DISCONNECT_INDICATION, NULL); /* Remove all discoveries discovered at this link */ irlmp_expire_discoveries(irlmp->cachelog, link->saddr, TRUE); /* Final cleanup */ del_timer(&link->idle_timer); link->magic = 0; hashbin_delete(link->lsaps, (FREE_FUNC) __irlmp_close_lsap); kfree(link); } }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)7165.74%350.00%
Jean Tourrilhes2523.15%233.33%
Hinko Kocevar1211.11%116.67%
Total108100.00%6100.00%

/* * Function irlmp_connect_request (handle, dlsap, userdata) * * Connect with a peer LSAP * */
int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel, __u32 saddr, __u32 daddr, struct qos_info *qos, struct sk_buff *userdata) { struct sk_buff *tx_skb = userdata; struct lap_cb *lap; struct lsap_cb *lsap; int ret; IRDA_ASSERT(self != NULL, return -EBADR;); IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -EBADR;); pr_debug("%s(), slsap_sel=%02x, dlsap_sel=%02x, saddr=%08x, daddr=%08x\n", __func__, self->slsap_sel, dlsap_sel, saddr, daddr); if (test_bit(0, &self->connected)) { ret = -EISCONN; goto err; } /* Client must supply destination device address */ if (!daddr) { ret = -EINVAL; goto err; } /* Any userdata? */ if (tx_skb == NULL) { tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC); if (!tx_skb) return -ENOMEM; skb_reserve(tx_skb, LMP_MAX_HEADER); } /* Make room for MUX control header (3 bytes) */ IRDA_ASSERT(skb_headroom(tx_skb) >= LMP_CONTROL_HEADER, return -1;); skb_push(tx_skb, LMP_CONTROL_HEADER); self->dlsap_sel = dlsap_sel; /* * Find the link to where we should try to connect since there may * be more than one IrDA port on this machine. If the client has * passed us the saddr (and already knows which link to use), then * we use that to find the link, if not then we have to look in the * discovery log and check if any of the links has discovered a * device with the given daddr */ if ((!saddr) || (saddr == DEV_ADDR_ANY)) { discovery_t *discovery; unsigned long flags; spin_lock_irqsave(&irlmp->cachelog->hb_spinlock, flags); if (daddr != DEV_ADDR_ANY) discovery = hashbin_find(irlmp->cachelog, daddr, NULL); else { pr_debug("%s(), no daddr\n", __func__); discovery = (discovery_t *) hashbin_get_first(irlmp->cachelog); } if (discovery) { saddr = discovery->data.saddr; daddr = discovery->data.daddr; } spin_unlock_irqrestore(&irlmp->cachelog->hb_spinlock, flags); } lap = hashbin_lock_find(irlmp->links, saddr, NULL); if (lap == NULL) { pr_debug("%s(), Unable to find a usable link!\n", __func__); ret = -EHOSTUNREACH; goto err; } /* Check if LAP is disconnected or already connected */ if (lap->daddr == DEV_ADDR_ANY) lap->daddr = daddr; else if (lap->daddr != daddr) { /* Check if some LSAPs are active on this LAP */ if (HASHBIN_GET_SIZE(lap->lsaps) == 0) { /* No active connection, but LAP hasn't been * disconnected yet (waiting for timeout in LAP). * Maybe we could give LAP a bit of help in this case. */ pr_debug("%s(), sorry, but I'm waiting for LAP to timeout!\n", __func__); ret = -EAGAIN; goto err; } /* LAP is already connected to a different node, and LAP * can only talk to one node at a time */ pr_debug("%s(), sorry, but link is busy!\n", __func__); ret = -EBUSY; goto err; } self->lap = lap; /* * Remove LSAP from list of unconnected LSAPs and insert it into the * list of connected LSAPs for the particular link */ lsap = hashbin_remove(irlmp->unconnected_lsaps, (long) self, NULL); IRDA_ASSERT(lsap != NULL, return -1;); IRDA_ASSERT(lsap->magic == LMP_LSAP_MAGIC, return -1;); IRDA_ASSERT(lsap->lap != NULL, return -1;); IRDA_ASSERT(lsap->lap->magic == LMP_LAP_MAGIC, return -1;); hashbin_insert(self->lap->lsaps, (irda_queue_t *) self, (long) self, NULL); set_bit(0, &self->connected); /* TRUE */ /* * User supplied qos specifications? */ if (qos) self->qos = *qos; irlmp_do_lsap_event(self, LM_CONNECT_REQUEST, tx_skb); /* Drop reference count - see irlap_data_request(). */ dev_kfree_skb(tx_skb); return 0; err: /* Cleanup */ if(tx_skb) dev_kfree_skb(tx_skb); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)36869.17%735.00%
Jean Tourrilhes12723.87%630.00%
Linus Torvalds213.95%210.00%
Harvey Harrison50.94%15.00%
Joe Perches50.94%15.00%
Samuel Ortiz40.75%210.00%
Martin Dalecki20.38%15.00%
Total532100.00%20100.00%

EXPORT_SYMBOL(irlmp_connect_request); /* * Function irlmp_connect_indication (self) * * Incoming connection * */
void irlmp_connect_indication(struct lsap_cb *self, struct sk_buff *skb) { int max_seg_size; int lap_header_size; int max_header_size; IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;); IRDA_ASSERT(skb != NULL, return;); IRDA_ASSERT(self->lap != NULL, return;); pr_debug("%s(), slsap_sel=%02x, dlsap_sel=%02x\n", __func__, self->slsap_sel, self->dlsap_sel); /* Note : self->lap is set in irlmp_link_data_indication(), * (case CONNECT_CMD:) because we have no way to set it here. * Similarly, self->dlsap_sel is usually set in irlmp_find_lsap(). * Jean II */ self->qos = *self->lap->qos; max_seg_size = self->lap->qos->data_size.value-LMP_HEADER; lap_header_size = IRLAP_GET_HEADER_SIZE(self->lap->irlap); max_header_size = LMP_HEADER + lap_header_size; /* Hide LMP_CONTROL_HEADER header from layer above */ skb_pull(skb, LMP_CONTROL_HEADER); if (self->notify.connect_indication) { /* Don't forget to refcount it - see irlap_driver_rcv(). */ skb_get(skb); self->notify.connect_indication(self->notify.instance, self, &self->qos, max_seg_size, max_header_size, skb); } }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)14389.38%440.00%
Jean Tourrilhes148.75%330.00%
Joe Perches10.62%110.00%
Linus Torvalds10.62%110.00%
Harvey Harrison10.62%110.00%
Total160100.00%10100.00%

/* * Function irlmp_connect_response (handle, userdata) * * Service user is accepting connection * */
int irlmp_connect_response(struct lsap_cb *self, struct sk_buff *userdata) { IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); IRDA_ASSERT(userdata != NULL, return -1;); /* We set the connected bit and move the lsap to the connected list * in the state machine itself. Jean II */ pr_debug("%s(), slsap_sel=%02x, dlsap_sel=%02x\n", __func__, self->slsap_sel, self->dlsap_sel); /* Make room for MUX control header (3 bytes) */ IRDA_ASSERT(skb_headroom(userdata) >= LMP_CONTROL_HEADER, return -1;); skb_push(userdata, LMP_CONTROL_HEADER); irlmp_do_lsap_event(self, LM_CONNECT_RESPONSE, userdata); /* Drop reference count - see irlap_data_request(). */ dev_kfree_skb(userdata); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)7883.87%440.00%
Jean Tourrilhes1313.98%440.00%
Joe Perches11.08%110.00%
Harvey Harrison11.08%110.00%
Total93100.00%10100.00%

EXPORT_SYMBOL(irlmp_connect_response); /* * Function irlmp_connect_confirm (handle, skb) * * LSAP connection confirmed peer device! */
void irlmp_connect_confirm(struct lsap_cb *self, struct sk_buff *skb) { int max_header_size; int lap_header_size; int max_seg_size; IRDA_ASSERT(skb != NULL, return;); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;); IRDA_ASSERT(self->lap != NULL, return;); self->qos = *self->lap->qos; max_seg_size = self->lap->qos->data_size.value-LMP_HEADER; lap_header_size = IRLAP_GET_HEADER_SIZE(self->lap->irlap); max_header_size = LMP_HEADER + lap_header_size; pr_debug("%s(), max_header_size=%d\n", __func__, max_header_size); /* Hide LMP_CONTROL_HEADER header from layer above */ skb_pull(skb, LMP_CONTROL_HEADER); if (self->notify.connect_confirm) { /* Don't forget to refcount it - see irlap_driver_rcv() */ skb_get(skb); self->notify.connect_confirm(self->notify.instance, self, &self->qos, max_seg_size, max_header_size, skb); } }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)13990.85%550.00%
Jean Tourrilhes127.84%330.00%
Harvey Harrison10.65%110.00%
Joe Perches10.65%110.00%
Total153100.00%10100.00%

/* * Function irlmp_dup (orig, instance) * * Duplicate LSAP, can be used by servers to confirm a connection on a * new LSAP so it can keep listening on the old one. * */
struct lsap_cb *irlmp_dup(struct lsap_cb *orig, void *instance) { struct lsap_cb *new; unsigned long flags; spin_lock_irqsave(&irlmp->unconnected_lsaps->hb_spinlock, flags); /* Only allowed to duplicate unconnected LSAP's, and only LSAPs * that have received a connect indication. Jean II */ if ((!hashbin_find(irlmp->unconnected_lsaps, (long) orig, NULL)) || (orig->lap == NULL)) { pr_debug("%s(), invalid LSAP (wrong state)\n", __func__); spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags); return NULL; } /* Allocate a new instance */ new = kmemdup(orig, sizeof(*new), GFP_ATOMIC); if (!new) { pr_debug("%s(), unable to kmalloc\n", __func__); spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags); return NULL; } /* new->lap = orig->lap; => done in the memcpy() */ /* new->slsap_sel = orig->slsap_sel; => done in the memcpy() */ new->conn_skb = NULL; spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags); /* Not everything is the same */ new->notify.instance = instance; init_timer(&new->watchdog_timer); hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) new, (long) new, NULL); #ifdef CONFIG_IRDA_CACHE_LAST_LSAP /* Make sure that we invalidate the LSAP cache */ new->lap->cache.valid = FALSE; #endif /* CONFIG_IRDA_CACHE_LAST_LSAP */ return new; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)11956.40%218.18%
Jean Tourrilhes8339.34%654.55%
Arnaldo Carvalho de Melo52.37%19.09%
Harvey Harrison20.95%19.09%
Joe Perches20.95%19.09%
Total211100.00%11100.00%

/* * Function irlmp_disconnect_request (handle, userdata) * * The service user is requesting disconnection, this will not remove the * LSAP, but only mark it as disconnected */
int irlmp_disconnect_request(struct lsap_cb *self, struct sk_buff *userdata) { struct lsap_cb *lsap; IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); IRDA_ASSERT(userdata != NULL, return -1;); /* Already disconnected ? * There is a race condition between irlmp_disconnect_indication() * and us that might mess up the hashbins below. This fixes it. * Jean II */ if (! test_and_clear_bit(0, &self->connected)) { pr_debug("%s(), already disconnected!\n", __func__); dev_kfree_skb(userdata); return -1; } skb_push(userdata, LMP_CONTROL_HEADER); /* * Do the event before the other stuff since we must know * which lap layer that the frame should be transmitted on */ irlmp_do_lsap_event(self, LM_DISCONNECT_REQUEST, userdata); /* Drop reference count - see irlap_data_request(). */ dev_kfree_skb(userdata); /* * Remove LSAP from list of connected LSAPs for the particular link * and insert it into the list of unconnected LSAPs */ IRDA_ASSERT(self->lap != NULL, return -1;); IRDA_ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;); IRDA_ASSERT(self->lap->lsaps != NULL, return -1;); lsap = hashbin_remove(self->lap->lsaps, (long) self, NULL); #ifdef CONFIG_IRDA_CACHE_LAST_LSAP self->lap->cache.valid = FALSE; #endif IRDA_ASSERT(lsap != NULL, return -1;); IRDA_ASSERT(lsap->magic == LMP_LSAP_MAGIC, return -1;); IRDA_ASSERT(lsap == self, return -1;); hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) self, (long) self, NULL); /* Reset some values */ self->dlsap_sel = LSAP_ANY; self->lap = NULL; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)16874.34%430.77%
Jean Tourrilhes3415.04%538.46%
Linus Torvalds208.85%17.69%
Martin Dalecki20.88%17.69%
Joe Perches10.44%17.69%
Harvey Harrison10.44%17.69%
Total226100.00%13100.00%

EXPORT_SYMBOL(irlmp_disconnect_request); /* * Function irlmp_disconnect_indication (reason, userdata) * * LSAP is being closed! */
void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason, struct sk_buff *skb) { struct lsap_cb *lsap; pr_debug("%s(), reason=%s [%d]\n", __func__, irlmp_reason_str(reason), reason); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;); pr_debug("%s(), slsap_sel=%02x, dlsap_sel=%02x\n", __func__, self->slsap_sel, self->dlsap_sel); /* Already disconnected ? * There is a race condition between irlmp_disconnect_request() * and us that might mess up the hashbins below. This fixes it. * Jean II */ if (! test_and_clear_bit(0, &self->connected)) { pr_debug("%s(), already disconnected!\n", __func__); return; } /* * Remove association between this LSAP and the link it used */ IRDA_ASSERT(self->lap != NULL, return;); IRDA_ASSERT(self->lap->lsaps != NULL, return;); lsap = hashbin_remove(self->lap->lsaps, (long) self, NULL); #ifdef CONFIG_IRDA_CACHE_LAST_LSAP self->lap->cache.valid = FALSE; #endif IRDA_ASSERT(lsap != NULL, return;); IRDA_ASSERT(lsap == self, return;); hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) lsap, (long) lsap, NULL); self->dlsap_sel = LSAP_ANY; self->lap = NULL; /* * Inform service user */ if (self->notify.disconnect_indication) { /* Don't forget to refcount it - see irlap_driver_rcv(). */ if(skb) skb_get(skb); self->notify.disconnect_indication(self->notify.instance, self, reason, skb); } else { pr_debug("%s(), no handler\n", __func__); } }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)15365.38%533.33%
Jean Tourrilhes4418.80%533.33%
Linus Torvalds229.40%16.67%
Dan Carpenter62.56%16.67%
Joe Perches41.71%16.67%
Harvey Harrison41.71%16.67%
Martin Dalecki10.43%16.67%
Total234100.00%15100.00%

/* * Function irlmp_do_expiry (void) * * Do a cleanup of the discovery log (remove old entries) * * Note : separate from irlmp_do_discovery() so that we can handle * passive discovery properly. */
void irlmp_do_expiry(void) { struct lap_cb *lap; /* * Expire discovery on all links which are *not* connected. * On links which are connected, we can't do discovery * anymore and can't refresh the log, so we freeze the * discovery log to keep info about the device we are * connected to. * This info is mandatory if we want irlmp_connect_request() * to work properly. - Jean II */ lap = (struct lap_cb *) hashbin_get_first(irlmp->links); while (lap != NULL) { IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return;); if (lap->lap_state == LAP_STANDBY) { /* Expire discoveries discovered on this link */ irlmp_expire_discoveries(irlmp->cachelog, lap->saddr, FALSE); } lap = (struct lap_cb *) hashbin_get_next(irlmp->links); } }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds7593.75%125.00%
Al Viro33.75%125.00%
Jean Tourrilhes22.50%250.00%
Total80100.00%4100.00%

/* * Function irlmp_do_discovery (nslots) * * Do some discovery on all links * * Note : log expiry is done above. */
void irlmp_do_discovery(int nslots) { struct lap_cb *lap; __u16 *data_hintsp; /* Make sure the value is sane */ if ((nslots != 1) && (nslots != 6) && (nslots != 8) && (nslots != 16)){ net_warn_ratelimited("%s: invalid value for number of slots!\n", __func__); nslots = sysctl_discovery_slots = 8; } /* Construct new discovery info to be used by IrLAP, */ data_hintsp = (__u16 *) irlmp->discovery_cmd.data.hints; put_unaligned(irlmp->hints.word, data_hintsp); /* * Set character set for device name (we use ASCII), and * copy device name. Remember to make room for a \0 at the * end */ irlmp->discovery_cmd.data.charset = CS_ASCII; strncpy(irlmp->discovery_cmd.data.info, sysctl_devname, NICKNAME_MAX_LEN); irlmp->discovery_cmd.name_len = strlen(irlmp->discovery_cmd.data.info); irlmp->discovery_cmd.nslots = nslots; /* * Try to send discovery packets on all links */ lap = (struct lap_cb *) hashbin_get_first(irlmp->links); while (lap != NULL) { IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return;); if (lap->lap_state == LAP_STANDBY) { /* Try to discover */ irlmp_do_lap_event(lap, LM_LAP_DISCOVERY_REQUEST, NULL); } lap = (struct lap_cb *) hashbin_get_next(irlmp->links); } }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)16884.00%545.45%
David S. Miller168.00%19.09%
Jean Tourrilhes115.50%218.18%
Martin Dalecki31.50%19.09%
Joe Perches10.50%19.09%
Harvey Harrison10.50%19.09%
Total200100.00%11100.00%

/* * Function irlmp_discovery_request (nslots) * * Do a discovery of devices in front of the computer * * If the caller has registered a client discovery callback, this * allow him to receive the full content of the discovery log through * this callback (as normally he will receive only new discoveries). */
void irlmp_discovery_request(int nslots) { /* Return current cached discovery log (in full) */ irlmp_discovery_confirm(irlmp->cachelog, DISCOVERY_LOG); /* * Start a single discovery operation if discovery is not already * running */ if (!sysctl_discovery) { /* Check if user wants to override the default */ if (nslots == DISCOVERY_DEFAULT_SLOTS) nslots = sysctl_discovery_slots; irlmp_do_discovery(nslots); /* Note : we never do expiry here. Expiry will run on the * discovery timer regardless of the state of sysctl_discovery * Jean II */ } }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)2558.14%342.86%
Linus Torvalds1432.56%114.29%
Jean Tourrilhes36.98%228.57%
Hideaki Yoshifuji / 吉藤英明12.33%114.29%
Total43100.00%7100.00%

EXPORT_SYMBOL(irlmp_discovery_request); /* * Function irlmp_get_discoveries (pn, mask, slots) * * Return the current discovery log * * If discovery is not enabled, you should call this function again * after 1 or 2 seconds (i.e. after discovery has been done). */
struct irda_device_info *irlmp_get_discoveries(int *pn, __u16 mask, int nslots) { /* If discovery is not enabled, it's likely that the discovery log * will be empty. So, we trigger a single discovery, so that next * time the user call us there might be some results in the log. * Jean II */ if (!sysctl_discovery) { /* Check if user wants to override the default */ if (nslots == DISCOVERY_DEFAULT_SLOTS) nslots = sysctl_discovery_slots; /* Start discovery - will complete sometime later */ irlmp_do_discovery(nslots); /* Note : we never do expiry here. Expiry will run on the * discovery timer regardless of the state of sysctl_discovery * Jean II */ } /* Return current cached discovery log */ return irlmp_copy_discoveries(irlmp->cachelog, pn, mask, TRUE); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds2950.00%133.33%
Linus Torvalds (pre-git)2746.55%133.33%
Jean Tourrilhes23.45%133.33%
Total58100.00%3100.00%

EXPORT_SYMBOL(irlmp_get_discoveries); /* * Function irlmp_notify_client (log) * * Notify all about discovered devices * * Clients registered with IrLMP are : * o IrComm * o IrLAN * o Any socket (in any state - ouch, that may be a lot !) * The client may have defined a callback to be notified in case of * partial/selective discovery based on the hints that it passed to IrLMP. */
static inline void irlmp_notify_client(irlmp_client_t *client, hashbin_t *log, DISCOVERY_MODE mode) { discinfo_t *discoveries; /* Copy of the discovery log */ int number; /* Number of nodes in the log */ int i; /* Check if client wants or not partial/selective log (optimisation) */ if (!client->disco_callback) return; /* * Locking notes : * the old code was manipulating the log directly, which was * very racy. Now, we use copy_discoveries, that protects * itself while dumping the log for us. * The overhead of the copy is compensated by the fact that * we only pass new discoveries in normal mode and don't * pass the same old entry every 3s to the caller as we used * to do (virtual function calling is expensive). * Jean II */ /* * Now, check all discovered devices (if any), and notify client * only about the services that the client is interested in * We also notify only about the new devices unless the caller * explicitly request a dump of the log. Jean II */ discoveries = irlmp_copy_discoveries(log, &number, client->hint_mask.word, (mode == DISCOVERY_LOG)); /* Check if the we got some results */ if (discoveries == NULL) return; /* No nodes discovered */ /* Pass all entries to the listener */ for(i = 0; i < number; i++) client->disco_callback(&(discoveries[i]), mode, client->priv); /* Free up our buffer */ kfree(discoveries); }

Contributors

PersonTokensPropCommitsCommitProp
Jean Tourrilhes6054.05%233.33%
Linus Torvalds (pre-git)5045.05%350.00%
Alan Cox10.90%116.67%
Total111100.00%6100.00%

/* * Function irlmp_discovery_confirm ( self, log) * * Some device(s) answered to our discovery request! Check to see which * device it is, and give indication to the client(s) * */
void irlmp_discovery_confirm(hashbin_t *log, DISCOVERY_MODE mode) { irlmp_client_t *client; irlmp_client_t *client_next; IRDA_ASSERT(log != NULL, return;); if (!(HASHBIN_GET_SIZE(log))) return; /* For each client - notify callback may touch client list */ client = (irlmp_client_t *) hashbin_get_first(irlmp->clients); while (NULL != hashbin_find_next(irlmp->clients, (long) client, NULL, (void *) &client_next) ) { /* Check if we should notify client */ irlmp_notify_client(client, log, mode); client = client_next; } }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)6165.59%450.00%
Jean Tourrilhes3234.41%450.00%
Total93100.00%8100.00%

/* * Function irlmp_discovery_expiry (expiry) * * This device is no longer been discovered, and therefore it is being * purged from the discovery log. Inform all clients who have * registered for this event... * * Note : called exclusively from discovery.c * Note : this is no longer called under discovery spinlock, so the * client can do whatever he wants in the callback. */
void irlmp_discovery_expiry(discinfo_t *expiries, int number) { irlmp_client_t *client; irlmp_client_t *client_next; int i; IRDA_ASSERT(expiries != NULL, return;); /* For each client - notify callback may touch client list */ client = (irlmp_client_t *) hashbin_get_first(irlmp->clients); while (NULL != hashbin_find_next(irlmp->clients, (long) client, NULL, (void *) &client_next) ) { /* Pass all entries to the listener */ for(i = 0; i < number; i++) { /* Check if we should notify client */ if ((client->expir_callback) && (client->hint_mask.word & get_unaligned((__u16 *)expiries[i].hints) & 0x7f7f) ) client->expir_callback(&(expiries[i]), EXPIRY_TIMEOUT, client->priv); } /* Next client */ client = client_next; } }

Contributors

PersonTokensPropCommitsCommitProp
Jean Tourrilhes7048.61%466.67%
Linus Torvalds (pre-git)6947.92%116.67%
Graf Yang53.47%116.67%
Total144100.00%6100.00%

/* * Function irlmp_get_discovery_response () * * Used by IrLAP to get the discovery info it needs when answering * discovery requests by other devices. */
discovery_t *irlmp_get_discovery_response(void) { IRDA_ASSERT(irlmp != NULL, return NULL;); put_unaligned(irlmp->hints.word, (__u16 *)irlmp->discovery_rsp.data.hints); /* * Set character set for device name (we use ASCII), and * copy device name. Remember to make room for a \0 at the * end */ irlmp->discovery_rsp.data.charset = CS_ASCII; strncpy(irlmp->discovery_rsp.data.info, sysctl_devname, NICKNAME_MAX_LEN); irlmp->discovery_rsp.name_len = strlen(irlmp->discovery_rsp.data.info); return &irlmp->discovery_rsp; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)5767.06%337.50%
Jean Tourrilhes1315.29%225.00%
Graf Yang1112.94%112.50%
Al Viro33.53%112.50%
Martin Dalecki11.18%112.50%
Total85100.00%8100.00%

/* * Function irlmp_data_request (self, skb) * * Send some data to peer device * * Note on skb management : * After calling the lower layers of the IrDA stack, we always * kfree() the skb, which drop the reference count (and potentially * destroy it). * IrLMP and IrLAP may queue the packet, and in those cases will need * to use skb_get() to keep it around. * Jean II */
int irlmp_data_request(struct lsap_cb *self, struct sk_buff *userdata) { int ret; IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); /* Make room for MUX header */ IRDA_ASSERT(skb_headroom(userdata) >= LMP_HEADER, return -1;); skb_push(userdata, LMP_HEADER); ret = irlmp_do_lsap_event(self, LM_DATA_REQUEST, userdata); /* Drop reference count - see irlap_data_request(). */ dev_kfree_skb(userdata); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)5271.23%250.00%
Jean Tourrilhes2128.77%250.00%
Total73100.00%4100.00%

EXPORT_SYMBOL(irlmp_data_request); /* * Function irlmp_data_indication (handle, skb) * * Got data from LAP layer so pass it up to upper layer * */
void irlmp_data_indication(struct lsap_cb *self, struct sk_buff *skb) { /* Hide LMP header from layer above */ skb_pull(skb, LMP_HEADER); if (self->notify.data_indication) { /* Don't forget to refcount it - see irlap_driver_rcv(). */ skb_get(skb); self->notify.data_indication(self->notify.instance, self, skb); } }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)4885.71%150.00%
Jean Tourrilhes814.29%150.00%
Total56100.00%2100.00%

/* * Function irlmp_udata_request (self, skb) */
int irlmp_udata_request(struct lsap_cb *self, struct sk_buff *userdata) { int ret; IRDA_ASSERT(userdata != NULL, return -1;); /* Make room for MUX header */ IRDA_ASSERT(skb_headroom(userdata) >= LMP_HEADER, return -1;); skb_push(userdata, LMP_HEADER); ret = irlmp_do_lsap_event(self, LM_UDATA_REQUEST, userdata); /* Drop reference count - see irlap_data_request(). */ dev_kfree_skb(userdata); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)4367.19%250.00%
Jean Tourrilhes2132.81%250.00%
Total64100.00%4100.00%

/* * Function irlmp_udata_indication (self, skb) * * Send unreliable data (but still within the connection) * */
void irlmp_udata_indication(struct lsap_cb *self, struct sk_buff *skb) { IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;); IRDA_ASSERT(skb != NULL, return;); /* Hide LMP header from layer above */ skb_pull(skb, LMP_HEADER); if (self->notify.udata_indication) { /* Don't forget to refcount it - see irlap_driver_rcv(). */ skb_get(skb); self->notify.udata_indication(self->notify.instance, self, skb); } }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)6685.71%133.33%
Jean Tourrilhes1114.29%266.67%
Total77100.00%3100.00%

/* * Function irlmp_connless_data_request (self, skb) */ #ifdef CONFIG_IRDA_ULTRA
int irlmp_connless_data_request(struct lsap_cb *self, struct sk_buff *userdata, __u8 pid) { struct sk_buff *clone_skb; struct lap_cb *lap; IRDA_ASSERT(userdata != NULL, return -1;); /* Make room for MUX and PID header */ IRDA_ASSERT(skb_headroom(userdata) >= LMP_HEADER+LMP_PID_HEADER, return -1;); /* Insert protocol identifier */ skb_push(userdata, LMP_PID_HEADER); if(self != NULL) userdata->data[0] = self->pid; else userdata->data[0] = pid; /* Connectionless sockets must use 0x70 */ skb_push(userdata, LMP_HEADER); userdata->data[0] = userdata->data[1] = LSAP_CONNLESS; /* Try to send Connectionless packets out on all links */ lap = (struct lap_cb *) hashbin_get_first(irlmp->links); while (lap != NULL) { IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return -1;); clone_skb = skb_clone(userdata, GFP_ATOMIC); if (!clone_skb) { dev_kfree_skb(userdata); return -ENOMEM; } irlap_unitdata_request(lap->irlap, clone_skb); /* irlap_unitdata_request() don't increase refcount, * so no dev_kfree_skb() - Jean II */ lap = (struct lap_cb *) hashbin_get_next(irlmp->links); } dev_kfree_skb(userdata); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)15579.49%240.00%
Jean Tourrilhes4020.51%360.00%
Total195100.00%5100.00%

#endif /* CONFIG_IRDA_ULTRA */ /* * Function irlmp_connless_data_indication (self, skb) * * Receive unreliable data outside any connection. Mostly used by Ultra * */ #ifdef CONFIG_IRDA_ULTRA
void irlmp_connless_data_indication(struct lsap_cb *self, struct sk_buff *skb) { IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;); IRDA_ASSERT(skb != NULL, return;); /* Hide LMP and PID header from layer above */ skb_pull(skb, LMP_HEADER+LMP_PID_HEADER); if (self->notify.udata_indication) { /* Don't forget to refcount it - see irlap_driver_rcv(). */ skb_get(skb); self->notify.udata_indication(self->notify.instance, self, skb); } }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)6886.08%250.00%
Jean Tourrilhes1113.92%250.00%
Total79100.00%4100.00%

#endif /* CONFIG_IRDA_ULTRA */ /* * Propagate status indication from LAP to LSAPs (via LMP) * This don't trigger any change of state in lap_cb, lmp_cb or lsap_cb, * and the event is stateless, therefore we can bypass both state machines * and send the event direct to the LSAP user. * Jean II */
void irlmp_status_indication(struct lap_cb *self, LINK_STATUS link, LOCK_STATUS lock) { struct lsap_cb *next; struct lsap_cb *curr; /* Send status_indication to all LSAPs using this link */ curr = (struct lsap_cb *) hashbin_get_first( self->lsaps); while (NULL != hashbin_find_next(self->lsaps, (long) curr, NULL, (void *) &next) ) { IRDA_ASSERT(curr->magic == LMP_LSAP_MAGIC, return;); /* * Inform service user if he has requested it */ if (curr->notify.status_indication != NULL) curr->notify.status_indication(curr->notify.instance, link, lock); else pr_debug("%s(), no handler\n", __func__); curr = next; } }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)8775.65%228.57%
Jean Tourrilhes2622.61%342.86%
Joe Perches10.87%114.29%
Harvey Harrison10.87%114.29%
Total115100.00%7100.00%

/* * Receive flow control indication from LAP. * LAP want us to send it one more frame. We implement a simple round * robin scheduler between the active sockets so that we get a bit of * fairness. Note that the round robin is far from perfect, but it's * better than nothing. * We then poll the selected socket so that we can do synchronous * refilling of IrLAP (which allow to minimise the number of buffers). * Jean II */
void irlmp_flow_indication(struct lap_cb *self, LOCAL_FLOW flow) { struct lsap_cb *next; struct lsap_cb *curr; int lsap_todo; IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;); IRDA_ASSERT(flow == FLOW_START, return;); /* Get the number of lsap. That's the only safe way to know * that we have looped around... - Jean II */ lsap_todo = HASHBIN_GET_SIZE(self->lsaps); pr_debug("%s() : %d lsaps to scan\n", __func__, lsap_todo); /* Poll lsap in order until the queue is full or until we * tried them all. * Most often, the current LSAP will have something to send, * so we will go through this loop only once. - Jean II */ while((lsap_todo--) && (IRLAP_GET_TX_QUEUE_LEN(self->irlap) < LAP_HIGH_THRESHOLD)) { /* Try to find the next lsap we should poll. */ next = self->flow_next; /* If we have no lsap, restart from first one */ if(next == NULL) next = (struct lsap_cb *) hashbin_get_first(self->lsaps); /* Verify current one and find the next one */ curr = hashbin_find_next(self->lsaps, (long) next, NULL, (void *) &self->flow_next); /* Uh-oh... Paranoia */ if(curr == NULL) break; pr_debug("%s() : curr is %p, next was %p and is now %p, still %d to go - queue len = %d\n", __func__, curr, next, self->flow_next, lsap_todo, IRLAP_GET_TX_QUEUE_LEN(self->irlap)); /* Inform lsap user that it can send one more packet. */ if (curr->notify.flow_indication != NULL) curr->notify.flow_indication(curr->notify.instance, curr, flow); else pr_debug("%s(), no handler\n", __func__); } }

Contributors

PersonTokensPropCommitsCommitProp
Jean Tourrilhes19697.03%466.67%
Harvey Harrison31.49%116.67%
Joe Perches31.49%116.67%
Total202100.00%6100.00%

#if 0 /* * Function irlmp_hint_to_service (hint) * * Returns a list of all servics contained in the given hint bits. This * function assumes that the hint bits have the size of two bytes only */ __u8 *irlmp_hint_to_service(__u8 *hint) { __u8 *service; int i = 0; /* * Allocate array to store services in. 16 entries should be safe * since we currently only support 2 hint bytes */ service = kmalloc(16, GFP_ATOMIC); if (!service) return NULL; if (!hint[0]) { pr_debug("<None>\n"); kfree(service); return NULL; } if (hint[0] & HINT_PNP) pr_debug("PnP Compatible "); if (hint[0] & HINT_PDA) pr_debug("PDA/Palmtop "); if (hint[0] & HINT_COMPUTER) pr_debug("Computer "); if (hint[0] & HINT_PRINTER) { pr_debug("Printer "); service[i++] = S_PRINTER; } if (hint[0] & HINT_MODEM) pr_debug("Modem "); if (hint[0] & HINT_FAX) pr_debug("Fax "); if (hint[0] & HINT_LAN) { pr_debug("LAN Access "); service[i++] = S_LAN; } /* * Test if extension byte exists. This byte will usually be * there, but this is not really required by the standard. * (IrLMP p. 29) */ if (hint[0] & HINT_EXTENSION) { if (hint[1] & HINT_TELEPHONY) { pr_debug("Telephony "); service[i++] = S_TELEPHONY; } if (hint[1] & HINT_FILE_SERVER) pr_debug("File Server "); if (hint[1] & HINT_COMM) { pr_debug("IrCOMM "); service[i++] = S_COMM; } if (hint[1] & HINT_OBEX) { pr_debug("IrOBEX "); service[i++] = S_OBEX; } } pr_debug("\n"); /* So that client can be notified about any discovery */ service[i++] = S_ANY; service[i] = S_END; return service; } #endif static const __u16 service_hint_mapping[S_END][2] = { { HINT_PNP, 0 }, /* S_PNP */ { HINT_PDA, 0 }, /* S_PDA */ { HINT_COMPUTER, 0 }, /* S_COMPUTER */ { HINT_PRINTER, 0 }, /* S_PRINTER */ { HINT_MODEM, 0 }, /* S_MODEM */ { HINT_FAX, 0 }, /* S_FAX */ { HINT_LAN, 0 }, /* S_LAN */ { HINT_EXTENSION, HINT_TELEPHONY }, /* S_TELEPHONY */ { HINT_EXTENSION, HINT_COMM }, /* S_COMM */ { HINT_EXTENSION, HINT_OBEX }, /* S_OBEX */ { 0xFF, 0xFF }, /* S_ANY */ }; /* * Function irlmp_service_to_hint (service) * * Converts a service type, to a hint bit * * Returns: a 16 bit hint value, with the service bit set */
__u16 irlmp_service_to_hint(int service) { __u16_host_order hint; hint.byte[0] = service_hint_mapping[service][0]; hint.byte[1] = service_hint_mapping[service][1]; return hint.word; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)4086.96%375.00%
Jean Tourrilhes613.04%125.00%
Total46100.00%4100.00%

EXPORT_SYMBOL(irlmp_service_to_hint); /* * Function irlmp_register_service (service) * * Register local service with IrLMP * */
void *irlmp_register_service(__u16 hints) { irlmp_service_t *service; pr_debug("%s(), hints = %04x\n", __func__, hints); /* Make a new registration */ service = kmalloc(sizeof(irlmp_service_t), GFP_ATOMIC); if (!service) return NULL; service->hints.word = hints; hashbin_insert(irlmp->services, (irda_queue_t *) service, (long) service, NULL); irlmp->hints.word |= hints; return (void *)service; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)6069.77%333.33%
Jean Tourrilhes2326.74%333.33%
Al Viro11.16%111.11%
Harvey Harrison11.16%111.11%
Joe Perches11.16%111.11%
Total86100.00%9100.00%

EXPORT_SYMBOL(irlmp_register_service); /* * Function irlmp_unregister_service (handle) * * Unregister service with IrLMP. * * Returns: 0 on success, -1 on error */
int irlmp_unregister_service(void *handle) { irlmp_service_t *service; unsigned long flags; if (!handle) return -1; /* Caller may call with invalid handle (it's legal) - Jean II */ service = hashbin_lock_find(irlmp->services, (long) handle, NULL); if (!service) { pr_debug("%s(), Unknown service!\n", __func__); return -1; } hashbin_remove_this(irlmp->services, (irda_queue_t *) service); kfree(service); /* Remove old hint bits */ irlmp->hints.word = 0; /* Refresh current hint bits */ spin_lock_irqsave(&irlmp->services->hb_spinlock, flags); service = (irlmp_service_t *) hashbin_get_first(irlmp->services); while (service) { irlmp->hints.word |= service->hints.word; service = (irlmp_service_t *)hashbin_get_next(irlmp->services); } spin_unlock_irqrestore(&irlmp->services->hb_spinlock, flags); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)11370.62%225.00%
Jean Tourrilhes4528.12%450.00%
Joe Perches10.62%112.50%
Harvey Harrison10.62%112.50%
Total160100.00%8100.00%

EXPORT_SYMBOL(irlmp_unregister_service); /* * Function irlmp_register_client (hint_mask, callback1, callback2) * * Register a local client with IrLMP * First callback is selective discovery (based on hints) * Second callback is for selective discovery expiries * * Returns: handle > 0 on success, 0 on error */
void *irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 disco_clb, DISCOVERY_CALLBACK2 expir_clb, void *priv) { irlmp_client_t *client; IRDA_ASSERT(irlmp != NULL, return NULL;); /* Make a new registration */ client = kmalloc(sizeof(irlmp_client_t), GFP_ATOMIC); if (!client) return NULL; /* Register the details */ client->hint_mask.word = hint_mask; client->disco_callback = disco_clb; client->expir_callback = expir_clb; client->priv = priv; hashbin_insert(irlmp->clients, (irda_queue_t *) client, (long) client, NULL); return (void *) client; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)8883.81%342.86%
Jean Tourrilhes1514.29%342.86%
Al Viro21.90%114.29%
Total105100.00%7100.00%

EXPORT_SYMBOL(irlmp_register_client); /* * Function irlmp_update_client (handle, hint_mask, callback1, callback2) * * Updates specified client (handle) with possibly new hint_mask and * callback * * Returns: 0 on success, -1 on error */
int irlmp_update_client(void *handle, __u16 hint_mask, DISCOVERY_CALLBACK1 disco_clb, DISCOVERY_CALLBACK2 expir_clb, void *priv) { irlmp_client_t *client; if (!handle) return -1; client = hashbin_lock_find(irlmp->clients, (long) handle, NULL); if (!client) { pr_debug("%s(), Unknown client!\n", __func__); return -1; } client->hint_mask.word = hint_mask; client->disco_callback = disco_clb; client->expir_callback = expir_clb; client->priv = priv; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)8586.73%333.33%
Jean Tourrilhes1111.22%444.44%
Harvey Harrison11.02%111.11%
Joe Perches11.02%111.11%
Total98100.00%9100.00%

EXPORT_SYMBOL(irlmp_update_client); /* * Function irlmp_unregister_client (handle) * * Returns: 0 on success, -1 on error * */
int irlmp_unregister_client(void *handle) { struct irlmp_client *client; if (!handle) return -1; /* Caller may call with invalid handle (it's legal) - Jean II */ client = hashbin_lock_find(irlmp->clients, (long) handle, NULL); if (!client) { pr_debug("%s(), Unknown client!\n", __func__); return -1; } pr_debug("%s(), removing client!\n", __func__); hashbin_remove_this(irlmp->clients, (irda_queue_t *) client); kfree(client); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)6575.58%228.57%
Jean Tourrilhes1719.77%342.86%
Joe Perches22.33%114.29%
Harvey Harrison22.33%114.29%
Total86100.00%7100.00%

EXPORT_SYMBOL(irlmp_unregister_client); /* * Function irlmp_slsap_inuse (slsap) * * Check if the given source LSAP selector is in use * * This function is clearly not very efficient. On the mitigating side, the * stack make sure that in 99% of the cases, we are called only once * for each socket allocation. We could probably keep a bitmap * of the allocated LSAP, but I'm not sure the complexity is worth it. * Jean II */
static int irlmp_slsap_inuse(__u8 slsap_sel) { struct lsap_cb *self; struct lap_cb *lap; unsigned long flags; IRDA_ASSERT(irlmp != NULL, return TRUE;); IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return TRUE;); IRDA_ASSERT(slsap_sel != LSAP_ANY, return TRUE;); #ifdef CONFIG_IRDA_ULTRA /* Accept all bindings to the connectionless LSAP */ if (slsap_sel == LSAP_CONNLESS) return FALSE; #endif /* CONFIG_IRDA_ULTRA */ /* Valid values are between 0 and 127 (0x0-0x6F) */ if (slsap_sel > LSAP_MAX) return TRUE; /* * Check if slsap is already in use. To do this we have to loop over * every IrLAP connection and check every LSAP associated with each * the connection. */ spin_lock_irqsave_nested(&irlmp->links->hb_spinlock, flags, SINGLE_DEPTH_NESTING); lap = (struct lap_cb *) hashbin_get_first(irlmp->links); while (lap != NULL) { IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, goto errlap;); /* Careful for priority inversions here ! * irlmp->links is never taken while another IrDA * spinlock is held, so we are safe. Jean II */ spin_lock(&lap->lsaps->hb_spinlock); /* For this IrLAP, check all the LSAPs */ self = (struct lsap_cb *) hashbin_get_first(lap->lsaps); while (self != NULL) { IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, goto errlsap;); if ((self->slsap_sel == slsap_sel)) { pr_debug("Source LSAP selector=%02x in use\n", self->slsap_sel); goto errlsap; } self = (struct lsap_cb*) hashbin_get_next(lap->lsaps); } spin_unlock(&lap->lsaps->hb_spinlock); /* Next LAP */ lap = (struct lap_cb *) hashbin_get_next(irlmp->links); } spin_unlock_irqrestore(&irlmp->links->hb_spinlock, flags); /* * Server sockets are typically waiting for connections and * therefore reside in the unconnected list. We don't want * to give out their LSAPs for obvious reasons... * Jean II */ spin_lock_irqsave(&irlmp->unconnected_lsaps->hb_spinlock, flags); self = (struct lsap_cb *) hashbin_get_first(irlmp->unconnected_lsaps); while (self != NULL) { IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, goto erruncon;); if ((self->slsap_sel == slsap_sel)) { pr_debug("Source LSAP selector=%02x in use (unconnected)\n", self->slsap_sel); goto erruncon; } self = (struct lsap_cb*) hashbin_get_next(irlmp->unconnected_lsaps); } spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags); return FALSE; /* Error exit from within one of the two nested loops. * Make sure we release the right spinlock in the righ order. * Jean II */ errlsap: spin_unlock(&lap->lsaps->hb_spinlock); IRDA_ASSERT_LABEL(errlap:) spin_unlock_irqrestore(&irlmp->links->hb_spinlock, flags); return TRUE; /* Error exit from within the unconnected loop. * Just one spinlock to release... Jean II */ erruncon: spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags); return TRUE; }

Contributors

PersonTokensPropCommitsCommitProp
Jean Tourrilhes19852.80%327.27%
Linus Torvalds (pre-git)16644.27%327.27%
David S. Miller41.07%19.09%
Peter Zijlstra30.80%19.09%
Joe Perches20.53%19.09%
Adrian Bunk10.27%19.09%
Steven Cole10.27%19.09%
Total375100.00%11100.00%

/* * Function irlmp_find_free_slsap () * * Find a free source LSAP to use. This function is called if the service * user has requested a source LSAP equal to LM_ANY */
static __u8 irlmp_find_free_slsap(void) { __u8 lsap_sel; int wrapped = 0; IRDA_ASSERT(irlmp != NULL, return -1;); IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return -1;); /* Most users don't really care which LSAPs they are given, * and therefore we automatically give them a free LSAP. * This function try to find a suitable LSAP, i.e. which is * not in use and is within the acceptable range. Jean II */ do { /* Always increment to LSAP number before using it. * In theory, we could reuse the last LSAP number, as long * as it is no longer in use. Some IrDA stack do that. * However, the previous socket may be half closed, i.e. * we closed it, we think it's no longer in use, but the * other side did not receive our close and think it's * active and still send data on it. * This is similar to what is done with PIDs and TCP ports. * Also, this reduce the number of calls to irlmp_slsap_inuse() * which is an expensive function to call. * Jean II */ irlmp->last_lsap_sel++; /* Check if we need to wraparound (0x70-0x7f are reserved) */ if (irlmp->last_lsap_sel > LSAP_MAX) { /* 0x00-0x10 are also reserved for well know ports */ irlmp->last_lsap_sel = 0x10; /* Make sure we terminate the loop */ if (wrapped++) { net_err_ratelimited("%s: no more free LSAPs !\n", __func__); return 0; } } /* If the LSAP is in use, try the next one. * Despite the autoincrement, we need to check if the lsap * is really in use or not, first because LSAP may be * directly allocated in irlmp_open_lsap(), and also because * we may wraparound on old sockets. Jean II */ } while (irlmp_slsap_inuse(irlmp->last_lsap_sel)); /* Got it ! */ lsap_sel = irlmp->last_lsap_sel; pr_debug("%s(), found free lsap_sel=%02x\n", __func__, lsap_sel); return lsap_sel; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)6861.82%330.00%
Jean Tourrilhes3733.64%330.00%
Harvey Harrison21.82%110.00%
Joe Perches21.82%220.00%
Adrian Bunk10.91%110.00%
Total110100.00%10100.00%

/* * Function irlmp_convert_lap_reason (lap_reason) * * Converts IrLAP disconnect reason codes to IrLMP disconnect reason * codes * */
LM_REASON irlmp_convert_lap_reason( LAP_REASON lap_reason) { int reason = LM_LAP_DISCONNECT; switch (lap_reason) { case LAP_DISC_INDICATION: /* Received a disconnect request from peer */ pr_debug("%s(), LAP_DISC_INDICATION\n", __func__); reason = LM_USER_REQUEST; break; case LAP_NO_RESPONSE: /* To many retransmits without response */ pr_debug("%s(), LAP_NO_RESPONSE\n", __func__); reason = LM_LAP_DISCONNECT; break; case LAP_RESET_INDICATION: pr_debug("%s(), LAP_RESET_INDICATION\n", __func__); reason = LM_LAP_RESET; break; case LAP_FOUND_NONE: case LAP_MEDIA_BUSY: case LAP_PRIMARY_CONFLICT: pr_debug("%s(), LAP_FOUND_NONE, LAP_MEDIA_BUSY or LAP_PRIMARY_CONFLICT\n", __func__); reason = LM_CONNECT_FAILURE; break; default: pr_debug("%s(), Unknown IrLAP disconnect reason %d!\n", __func__, lap_reason); reason = LM_LAP_DISCONNECT; break; } return reason; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)8580.95%233.33%
Jean Tourrilhes98.57%116.67%
Joe Perches54.76%116.67%
Harvey Harrison54.76%116.67%
André Goddard Rosa10.95%116.67%
Total105100.00%6100.00%

#ifdef CONFIG_PROC_FS struct irlmp_iter_state { hashbin_t *hashbin; }; #define LSAP_START_TOKEN ((void *)1) #define LINK_START_TOKEN ((void *)2)
static void *irlmp_seq_hb_idx(struct irlmp_iter_state *iter, loff_t *off) { void *element; spin_lock_irq(&iter->hashbin->hb_spinlock); for (element = hashbin_get_first(iter->hashbin); element != NULL; element = hashbin_get_next(iter->hashbin)) { if (!off || (*off)-- == 0) { /* NB: hashbin left locked */ return element; } } spin_unlock_irq(&iter->hashbin->hb_spinlock); iter->hashbin = NULL; return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Hemminger6569.15%233.33%
Linus Torvalds (pre-git)1920.21%116.67%
Jean Tourrilhes66.38%116.67%
Dan Carpenter22.13%116.67%
David S. Miller22.13%116.67%
Total94100.00%6100.00%


static void *irlmp_seq_start(struct seq_file *seq, loff_t *pos) { struct irlmp_iter_state *iter = seq->private; void *v; loff_t off = *pos; iter->hashbin = NULL; if (off-- == 0) return LSAP_START_TOKEN; iter->hashbin = irlmp->unconnected_lsaps; v = irlmp_seq_hb_idx(iter, &off); if (v) return v; if (off-- == 0) return LINK_START_TOKEN; iter->hashbin = irlmp->links; return irlmp_seq_hb_idx(iter, &off); }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Hemminger9390.29%360.00%
Jean Tourrilhes87.77%120.00%
Linus Torvalds (pre-git)21.94%120.00%
Total103100.00%5100.00%


static void *irlmp_seq_next(struct seq_file *seq, void *v, loff_t *pos) { struct irlmp_iter_state *iter = seq->private; ++*pos; if (v == LSAP_START_TOKEN) { /* start of list of lsaps */ iter->hashbin = irlmp->unconnected_lsaps; v = irlmp_seq_hb_idx(iter, NULL); return v ? v : LINK_START_TOKEN; } if (v == LINK_START_TOKEN) { /* start of list of links */ iter->hashbin = irlmp->links; return irlmp_seq_hb_idx(iter, NULL); } v = hashbin_get_next(iter->hashbin); if (v == NULL) { /* no more in this hash bin */ spin_unlock_irq(&iter->hashbin->hb_spinlock); if (iter->hashbin == irlmp->unconnected_lsaps) v = LINK_START_TOKEN; iter->hashbin = NULL; } return v; }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Hemminger13292.96%250.00%
Linus Torvalds (pre-git)96.34%125.00%
David S. Miller10.70%125.00%
Total142100.00%4100.00%


static void irlmp_seq_stop(struct seq_file *seq, void *v) { struct irlmp_iter_state *iter = seq->private; if (iter->hashbin) spin_unlock_irq(&iter->hashbin->hb_spinlock); }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Hemminger3895.00%133.33%
David S. Miller12.50%133.33%
Linus Torvalds (pre-git)12.50%133.33%
Total40100.00%3100.00%


static int irlmp_seq_show(struct seq_file *seq, void *v) { const struct irlmp_iter_state *iter = seq->private; struct lsap_cb *self = v; if (v == LSAP_START_TOKEN) seq_puts(seq, "Unconnected LSAPs:\n"); else if (v == LINK_START_TOKEN) seq_puts(seq, "\nRegistered Link Layers:\n"); else if (iter->hashbin == irlmp->unconnected_lsaps) { self = v; IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -EINVAL; ); seq_printf(seq, "lsap state: %s, ", irlsap_state[ self->lsap_state]); seq_printf(seq, "slsap_sel: %#02x, dlsap_sel: %#02x, ", self->slsap_sel, self->dlsap_sel); seq_printf(seq, "(%s)", self->notify.name); seq_printf(seq, "\n"); } else if (iter->hashbin == irlmp->links) { struct lap_cb *lap = v; seq_printf(seq, "lap state: %s, ", irlmp_state[lap->lap_state]); seq_printf(seq, "saddr: %#08x, daddr: %#08x, ", lap->saddr, lap->daddr); seq_printf(seq, "num lsaps: %d", HASHBIN_GET_SIZE(lap->lsaps)); seq_printf(seq, "\n"); /* Careful for priority inversions here ! * All other uses of attrib spinlock are independent of * the object spinlock, so we are safe. Jean II */ spin_lock(&lap->lsaps->hb_spinlock); seq_printf(seq, "\n Connected LSAPs:\n"); for (self = (struct lsap_cb *) hashbin_get_first(lap->lsaps); self != NULL; self = (struct lsap_cb *)hashbin_get_next(lap->lsaps)) { IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, goto outloop;); seq_printf(seq, " lsap state: %s, ", irlsap_state[ self->lsap_state]); seq_printf(seq, "slsap_sel: %#02x, dlsap_sel: %#02x, ", self->slsap_sel, self->dlsap_sel); seq_printf(seq, "(%s)", self->notify.name); seq_putc(seq, '\n'); } IRDA_ASSERT_LABEL(outloop:) spin_unlock(&lap->lsaps->hb_spinlock); seq_putc(seq, '\n'); } else return -EINVAL; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Hemminger19858.06%111.11%
Linus Torvalds (pre-git)10831.67%333.33%
Jean Tourrilhes236.74%222.22%
Linus Torvalds72.05%111.11%
David S. Miller41.17%111.11%
Steven Cole10.29%111.11%
Total341100.00%9100.00%

static const struct seq_operations irlmp_seq_ops = { .start = irlmp_seq_start, .next = irlmp_seq_next, .stop = irlmp_seq_stop, .show = irlmp_seq_show, };
static int irlmp_seq_open(struct inode *inode, struct file *file) { IRDA_ASSERT(irlmp != NULL, return -EINVAL;); return seq_open_private(file, &irlmp_seq_ops, sizeof(struct irlmp_iter_state)); }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Hemminger2565.79%120.00%
Pavel Emelyanov821.05%120.00%
Linus Torvalds (pre-git)37.89%120.00%
Jean Tourrilhes25.26%240.00%
Total38100.00%5100.00%

const struct file_operations irlmp_seq_fops = { .owner = THIS_MODULE, .open = irlmp_seq_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release_private, }; #endif /* PROC_FS */

Overall Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)397259.49%1217.14%
Jean Tourrilhes153122.93%1724.29%
Stephen Hemminger70410.54%45.71%
Linus Torvalds2153.22%710.00%
Dan Carpenter420.63%22.86%
Joe Perches380.57%22.86%
Harvey Harrison340.51%11.43%
David S. Miller310.46%34.29%
Martin Dalecki170.25%11.43%
Adrian Bunk170.25%11.43%
Graf Yang160.24%11.43%
Hinko Kocevar120.18%11.43%
Al Viro90.13%22.86%
Pavel Emelyanov80.12%11.43%
Arnaldo Carvalho de Melo50.07%11.43%
Ross Burton40.06%11.43%
Steven Cole40.06%22.86%
Samuel Ortiz40.06%22.86%
Peter Zijlstra30.04%11.43%
Panagiotis Issaris30.04%11.43%
André Goddard Rosa20.03%11.43%
Alan Cox10.01%11.43%
Fengguang Wu10.01%11.43%
Hideaki Yoshifuji / 吉藤英明10.01%11.43%
Arjan van de Ven10.01%11.43%
Jan Engelhardt10.01%11.43%
Philippe De Muyter10.01%11.43%
Total6677100.00%70100.00%
Directory: net/irda
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.