📄 irlap_frame.c
字号:
irlap_send_i_frame(self, tx_skb, RSP_FRAME); } else { irlap_send_ui_frame(self, skb_get(skb), self->caddr, RSP_FRAME); self->window -= 1; }}/* * Function irlap_resend_rejected_frames (nr) * * Resend frames which has not been acknowledged. Should be safe to * traverse the list without locking it since this function will only be * called from interrupt context (BH) */void irlap_resend_rejected_frames(struct irlap_cb *self, int command){ struct sk_buff *tx_skb; struct sk_buff *skb; int count; IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LAP_MAGIC, return;); /* Initialize variables */ count = skb_queue_len(&self->wx_list); /* Resend unacknowledged frame(s) */ skb = skb_peek(&self->wx_list); while (skb != NULL) { irlap_wait_min_turn_around(self, &self->qos_tx); /* We copy the skb to be retransmitted since we will have to * modify it. Cloning will confuse packet sniffers */ /* tx_skb = skb_clone( skb, GFP_ATOMIC); */ tx_skb = skb_copy(skb, GFP_ATOMIC); if (!tx_skb) { IRDA_DEBUG(0, "%s(), unable to copy\n", __FUNCTION__); return; } /* Clear old Nr field + poll bit */ tx_skb->data[1] &= 0x0f; /* * Set poll bit on the last frame retransmitted */ if (count-- == 1) tx_skb->data[1] |= PF_BIT; /* Set p/f bit */ else tx_skb->data[1] &= ~PF_BIT; /* Clear p/f bit */ irlap_send_i_frame(self, tx_skb, command); /* * If our skb is the last buffer in the list, then * we are finished, if not, move to the next sk-buffer */ if (skb == skb_peek_tail(&self->wx_list)) skb = NULL; else skb = skb->next; }#if 0 /* Not yet */ /* * We can now fill the window with additional data frames */ while (!skb_queue_empty(&self->txq)) { IRDA_DEBUG(0, "%s(), sending additional frames!\n", __FUNCTION__); if (self->window > 0) { skb = skb_dequeue( &self->txq); IRDA_ASSERT(skb != NULL, return;); /* * If send window > 1 then send frame with pf * bit cleared */ if ((self->window > 1) && !skb_queue_empty(&self->txq)) { irlap_send_data_primary(self, skb); } else { irlap_send_data_primary_poll(self, skb); } kfree_skb(skb); } }#endif}void irlap_resend_rejected_frame(struct irlap_cb *self, int command){ struct sk_buff *tx_skb; struct sk_buff *skb; IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LAP_MAGIC, return;); /* Resend unacknowledged frame(s) */ skb = skb_peek(&self->wx_list); if (skb != NULL) { irlap_wait_min_turn_around(self, &self->qos_tx); /* We copy the skb to be retransmitted since we will have to * modify it. Cloning will confuse packet sniffers */ /* tx_skb = skb_clone( skb, GFP_ATOMIC); */ tx_skb = skb_copy(skb, GFP_ATOMIC); if (!tx_skb) { IRDA_DEBUG(0, "%s(), unable to copy\n", __FUNCTION__); return; } /* Clear old Nr field + poll bit */ tx_skb->data[1] &= 0x0f; /* Set poll/final bit */ tx_skb->data[1] |= PF_BIT; /* Set p/f bit */ irlap_send_i_frame(self, tx_skb, command); }}/* * Function irlap_send_ui_frame (self, skb, command) * * Contruct and transmit an Unnumbered Information (UI) frame * */void irlap_send_ui_frame(struct irlap_cb *self, struct sk_buff *skb, __u8 caddr, int command){ IRDA_DEBUG(4, "%s()\n", __FUNCTION__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LAP_MAGIC, return;); IRDA_ASSERT(skb != NULL, return;); /* Insert connection address */ skb->data[0] = caddr | ((command) ? CMD_FRAME : 0); irlap_queue_xmit(self, skb);}/* * Function irlap_send_i_frame (skb) * * Contruct and transmit Information (I) frame */static void irlap_send_i_frame(struct irlap_cb *self, struct sk_buff *skb, int command){ /* Insert connection address */ skb->data[0] = self->caddr; skb->data[0] |= (command) ? CMD_FRAME : 0; /* Insert next to receive (Vr) */ skb->data[1] |= (self->vr << 5); /* insert nr */ irlap_queue_xmit(self, skb);}/* * Function irlap_recv_i_frame (skb, frame) * * Receive and parse an I (Information) frame, no harm in making it inline * since it's called only from one single place (irlap_driver_rcv). */static inline void irlap_recv_i_frame(struct irlap_cb *self, struct sk_buff *skb, struct irlap_info *info, int command){ info->nr = skb->data[1] >> 5; /* Next to receive */ info->pf = skb->data[1] & PF_BIT; /* Final bit */ info->ns = (skb->data[1] >> 1) & 0x07; /* Next to send */ /* Check if this is a command or a response frame */ if (command) irlap_do_event(self, RECV_I_CMD, skb, info); else irlap_do_event(self, RECV_I_RSP, skb, info);}/* * Function irlap_recv_ui_frame (self, skb, info) * * Receive and parse an Unnumbered Information (UI) frame * */static void irlap_recv_ui_frame(struct irlap_cb *self, struct sk_buff *skb, struct irlap_info *info){ IRDA_DEBUG( 4, "%s()\n", __FUNCTION__); info->pf = skb->data[1] & PF_BIT; /* Final bit */ irlap_do_event(self, RECV_UI_FRAME, skb, info);}/* * Function irlap_recv_frmr_frame (skb, frame) * * Received Frame Reject response. * */static void irlap_recv_frmr_frame(struct irlap_cb *self, struct sk_buff *skb, struct irlap_info *info){ __u8 *frame; int w, x, y, z; IRDA_DEBUG(0, "%s()\n", __FUNCTION__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LAP_MAGIC, return;); IRDA_ASSERT(skb != NULL, return;); IRDA_ASSERT(info != NULL, return;); if (!pskb_may_pull(skb, 4)) { IRDA_ERROR("%s: frame too short!\n", __FUNCTION__); return; } frame = skb->data; info->nr = frame[2] >> 5; /* Next to receive */ info->pf = frame[2] & PF_BIT; /* Final bit */ info->ns = (frame[2] >> 1) & 0x07; /* Next to send */ w = frame[3] & 0x01; x = frame[3] & 0x02; y = frame[3] & 0x04; z = frame[3] & 0x08; if (w) { IRDA_DEBUG(0, "Rejected control field is undefined or not " "implemented.\n"); } if (x) { IRDA_DEBUG(0, "Rejected control field was invalid because it " "contained a non permitted I field.\n"); } if (y) { IRDA_DEBUG(0, "Received I field exceeded the maximum negotiated " "for the existing connection or exceeded the maximum " "this station supports if no connection exists.\n"); } if (z) { IRDA_DEBUG(0, "Rejected control field control field contained an " "invalid Nr count.\n"); } irlap_do_event(self, RECV_FRMR_RSP, skb, info);}/* * Function irlap_send_test_frame (self, daddr) * * Send a test frame response * */void irlap_send_test_frame(struct irlap_cb *self, __u8 caddr, __u32 daddr, struct sk_buff *cmd){ struct sk_buff *tx_skb; struct test_frame *frame; __u8 *info; tx_skb = alloc_skb(cmd->len + sizeof(struct test_frame), GFP_ATOMIC); if (!tx_skb) return; /* Broadcast frames must include saddr and daddr fields */ if (caddr == CBROADCAST) { frame = (struct test_frame *) skb_put(tx_skb, sizeof(struct test_frame)); /* Insert the swapped addresses */ frame->saddr = cpu_to_le32(self->saddr); frame->daddr = cpu_to_le32(daddr); } else frame = (struct test_frame *) skb_put(tx_skb, LAP_ADDR_HEADER + LAP_CTRL_HEADER); frame->caddr = caddr; frame->control = TEST_RSP | PF_BIT; /* Copy info */ info = skb_put(tx_skb, cmd->len); memcpy(info, cmd->data, cmd->len); /* Return to sender */ irlap_wait_min_turn_around(self, &self->qos_tx); irlap_queue_xmit(self, tx_skb);}/* * Function irlap_recv_test_frame (self, skb) * * Receive a test frame * */static void irlap_recv_test_frame(struct irlap_cb *self, struct sk_buff *skb, struct irlap_info *info, int command){ struct test_frame *frame; IRDA_DEBUG(2, "%s()\n", __FUNCTION__); if (!pskb_may_pull(skb, sizeof(*frame))) { IRDA_ERROR("%s: frame too short!\n", __FUNCTION__); return; } frame = (struct test_frame *) skb->data; /* Broadcast frames must carry saddr and daddr fields */ if (info->caddr == CBROADCAST) { if (skb->len < sizeof(struct test_frame)) { IRDA_DEBUG(0, "%s() test frame too short!\n", __FUNCTION__); return; } /* Read and swap addresses */ info->daddr = le32_to_cpu(frame->saddr); info->saddr = le32_to_cpu(frame->daddr); /* Make sure frame is addressed to us */ if ((info->saddr != self->saddr) && (info->saddr != BROADCAST)) { return; } } if (command) irlap_do_event(self, RECV_TEST_CMD, skb, info); else irlap_do_event(self, RECV_TEST_RSP, skb, info);}/* * Function irlap_driver_rcv (skb, netdev, ptype) * * Called when a frame is received. Dispatches the right receive function * for processing of the frame. * * Note on skb management : * After calling the higher layers of the IrDA stack, we always * kfree() the skb, which drop the reference count (and potentially * destroy it). * If a higher layer of the stack want to keep the skb around (to put * in a queue or pass it to the higher layer), it will need to use * skb_get() to keep a reference on it. This is usually done at the * LMP level in irlmp.c. * Jean II */int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype, struct net_device *orig_dev){ struct irlap_info info; struct irlap_cb *self; int command; __u8 control; if (dev->nd_net != &init_net) goto out; /* FIXME: should we get our own field? */ self = (struct irlap_cb *) dev->atalk_ptr; /* If the net device is down, then IrLAP is gone! */ if (!self || self->magic != LAP_MAGIC) { dev_kfree_skb(skb); return -1; } /* We are no longer an "old" protocol, so we need to handle * share and non linear skbs. This should never happen, so * we don't need to be clever about it. Jean II */ if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { IRDA_ERROR("%s: can't clone shared skb!\n", __FUNCTION__); dev_kfree_skb(skb); return -1; } /* Check if frame is large enough for parsing */ if (!pskb_may_pull(skb, 2)) { IRDA_ERROR("%s: frame too short!\n", __FUNCTION__); dev_kfree_skb(skb); return -1; } command = skb->data[0] & CMD_FRAME; info.caddr = skb->data[0] & CBROADCAST; info.pf = skb->data[1] & PF_BIT; info.control = skb->data[1] & ~PF_BIT; /* Mask away poll/final bit */ control = info.control; /* First we check if this frame has a valid connection address */ if ((info.caddr != self->caddr) && (info.caddr != CBROADCAST)) { IRDA_DEBUG(0, "%s(), wrong connection address!\n", __FUNCTION__); goto out; } /* * Optimize for the common case and check if the frame is an * I(nformation) frame. Only I-frames have bit 0 set to 0 */ if (~control & 0x01) { irlap_recv_i_frame(self, skb, &info, command); goto out; } /* * We now check is the frame is an S(upervisory) frame. Only * S-frames have bit 0 set to 1 and bit 1 set to 0 */ if (~control & 0x02) { /* * Received S(upervisory) frame, check which frame type it is * only the first nibble is of interest */ switch (control & 0x0f) { case RR: irlap_recv_rr_frame(self, skb, &info, command); break; case RNR: irlap_recv_rnr_frame(self, skb, &info, command); break; case REJ: irlap_recv_rej_frame(self, skb, &info, command); break; case SREJ: irlap_recv_srej_frame(self, skb, &info, command); break; default: IRDA_WARNING("%s: Unknown S-frame %02x received!\n", __FUNCTION__, info.control); break; } goto out; } /* * This must be a C(ontrol) frame */ switch (control) { case XID_RSP: irlap_recv_discovery_xid_rsp(self, skb, &info); break; case XID_CMD: irlap_recv_discovery_xid_cmd(self, skb, &info); break; case SNRM_CMD: irlap_recv_snrm_cmd(self, skb, &info); break; case DM_RSP: irlap_do_event(self, RECV_DM_RSP, skb, &info); break; case DISC_CMD: /* And RD_RSP since they have the same value */ irlap_recv_disc_frame(self, skb, &info, command); break; case TEST_CMD: irlap_recv_test_frame(self, skb, &info, command); break; case UA_RSP: irlap_recv_ua_frame(self, skb, &info); break; case FRMR_RSP: irlap_recv_frmr_frame(self, skb, &info); break; case UI_FRAME: irlap_recv_ui_frame(self, skb, &info); break; default: IRDA_WARNING("%s: Unknown frame %02x received!\n", __FUNCTION__, info.control); break; }out: /* Always drop our reference on the skb */ dev_kfree_skb(skb); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -