⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 irlap_frame.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/********************************************************************* * * Filename:      irlap_frame.c * Version:       1.0 * Description:   Build and transmit IrLAP frames * Status:        Stable * Author:        Dag Brattli <dagb@cs.uit.no> * Created at:    Tue Aug 19 10:27:26 1997 * Modified at:   Wed Jan  5 08:59:04 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/skbuff.h>#include <linux/if.h>#include <linux/if_ether.h>#include <linux/netdevice.h>#include <linux/irda.h>#include <net/pkt_sched.h>#include <net/sock.h>#include <asm/byteorder.h>#include <net/irda/irda.h>#include <net/irda/irda_device.h>#include <net/irda/irlap.h>#include <net/irda/wrapper.h>#include <net/irda/timer.h>#include <net/irda/irlap_frame.h>#include <net/irda/qos.h>static void irlap_send_i_frame(struct irlap_cb *self, struct sk_buff *skb,			       int command);/* * Function irlap_insert_info (self, skb) * *    Insert minimum turnaround time and speed information into the skb. We *    need to do this since it's per packet relevant information. Safe to *    have this function inlined since it's only called from one place */static inline void irlap_insert_info(struct irlap_cb *self,				     struct sk_buff *skb){	struct irda_skb_cb *cb = (struct irda_skb_cb *) skb->cb;	/*	 * Insert MTT (min. turn time) and speed into skb, so that the	 * device driver knows which settings to use	 */	cb->magic = LAP_MAGIC;	cb->mtt = self->mtt_required;	cb->next_speed = self->speed;	/* Reset */	self->mtt_required = 0;	/*	 * Delay equals negotiated BOFs count, plus the number of BOFs to	 * force the negotiated minimum turnaround time	 */	cb->xbofs = self->bofs_count;	cb->next_xbofs = self->next_bofs;	cb->xbofs_delay = self->xbofs_delay;	/* Reset XBOF's delay (used only for getting min turn time) */	self->xbofs_delay = 0;	/* Put the correct xbofs value for the next packet */	self->bofs_count = self->next_bofs;}/* * Function irlap_queue_xmit (self, skb) * *    A little wrapper for dev_queue_xmit, so we can insert some common *    code into it. */void irlap_queue_xmit(struct irlap_cb *self, struct sk_buff *skb){	/* Some common init stuff */	skb->dev = self->netdev;	skb_reset_mac_header(skb);	skb_reset_network_header(skb);	skb_reset_transport_header(skb);	skb->protocol = htons(ETH_P_IRDA);	skb->priority = TC_PRIO_BESTEFFORT;	irlap_insert_info(self, skb);	if (unlikely(self->mode & IRDA_MODE_MONITOR)) {		IRDA_DEBUG(3, "%s(): %s is in monitor mode\n", __FUNCTION__,			   self->netdev->name);		dev_kfree_skb(skb);		return;	}	dev_queue_xmit(skb);}/* * Function irlap_send_snrm_cmd (void) * *    Transmits a connect SNRM command frame */void irlap_send_snrm_frame(struct irlap_cb *self, struct qos_info *qos){	struct sk_buff *tx_skb;	struct snrm_frame *frame;	int ret;	IRDA_ASSERT(self != NULL, return;);	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);	/* Allocate frame */	tx_skb = alloc_skb(sizeof(struct snrm_frame) +			   IRLAP_NEGOCIATION_PARAMS_LEN,			   GFP_ATOMIC);	if (!tx_skb)		return;	frame = (struct snrm_frame *) skb_put(tx_skb, 2);	/* Insert connection address field */	if (qos)		frame->caddr = CMD_FRAME | CBROADCAST;	else		frame->caddr = CMD_FRAME | self->caddr;	/* Insert control field */	frame->control = SNRM_CMD | PF_BIT;	/*	 *  If we are establishing a connection then insert QoS parameters	 */	if (qos) {		skb_put(tx_skb, 9); /* 25 left */		frame->saddr = cpu_to_le32(self->saddr);		frame->daddr = cpu_to_le32(self->daddr);		frame->ncaddr = self->caddr;		ret = irlap_insert_qos_negotiation_params(self, tx_skb);		if (ret < 0) {			dev_kfree_skb(tx_skb);			return;		}	}	irlap_queue_xmit(self, tx_skb);}/* * Function irlap_recv_snrm_cmd (skb, info) * *    Received SNRM (Set Normal Response Mode) command frame * */static void irlap_recv_snrm_cmd(struct irlap_cb *self, struct sk_buff *skb,				struct irlap_info *info){	struct snrm_frame *frame;	if (pskb_may_pull(skb,sizeof(struct snrm_frame))) {		frame = (struct snrm_frame *) skb->data;		/* Copy the new connection address ignoring the C/R bit */		info->caddr = frame->ncaddr & 0xFE;		/* Check if the new connection address is valid */		if ((info->caddr == 0x00) || (info->caddr == 0xfe)) {			IRDA_DEBUG(3, "%s(), invalid connection address!\n",				   __FUNCTION__);			return;		}		/* Copy peer device address */		info->daddr = le32_to_cpu(frame->saddr);		info->saddr = le32_to_cpu(frame->daddr);		/* Only accept if addressed directly to us */		if (info->saddr != self->saddr) {			IRDA_DEBUG(2, "%s(), not addressed to us!\n",				   __FUNCTION__);			return;		}		irlap_do_event(self, RECV_SNRM_CMD, skb, info);	} else {		/* Signal that this SNRM frame does not contain and I-field */		irlap_do_event(self, RECV_SNRM_CMD, skb, NULL);	}}/* * Function irlap_send_ua_response_frame (qos) * *    Send UA (Unnumbered Acknowledgement) frame * */void irlap_send_ua_response_frame(struct irlap_cb *self, struct qos_info *qos){	struct sk_buff *tx_skb;	struct ua_frame *frame;	int ret;	IRDA_DEBUG(2, "%s() <%ld>\n", __FUNCTION__, jiffies);	IRDA_ASSERT(self != NULL, return;);	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);	/* Allocate frame */	tx_skb = alloc_skb(sizeof(struct ua_frame) +			   IRLAP_NEGOCIATION_PARAMS_LEN,			   GFP_ATOMIC);	if (!tx_skb)		return;	frame = (struct ua_frame *) skb_put(tx_skb, 10);	/* Build UA response */	frame->caddr = self->caddr;	frame->control = UA_RSP | PF_BIT;	frame->saddr = cpu_to_le32(self->saddr);	frame->daddr = cpu_to_le32(self->daddr);	/* Should we send QoS negotiation parameters? */	if (qos) {		ret = irlap_insert_qos_negotiation_params(self, tx_skb);		if (ret < 0) {			dev_kfree_skb(tx_skb);			return;		}	}	irlap_queue_xmit(self, tx_skb);}/* * Function irlap_send_dm_frame (void) * *    Send disconnected mode (DM) frame * */void irlap_send_dm_frame( struct irlap_cb *self){	struct sk_buff *tx_skb = NULL;	struct dm_frame *frame;	IRDA_ASSERT(self != NULL, return;);	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);	tx_skb = alloc_skb(sizeof(struct dm_frame), GFP_ATOMIC);	if (!tx_skb)		return;	frame = (struct dm_frame *)skb_put(tx_skb, 2);	if (self->state == LAP_NDM)		frame->caddr = CBROADCAST;	else		frame->caddr = self->caddr;	frame->control = DM_RSP | PF_BIT;	irlap_queue_xmit(self, tx_skb);}/* * Function irlap_send_disc_frame (void) * *    Send disconnect (DISC) frame * */void irlap_send_disc_frame(struct irlap_cb *self){	struct sk_buff *tx_skb = NULL;	struct disc_frame *frame;	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);	IRDA_ASSERT(self != NULL, return;);	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);	tx_skb = alloc_skb(sizeof(struct disc_frame), GFP_ATOMIC);	if (!tx_skb)		return;	frame = (struct disc_frame *)skb_put(tx_skb, 2);	frame->caddr = self->caddr | CMD_FRAME;	frame->control = DISC_CMD | PF_BIT;	irlap_queue_xmit(self, tx_skb);}/* * Function irlap_send_discovery_xid_frame (S, s, command) * *    Build and transmit a XID (eXchange station IDentifier) discovery *    frame. */void irlap_send_discovery_xid_frame(struct irlap_cb *self, int S, __u8 s,				    __u8 command, discovery_t *discovery){	struct sk_buff *tx_skb = NULL;	struct xid_frame *frame;	__u32 bcast = BROADCAST;	__u8 *info;	IRDA_DEBUG(4, "%s(), s=%d, S=%d, command=%d\n", __FUNCTION__,		   s, S, command);	IRDA_ASSERT(self != NULL, return;);	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);	IRDA_ASSERT(discovery != NULL, return;);	tx_skb = alloc_skb(sizeof(struct xid_frame) + IRLAP_DISCOVERY_INFO_LEN,			   GFP_ATOMIC);	if (!tx_skb)		return;	skb_put(tx_skb, 14);	frame = (struct xid_frame *) tx_skb->data;	if (command) {		frame->caddr = CBROADCAST | CMD_FRAME;		frame->control =  XID_CMD | PF_BIT;	} else {		frame->caddr = CBROADCAST;		frame->control =  XID_RSP | PF_BIT;	}	frame->ident = XID_FORMAT;	frame->saddr = cpu_to_le32(self->saddr);	if (command)		frame->daddr = cpu_to_le32(bcast);	else		frame->daddr = cpu_to_le32(discovery->data.daddr);	switch (S) {	case 1:		frame->flags = 0x00;		break;	case 6:		frame->flags = 0x01;		break;	case 8:		frame->flags = 0x02;		break;	case 16:		frame->flags = 0x03;		break;	default:		frame->flags = 0x02;		break;	}	frame->slotnr = s;	frame->version = 0x00;	/*	 *  Provide info for final slot only in commands, and for all	 *  responses. Send the second byte of the hint only if the	 *  EXTENSION bit is set in the first byte.	 */	if (!command || (frame->slotnr == 0xff)) {		int len;		if (discovery->data.hints[0] & HINT_EXTENSION) {			info = skb_put(tx_skb, 2);			info[0] = discovery->data.hints[0];			info[1] = discovery->data.hints[1];		} else {			info = skb_put(tx_skb, 1);			info[0] = discovery->data.hints[0];		}		info = skb_put(tx_skb, 1);		info[0] = discovery->data.charset;		len = IRDA_MIN(discovery->name_len, skb_tailroom(tx_skb));		info = skb_put(tx_skb, len);		memcpy(info, discovery->data.info, len);	}	irlap_queue_xmit(self, tx_skb);}/* * Function irlap_recv_discovery_xid_rsp (skb, info) * *    Received a XID discovery response * */static void irlap_recv_discovery_xid_rsp(struct irlap_cb *self,					 struct sk_buff *skb,					 struct irlap_info *info){	struct xid_frame *xid;	discovery_t *discovery = NULL;	__u8 *discovery_info;	char *text;	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);	IRDA_ASSERT(self != NULL, return;);	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);	if (!pskb_may_pull(skb, sizeof(struct xid_frame))) {		IRDA_ERROR("%s: frame too short!\n", __FUNCTION__);		return;	}	xid = (struct xid_frame *) skb->data;	info->daddr = le32_to_cpu(xid->saddr);	info->saddr = le32_to_cpu(xid->daddr);	/* Make sure frame is addressed to us */	if ((info->saddr != self->saddr) && (info->saddr != BROADCAST)) {		IRDA_DEBUG(0, "%s(), frame is not addressed to us!\n",			   __FUNCTION__);		return;	}	if ((discovery = kzalloc(sizeof(discovery_t), GFP_ATOMIC)) == NULL) {		IRDA_WARNING("%s: kmalloc failed!\n", __FUNCTION__);		return;	}	discovery->data.daddr = info->daddr;	discovery->data.saddr = self->saddr;	discovery->timestamp = jiffies;	IRDA_DEBUG(4, "%s(), daddr=%08x\n", __FUNCTION__,		   discovery->data.daddr);	discovery_info = skb_pull(skb, sizeof(struct xid_frame));	/* Get info returned from peer */	discovery->data.hints[0] = discovery_info[0];	if (discovery_info[0] & HINT_EXTENSION) {		IRDA_DEBUG(4, "EXTENSION\n");		discovery->data.hints[1] = discovery_info[1];		discovery->data.charset = discovery_info[2];		text = (char *) &discovery_info[3];	} else {		discovery->data.hints[1] = 0;		discovery->data.charset = discovery_info[1];		text = (char *) &discovery_info[2];	}	/*	 *  Terminate info string, should be safe since this is where the	 *  FCS bytes resides.	 */	skb->data[skb->len] = '\0';	strncpy(discovery->data.info, text, NICKNAME_MAX_LEN);	discovery->name_len = strlen(discovery->data.info);	info->discovery = discovery;	irlap_do_event(self, RECV_DISCOVERY_XID_RSP, skb, info);}/* * Function irlap_recv_discovery_xid_cmd (skb, info) * *    Received a XID discovery command * */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -