/*************************************************************************** strange_usb_sticks0x05bf.c -------------------------- purpose : Issues rehat-bug #683265, see "https://bugzilla.redhat.com/show_bug.cgi?id=683265" begin : Mon May 30 10:00:00 CEST 2011 changes : * Thu Jun 02 10:00:00 CEST 2011: "debug = 0; // granted by compiler" Version 0.0.1: The modification lies between <@0x05bf_0.0.1>- and -tags. copyright : (C) 2011 by Thomas Bruecker email : public0x05bf@bluewin.ch version : 0.0.1 ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * * ***************************************************************************/ #include #include #include #include /* "struct scsi_cmnd" */ #include /* "struct scsi_device" */ #include /* "struct scsi_sense_hdr" */ #include /* "struct scsi_host" */ #include /* "struct usb_device" */ #include /* "struct usb_device_descriptor" */ #include "debug0x05bf.h" #include "strange_usb_sticks0x05bf.h" #include "usb.h" /* host_to_us */ void __exit exit_strange_usb_sticks(void); static inline void fake_scsi_command_result(struct scsi_cmnd *cmnd); static void __init hook_strange_usb_sticks(void); int __init init_strange_usb_sticks(void); static inline int is_strange_usb_stick(struct scsi_cmnd *cmnd); void __init read_parameters(void); static inline struct usb_device_descriptor* scsi_cmnd_to_usb_device_descriptor(struct scsi_cmnd *cmnd); static void scsi_cmnd_to_usb_product_id( struct scsi_cmnd *cmnd, struct usb_product_id *usb_id ); static void __exit unhook_strange_usb_sticks(void); #define MODULE_INFO_TAB0x05bf " " #define MODULE_NAME0x05bf "strange_usb_sticks" MODULE_AUTHOR("Thomas Bruecker "); MODULE_DESCRIPTION( "Handles strange usb-sticks, see rehat-bug #683265:\n" MODULE_INFO_TAB0x05bf "\"https://bugzilla.redhat.com/show_bug.cgi?id=683265\"" ); MODULE_LICENSE("GPL"); /* <@0x05bf_0.0.1> */ MODULE_VERSION("0.0.1betabeta"); /* */ module_init(init_strange_usb_sticks); module_exit(exit_strange_usb_sticks); /** * MODULE PARAMETERS */ #define MODULE_PARM_DESC_TAB0x05bf " " #define PARAM_PERM0x05bf 00444 /* the permissions for module_parms: -r--r--r-- */ /* 00666 does not work */ /* <@0x05bf_0.0.1> */ int debug; /* */ module_param(debug, int, PARAM_PERM0x05bf); MODULE_PARM_DESC(debug, " Set \"debug=1\" for debug messages."); int vendor0; int product0; module_param_named(Vendor0, vendor0, int, PARAM_PERM0x05bf); module_param_named(ProdId0, product0, int, PARAM_PERM0x05bf); int vendor1; int product1; module_param_named(Vendor1, vendor1, int, PARAM_PERM0x05bf); module_param_named(ProdId1, product1, int, PARAM_PERM0x05bf); int vendor2; int product2; module_param_named(Vendor2, vendor2, int, PARAM_PERM0x05bf); module_param_named(ProdId2, product2, int, PARAM_PERM0x05bf); int vendor3; int product3; module_param_named(Vendor3, vendor3, int, PARAM_PERM0x05bf); module_param_named(ProdId3, product3, int, PARAM_PERM0x05bf); int vendor4; int product4; module_param_named(Vendor4, vendor4, int, PARAM_PERM0x05bf); module_param_named(ProdId4, product4, int, PARAM_PERM0x05bf); int vendor5; int product5; module_param_named(Vendor5, vendor5, int, PARAM_PERM0x05bf); module_param_named(ProdId5, product5, int, PARAM_PERM0x05bf); int vendor6; int product6; module_param_named(Vendor6, vendor6, int, PARAM_PERM0x05bf); module_param_named(ProdId6, product6, int, PARAM_PERM0x05bf); int vendor7; int product7; module_param_named(Vendor7, vendor7, int, PARAM_PERM0x05bf); module_param_named(ProdId7, product7, int, PARAM_PERM0x05bf); int vendor8; int product8; module_param_named(Vendor8, vendor8, int, PARAM_PERM0x05bf); module_param_named(ProdId8, product8, int, PARAM_PERM0x05bf); int vendor9; int product9; module_param_named(Vendor9, vendor9, int, PARAM_PERM0x05bf); module_param_named(ProdId9, product9, int, PARAM_PERM0x05bf); MODULE_PARM_DESC( vendorX, " Applies to \"Vendor0\" ... \"Vendor9\";\n" MODULE_PARM_DESC_TAB0x05bf "Vendor# in hex,\n" MODULE_PARM_DESC_TAB0x05bf "e.g. for the \"/proc/bus/usb/devices\"-line:\n" MODULE_PARM_DESC_TAB0x05bf "\"P: Vendor=0781 ProdID=5406 Rev= 2.00\"\n" MODULE_PARM_DESC_TAB0x05bf "enter (for \"Vendor0\"): \"Vendor0=0x0781\"." ); MODULE_PARM_DESC( ProdIdX, " Applies to \"ProdID0\" ... \"ProdID9\";\n" MODULE_PARM_DESC_TAB0x05bf "ProdID# in hex\n" MODULE_PARM_DESC_TAB0x05bf "(\"-1\" means \"all products of that vendor\")\n" MODULE_PARM_DESC_TAB0x05bf "or, e.g. for the \"/proc/bus/usb/devices\"-line:\n" MODULE_PARM_DESC_TAB0x05bf "\"P: Vendor=0781 ProdID=5406 Rev= 2.00\"\n" MODULE_PARM_DESC_TAB0x05bf "enter (for \"ProdID0\"): \"ProdID0=0x5406\".\n\n" MODULE_PARM_DESC_TAB0x05bf "WATCH!!!: After a \"parm\" \"VendorK=0\" or\n" MODULE_PARM_DESC_TAB0x05bf "not set, the succeding \"parm\"s\n" MODULE_PARM_DESC_TAB0x05bf "( L > 0: \"Vendor{K+L}\", \"ProdID{K+L}\" )\n" MODULE_PARM_DESC_TAB0x05bf "are ignored." ); struct usb_product_id usb_ids[10]; void __exit exit_strange_usb_sticks() { unhook_strange_usb_sticks(); printk(KERN_INFO "Module \"" MODULE_NAME0x05bf "\" is unloading.\n"); } /** * fake_scsi_command_result -- the scsi-command "cmnd" is handled by this * function by returning the scsi-error: "DID_ERROR" and by setting the * results of the command so, that the function * "drivers/scsi/sr.c/sr_get_events()" at line #169 (does not return the * event "DISK_EVENT_MEDIA_CHANGE") <==> "no media change" */ static inline void fake_scsi_command_result(struct scsi_cmnd *cmnd) { /* set the result "sense" so, that at lines #187, #188 of the function "drivers/scsi/sr.c/sr_get_events()": "if (scsi_sense_valid(&sshdr) && sshdr.sense_key == UNIT_ATTENTION) return DISK_EVENT_MEDIA_CHANGE;" "return ..." is not executed: invalidate "sense" according to the function "include/scsi/scsi_eh.h/scsi_sense_valid()" */ ((struct scsi_sense_hdr *)cmnd->request->sense)->response_code = 0; /* fake scsi-error, so that at lines #190, #191 of the function "drivers/scsi/sr.c/sr_get_events()": " if (result || be16_to_cpu(eh->data_len) < sizeof(*med)) return 0" (0 is returned) ==> no media-change */ cmnd->result = (DID_ERROR << 16); cmnd->scsi_done(cmnd); } /** * handle_strange_usb_sticks -- if an usb-stick is identified as 'strange', the * scsi-command cmnd is handled in this function * by "fake_scsi_command_result()" so that "no media change" is detected. * @cmnd * @returns: * * true = ( != 0 ) if the cmnd is handled by this function * * false = ( == 0 ) if the cmnd is to be queued normally */ int handle_strange_usb_sticks(struct scsi_cmnd *cmnd) { struct usb_product_id usb_id; /* for debug */ if (is_strange_usb_stick(cmnd)) { US0x05bf_DEBUG( scsi_cmnd_to_usb_product_id(cmnd, &usb_id); US0x05bf_DEBUGP( "handling a stick with usb-id = (0x%x, 0x%x)\n", usb_id.vendor, usb_id.product ); ); fake_scsi_command_result(cmnd); return 1; } /* else */ return 0; } static void __init hook_strange_usb_sticks() { set_strange_usb_sticks_hook0x05bf(handle_strange_usb_sticks); } int __init init_strange_usb_sticks() { int i; /* for debug */ printk(KERN_INFO "Module \"" MODULE_NAME0x05bf "\" is loading.\n"); read_parameters(); US0x05bf_DEBUG( for (i = 0; i < sizeof(usb_ids); i++) { if (!(usb_ids[i].vendor)) /* end of array */ break; /* else */ US0x05bf_DEBUGP( "usb-id[%i] = (0x%x, 0x%x)\n", i, usb_ids[i].vendor, usb_ids[i].product ); } ); hook_strange_usb_sticks(); return 0; } /** * is_strange_usb_stick * @cmnd * @returns: * * true = ( != 0 ) if it is a strange usb-stick * * false = ( == 0 ) else */ static inline int is_strange_usb_stick(struct scsi_cmnd *cmnd) { int i; struct usb_product_id usb_id; scsi_cmnd_to_usb_product_id(cmnd, &usb_id); for (i = 0; i < sizeof(usb_ids); i++) { if (!(usb_ids[i].vendor)) /* end of array */ return 0; if (usb_ids[i].vendor == usb_id.vendor) if ( (usb_ids[i].product == -1) || /* all products */ (usb_ids[i].product == usb_id.product) ) return 1; /* else */ /* else */ } return 0; } void __init read_parameters() { usb_ids[0].vendor = vendor0; usb_ids[0].product = product0; usb_ids[1].vendor = vendor1; usb_ids[1].product = product1; usb_ids[2].vendor = vendor2; usb_ids[2].product = product2; usb_ids[3].vendor = vendor3; usb_ids[3].product = product3; usb_ids[4].vendor = vendor4; usb_ids[4].product = product4; usb_ids[5].vendor = vendor5; usb_ids[5].product = product5; usb_ids[6].vendor = vendor6; usb_ids[6].product = product6; usb_ids[7].vendor = vendor7; usb_ids[7].product = product7; usb_ids[8].vendor = vendor8; usb_ids[8].product = product8; usb_ids[9].vendor = vendor9; usb_ids[9].product = product9; }; static inline struct usb_device_descriptor* scsi_cmnd_to_usb_device_descriptor(struct scsi_cmnd *cmnd) { return &(host_to_us(cmnd->device->host)->pusb_dev->descriptor); } /** * scsi_cmnd_to_usb_product_id -- fill "usb_id" "with usb_product_id" supplied * by cmnd * @cmnd * @usb_id: the "usb_id" to be filled */ static void scsi_cmnd_to_usb_product_id( struct scsi_cmnd *cmnd, struct usb_product_id *usb_id ) { struct usb_device_descriptor *descriptor; descriptor = scsi_cmnd_to_usb_device_descriptor(cmnd); usb_id->product = le16_to_cpu(descriptor->idProduct); usb_id->vendor = le16_to_cpu(descriptor->idVendor); } static void __exit unhook_strange_usb_sticks() { set_strange_usb_sticks_hook0x05bf(NULL); }