📄 irttp.c
字号:
* a while before it's run... - Jean II */ /* * If the peer device has given us some credits and we didn't have * anyone from before, then we need to shedule the tx queue. * We need to do that because our Tx have stopped (so we may not * get any LAP flow indication) and the user may be stopped as * well. - Jean II */ if (self->send_credit == n) { /* Restart pushing stuff to LAP */ irttp_run_tx_queue(self); /* Note : we don't want to schedule the todo timer * because it has horrible latency. No tasklets * because the tasklet API is broken. - Jean II */ } return 0;}/* * Function irttp_status_indication (self, reason) * * Status_indication, just pass to the higher layer... * */static void irttp_status_indication(void *instance, LINK_STATUS link, LOCK_STATUS lock){ struct tsap_cb *self; IRDA_DEBUG(4, "%s()\n", __FUNCTION__); self = (struct tsap_cb *) instance; IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;); /* Check if client has already closed the TSAP and gone away */ if (self->close_pend) return; /* * Inform service user if he has requested it */ if (self->notify.status_indication != NULL) self->notify.status_indication(self->notify.instance, link, lock); else IRDA_DEBUG(2, "%s(), no handler\n", __FUNCTION__);}/* * Function irttp_flow_indication (self, reason) * * Flow_indication : IrLAP tells us to send more data. * */static void irttp_flow_indication(void *instance, void *sap, LOCAL_FLOW flow){ struct tsap_cb *self; self = (struct tsap_cb *) instance; IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;); IRDA_DEBUG(4, "%s(instance=%p)\n", __FUNCTION__, self); /* We are "polled" directly from LAP, and the LAP want to fill * its Tx window. We want to do our best to send it data, so that * we maximise the window. On the other hand, we want to limit the * amount of work here so that LAP doesn't hang forever waiting * for packets. - Jean II */ /* Try to send some packets. Currently, LAP calls us every time * there is one free slot, so we will send only one packet. * This allow the scheduler to do its round robin - Jean II */ irttp_run_tx_queue(self); /* Note regarding the interraction with higher layer. * irttp_run_tx_queue() may call the client when its queue * start to empty, via notify.flow_indication(). Initially. * I wanted this to happen in a tasklet, to avoid client * grabbing the CPU, but we can't use tasklets safely. And timer * is definitely too slow. * This will happen only once per LAP window, and usually at * the third packet (unless window is smaller). LAP is still * doing mtt and sending first packet so it's sort of OK * to do that. Jean II */ /* If we need to send disconnect. try to do it now */ if(self->disconnect_pend) irttp_start_todo_timer(self, 0);}/* * Function irttp_flow_request (self, command) * * This function could be used by the upper layers to tell IrTTP to stop * delivering frames if the receive queues are starting to get full, or * to tell IrTTP to start delivering frames again. */void irttp_flow_request(struct tsap_cb *self, LOCAL_FLOW flow){ IRDA_DEBUG(1, "%s()\n", __FUNCTION__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;); switch (flow) { case FLOW_STOP: IRDA_DEBUG(1, "%s(), flow stop\n", __FUNCTION__); self->rx_sdu_busy = TRUE; break; case FLOW_START: IRDA_DEBUG(1, "%s(), flow start\n", __FUNCTION__); self->rx_sdu_busy = FALSE; /* Client say he can accept more data, try to free our * queues ASAP - Jean II */ irttp_run_rx_queue(self); break; default: IRDA_DEBUG(1, "%s(), Unknown flow command!\n", __FUNCTION__); }}EXPORT_SYMBOL(irttp_flow_request);/* * Function irttp_connect_request (self, dtsap_sel, daddr, qos) * * Try to connect to remote destination TSAP selector * */int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel, __u32 saddr, __u32 daddr, struct qos_info *qos, __u32 max_sdu_size, struct sk_buff *userdata){ struct sk_buff *tx_skb; __u8 *frame; __u8 n; IRDA_DEBUG(4, "%s(), max_sdu_size=%d\n", __FUNCTION__, max_sdu_size); IRDA_ASSERT(self != NULL, return -EBADR;); IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -EBADR;); if (self->connected) { if(userdata) dev_kfree_skb(userdata); return -EISCONN; } /* Any userdata supplied? */ if (userdata == NULL) { tx_skb = alloc_skb(TTP_MAX_HEADER + TTP_SAR_HEADER, GFP_ATOMIC); if (!tx_skb) return -ENOMEM; /* Reserve space for MUX_CONTROL and LAP header */ skb_reserve(tx_skb, TTP_MAX_HEADER + TTP_SAR_HEADER); } else { tx_skb = userdata; /* * Check that the client has reserved enough space for * headers */ IRDA_ASSERT(skb_headroom(userdata) >= TTP_MAX_HEADER, { dev_kfree_skb(userdata); return -1; } ); } /* Initialize connection parameters */ self->connected = FALSE; self->avail_credit = 0; self->rx_max_sdu_size = max_sdu_size; self->rx_sdu_size = 0; self->rx_sdu_busy = FALSE; self->dtsap_sel = dtsap_sel; n = self->initial_credit; self->remote_credit = 0; self->send_credit = 0; /* * Give away max 127 credits for now */ if (n > 127) { self->avail_credit=n-127; n = 127; } self->remote_credit = n; /* SAR enabled? */ if (max_sdu_size > 0) { IRDA_ASSERT(skb_headroom(tx_skb) >= (TTP_MAX_HEADER + TTP_SAR_HEADER), { dev_kfree_skb(tx_skb); return -1; } ); /* Insert SAR parameters */ frame = skb_push(tx_skb, TTP_HEADER+TTP_SAR_HEADER); frame[0] = TTP_PARAMETERS | n; frame[1] = 0x04; /* Length */ frame[2] = 0x01; /* MaxSduSize */ frame[3] = 0x02; /* Value length */ put_unaligned(cpu_to_be16((__u16) max_sdu_size), (__be16 *)(frame+4)); } else { /* Insert plain TTP header */ frame = skb_push(tx_skb, TTP_HEADER); /* Insert initial credit in frame */ frame[0] = n & 0x7f; } /* Connect with IrLMP. No QoS parameters for now */ return irlmp_connect_request(self->lsap, dtsap_sel, saddr, daddr, qos, tx_skb);}EXPORT_SYMBOL(irttp_connect_request);/* * Function irttp_connect_confirm (handle, qos, skb) * * Sevice user confirms TSAP connection with peer. * */static void irttp_connect_confirm(void *instance, void *sap, struct qos_info *qos, __u32 max_seg_size, __u8 max_header_size, struct sk_buff *skb){ struct tsap_cb *self; int parameters; int ret; __u8 plen; __u8 n; IRDA_DEBUG(4, "%s()\n", __FUNCTION__); self = (struct tsap_cb *) instance; IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;); IRDA_ASSERT(skb != NULL, return;); self->max_seg_size = max_seg_size - TTP_HEADER; self->max_header_size = max_header_size + TTP_HEADER; /* * Check if we have got some QoS parameters back! This should be the * negotiated QoS for the link. */ if (qos) { IRDA_DEBUG(4, "IrTTP, Negotiated BAUD_RATE: %02x\n", qos->baud_rate.bits); IRDA_DEBUG(4, "IrTTP, Negotiated BAUD_RATE: %d bps.\n", qos->baud_rate.value); } n = skb->data[0] & 0x7f; IRDA_DEBUG(4, "%s(), Initial send_credit=%d\n", __FUNCTION__, n); self->send_credit = n; self->tx_max_sdu_size = 0; self->connected = TRUE; parameters = skb->data[0] & 0x80; IRDA_ASSERT(skb->len >= TTP_HEADER, return;); skb_pull(skb, TTP_HEADER); if (parameters) { plen = skb->data[0]; ret = irda_param_extract_all(self, skb->data+1, IRDA_MIN(skb->len-1, plen), ¶m_info); /* Any errors in the parameter list? */ if (ret < 0) { IRDA_WARNING("%s: error extracting parameters\n", __FUNCTION__); dev_kfree_skb(skb); /* Do not accept this connection attempt */ return; } /* Remove parameters */ skb_pull(skb, IRDA_MIN(skb->len, plen+1)); } IRDA_DEBUG(4, "%s() send=%d,avail=%d,remote=%d\n", __FUNCTION__, self->send_credit, self->avail_credit, self->remote_credit); IRDA_DEBUG(2, "%s(), MaxSduSize=%d\n", __FUNCTION__, self->tx_max_sdu_size); if (self->notify.connect_confirm) { self->notify.connect_confirm(self->notify.instance, self, qos, self->tx_max_sdu_size, self->max_header_size, skb); } else dev_kfree_skb(skb);}/* * Function irttp_connect_indication (handle, skb) * * Some other device is connecting to this TSAP * */void irttp_connect_indication(void *instance, void *sap, struct qos_info *qos, __u32 max_seg_size, __u8 max_header_size, struct sk_buff *skb){ struct tsap_cb *self; struct lsap_cb *lsap; int parameters; int ret; __u8 plen; __u8 n; self = (struct tsap_cb *) instance; IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;); IRDA_ASSERT(skb != NULL, return;); lsap = (struct lsap_cb *) sap; self->max_seg_size = max_seg_size - TTP_HEADER; self->max_header_size = max_header_size+TTP_HEADER; IRDA_DEBUG(4, "%s(), TSAP sel=%02x\n", __FUNCTION__, self->stsap_sel); /* Need to update dtsap_sel if its equal to LSAP_ANY */ self->dtsap_sel = lsap->dlsap_sel; n = skb->data[0] & 0x7f; self->send_credit = n; self->tx_max_sdu_size = 0; parameters = skb->data[0] & 0x80; IRDA_ASSERT(skb->len >= TTP_HEADER, return;); skb_pull(skb, TTP_HEADER); if (parameters) { plen = skb->data[0]; ret = irda_param_extract_all(self, skb->data+1, IRDA_MIN(skb->len-1, plen), ¶m_info); /* Any errors in the parameter list? */ if (ret < 0) { IRDA_WARNING("%s: error extracting parameters\n", __FUNCTION__); dev_kfree_skb(skb); /* Do not accept this connection attempt */ return; } /* Remove parameters */ skb_pull(skb, IRDA_MIN(skb->len, plen+1)); } if (self->notify.connect_indication) { self->notify.connect_indication(self->notify.instance, self, qos, self->tx_max_sdu_size, self->max_header_size, skb); } else dev_kfree_skb(skb);}/* * Function irttp_connect_response (handle, userdata) * * Service user is accepting the connection, just pass it down to * IrLMP! * */int irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size, struct sk_buff *userdata){ struct sk_buff *tx_skb; __u8 *frame; int ret; __u8 n; IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;); IRDA_DEBUG(4, "%s(), Source TSAP selector=%02x\n", __FUNCTION__, self->stsap_sel); /* Any userdata supplied? */ if (userdata == NULL) { tx_skb = alloc_skb(TTP_MAX_HEADER + TTP_SAR_HEADER, GFP_ATOMIC); if (!tx_skb) return -ENOMEM; /* Reserve space for MUX_CONTROL and LAP header */ skb_reserve(tx_skb, TTP_MAX_HEADER + TTP_SAR_HEADER); } else { tx_skb = userdata; /* * Check that the client has reserved enough space for * headers */ IRDA_ASSERT(skb_headroom(userdata) >= TTP_MAX_HEADER, { dev_kfree_skb(userdata); return -1; } ); } self->avail_credit = 0; self->remote_credit = 0; self->rx_max_sdu_size = max_sdu_size; self->rx_sdu_size = 0; self->rx_sdu_busy = FALSE; n = self->initial_credit; /* Frame has only space for max 127 credits (7 bits) */ if (n > 127) { self->avail_credit = n - 127; n = 127; } self->remote_credit = n; self->connected = TRUE; /* SAR enabled? */ if (max_sdu_size > 0) { IRDA_ASSERT(skb_headroom(tx_skb) >= (TTP_MAX_HEADER + TTP_SAR_HEADER), { dev_kfree_skb(tx_skb); return -1; } ); /* Insert TTP header with SAR parameters */ frame = skb_push(tx_skb, TTP_HEADER+TTP_SAR_HEADER); frame[0] = TTP_PARAMETERS | n; frame[1] = 0x04; /* Length */ /* irda_param_insert(self, IRTTP_MAX_SDU_SIZE, frame+1, *//* TTP_SAR_HEADER, ¶m_info) */ frame[2] = 0x01; /* MaxSduSize */ frame[3] = 0x02; /* Value length */ put_unaligned(cpu_to_be16((__u16) max_sdu_size), (__be16 *)(frame+4)); } else { /* Insert TTP header */ frame = skb_push(tx_skb, TTP_HEADER); frame[0] = n & 0x7f; } ret = irlmp_connect_response(self->lsap, tx_skb); return ret;}EXPORT_SYMBOL(irttp_connect_response);/* * Function irttp_dup (self, instance)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -