📄 irlap_frame.c
字号:
/********************************************************************* * * 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 + -