Fix FCP and ARM source node ID on firewire-core
The firewire-core (juju) backend of libraw1394 installs address range mappings on the default ioctl fd, i.e. a file that represents a random device on the chosen port. It receives incoming requests from any sender node via this address range mapping. Due to a kernel ABI limitation, the sender node ID is not known though. So far libraw1394 simply assumed the node ID of the device that provided the default ioctl fd. This only works if there is only one accessible fd on the entire bus. This limitation caused for example libffado to fail to work with another AV/C or IIDC device attached to the bus, because node IDs of FCP requests and FCP responses did not match since the latter were wrong. FCP clients which did not check sender node IDs were seemingly not affected by this bug. The bug is fixed by a kernel ABI extension in Linux 2.6.36. This libraw1394 change implements libraw1394's counterpart to this ABI extension. Hence this libraw1394 fix requires - kernel-headers 2.6.36 or later at build time of libraw1394 - kernel 2.6.36 or later at runtime. Otherwise, libraw1394 simply degrades to the faulty previous behaviour. Side note: The change of IMPLEMENTED_CDEV_ABI_VERSION to 4 requires that we fill in struct fw_cdev_allocate.region_end which was added in the ABI v4. Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
This commit is contained in:
parent
3fc1f00be3
commit
d3ace3dfb4
111
src/fw.c
111
src/fw.c
|
@ -28,7 +28,11 @@
|
|||
/*
|
||||
* ABI version history is documented in linux/firewire-cdev.h.
|
||||
*/
|
||||
#ifdef FW_CDEV_EVENT_REQUEST2
|
||||
#define IMPLEMENTED_CDEV_ABI_VERSION 4
|
||||
#else
|
||||
#define IMPLEMENTED_CDEV_ABI_VERSION 2
|
||||
#endif
|
||||
|
||||
int
|
||||
fw_errcode_to_errno(raw1394_errcode_t errcode)
|
||||
|
@ -215,17 +219,20 @@ handle_lost_device(fw_handle_t handle, int i)
|
|||
|
||||
struct address_closure {
|
||||
int (*callback)(raw1394handle_t handle, struct address_closure *ac,
|
||||
struct fw_cdev_event_request *request, int i);
|
||||
int tcode, unsigned long long offset,
|
||||
int source_node_id, unsigned kernel_handle,
|
||||
size_t length, void *data);
|
||||
};
|
||||
|
||||
static int
|
||||
handle_fcp_request(raw1394handle_t handle, struct address_closure *ac,
|
||||
struct fw_cdev_event_request *request, int i)
|
||||
int tcode, unsigned long long offset, int source_node_id,
|
||||
unsigned kernel_handle, size_t length, void *data)
|
||||
{
|
||||
struct fw_cdev_send_response response;
|
||||
int is_response;
|
||||
|
||||
response.handle = request->handle;
|
||||
response.handle = kernel_handle;
|
||||
response.rcode = RCODE_COMPLETE;
|
||||
response.length = 0;
|
||||
response.data = 0;
|
||||
|
@ -233,23 +240,20 @@ handle_fcp_request(raw1394handle_t handle, struct address_closure *ac,
|
|||
if (handle->mode.fw->fcp_handler == NULL)
|
||||
response.rcode = RCODE_ADDRESS_ERROR;
|
||||
|
||||
if (request->tcode >= TCODE_WRITE_RESPONSE)
|
||||
if (tcode >= TCODE_WRITE_RESPONSE)
|
||||
response.rcode = RCODE_CONFLICT_ERROR;
|
||||
|
||||
if (ioctl(handle->mode.fw->devices[i].fd,
|
||||
if (ioctl(handle->mode.fw->ioctl_fd,
|
||||
FW_CDEV_IOC_SEND_RESPONSE, &response) < 0)
|
||||
return -1;
|
||||
|
||||
if (response.rcode != RCODE_COMPLETE)
|
||||
return 0;
|
||||
|
||||
is_response = request->offset >= CSR_REGISTER_BASE + CSR_FCP_RESPONSE;
|
||||
is_response = offset >= CSR_REGISTER_BASE + CSR_FCP_RESPONSE;
|
||||
|
||||
return handle->mode.fw->fcp_handler(handle,
|
||||
handle->mode.fw->devices[i].node_id,
|
||||
is_response,
|
||||
request->length,
|
||||
(unsigned char *) request->data);
|
||||
return handle->mode.fw->fcp_handler(handle, source_node_id,
|
||||
is_response, length, data);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -307,7 +311,22 @@ handle_device_event(raw1394handle_t handle,
|
|||
|
||||
case FW_CDEV_EVENT_REQUEST:
|
||||
ac = u64_to_ptr(u->request.closure);
|
||||
return ac->callback(handle, ac, &u->request, i);
|
||||
return ac->callback(handle, ac, u->request.tcode,
|
||||
u->request.offset,
|
||||
/* wild guess, but can't do better */
|
||||
fwhandle->devices[i].node_id,
|
||||
u->request.handle,
|
||||
u->request.length, u->request.data);
|
||||
|
||||
#ifdef FW_CDEV_EVENT_REQUEST2 /* added in kernel 2.6.36 */
|
||||
case FW_CDEV_EVENT_REQUEST2:
|
||||
ac = u64_to_ptr(u->request.closure);
|
||||
return ac->callback(handle, ac, u->request2.tcode,
|
||||
u->request2.offset,
|
||||
u->request2.source_node_id,
|
||||
u->request2.handle,
|
||||
u->request2.length, u->request2.data);
|
||||
#endif
|
||||
|
||||
#ifdef FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED /* added in kernel 2.6.30 */
|
||||
case FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED:
|
||||
|
@ -695,7 +714,7 @@ struct request_response_block {
|
|||
};
|
||||
|
||||
struct allocation {
|
||||
struct address_closure closure;
|
||||
struct address_closure closure; /* must be first member */
|
||||
struct allocation *next;
|
||||
__u32 handle;
|
||||
byte_t *buffer;
|
||||
|
@ -710,7 +729,8 @@ struct allocation {
|
|||
|
||||
static int
|
||||
handle_arm_request(raw1394handle_t handle, struct address_closure *ac,
|
||||
struct fw_cdev_event_request *request, int i)
|
||||
int tcode, unsigned long long offset, int source_node_id,
|
||||
unsigned kernel_handle, size_t length, void *data)
|
||||
{
|
||||
fw_handle_t fwhandle = handle->mode.fw;
|
||||
struct allocation *allocation = (struct allocation *) ac;
|
||||
|
@ -718,19 +738,19 @@ handle_arm_request(raw1394handle_t handle, struct address_closure *ac,
|
|||
struct fw_cdev_send_response response;
|
||||
arm_options_t type;
|
||||
size_t in_length;
|
||||
int offset;
|
||||
int pos;
|
||||
|
||||
offset = request->offset - allocation->offset;
|
||||
response.handle = request->handle;
|
||||
pos = offset - allocation->offset;
|
||||
response.handle = kernel_handle;
|
||||
|
||||
switch (request->tcode) {
|
||||
switch (tcode) {
|
||||
case TCODE_WRITE_QUADLET_REQUEST:
|
||||
case TCODE_WRITE_BLOCK_REQUEST:
|
||||
printf("got write request, offset=0x%012llx, length=%d\n",
|
||||
request->offset, request->length);
|
||||
offset, (int)length);
|
||||
|
||||
type = RAW1394_ARM_WRITE;
|
||||
in_length = request->length;
|
||||
in_length = length;
|
||||
response.rcode = RCODE_COMPLETE;
|
||||
response.length = 0;
|
||||
response.data = 0;
|
||||
|
@ -739,18 +759,29 @@ handle_arm_request(raw1394handle_t handle, struct address_closure *ac,
|
|||
case TCODE_READ_QUADLET_REQUEST:
|
||||
case TCODE_READ_BLOCK_REQUEST:
|
||||
printf("got read request, offset=0x%012llx, length=%d\n",
|
||||
request->offset, request->length);
|
||||
offset, (int)length);
|
||||
|
||||
type = RAW1394_ARM_READ;
|
||||
in_length = 0;
|
||||
response.rcode = RCODE_COMPLETE;
|
||||
response.length = request->length;
|
||||
response.data = ptr_to_u64(allocation->data + offset);
|
||||
response.length = length;
|
||||
response.data = ptr_to_u64(allocation->data + pos);
|
||||
break;
|
||||
|
||||
case TCODE_LOCK_REQUEST:
|
||||
/*
|
||||
* TCODE_LOCK_REQUEST is generated by ABI v3 and older, cannot
|
||||
* be handled. Fall through for now. FIXME.
|
||||
*/
|
||||
case TCODE_LOCK_MASK_SWAP:
|
||||
case TCODE_LOCK_COMPARE_SWAP:
|
||||
case TCODE_LOCK_FETCH_ADD:
|
||||
case TCODE_LOCK_LITTLE_ADD:
|
||||
case TCODE_LOCK_BOUNDED_ADD:
|
||||
case TCODE_LOCK_WRAP_ADD:
|
||||
case TCODE_LOCK_VENDOR_DEPENDENT:
|
||||
type = RAW1394_ARM_LOCK;
|
||||
in_length = request->length;
|
||||
in_length = length;
|
||||
response.length = 4;
|
||||
break;
|
||||
|
||||
|
@ -764,17 +795,16 @@ handle_arm_request(raw1394handle_t handle, struct address_closure *ac,
|
|||
response.rcode = RCODE_TYPE_ERROR;
|
||||
response.length = 0;
|
||||
response.data = 0;
|
||||
if (ioctl(fwhandle->devices[i].fd,
|
||||
if (ioctl(fwhandle->ioctl_fd,
|
||||
FW_CDEV_IOC_SEND_RESPONSE, &response) < 0)
|
||||
return -1;
|
||||
} else if (!(allocation->client_transactions & type)) {
|
||||
if (type == RAW1394_ARM_WRITE)
|
||||
memcpy(allocation->data + offset,
|
||||
request->data, request->length);
|
||||
memcpy(allocation->data + pos, data, length);
|
||||
else if (type == RAW1394_ARM_LOCK)
|
||||
/* FIXME: do lock ops here */;
|
||||
|
||||
if (ioctl(fwhandle->devices[i].fd,
|
||||
if (ioctl(fwhandle->ioctl_fd,
|
||||
FW_CDEV_IOC_SEND_RESPONSE, &response) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
@ -792,30 +822,28 @@ handle_arm_request(raw1394handle_t handle, struct address_closure *ac,
|
|||
rrb->request_response.response = &rrb->response;
|
||||
|
||||
rrb->request.destination_nodeid = fwhandle->reset.local_node_id;
|
||||
rrb->request.source_nodeid = fwhandle->devices[i].node_id;
|
||||
rrb->request.destination_offset = request->offset;
|
||||
rrb->request.source_nodeid = source_node_id;
|
||||
rrb->request.destination_offset = offset;
|
||||
rrb->request.tlabel = 0;
|
||||
if (request->tcode < 0x10) {
|
||||
rrb->request.tcode = request->tcode;
|
||||
if (tcode < 0x10) {
|
||||
rrb->request.tcode = tcode;
|
||||
rrb->request.extended_transaction_code = 0;
|
||||
} else {
|
||||
rrb->request.tcode = TCODE_LOCK_REQUEST;
|
||||
rrb->request.extended_transaction_code = request->tcode - 0x10;
|
||||
rrb->request.extended_transaction_code = tcode - 0x10;
|
||||
}
|
||||
rrb->request.generation = fwhandle->reset.generation;
|
||||
rrb->request.buffer_length = in_length;
|
||||
rrb->request.buffer = rrb->data;
|
||||
memcpy(rrb->request.buffer, request->data, in_length);
|
||||
memcpy(rrb->request.buffer, data, in_length);
|
||||
|
||||
rrb->response.response_code = response.rcode;
|
||||
rrb->response.buffer_length = response.length;
|
||||
rrb->response.buffer = rrb->data + in_length;
|
||||
memcpy(rrb->response.buffer,
|
||||
allocation->data + offset, response.length);
|
||||
memcpy(rrb->response.buffer, allocation->data + pos, response.length);
|
||||
|
||||
return fwhandle->arm_tag_handler(handle, allocation->tag, type,
|
||||
request->length,
|
||||
&rrb->request_response);
|
||||
length, &rrb->request_response);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -849,7 +877,9 @@ fw_arm_register(fw_handle_t handle, nodeaddr_t start,
|
|||
request.offset = start;
|
||||
request.length = length;
|
||||
request.closure = ptr_to_u64(&allocation->closure);
|
||||
|
||||
#if IMPLEMENTED_CDEV_ABI_VERSION >= 4
|
||||
request.region_end = start + length;
|
||||
#endif
|
||||
retval = ioctl(handle->ioctl_fd, FW_CDEV_IOC_ALLOCATE, &request);
|
||||
if (retval < 0) {
|
||||
free(allocation);
|
||||
|
@ -1343,6 +1373,9 @@ fw_start_fcp_listen(fw_handle_t handle)
|
|||
request.offset = CSR_REGISTER_BASE + CSR_FCP_COMMAND;
|
||||
request.length = CSR_FCP_END - CSR_FCP_COMMAND;
|
||||
request.closure = ptr_to_u64(closure);
|
||||
#if IMPLEMENTED_CDEV_ABI_VERSION >= 4
|
||||
request.region_end = CSR_REGISTER_BASE + CSR_FCP_END;
|
||||
#endif
|
||||
if (ioctl(handle->ioctl_fd, FW_CDEV_IOC_ALLOCATE, &request) < 0)
|
||||
return -1;
|
||||
|
||||
|
|
Reference in New Issue