📄 irlap.c
字号:
*/#ifdef CONFIG_IRDA_ULTRAvoid irlap_unitdata_indication(struct irlap_cb *self, struct sk_buff *skb){ IRDA_DEBUG(1, __FUNCTION__ "()\n"); ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); ASSERT(skb != NULL, return;); /* Hide LAP header from IrLMP layer */ skb_pull(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER); skb_get(skb); /*LEVEL4*/ irlmp_link_unitdata_indication(self->notify.instance, skb);}#endif /* CONFIG_IRDA_ULTRA *//* * Function irlap_disconnect_request (void) * * Request to disconnect connection by service user */void irlap_disconnect_request(struct irlap_cb *self) { IRDA_DEBUG(3, __FUNCTION__ "()\n"); ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); /* Don't disconnect until all data frames are successfully sent */ if (skb_queue_len(&self->txq) > 0) { self->disconnect_pending = TRUE; return; } /* Check if we are in the right state for disconnecting */ switch (self->state) { case LAP_XMIT_P: /* FALLTROUGH */ case LAP_XMIT_S: /* FALLTROUGH */ case LAP_CONN: /* FALLTROUGH */ case LAP_RESET_WAIT: /* FALLTROUGH */ case LAP_RESET_CHECK: irlap_do_event(self, DISCONNECT_REQUEST, NULL, NULL); break; default: IRDA_DEBUG(2, __FUNCTION__ "(), disconnect pending!\n"); self->disconnect_pending = TRUE; break; }}/* * Function irlap_disconnect_indication (void) * * Disconnect request from other device * */void irlap_disconnect_indication(struct irlap_cb *self, LAP_REASON reason) { IRDA_DEBUG(1, __FUNCTION__ "(), reason=%s\n", lap_reasons[reason]); ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); /* Flush queues */ irlap_flush_all_queues(self); switch (reason) { case LAP_RESET_INDICATION: IRDA_DEBUG(1, __FUNCTION__ "(), Sending reset request!\n"); irlap_do_event(self, RESET_REQUEST, NULL, NULL); break; case LAP_NO_RESPONSE: /* FALLTROUGH */ case LAP_DISC_INDICATION: /* FALLTROUGH */ case LAP_FOUND_NONE: /* FALLTROUGH */ case LAP_MEDIA_BUSY: irlmp_link_disconnect_indication(self->notify.instance, self, reason, NULL); break; default: ERROR(__FUNCTION__ "(), Unknown reason %d\n", reason); }}/* * Function irlap_discovery_request (gen_addr_bit) * * Start one single discovery operation. * */void irlap_discovery_request(struct irlap_cb *self, discovery_t *discovery) { struct irlap_info info; ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); ASSERT(discovery != NULL, return;); IRDA_DEBUG(4, __FUNCTION__ "(), nslots = %d\n", discovery->nslots); ASSERT((discovery->nslots == 1) || (discovery->nslots == 6) || (discovery->nslots == 8) || (discovery->nslots == 16), return;); /* Discovery is only possible in NDM mode */ if (self->state != LAP_NDM) { IRDA_DEBUG(4, __FUNCTION__ "(), discovery only possible in NDM mode\n"); irlap_discovery_confirm(self, NULL); /* Note : in theory, if we are not in NDM, we could postpone * the discovery like we do for connection request. * In practice, it's not worth it. If the media was busy, * it's likely next time around it won't be busy. If we are * in REPLY state, we will get passive discovery info & event. * Jean II */ return; } /* Check if last discovery request finished in time, or if * it was aborted due to the media busy flag. */ if (self->discovery_log != NULL) { hashbin_delete(self->discovery_log, (FREE_FUNC) kfree); self->discovery_log = NULL; } self->discovery_log= hashbin_new(HB_LOCAL); info.S = discovery->nslots; /* Number of slots */ info.s = 0; /* Current slot */ self->discovery_cmd = discovery; info.discovery = discovery; /* sysctl_slot_timeout bounds are checked in irsysctl.c - Jean II */ self->slot_timeout = sysctl_slot_timeout * HZ / 1000; irlap_do_event(self, DISCOVERY_REQUEST, NULL, &info);}/* * Function irlap_discovery_confirm (log) * * A device has been discovered in front of this station, we * report directly to LMP. */void irlap_discovery_confirm(struct irlap_cb *self, hashbin_t *discovery_log) { ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); ASSERT(self->notify.instance != NULL, return;); /* * Check for successful discovery, since we are then allowed to clear * the media busy condition (IrLAP 6.13.4 - p.94). This should allow * us to make connection attempts much faster and easier (i.e. no * collisions). * Setting media busy to false will also generate an event allowing * to process pending events in NDM state machine. * Note : the spec doesn't define what's a successful discovery is. * If we want Ultra to work, it's successful even if there is * nobody discovered - Jean II */ if (discovery_log) irda_device_set_media_busy(self->netdev, FALSE); /* Inform IrLMP */ irlmp_link_discovery_confirm(self->notify.instance, discovery_log);}/* * Function irlap_discovery_indication (log) * * Somebody is trying to discover us! * */void irlap_discovery_indication(struct irlap_cb *self, discovery_t *discovery) { IRDA_DEBUG(4, __FUNCTION__ "()\n"); ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); ASSERT(discovery != NULL, return;); ASSERT(self->notify.instance != NULL, return;); /* A device is very likely to connect immediately after it performs * a successful discovery. This means that in our case, we are much * more likely to receive a connection request over the medium. * So, we backoff to avoid collisions. * IrLAP spec 6.13.4 suggest 100ms... * Note : this little trick actually make a *BIG* difference. If I set * my Linux box with discovery enabled and one Ultra frame sent every * second, my Palm has no trouble connecting to it every time ! * Jean II */ irda_device_set_media_busy(self->netdev, SMALL); irlmp_link_discovery_indication(self->notify.instance, discovery);}/* * Function irlap_status_indication (quality_of_link) * * * */void irlap_status_indication(struct irlap_cb *self, int quality_of_link) { switch (quality_of_link) { case STATUS_NO_ACTIVITY: MESSAGE("IrLAP, no activity on link!\n"); break; case STATUS_NOISY: MESSAGE("IrLAP, noisy link!\n"); break; default: break; } irlmp_status_indication(self->notify.instance, quality_of_link, LOCK_NO_CHANGE);}/* * Function irlap_reset_indication (void) * * * */void irlap_reset_indication(struct irlap_cb *self){ IRDA_DEBUG(1, __FUNCTION__ "()\n"); ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); if (self->state == LAP_RESET_WAIT) irlap_do_event(self, RESET_REQUEST, NULL, NULL); else irlap_do_event(self, RESET_RESPONSE, NULL, NULL);}/* * Function irlap_reset_confirm (void) * * * */void irlap_reset_confirm(void){ IRDA_DEBUG(1, __FUNCTION__ "()\n");}/* * Function irlap_generate_rand_time_slot (S, s) * * Generate a random time slot between s and S-1 where * S = Number of slots (0 -> S-1) * s = Current slot */int irlap_generate_rand_time_slot(int S, int s) { static int rand; int slot; ASSERT((S - s) > 0, return 0;); rand += jiffies; rand ^= (rand << 12); rand ^= (rand >> 20); slot = s + rand % (S-s); ASSERT((slot >= s) || (slot < S), return 0;); return slot;}/* * Function irlap_update_nr_received (nr) * * Remove all acknowledged frames in current window queue. This code is * not intuitive and you should not try to change it. If you think it * contains bugs, please mail a patch to the author instead. */void irlap_update_nr_received(struct irlap_cb *self, int nr) { struct sk_buff *skb = NULL; int count = 0; /* * Remove all the ack-ed frames from the window queue. */ /* * Optimize for the common case. It is most likely that the receiver * will acknowledge all the frames we have sent! So in that case we * delete all frames stored in window. */ if (nr == self->vs) { while ((skb = skb_dequeue(&self->wx_list)) != NULL) { dev_kfree_skb(skb); } /* The last acked frame is the next to send minus one */ self->va = nr - 1; } else { /* Remove all acknowledged frames in current window */ while ((skb_peek(&self->wx_list) != NULL) && (((self->va+1) % 8) != nr)) { skb = skb_dequeue(&self->wx_list); dev_kfree_skb(skb); self->va = (self->va + 1) % 8; count++; } } /* Advance window */ self->window = self->window_size - skb_queue_len(&self->wx_list);}/* * Function irlap_validate_ns_received (ns) * * Validate the next to send (ns) field from received frame. */int irlap_validate_ns_received(struct irlap_cb *self, int ns) { /* ns as expected? */ if (ns == self->vr) return NS_EXPECTED; /* * Stations are allowed to treat invalid NS as unexpected NS * IrLAP, Recv ... with-invalid-Ns. p. 84 */ return NS_UNEXPECTED; /* return NR_INVALID; */}/* * Function irlap_validate_nr_received (nr) * * Validate the next to receive (nr) field from received frame. * */int irlap_validate_nr_received(struct irlap_cb *self, int nr) { /* nr as expected? */ if (nr == self->vs) { IRDA_DEBUG(4, __FUNCTION__ "(), expected!\n"); return NR_EXPECTED; } /* * unexpected nr? (but within current window), first we check if the * ns numbers of the frames in the current window wrap. */ if (self->va < self->vs) { if ((nr >= self->va) && (nr <= self->vs)) return NR_UNEXPECTED; } else { if ((nr >= self->va) || (nr <= self->vs)) return NR_UNEXPECTED; } /* Invalid nr! */ return NR_INVALID;}/* * Function irlap_initiate_connection_state () * * Initialize the connection state parameters * */void irlap_initiate_connection_state(struct irlap_cb *self) { IRDA_DEBUG(4, __FUNCTION__ "()\n"); ASSERT(self != NULL, return;); ASSERT(self->magic == LAP_MAGIC, return;); /* Next to send and next to receive */ self->vs = self->vr = 0; /* Last frame which got acked (0 - 1) % 8 */ self->va = 7; self->window = 1; self->remote_busy = FALSE; self->retry_count = 0;}/* * Function irlap_wait_min_turn_around (self, qos) * * Wait negotiated minimum turn around time, this function actually sets * the number of BOS's that must be sent before the next transmitted
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -