📄 iriap.c
字号:
__be32 tmp_be32; __be16 tmp_be16; __u8 *fp; IRDA_DEBUG(4, "%s()\n", __FUNCTION__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IAS_MAGIC, return;); IRDA_ASSERT(value != NULL, return;); IRDA_ASSERT(value->len <= 1024, return;); /* Initialize variables */ n = 0; /* * We must adjust the size of the response after the length of the * value. We add 32 bytes because of the 6 bytes for the frame and * max 5 bytes for the value coding. */ tx_skb = alloc_skb(value->len + self->max_header_size + 32, GFP_ATOMIC); if (!tx_skb) return; /* Reserve space for MUX and LAP header */ skb_reserve(tx_skb, self->max_header_size); skb_put(tx_skb, 6); fp = tx_skb->data; /* Build frame */ fp[n++] = GET_VALUE_BY_CLASS | IAP_LST; fp[n++] = ret_code; /* Insert list length (MSB first) */ tmp_be16 = __constant_htons(0x0001); memcpy(fp+n, &tmp_be16, 2); n += 2; /* Insert object identifier ( MSB first) */ tmp_be16 = cpu_to_be16(obj_id); memcpy(fp+n, &tmp_be16, 2); n += 2; switch (value->type) { case IAS_STRING: skb_put(tx_skb, 3 + value->len); fp[n++] = value->type; fp[n++] = 0; /* ASCII */ fp[n++] = (__u8) value->len; memcpy(fp+n, value->t.string, value->len); n+=value->len; break; case IAS_INTEGER: skb_put(tx_skb, 5); fp[n++] = value->type; tmp_be32 = cpu_to_be32(value->t.integer); memcpy(fp+n, &tmp_be32, 4); n += 4; break; case IAS_OCT_SEQ: skb_put(tx_skb, 3 + value->len); fp[n++] = value->type; tmp_be16 = cpu_to_be16(value->len); memcpy(fp+n, &tmp_be16, 2); n += 2; memcpy(fp+n, value->t.oct_seq, value->len); n+=value->len; break; case IAS_MISSING: IRDA_DEBUG( 3, "%s: sending IAS_MISSING\n", __FUNCTION__); skb_put(tx_skb, 1); fp[n++] = value->type; break; default: IRDA_DEBUG(0, "%s(), type not implemented!\n", __FUNCTION__); break; } iriap_do_r_connect_event(self, IAP_CALL_RESPONSE, tx_skb); /* Drop reference count - see state_r_execute(). */ dev_kfree_skb(tx_skb);}/* * Function iriap_getvaluebyclass_indication (self, skb) * * getvaluebyclass is requested from peer LM-IAS * */static void iriap_getvaluebyclass_indication(struct iriap_cb *self, struct sk_buff *skb){ struct ias_object *obj; struct ias_attrib *attrib; int name_len; int attr_len; char name[IAS_MAX_CLASSNAME + 1]; /* 60 bytes */ char attr[IAS_MAX_ATTRIBNAME + 1]; /* 60 bytes */ __u8 *fp; int n; IRDA_DEBUG(4, "%s()\n", __FUNCTION__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IAS_MAGIC, return;); IRDA_ASSERT(skb != NULL, return;); fp = skb->data; n = 1; name_len = fp[n++]; memcpy(name, fp+n, name_len); n+=name_len; name[name_len] = '\0'; attr_len = fp[n++]; memcpy(attr, fp+n, attr_len); n+=attr_len; attr[attr_len] = '\0'; IRDA_DEBUG(4, "LM-IAS: Looking up %s: %s\n", name, attr); obj = irias_find_object(name); if (obj == NULL) { IRDA_DEBUG(2, "LM-IAS: Object %s not found\n", name); iriap_getvaluebyclass_response(self, 0x1235, IAS_CLASS_UNKNOWN, &irias_missing); return; } IRDA_DEBUG(4, "LM-IAS: found %s, id=%d\n", obj->name, obj->id); attrib = irias_find_attrib(obj, attr); if (attrib == NULL) { IRDA_DEBUG(2, "LM-IAS: Attribute %s not found\n", attr); iriap_getvaluebyclass_response(self, obj->id, IAS_ATTRIB_UNKNOWN, &irias_missing); return; } /* We have a match; send the value. */ iriap_getvaluebyclass_response(self, obj->id, IAS_SUCCESS, attrib->value); return;}/* * Function iriap_send_ack (void) * * Currently not used * */void iriap_send_ack(struct iriap_cb *self){ struct sk_buff *tx_skb; __u8 *frame; IRDA_DEBUG(2, "%s()\n", __FUNCTION__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IAS_MAGIC, return;); tx_skb = alloc_skb(LMP_MAX_HEADER + 1, GFP_ATOMIC); if (!tx_skb) return; /* Reserve space for MUX and LAP header */ skb_reserve(tx_skb, self->max_header_size); skb_put(tx_skb, 1); frame = tx_skb->data; /* Build frame */ frame[0] = IAP_LST | IAP_ACK | self->operation; irlmp_data_request(self->lsap, tx_skb);}void iriap_connect_request(struct iriap_cb *self){ int ret; IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IAS_MAGIC, return;); ret = irlmp_connect_request(self->lsap, LSAP_IAS, self->saddr, self->daddr, NULL, NULL); if (ret < 0) { IRDA_DEBUG(0, "%s(), connect failed!\n", __FUNCTION__); self->confirm(IAS_DISCONNECT, 0, NULL, self->priv); }}/* * Function iriap_connect_confirm (handle, skb) * * LSAP connection confirmed! * */static void iriap_connect_confirm(void *instance, void *sap, struct qos_info *qos, __u32 max_seg_size, __u8 max_header_size, struct sk_buff *skb){ struct iriap_cb *self; self = (struct iriap_cb *) instance; IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IAS_MAGIC, return;); IRDA_ASSERT(skb != NULL, return;); self->max_data_size = max_seg_size; self->max_header_size = max_header_size; del_timer(&self->watchdog_timer); iriap_do_client_event(self, IAP_LM_CONNECT_CONFIRM, skb); /* Drop reference count - see state_s_make_call(). */ dev_kfree_skb(skb);}/* * Function iriap_connect_indication ( handle, skb) * * Remote LM-IAS is requesting connection * */static void iriap_connect_indication(void *instance, void *sap, struct qos_info *qos, __u32 max_seg_size, __u8 max_header_size, struct sk_buff *skb){ struct iriap_cb *self, *new; IRDA_DEBUG(1, "%s()\n", __FUNCTION__); self = (struct iriap_cb *) instance; IRDA_ASSERT(skb != NULL, return;); IRDA_ASSERT(self != NULL, goto out;); IRDA_ASSERT(self->magic == IAS_MAGIC, goto out;); /* Start new server */ new = iriap_open(LSAP_IAS, IAS_SERVER, NULL, NULL); if (!new) { IRDA_DEBUG(0, "%s(), open failed\n", __FUNCTION__); goto out; } /* Now attach up the new "socket" */ new->lsap = irlmp_dup(self->lsap, new); if (!new->lsap) { IRDA_DEBUG(0, "%s(), dup failed!\n", __FUNCTION__); goto out; } new->max_data_size = max_seg_size; new->max_header_size = max_header_size; /* Clean up the original one to keep it in listen state */ irlmp_listen(self->lsap); iriap_do_server_event(new, IAP_LM_CONNECT_INDICATION, skb);out: /* Drop reference count - see state_r_disconnect(). */ dev_kfree_skb(skb);}/* * Function iriap_data_indication (handle, skb) * * Receives data from connection identified by handle from IrLMP * */static int iriap_data_indication(void *instance, void *sap, struct sk_buff *skb){ struct iriap_cb *self; __u8 *frame; __u8 opcode; IRDA_DEBUG(3, "%s()\n", __FUNCTION__); self = (struct iriap_cb *) instance; IRDA_ASSERT(skb != NULL, return 0;); IRDA_ASSERT(self != NULL, goto out;); IRDA_ASSERT(self->magic == IAS_MAGIC, goto out;); frame = skb->data; if (self->mode == IAS_SERVER) { /* Call server */ IRDA_DEBUG(4, "%s(), Calling server!\n", __FUNCTION__); iriap_do_r_connect_event(self, IAP_RECV_F_LST, skb); goto out; } opcode = frame[0]; if (~opcode & IAP_LST) { IRDA_WARNING("%s:, IrIAS multiframe commands or " "results is not implemented yet!\n", __FUNCTION__); goto out; } /* Check for ack frames since they don't contain any data */ if (opcode & IAP_ACK) { IRDA_DEBUG(0, "%s() Got ack frame!\n", __FUNCTION__); goto out; } opcode &= ~IAP_LST; /* Mask away LST bit */ switch (opcode) { case GET_INFO_BASE: IRDA_DEBUG(0, "IrLMP GetInfoBaseDetails not implemented!\n"); break; case GET_VALUE_BY_CLASS: iriap_do_call_event(self, IAP_RECV_F_LST, NULL); switch (frame[1]) { case IAS_SUCCESS: iriap_getvaluebyclass_confirm(self, skb); break; case IAS_CLASS_UNKNOWN: IRDA_DEBUG(1, "%s(), No such class!\n", __FUNCTION__); /* Finished, close connection! */ iriap_disconnect_request(self); /* * Warning, the client might close us, so remember * no to use self anymore after calling confirm */ if (self->confirm) self->confirm(IAS_CLASS_UNKNOWN, 0, NULL, self->priv); break; case IAS_ATTRIB_UNKNOWN: IRDA_DEBUG(1, "%s(), No such attribute!\n", __FUNCTION__); /* Finished, close connection! */ iriap_disconnect_request(self); /* * Warning, the client might close us, so remember * no to use self anymore after calling confirm */ if (self->confirm) self->confirm(IAS_ATTRIB_UNKNOWN, 0, NULL, self->priv); break; } break; default: IRDA_DEBUG(0, "%s(), Unknown op-code: %02x\n", __FUNCTION__, opcode); break; }out: /* Cleanup - sub-calls will have done skb_get() as needed. */ dev_kfree_skb(skb); return 0;}/* * Function iriap_call_indication (self, skb) * * Received call to server from peer LM-IAS * */void iriap_call_indication(struct iriap_cb *self, struct sk_buff *skb){ __u8 *fp; __u8 opcode; IRDA_DEBUG(4, "%s()\n", __FUNCTION__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IAS_MAGIC, return;); IRDA_ASSERT(skb != NULL, return;); fp = skb->data; opcode = fp[0]; if (~opcode & 0x80) { IRDA_WARNING("%s: IrIAS multiframe commands or results " "is not implemented yet!\n", __FUNCTION__); return; } opcode &= 0x7f; /* Mask away LST bit */ switch (opcode) { case GET_INFO_BASE: IRDA_WARNING("%s: GetInfoBaseDetails not implemented yet!\n", __FUNCTION__); break; case GET_VALUE_BY_CLASS: iriap_getvaluebyclass_indication(self, skb); break; } /* skb will be cleaned up in iriap_data_indication */}/* * Function iriap_watchdog_timer_expired (data) * * Query has taken too long time, so abort * */static void iriap_watchdog_timer_expired(void *data){ struct iriap_cb *self = (struct iriap_cb *) data; IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IAS_MAGIC, return;); /* iriap_close(self); */}#ifdef CONFIG_PROC_FSstatic const char *ias_value_types[] = { "IAS_MISSING", "IAS_INTEGER", "IAS_OCT_SEQ", "IAS_STRING"};static inline struct ias_object *irias_seq_idx(loff_t pos){ struct ias_object *obj; for (obj = (struct ias_object *) hashbin_get_first(irias_objects); obj; obj = (struct ias_object *) hashbin_get_next(irias_objects)) { if (pos-- == 0) break; } return obj;}static void *irias_seq_start(struct seq_file *seq, loff_t *pos){ spin_lock_irq(&irias_objects->hb_spinlock); return *pos ? irias_seq_idx(*pos - 1) : SEQ_START_TOKEN;}static void *irias_seq_next(struct seq_file *seq, void *v, loff_t *pos){ ++*pos; return (v == SEQ_START_TOKEN) ? (void *) hashbin_get_first(irias_objects) : (void *) hashbin_get_next(irias_objects);}static void irias_seq_stop(struct seq_file *seq, void *v){ spin_unlock_irq(&irias_objects->hb_spinlock);}static int irias_seq_show(struct seq_file *seq, void *v){ if (v == SEQ_START_TOKEN) seq_puts(seq, "LM-IAS Objects:\n"); else { struct ias_object *obj = v; struct ias_attrib *attrib; IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return -EINVAL;); seq_printf(seq, "name: %s, id=%d\n", obj->name, obj->id); /* Careful for priority inversions here ! * All other uses of attrib spinlock are independent of * the object spinlock, so we are safe. Jean II */ spin_lock(&obj->attribs->hb_spinlock); /* List all attributes for this object */ for (attrib = (struct ias_attrib *) hashbin_get_first(obj->attribs); attrib != NULL; attrib = (struct ias_attrib *) hashbin_get_next(obj->attribs)) { IRDA_ASSERT(attrib->magic == IAS_ATTRIB_MAGIC, goto outloop; ); seq_printf(seq, " - Attribute name: \"%s\", ", attrib->name); seq_printf(seq, "value[%s]: ", ias_value_types[attrib->value->type]); switch (attrib->value->type) { case IAS_INTEGER: seq_printf(seq, "%d\n", attrib->value->t.integer); break; case IAS_STRING: seq_printf(seq, "\"%s\"\n", attrib->value->t.string); break; case IAS_OCT_SEQ: seq_printf(seq, "octet sequence (%d bytes)\n", attrib->value->len); break; case IAS_MISSING: seq_puts(seq, "missing\n"); break; default: seq_printf(seq, "type %d?\n", attrib->value->type); } seq_putc(seq, '\n'); } IRDA_ASSERT_LABEL(outloop:) spin_unlock(&obj->attribs->hb_spinlock); } return 0;}static const struct seq_operations irias_seq_ops = { .start = irias_seq_start, .next = irias_seq_next, .stop = irias_seq_stop, .show = irias_seq_show,};static int irias_seq_open(struct inode *inode, struct file *file){ IRDA_ASSERT( irias_objects != NULL, return -EINVAL;); return seq_open(file, &irias_seq_ops);}const struct file_operations irias_seq_fops = { .owner = THIS_MODULE, .open = irias_seq_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release,};#endif /* PROC_FS */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -