📄 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.* 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.** 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 <string.h>#include "skbuff.h"#include "irda.h"#include "irda_device.h"#include "irqueue.h"#include "irlmp.h"#include "irlmp_frame.h"#include "irlap_frame.h"#include "irlap.h"#include "timer.h"#include "qos.h"hashbin_t *irlap = NULL;int sysctl_slot_timeout = SLOT_TIMEOUT * 1000 / HZ;/* This is the delay of missed pf period before generating an event* to the application. The spec mandate 3 seconds, but in some cases* it's way too long. - Jean II */int sysctl_warn_noreply_time = 3;extern void irlap_queue_xmit(struct irlap_cb *self, struct sk_buff *skb);static void __irlap_close(struct irlap_cb *self);static void irlap_init_qos_capabilities(struct irlap_cb *self, struct qos_info *qos_user);#ifdef CONFIG_IRDA_DEBUGstatic 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",};#endif /* CONFIG_IRDA_DEBUG */int irlap_init(void){/* Check if the compiler did its job properly. * May happen on some ARM configuration, check with Russell King. */ IRDA_ASSERT(sizeof(struct xid_frame) == 14, ;); IRDA_ASSERT(sizeof(struct test_frame) == 10, ;); IRDA_ASSERT(sizeof(struct ua_frame) == 10, ;); IRDA_ASSERT(sizeof(struct snrm_frame) == 11, ;); IRDA_DEBUG(1, "%s()\n", __FUNCTION__); /* Allocate master array */ irlap = hashbin_new(HB_LOCK); if (irlap == NULL) { IRDA_ERROR("%s: can't allocate irlap hashbin!\n", __FUNCTION__); return -ENOMEM; } return 0;}void irlap_cleanup(void){ IRDA_ASSERT(irlap != NULL, return;); hashbin_delete(irlap, (FREE_FUNC) __irlap_close);}void get_random_bytes(__u32* data,__u32 len){ static int temp = 1; temp++;#ifdef BIG_ENDIN switch(len) { case 1: if (temp >= 0xff) { temp = 0x01; } *data = temp<<24; break; case 2: if (temp >= 0xffff) { temp = 0x01; } *data = temp<<16; break; case 4: if (temp >= BROADCAST) { temp = 1; } default: *data = temp; break; }#else switch(len) { case 1: if (temp >= 0xff) { temp = 0x01; } break; case 2: if (temp >= 0xffff) { temp = 0x01; } break; case 4: if (temp >= BROADCAST) { temp = 1; } default: break; } *data = temp;#endif }/** Function irlap_open (driver)** Initialize IrLAP layer**/struct irlap_cb *irlap_open(struct net_device *dev, struct qos_info *qos, const char *hw_name){ struct irlap_cb *self; IRDA_DEBUG(4, "%s()\n", __FUNCTION__); /* Initialize the irlap structure. */ self =(struct irlap_cb*) malloc(sizeof(struct irlap_cb)); if (self == NULL) { IRDA_ERROR("%s() can not allocate memory\n",__FUNCTION__); 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; /* Copy hardware name */ if(hw_name != NULL) { strncpy(self->hw_name, hw_name, sizeof(self->hw_name)); } else { self->hw_name[0] = '\0'; } /* FIXME: should we get our own field? */ dev->atalk_ptr = self; self->state = 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! */ /* We don't want the broadcast address, neither the NULL address * (most often used to signify "invalid"), and we don't want an * address already in use (otherwise connect won't be able * to select the proper link). - Jean II */ do { //xugangan 没有考虑大小端 get_random_bytes(&self->saddr, sizeof(self->saddr)); } while ((self->saddr == 0x0) || (self->saddr == BROADCAST) || (hashbin_lock_find(irlap, self->saddr, NULL)) ); 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 */ self->state = 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){ IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LAP_MAGIC, return;); /* Stop timers */ del_timer(&self->slot_timerid); del_timer(&self->query_timerid); del_timer(&self->discovery_timerid); del_timer(&self->final_timerid); del_timer(&self->poll_timerid); del_timer(&self->wd_timerid); del_timer(&self->backoff_timerid); del_timer(&self->media_busy_timerid); irlap_flush_all_queues(self); self->magic = 0; free(self); self = NULL;}/** Function irlap_close (self)** Remove IrLAP instance**/void irlap_close(struct irlap_cb *self){ struct irlap_cb *lap; IRDA_DEBUG(4, "%s() self = %x,self->magic= %x\n", __FUNCTION__,self,self->magic); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LAP_MAGIC, return;); /* We used to send a LAP_DISC_INDICATION here, but this was * racy. This has been move within irlmp_unregister_link() * itself. Jean II */ /* Kill the LAP and all LSAPs on top of it */ 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(4, "%s(), Didn't find myself!\n", __FUNCTION__); 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(1, "%s()\n", __FUNCTION__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LAP_MAGIC, return;); irlap_init_qos_capabilities(self, NULL); /* No user QoS! */ 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 incoming connection**/void irlap_connect_response(struct irlap_cb *self, struct sk_buff *userdata){ IRDA_DEBUG(2, "%s()\n", __FUNCTION__); irlap_do_event(self, CONNECT_RESPONSE, userdata, NULL);}/** 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, "%s(), daddr=0x%08x ,\n", __FUNCTION__, daddr); IRDA_ASSERT(self != NULL, return;); IRDA_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) { IRDA_DEBUG(1, "%s(), connect_pending flase\n", __FUNCTION__); irlap_do_event(self, CONNECT_REQUEST, NULL, NULL); } else { IRDA_DEBUG(1, "%s(), connect_pending true\n", __FUNCTION__); 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(1, "%s()\n", __FUNCTION__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LAP_MAGIC, return;); irlmp_link_connect_confirm(self->notify.instance, &self->qos_tx, skb);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -