📄 irlap.c
字号:
/********************************************************************* * * Filename: irlap.c * Version: 1.0 * Description: IrLAP implementation for Linux * Status: Stable * Author: Dag Brattli <dagb@cs.uit.no> * Created at: Mon Aug 4 20:40:53 1997 * Modified at: Tue Dec 14 09:26:44 1999 * Modified by: Dag Brattli <dagb@cs.uit.no> * * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved. * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * ********************************************************************/#include <linux/config.h>#include <linux/malloc.h>#include <linux/string.h>#include <linux/skbuff.h>#include <linux/delay.h>#include <linux/proc_fs.h>#include <linux/init.h>#include <linux/random.h>#include <net/irda/irda.h>#include <net/irda/irda_device.h>#include <net/irda/irqueue.h>#include <net/irda/irlmp.h>#include <net/irda/irlmp_frame.h>#include <net/irda/irlap_frame.h>#include <net/irda/irlap.h>#include <net/irda/timer.h>#include <net/irda/qos.h>#include <net/irda/irlap_comp.h>hashbin_t *irlap = NULL;int sysctl_slot_timeout = SLOT_TIMEOUT * 1000 / HZ;static void __irlap_close(struct irlap_cb *self);static char *lap_reasons[] = { "ERROR, NOT USED", "LAP_DISC_INDICATION", "LAP_NO_RESPONSE", "LAP_RESET_INDICATION", "LAP_FOUND_NONE", "LAP_MEDIA_BUSY", "LAP_PRIMARY_CONFLICT", "ERROR, NOT USED",};#ifdef CONFIG_PROC_FSint irlap_proc_read(char *, char **, off_t, int);#endif /* CONFIG_PROC_FS */int __init irlap_init(void){ /* Allocate master array */ irlap = hashbin_new(HB_LOCAL); if (irlap == NULL) { ERROR(__FUNCTION__ "(), can't allocate irlap hashbin!\n"); return -ENOMEM; }#ifdef CONFIG_IRDA_COMPRESSION irlap_compressors = hashbin_new(HB_LOCAL); if (irlap_compressors == NULL) { WARNING(__FUNCTION__ "(), can't allocate compressors hashbin!\n"); return -ENOMEM; }#endif return 0;}void irlap_cleanup(void){ ASSERT(irlap != NULL, return;); hashbin_delete(irlap, (FREE_FUNC) __irlap_close);#ifdef CONFIG_IRDA_COMPRESSION hashbin_delete(irlap_compressors, (FREE_FUNC) kfree);#endif}/* * Function irlap_open (driver) * * Initialize IrLAP layer * */struct irlap_cb *irlap_open(struct net_device *dev, struct qos_info *qos){ struct irlap_cb *self; IRDA_DEBUG(4, __FUNCTION__ "()\n"); /* Initialize the irlap structure. */ self = kmalloc(sizeof(struct irlap_cb), GFP_KERNEL); if (self == NULL) return NULL; memset(self, 0, sizeof(struct irlap_cb)); self->magic = LAP_MAGIC; /* Make a binding between the layers */ self->netdev = dev; self->qos_dev = qos; /* FIXME: should we get our own field? */ dev->atalk_ptr = self; irlap_next_state(self, LAP_OFFLINE); /* Initialize transmit queue */ skb_queue_head_init(&self->txq); skb_queue_head_init(&self->txq_ultra); skb_queue_head_init(&self->wx_list); /* My unique IrLAP device address! */ get_random_bytes(&self->saddr, sizeof(self->saddr)); memcpy(dev->dev_addr, &self->saddr, 4); init_timer(&self->slot_timer); init_timer(&self->query_timer); init_timer(&self->discovery_timer); init_timer(&self->final_timer); init_timer(&self->poll_timer); init_timer(&self->wd_timer); init_timer(&self->backoff_timer); init_timer(&self->media_busy_timer); irlap_apply_default_connection_parameters(self); self->N3 = 3; /* # connections attemts to try before giving up */ irlap_next_state(self, LAP_NDM); hashbin_insert(irlap, (irda_queue_t *) self, self->saddr, NULL); irlmp_register_link(self, self->saddr, &self->notify); return self;}/* * Function __irlap_close (self) * * Remove IrLAP and all allocated memory. Stop any pending timers. * */static void __irlap_close(struct irlap_cb *self){ ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); /* Stop timers */ del_timer(&self->slot_timer); del_timer(&self->query_timer); del_timer(&self->discovery_timer); del_timer(&self->final_timer); del_timer(&self->poll_timer); del_timer(&self->wd_timer); del_timer(&self->backoff_timer); del_timer(&self->media_busy_timer); irlap_flush_all_queues(self); self->magic = 0; kfree(self);}/* * Function irlap_close (self) * * Remove IrLAP instance * */void irlap_close(struct irlap_cb *self) { struct irlap_cb *lap; IRDA_DEBUG(4, __FUNCTION__ "()\n"); ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); irlap_disconnect_indication(self, LAP_DISC_INDICATION); irlmp_unregister_link(self->saddr); self->notify.instance = NULL; /* Be sure that we manage to remove ourself from the hash */ lap = hashbin_remove(irlap, self->saddr, NULL); if (!lap) { IRDA_DEBUG(1, __FUNCTION__ "(), Didn't find myself!\n"); return; } __irlap_close(lap);}/* * Function irlap_connect_indication (self, skb) * * Another device is attempting to make a connection * */void irlap_connect_indication(struct irlap_cb *self, struct sk_buff *skb) { IRDA_DEBUG(4, __FUNCTION__ "()\n"); ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); irlap_init_qos_capabilities(self, NULL); /* No user QoS! */ skb_get(skb); /*LEVEL4*/ irlmp_link_connect_indication(self->notify.instance, self->saddr, self->daddr, &self->qos_tx, skb);}/* * Function irlap_connect_response (self, skb) * * Service user has accepted incomming connection * */void irlap_connect_response(struct irlap_cb *self, struct sk_buff *skb) { IRDA_DEBUG(4, __FUNCTION__ "()\n"); irlap_do_event(self, CONNECT_RESPONSE, skb, NULL); kfree_skb(skb);}/* * Function irlap_connect_request (self, daddr, qos_user, sniff) * * Request connection with another device, sniffing is not implemented * yet. * */void irlap_connect_request(struct irlap_cb *self, __u32 daddr, struct qos_info *qos_user, int sniff) { IRDA_DEBUG(3, __FUNCTION__ "(), daddr=0x%08x\n", daddr); ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); self->daddr = daddr; /* * If the service user specifies QoS values for this connection, * then use them */ irlap_init_qos_capabilities(self, qos_user); if ((self->state == LAP_NDM) && !self->media_busy) irlap_do_event(self, CONNECT_REQUEST, NULL, NULL); else self->connect_pending = TRUE;}/* * Function irlap_connect_confirm (self, skb) * * Connection request has been accepted * */void irlap_connect_confirm(struct irlap_cb *self, struct sk_buff *skb){ IRDA_DEBUG(4, __FUNCTION__ "()\n"); ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); skb_get(skb); /*LEVEL4*/ irlmp_link_connect_confirm(self->notify.instance, &self->qos_tx, skb);}/* * Function irlap_data_indication (self, skb) * * Received data frames from IR-port, so we just pass them up to * IrLMP for further processing * */void irlap_data_indication(struct irlap_cb *self, struct sk_buff *skb, int unreliable) { /* Hide LAP header from IrLMP layer */ skb_pull(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);#ifdef CONFIG_IRDA_COMPRESSION if (self->qos_tx.compression.value) { skb_get(skb); /*LEVEL4*/ skb = irlap_decompress_frame(self, skb); if (!skb) { IRDA_DEBUG(1, __FUNCTION__ "(), Decompress error!\n"); return; } }#endif skb_get(skb); /*LEVEL4*/ irlmp_link_data_indication(self->notify.instance, skb, unreliable);}/* * Function irlap_data_request (self, skb) * * Queue data for transmission, must wait until XMIT state * */void irlap_data_request(struct irlap_cb *self, struct sk_buff *skb, int unreliable){ ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); IRDA_DEBUG(3, __FUNCTION__ "()\n");#ifdef CONFIG_IRDA_COMPRESSION if (self->qos_tx.compression.value) { skb = irlap_compress_frame(self, skb); if (!skb) { IRDA_DEBUG(1, __FUNCTION__ "(), Compress error!\n"); return; } }#endif ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER), return;); skb_push(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER); /* * Must set frame format now so that the rest of the code knows * if its dealing with an I or an UI frame */ if (unreliable) skb->data[1] = UI_FRAME; else skb->data[1] = I_FRAME; /* * Send event if this frame only if we are in the right state * FIXME: udata should be sent first! (skb_queue_head?) */ if ((self->state == LAP_XMIT_P) || (self->state == LAP_XMIT_S)) { /* * Check if the transmit queue contains some unsent frames, * and if so, make sure they are sent first */ if (!skb_queue_empty(&self->txq)) { skb_queue_tail(&self->txq, skb); skb = skb_dequeue(&self->txq); ASSERT(skb != NULL, return;); } irlap_do_event(self, SEND_I_CMD, skb, NULL); kfree_skb(skb); } else skb_queue_tail(&self->txq, skb);}/* * Function irlap_unitdata_request (self, skb) * * Send Ultra data. This is data that must be sent outside any connection * */#ifdef CONFIG_IRDA_ULTRAvoid irlap_unitdata_request(struct irlap_cb *self, struct sk_buff *skb){ ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); IRDA_DEBUG(3, __FUNCTION__ "()\n"); ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER), return;); skb_push(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER); skb->data[0] = CBROADCAST; skb->data[1] = UI_FRAME; skb_queue_tail(&self->txq_ultra, skb); irlap_do_event(self, SEND_UI_FRAME, NULL, NULL);}#endif /*CONFIG_IRDA_ULTRA *//* * Function irlap_udata_indication (self, skb) * * Receive Ultra data. This is data that is received outside any connection * */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -