Index: iet-0.4.10/Makefile diff -u iet-0.4.10/Makefile:1.1 iet-0.4.10/Makefile:1.3 --- iet-0.4.10/Makefile:1.1 Sat Jun 11 11:30:57 2005 +++ iet-0.4.10/Makefile Thu Jun 16 02:32:24 2005 @@ -17,7 +17,13 @@ all: progs mods -mods: +CSSSRC = kernel/css-auth.c kernel/css-auth.h kernel/css.h kernel/csstable.c +kernel/css-auth.c: css-auth/css-auth.c + sed -e 's:\(^# *include *.*$$\):/* \1 */:' $< > $@ +kernel/%: css-auth/% + ln -s ../$< $@ + +mods: $(CSSSRC) $(MAKE) -C $(KERNELSRC) SUBDIRS=$(shell pwd)/kernel modules progs: @@ -45,3 +51,4 @@ clean: $(MAKE) -C usr clean $(MAKE) -C $(KERNELSRC) SUBDIRS=$(shell pwd)/kernel clean + for i in $(CSSSRC); do if [ -h $$i ]; then $(RM) $$i; else :; fi; done Index: iet-0.4.10/include/iet_u.h diff -u iet-0.4.10/include/iet_u.h:1.1 iet-0.4.10/include/iet_u.h:1.2 --- iet-0.4.10/include/iet_u.h:1.1 Sat Jun 11 11:30:57 2005 +++ iet-0.4.10/include/iet_u.h Wed Jun 15 18:33:03 2005 @@ -103,11 +103,15 @@ u32 state; }; +#ifndef DEFAULT_NR_WTHREADS #define DEFAULT_NR_WTHREADS 8 +#endif #define MIN_NR_WTHREADS 1 #define MAX_NR_WTHREADS 128 +#ifndef DEFAULT_NR_QUEUED_CMNDS #define DEFAULT_NR_QUEUED_CMNDS 32 +#endif #define MIN_NR_QUEUED_CMNDS 4 #define MAX_NR_QUEUED_CMNDS 256 Index: iet-0.4.10/include/rmmc_aux.h diff -u /dev/null iet-0.4.10/include/rmmc_aux.h:1.1 --- /dev/null Thu Jun 16 18:47:33 2005 +++ iet-0.4.10/include/rmmc_aux.h Sat Jun 11 11:44:09 2005 @@ -0,0 +1,202 @@ +/* + * Target device file I/O for read-only(or reduced) mmc + * (C) 2004-2005 Junjiro Okajima + * This code is licenced under the GPL. + */ + +#ifndef rmmc_aux_h +#define rmmc_aux_h + +static char rmmc_aux__h[] __attribute__ ((unused, nocommon)) + = "@(#) $Id: rmmc_aux.h,v 1.1 2005/06/11 02:44:09 jro Exp $"; + +#include + +/* + * file format + */ +struct rmmc_aux_offlen { + u32 offset; + u32 length; +}; + +/* based upon raw responses */ +struct rmmc_aux_discinfo { + u8 data[0]; +}; + +enum { DslPhys, DslCprt, DslManuf, LastDslData }; +struct rmmc_aux_layer { + /* offset from next 'data' */ + struct rmmc_aux_offlen offlen[LastDslData]; + + u8 data[0]; +}; + +struct rmmc_aux_dvdst { + u8 nlayer; + u8 pad[3]; + u8 dkey[4 + 2048]; + + /* offset from next 'data' */ + struct rmmc_aux_offlen offlen[DVD_LAYERS]; + + struct rmmc_aux_layer data[0]; +}; + +struct rmmc_aux_tpa { + /* un-implemented */ + u8 data[0]; +}; + +enum { Type1_0, Type1_1, LastType1 }; +struct rmmc_aux_trkinfo { + /* offset from next 'data' */ + struct rmmc_aux_offlen offlen[LastType1]; + + u8 data[0]; +}; + +struct rmmc_aux_tk { + /* start and end */ + u32 lba[2]; + + u8 cpbits; + u8 tk[5]; + u8 pad[2]; +}; + +struct rmmc_aux_rkey { + u32 ntitle; + struct rmmc_aux_tk data[0]; +}; + +enum { + DISC_INFO, // GPCMD_READ_DISC_INFO + DVD_STRUCTURE, // GPCMD_READ_DVD_STRUCTURE or READ DISC STRUCTURE command + TOC_PMA_ATIP, // GPCMD_READ_TOC_PMA_ATIP + REPORT_KEY, // GPCMD_REPORT_KEY + //TRACK_INFO, // GPCMD_READ_TRACK_RZONE_INFO + LastCmd +}; + +#define RmmcAuxMagicStr "rmmcaux" +struct rmmc_aux_file_v0 { + u8 magic[16]; + u32 version; + + /* all data, should be match to the total of 'length's in 'offlen'' */ + u32 size; + + /* sum of all 'data' */ + u32 sum; + + u32 salt[4]; + + /* offset from next 'data' */ + struct rmmc_aux_offlen offlen[LastCmd]; + + /* responses */ + u8 data[0]; +}; +#define rmmc_aux_file rmmc_aux_file_v0 +/* +#if sizeof(RmmcAuxMagicStr)-1 > sizeof(struct rmmc_aux_file_v0.magic) +#error magic string macro it too long. +#endif +*/ + +static inline void +set_offlen(struct rmmc_aux_offlen p[], u32 offset, u32 length) +{ + p->offset = cpu_to_be32(offset); + p->length = cpu_to_be32(length); +} + +/* + * simple macros for reading the aux file + */ +#define define_ol(name, basetype, lim) \ +static inline void* \ +name(basetype base[], int ind, u32 len[]) \ +{ \ + struct rmmc_aux_offlen *p; \ + u8 *o; \ + /* if (!base || ind >= (lim)) return NULL */; \ + o = (void*)base->data; \ + p = base->offlen; \ + p += ind; \ + *len = be32_to_cpu(p->length); \ + return o+be32_to_cpu(p->offset); \ +} + +define_ol(offlenof_aux, struct rmmc_aux_file, LastCmd); +define_ol(offlenof_dvdst, + struct rmmc_aux_dvdst, ((struct rmmc_aux_dvdst *) base)->nlayer); +define_ol(offlenof_layer, struct rmmc_aux_layer, LastDslData); + +static inline struct rmmc_aux_discinfo *offlen_discinfo(struct rmmc_aux_file + aux[], u32 len[]) +{ + return offlenof_aux(aux, DISC_INFO, len); +} +static inline struct rmmc_aux_dvdst *offlen_dvdst(struct rmmc_aux_file aux[], + u32 len[]) +{ + return offlenof_aux(aux, DVD_STRUCTURE, len); +} +static inline struct rmmc_aux_tpa *offlen_tpa(struct rmmc_aux_file aux[], + u32 len[]) +{ + return offlenof_aux(aux, TOC_PMA_ATIP, len); +} +static inline struct rmmc_aux_rkey *offlen_rkey(struct rmmc_aux_file aux[], + u32 len[]) +{ + return offlenof_aux(aux, REPORT_KEY, len); +} + +static inline struct rmmc_aux_layer *offlen_layer(struct rmmc_aux_dvdst dvdst[], + int num, u32 len[]) +{ + return offlenof_dvdst(dvdst, num, len); +} + +static inline struct rmmc_aux_phys *offlen_phys(struct rmmc_aux_layer layer[], + u32 len[]) +{ + return offlenof_layer(layer, DslPhys, len); +} +static inline struct rmmc_aux_cprt *offlen_cprt(struct rmmc_aux_layer layer[], + u32 len[]) +{ + return offlenof_layer(layer, DslCprt, len); +} +static inline u8 *offlen_manuf(struct rmmc_aux_layer layer[], u32 len[]) +{ + return offlenof_layer(layer, DslManuf, len); +} + +/* + * tiny utilities for ietd. + */ +static inline u32 getu32(u8 a[]) +{ + return be32_to_cpu(*(u32 *) a); +} +static inline void putu32(u8 a[], u32 v) +{ + v = cpu_to_be32(v); + memcpy(a, &v, sizeof(u32)); +} +static inline u16 getu16(u8 a[]) +{ + return be16_to_cpu(*(u16 *) a); +} +static inline void putu16(u8 a[], u16 v) +{ + v = cpu_to_be16(v); + memcpy(a, &v, sizeof(u16)); +} + +#endif /* rmmc_aux_h */ Index: iet-0.4.10/kernel/Makefile diff -u iet-0.4.10/kernel/Makefile:1.1 iet-0.4.10/kernel/Makefile:1.6 --- iet-0.4.10/kernel/Makefile:1.1 Sat Jun 11 11:30:57 2005 +++ iet-0.4.10/kernel/Makefile Wed Jun 15 18:33:03 2005 @@ -7,10 +7,10 @@ # # Note 2! The CFLAGS definitions are now in the main makefile. EXTRA_CFLAGS += -I$(src)/../include obj-m += iscsi_trgt.o iscsi_trgt-objs := tio.o iscsi.o nthread.o wthread.o config.o digest.o \ conn.o session.o target.o volume.o iotype.o \ - file-io.o null-io.o target_disk.o event.o param.o - + file-io.o null-io.o target_disk.o event.o param.o \ + rmmc-io.o target_rmmc.o css-auth.o csstable.o Index: iet-0.4.10/kernel/conn.c diff -u iet-0.4.10/kernel/conn.c:1.1 iet-0.4.10/kernel/conn.c:1.7 --- iet-0.4.10/kernel/conn.c:1.1 Sat Jun 11 11:30:57 2005 +++ iet-0.4.10/kernel/conn.c Thu Jun 16 18:22:06 2005 @@ -102,6 +119,13 @@ list_del(&conn->poll_list); digest_cleanup(conn); + + { + struct target_type *type; + type = target_type_array[conn->session->target->trgt_param.target_type]; + if (type && type->clean_conn) + type->clean_conn(conn); + } kfree(conn); return 0; @@ -118,6 +142,14 @@ return -ENOMEM; memset(conn, 0, sizeof(*conn)); + { + struct target_type *type; + type = target_type_array[session->target->trgt_param.target_type]; + if (type && type->init_conn + && type->init_conn(conn)) + goto err; + } + conn->session = session; conn->cid = info->cid; conn->stat_sn = info->stat_sn; @@ -126,6 +158,7 @@ conn->hdigest_type = info->header_digest; conn->ddigest_type = info->data_digest; if (digest_init(conn) < 0) { + err: kfree(conn); return -ENOMEM; } Index: iet-0.4.10/kernel/file-io.c diff -u iet-0.4.10/kernel/file-io.c:1.1 iet-0.4.10/kernel/file-io.c:1.5 --- iet-0.4.10/kernel/file-io.c:1.1 Sat Jun 11 11:30:57 2005 +++ iet-0.4.10/kernel/file-io.c Mon Jun 13 23:15:43 2005 @@ -11,11 +11,7 @@ #include "iscsi.h" #include "iscsi_dbg.h" #include "iotype.h" - -struct fileio_data { - char *path; - struct file *filp; -}; +#include "file-io.h" static int fileio_make_request(struct iet_volume *lu, struct tio *tio, int rw) { @@ -112,7 +108,8 @@ return err; } -static int set_scsiid(struct iet_volume *volume, const char *id) +/* static */ +int set_scsiid(struct iet_volume *volume, const char *id) { size_t len; @@ -127,7 +124,8 @@ return 0; } -static void gen_scsiid(struct iet_volume *volume, struct inode *inode) +/* static */ +void gen_scsiid(struct iet_volume *volume, struct inode *inode) { int i; u32 *p; @@ -139,7 +137,7 @@ return; p = (u32 *) (volume->scsi_id + VENDOR_ID_LEN); - *(p + 0) = volume->target->target_type; + *(p + 0) = volume->target->trgt_param.target_type; *(p + 1) = volume->target->tid; *(p + 2) = (unsigned int) inode->i_ino; *(p + 3) = (unsigned int) inode->i_sb->s_dev; @@ -156,10 +154,11 @@ {Opt_err, NULL}, }; -static int parse_fileio_params(struct iet_volume *volume, char *params) +/* static */ +int parse_fileio_params(struct iet_volume *volume, char *params) { int err = 0; - char *p, *path = NULL, *scsiid = NULL; + char *p, *arg; while ((p = strsep(¶ms, ",")) != NULL) { substring_t args[MAX_OPT_ARGS]; @@ -171,19 +170,23 @@ case Opt_type: break; case Opt_scsiid: - if (!(scsiid = match_strdup(&args[0]))) { + if (!(arg = match_strdup(&args[0]))) { err = -ENOMEM; goto out; } - if ((err = set_scsiid(volume, scsiid)) < 0) + err = set_scsiid(volume, arg); + kfree(arg); + if (err < 0) goto out; break; case Opt_path: - if (!(path = match_strdup(&args[0]))) { + if (!(arg = match_strdup(&args[0]))) { err = -ENOMEM; goto out; } - if ((err = open_path(volume, path)) < 0) + err = open_path(volume, arg); + kfree(arg); + if (err < 0) return err; break; default: @@ -194,9 +197,6 @@ } out: - kfree(path); - kfree(scsiid); - return err; } Index: iet-0.4.10/kernel/file-io.h diff -u /dev/null iet-0.4.10/kernel/file-io.h:1.1 --- /dev/null Thu Jun 16 18:47:33 2005 +++ iet-0.4.10/kernel/file-io.h Sat Jun 11 11:44:09 2005 @@ -0,0 +1,14 @@ + +#ifndef file_io_h +#define file_io_h + +/* + * extracted from ./file-io.c in order to share. + */ + +struct fileio_data { + char *path; + struct file *filp; +}; + +#endif /* file_io_h */ Index: iet-0.4.10/kernel/iotype.c diff -u iet-0.4.10/kernel/iotype.c:1.1 iet-0.4.10/kernel/iotype.c:1.2 --- iet-0.4.10/kernel/iotype.c:1.1 Sat Jun 11 11:30:57 2005 +++ iet-0.4.10/kernel/iotype.c Sat Jun 11 11:44:09 2005 @@ -79,6 +79,7 @@ struct iotype *iotype_array[] = { &fileio, &nullio, + &rmmcio, }; int iotype_init(void) Index: iet-0.4.10/kernel/iotype.h diff -u iet-0.4.10/kernel/iotype.h:1.1 iet-0.4.10/kernel/iotype.h:1.2 --- iet-0.4.10/kernel/iotype.h:1.1 Sat Jun 11 11:30:57 2005 +++ iet-0.4.10/kernel/iotype.h Sat Jun 11 11:44:09 2005 @@ -21,6 +21,7 @@ extern struct iotype fileio; extern struct iotype nullio; +extern struct iotype rmmcio; extern int iotype_init(void); extern void iotype_exit(void); Index: iet-0.4.10/kernel/iscsi.c diff -u iet-0.4.10/kernel/iscsi.c:1.1 iet-0.4.10/kernel/iscsi.c:1.5 --- iet-0.4.10/kernel/iscsi.c:1.1 Sat Jun 11 11:30:57 2005 +++ iet-0.4.10/kernel/iscsi.c Tue Jun 14 16:58:28 2005 @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -707,6 +723,11 @@ *off = be64_to_cpu(*(u64 *)&cmd[2]); *len = be32_to_cpu(*(u32 *)&cmd[10]); break; + case GPCMD_SEND_KEY: + *off = 0; + *len = be16_to_cpu(*(u16*)(cmd+8)); + /* break; */ + return; default: BUG(); } @@ -910,6 +931,22 @@ case RELEASE: case RESERVE_10: case RELEASE_10: +/* jro: mmc cmnds */ + case GPCMD_READ_DVD_STRUCTURE: + case GPCMD_REPORT_KEY: + case GPCMD_READ_TOC_PMA_ATIP: + case GPCMD_MODE_SENSE_10: + case GPCMD_GET_EVENT_STATUS_NOTIFICATION: + case GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL: + + case GPCMD_READ_DISC_INFO: + case GPCMD_SEEK: + case GPCMD_GET_CONFIGURATION: + case GPCMD_READ_TRACK_RZONE_INFO: + case GPCMD_READ_SUBCHANNEL: + case GPCMD_READ_CD_MSF: + case GPCMD_READ_CD: +/* end of mmc cmnds */ { if (!(req_hdr->flags & ISCSI_CMD_FINAL) || req->pdu.datasize) { /* unexpected unsolicited data */ @@ -934,7 +971,7 @@ } set_offset_and_length(req->lun, req_hdr->scb, &offset, &length); - req->tio = tio_alloc(get_pgcnt(length, offset)); + req->tio = _tio_alloc(get_pgcnt(length, offset), 0); /* allocate pages later. */ tio_set(req->tio, length, offset); break; } @@ -942,6 +979,7 @@ case WRITE_10: case WRITE_16: case WRITE_VERIFY: + case GPCMD_SEND_KEY: /* jro: mmc cmnd */ { struct iscsi_sess_param *param = &conn->session->param; loff_t offset; Index: iet-0.4.10/kernel/iscsi.h diff -u iet-0.4.10/kernel/iscsi.h:1.1 iet-0.4.10/kernel/iscsi.h:1.11 --- iet-0.4.10/kernel/iscsi.h:1.1 Sat Jun 11 11:30:57 2005 +++ iet-0.4.10/kernel/iscsi.h Thu Jun 16 18:22:06 2005 @@ -45,6 +45,7 @@ struct tio { u32 pg_cnt; + u32 need_pages; pgoff_t idx; u32 offset; @@ -86,11 +87,12 @@ }; struct iscsi_cmnd; +struct iscsi_conn; struct target_type { - int id; - int (*execute_cmnd) (struct iscsi_cmnd *); + int (*init_conn)(struct iscsi_conn *); + int (*clean_conn)(struct iscsi_conn *); }; enum iscsi_device_state { @@ -115,8 +117,6 @@ struct worker_thread_info wthread_info; struct semaphore target_sem; - - int target_type; }; struct iscsi_queue { @@ -219,6 +221,8 @@ struct crypto_tfm *rx_digest_tfm; struct crypto_tfm *tx_digest_tfm; + + void *private; }; struct iscsi_pdu { @@ -323,13 +330,15 @@ /* tio.c */ extern int tio_init(void); extern void tio_exit(void); -extern struct tio *tio_alloc(int); +extern struct tio *_tio_alloc(int, int); +#define tio_alloc(n) _tio_alloc((n), 1) extern void tio_get(struct tio *); extern void tio_put(struct tio *); extern void tio_set(struct tio *, u32, loff_t); extern int tio_read(struct iet_volume *, struct tio *); extern int tio_write(struct iet_volume *, struct tio *); extern int tio_sync(struct iet_volume *, struct tio *); +extern int tio_add_pages(struct tio *, int); /* iotype.c */ extern struct iotype *get_iotype(const char *name); @@ -340,6 +349,9 @@ /* target_disk.c */ extern struct target_type disk_ops; + +/* target_rmmc.c */ +extern struct target_type rmmc_ops; /* event.c */ extern int event_send(u32, u64, u32, u32, int); Index: iet-0.4.10/kernel/iscsi_dbg.h diff -u iet-0.4.10/kernel/iscsi_dbg.h:1.1 iet-0.4.10/kernel/iscsi_dbg.h:1.3 --- iet-0.4.10/kernel/iscsi_dbg.h:1.1 Sat Jun 11 11:30:57 2005 +++ iet-0.4.10/kernel/iscsi_dbg.h Sat Jun 11 23:21:15 2005 @@ -10,6 +10,7 @@ #define D_THREAD (1UL << 6) #define D_TASK_MGT (1UL << 7) #define D_IOMODE (1UL << 8) +#define D_RMMC (1UL << 9) #define D_DATA (D_READ | D_WRITE) Index: iet-0.4.10/kernel/param.c diff -u iet-0.4.10/kernel/param.c:1.1 iet-0.4.10/kernel/param.c:1.5 --- iet-0.4.10/kernel/param.c:1.1 Sat Jun 11 11:30:57 2005 +++ iet-0.4.10/kernel/param.c Thu Jun 16 02:27:47 2005 @@ -9,7 +9,9 @@ #include "digest.h" struct target_type *target_type_array[] = { + /* the order, ie. the index is 'Type' parameter in the config file. */ &disk_ops, + &rmmc_ops }; #define CHECK_PARAM(info, iparam, word, min, max) \ @@ -111,7 +113,7 @@ CHECK_PARAM(info, iparam, wthreads, MIN_NR_WTHREADS, MAX_NR_WTHREADS); CHECK_PARAM(info, iparam, target_type, 0, - (unsigned int) ARRAY_SIZE(target_type_array)); + (unsigned int) ARRAY_SIZE(target_type_array)-1); CHECK_PARAM(info, iparam, queued_cmnds, MIN_NR_QUEUED_CMNDS, MAX_NR_QUEUED_CMNDS); } Index: iet-0.4.10/kernel/rmmc-io.c diff -u /dev/null iet-0.4.10/kernel/rmmc-io.c:1.11 --- /dev/null Thu Jun 16 18:47:33 2005 +++ iet-0.4.10/kernel/rmmc-io.c Thu Jun 16 18:22:06 2005 @@ -0,0 +1,471 @@ +/* + * Target device file I/O for read-only(or reduced) mmc + * (C) 2004-2005 Junjiro Okajima + * This code is licenced under the GPL. + * + * based on ietd file-io.c, which was + * (C) 2004 Fujita Tomonori + * licensed under the terms of the GPL. + */ + +static char rmmc_io_c[] __attribute__ ((unused, nocommon)) + = "@(#) $Id: rmmc-io.c,v 1.11 2005/06/16 09:22:06 jro Exp $"; + +#include "iscsi_dbg.h" +#include "iotype.h" +#include "rmmc-io.h" + +static spinlock_t auxinfo_lock = SPIN_LOCK_UNLOCKED; +static LIST_HEAD(auxinfo_list); +static DECLARE_MUTEX(auxinfo_sema); + +#define AuxExt ".aux" + +/* + * before calling me, you should lock the list + */ +static inline struct auxinfo *lookup_auxinfo(u8 auxpath[]) +{ + struct auxinfo *e; + + list_for_each_entry(e, &auxinfo_list, list) + if (e->auxpath && strcmp(e->auxpath, auxpath) == 0) // slow? + return e; + return NULL; +} + +static struct auxinfo *auxinfo_alloc(char auxpath[], int err[]) +{ + struct auxinfo *e; + void *label; + mm_segment_t oldfs; + struct file *filp = NULL; + struct inode *inode; + int n; + + *err = -ENOMEM; + e = kmalloc(sizeof(struct auxinfo), GFP_KERNEL); + if (!e) + return NULL; + /* dprintk(D_RMMC, "auxinfo %p\n", e); */ + label = &&err; + e->auxpath = kmalloc(strlen(auxpath) + 1, GFP_KERNEL); + if (!e->auxpath) + goto *label; + strcpy(e->auxpath, auxpath); + /* dprintk(D_RMMC, "auxpath %p\n", e->auxpath); */ + label = &&err1; + + oldfs = get_fs(); + set_fs(get_ds()); + filp = filp_open(auxpath, O_RDONLY | O_LARGEFILE, 0); + set_fs(oldfs); + if (IS_ERR(filp)) { + *err = PTR_ERR(filp); + goto *label; + } + label = &&err2; + + inode = filp->f_dentry->d_inode; + *err = -ESPIPE; + *err = -ENOMEM; + e->auxfile = kmalloc(inode->i_size, GFP_KERNEL); + if (!e->auxfile) + goto *label; + label = &&err3; + + *err = -EIO; + n = kernel_read(filp, 0, (void *) e->auxfile, inode->i_size); + filp_close(filp, NULL); + filp = NULL; + if (n != inode->i_size) + goto *label; + + INIT_LIST_HEAD(&e->list); + atomic_set(&e->ref, 1); + + return e; + err3: + kfree(e->auxfile); + err2: + if (filp) + filp_close(filp, NULL); + err1: + kfree(e->auxpath); + err: + kfree(e); + return NULL; +} + +/* + * before calling me, you should lock the list + * returns TRUE if it is freed, FALSE if not. + */ +static inline int auxinfo_unref(struct auxinfo e[]) +{ + int ret = 0; + + if (!atomic_dec_and_test(&e->ref)) + goto end; + + ret = -1; + list_del(&e->list); + /* dprintk(D_RMMC, "freeing %p{%p, %p}\n", e, e->auxpath, e->auxfile); */ + kfree(e->auxfile); + kfree(e->auxpath); + kfree(e); + end: + return ret; +} + +static int getauxinfo(struct rmmcio_volume p[]) +{ + int res; + int n = strlen(p->fileio_data->path); + char auxpath[n + sizeof(AuxExt)]; + + strcpy(auxpath, p->fileio_data->path); + strcpy(auxpath + n, AuxExt); + + spin_lock(&auxinfo_lock); + p->auxinfo = lookup_auxinfo(auxpath); + if (p->auxinfo) { + atomic_inc(&p->auxinfo->ref); + spin_unlock(&auxinfo_lock); + return 0; + } + spin_unlock(&auxinfo_lock); + + down(&auxinfo_sema); + /* + * search again + */ + spin_lock(&auxinfo_lock); + p->auxinfo = lookup_auxinfo(auxpath); + if (p->auxinfo) { + atomic_inc(&p->auxinfo->ref); + spin_unlock(&auxinfo_lock); + return 0; + } + spin_unlock(&auxinfo_lock); + + dprintk(D_RMMC, "creating aux for %s\n", auxpath); + p->auxinfo = auxinfo_alloc(auxpath, &res); + if (!p->auxinfo) + goto end; + +#if RMMC_DEBUG + { + struct rmmc_aux_dvdst *dvdst; + struct rmmc_aux_rkey *rkey; + struct rmmc_aux_tk *tk; + u32 len; + + res = -EDOM; + dprintk(D_RMMC, "%s %d\n", + p->auxinfo->auxfile->magic, + p->auxinfo->auxfile->version); + dvdst = offlen_dvdst(p->auxinfo->auxfile, &len); + if (!dvdst) + goto end; + dprintk(D_RMMC, "layers %d\n", dvdst->nlayer); + dprintk(D_RMMC, "dk{%02x %02x %02x %02x %02x}\n", + dvdst->dkey[4 + 0], dvdst->dkey[4 + 1], + dvdst->dkey[4 + 2], dvdst->dkey[4 + 3], + dvdst->dkey[4 + 4]); + rkey = offlen_rkey(p->auxinfo->auxfile, &len); + if (!rkey) + goto end; + dprintk(D_RMMC, "titles %d\n", be32_to_cpu(rkey->ntitle)); + tk = rkey->data; + if (!tk) + goto end; + dprintk(D_RMMC, "tk[0]{%02x %02x %02x %02x %02x}\n", + tk->tk[0], tk->tk[1], tk->tk[2], tk->tk[3], tk->tk[4]); + } +#endif + + res = 0; + spin_lock(&auxinfo_lock); + list_add_tail(&p->auxinfo->list, &auxinfo_list); + spin_unlock(&auxinfo_lock); + end: + up(&auxinfo_sema); + if (res) + eprintk("%s failed %d\n", auxpath, res); + return res; +} + +/* + * copied and modifed from file-io.c, unpleasantly. + * could we be happy if the readonly patch is merged? + */ +static int open_path(struct iet_volume *volume, const char *path) +{ + int err; + struct rmmcio_volume *p = volume->private; + struct fileio_data *info = p->fileio_data; + struct file *filp; + mm_segment_t oldfs; + + info->path = kmalloc(strlen(path) + 1, GFP_KERNEL); + if (!info->path) + return -ENOMEM; + strcpy(info->path, path); + + oldfs = get_fs(); + set_fs(get_ds()); + filp = filp_open(path, O_RDONLY|O_LARGEFILE, 0); + set_fs(oldfs); + + if (IS_ERR(filp)) { + kfree(info->path); + info->path = NULL; + + err = PTR_ERR(filp); + eprintk("Can't open %s %d\n", path, err); + return err; + } + + info->filp = filp; + if (filp->f_op->sendfile) + set_bit(RmmcSendfile, &p->flags); // might be cleared later. + + return 0; +} + +/* + * currently, the space chars are not allowed between the parameters. + */ +static inline int get_arg(char params[], char key[], int len, + char **found, char **arg, char **argend) +{ + *found = strstr(params, key); + if (!*found || strlen(*found) <= len) + return -EINVAL; + *arg = len+*found; + if (strstr(*arg, key)) + return -EINVAL; + *argend = strchr(*arg, ','); + if (*argend) + **argend = 0; + return 0; +} + +static inline void remove_param(char *begin, char end[]) +{ + if (end) + strcpy(begin, end+1); + else { + if (*(begin-1) == ',') begin--; + *begin = 0; + } +} + +static int parse_params(struct iet_volume *volume, char *params) +{ + int ret; + struct rmmcio_volume *rmmc_vol = volume->private; + char *found, *arg, *arg_end; + extern int parse_fileio_params(struct iet_volume *volume, char *params); + + /* dprintk(D_RMMC, "params %s\n", params); */ +#define Param "Path=" + ret = get_arg(params, Param, sizeof(Param)-1, &found, &arg, &arg_end); + if (ret) + goto bad_param; + ret = open_path(volume, arg); + if (ret) + return ret; + remove_param(found, arg_end); +#undef Param + + /* dprintk(D_RMMC, "params %s\n", params); */ +#define Param "Media=" + /* + * currently, there is no default value. + */ + ret = get_arg(params, Param, sizeof(Param)-1, &found, &arg, &arg_end); + if (ret) + goto err; + if (strcmp(arg, "CDROM") == 0) + set_bit(RmmcCDROM, &rmmc_vol->flags); + else if (strcmp(arg, "DVDROM") == 0) + set_bit(RmmcDVDROM, &rmmc_vol->flags); + else { + ret = -EINVAL; + goto err; + } + remove_param(found, arg_end); +#undef Param + + /* dprintk(D_RMMC, "params %s\n", params); */ +#define Param "Sendfile=" + /* + * must be after open_path() + */ + ret = get_arg(params, Param, sizeof(Param)-1, &found, &arg, &arg_end); + if (!ret) { + if (strcmp(arg, "0") == 0) + clear_bit(RmmcSendfile, &rmmc_vol->flags); + remove_param(found, arg_end); + } +#undef Param + + /* dprintk(D_RMMC, "params %s\n", params); */ + volume->private = rmmc_vol->fileio_data; + ret = parse_fileio_params(volume, params); + volume->private = rmmc_vol; + if (ret) + goto err; + + return ret; + + err: + if (rmmc_vol->fileio_data->filp) { + filp_close(rmmc_vol->fileio_data->filp, NULL); + rmmc_vol->fileio_data->filp = NULL; + } + if (rmmc_vol->fileio_data->path) { + kfree(rmmc_vol->fileio_data->path); + rmmc_vol->fileio_data->path = NULL; + } + + bad_param: + eprintk("%s\n", "Bad parameter"); + return ret; +} + +int rmmcio_attach(struct iet_volume *lu, char *args) +{ + int res; + struct rmmcio_volume *p; + struct inode *inode; + void *label = &&err; + extern void gen_scsiid(struct iet_volume *volume, struct inode *inode); + + if (lu->private) { + eprintk("already attached ? %d\n", lu->lun); + return -EBUSY; + } + + res = -ENOMEM; + lu->private = p = kmalloc(sizeof(*p), GFP_KERNEL); + if (!p) + goto *label; + /* dprintk(D_RMMC, "rmmc vol %p\n", p); */ + memset(p, 0, sizeof(*p)); + label = &&err1; + + p->fileio_data = kmalloc(sizeof(*p->fileio_data), GFP_KERNEL); + if (!p->fileio_data) + goto *label; + /* dprintk(D_RMMC, "fileio_data %p\n", p->fileio_data); */ + memset(p->fileio_data, 0, sizeof(*p->fileio_data)); + label = &&err2; + + res = parse_params(lu, args); + if (res < 0) + goto *label; + label = &&err3; + + inode = p->fileio_data->filp->f_dentry->d_inode; + lu->private = p->fileio_data; + gen_scsiid(lu, inode); + lu->private = p; + + if (S_ISREG(inode->i_mode)) { + /* nothing to do */ + } else if (S_ISBLK(inode->i_mode)) { + inode = inode->i_bdev->bd_inode; + } else { + eprintk("%s is not a block file %x\n", + p->fileio_data->path, inode->i_mode); + res = -EINVAL; + goto *label; + } + + if (isdvdrom(lu) && (res = getauxinfo(p))) + goto *label; + + lu->blk_shift = RmmcBlkShift; + lu->blk_cnt = inode->i_size >> lu->blk_shift; + return 0; + + err3: + filp_close(p->fileio_data->filp, NULL); + p->fileio_data->filp = NULL; + kfree(p->fileio_data->path); + p->fileio_data->path = NULL; + err2: + kfree(p->fileio_data); + p->fileio_data = NULL; + err1: + kfree(p); + err: + lu->private = NULL; + eprintk("failed %d\n", res); + return res; +} + +void rmmcio_detach(struct iet_volume *lu) +{ + struct rmmcio_volume *p; + struct iet_volume tmp_lu; + + p = lu->private; + if (p->auxinfo) + auxinfo_unref(p->auxinfo); + memcpy(&tmp_lu, lu, sizeof(lu)); + tmp_lu.private = p->fileio_data; + fileio.detach(&tmp_lu); + /*dprintk(D_RMMC, "detached fileio %p{%p}\n", + p->fileio_data, p->fileio_data->path); */ + kfree(p); + /* dprintk(D_RMMC, "freed rmmcio vol %p\n", p); */ + lu->private = NULL; +} + +int rmmcio_make_request(struct iet_volume *lu, struct tio *tio, int rw) +{ + struct rmmcio_volume *p; + struct iet_volume tmp_lu; + + if (rw != READ) + return -EACCES; + p = lu->private; + memcpy(&tmp_lu, lu, sizeof(lu)); // ng. slow. + tmp_lu.private = p->fileio_data; + return fileio.make_request(&tmp_lu, tio, READ); +} + +int rmmcio_sync(struct iet_volume *lu, struct tio *tio) +{ + BUG(); + return -1; +} + +void rmmcio_show(struct iet_volume *lu, struct seq_file *seq) +{ + struct rmmcio_volume *p; + struct iet_volume tmp_lu; + + p = lu->private; + seq_printf(seq, " media:%s", media_str(p)); + if (test_bit(RmmcSendfile, &p->flags)) + seq_printf(seq, " sfa"); //sendfile available + if (p->auxinfo) + seq_printf(seq, " auxref:%d", atomic_read(&p->auxinfo->ref)); + memcpy(&tmp_lu, lu, sizeof(lu)); + tmp_lu.private = p->fileio_data; + fileio.show(&tmp_lu, seq); +} + +struct iotype rmmcio = { + .name = "rmmcio", + .attach = rmmcio_attach, + .make_request = rmmcio_make_request, + .sync = rmmcio_sync, + .detach = rmmcio_detach, + .show = rmmcio_show, +}; Index: iet-0.4.10/kernel/rmmc-io.h diff -u /dev/null iet-0.4.10/kernel/rmmc-io.h:1.6 --- /dev/null Thu Jun 16 18:47:33 2005 +++ iet-0.4.10/kernel/rmmc-io.h Thu Jun 16 18:22:06 2005 @@ -0,0 +1,185 @@ +/* + * Target device file I/O for read-only(or reduced) mmc + * (C) 2004-2005 Junjiro Okajima + * This code is licenced under the GPL. + */ + +#ifndef rmmc_io_h +#define rmmc_io_h + +static char rmmc_io__h[] __attribute__ ((unused, nocommon)) + = "@(#) $Id: rmmc-io.h,v 1.6 2005/06/16 09:22:06 jro Exp $"; + +#include "file-io.h" +#include "rmmc_aux.h" + +#define RmmcBlkShift 11 +#define RmmcBlkSize (1<lun; + if (!lun) return NULL; + return lun->private; +} + +enum { + RmmcDVDROM, + RmmcCDROM, + /* define more media here */ + + RmmcSendfile // unset means 'read' method +}; + +static inline char *media_str(struct rmmcio_volume vol[]) +{ +#define A(n) if (test_bit(n, &vol->flags)) return 4+#n; + A(RmmcDVDROM); + A(RmmcCDROM); +#undef A + return "??"; +} + +static inline int test_media_type(struct iet_volume lun[], int n) +{ + struct rmmcio_volume *vol; + + if (!lun) return 0; + vol = lun->private; + /* if (!vol) return 0; */ + return test_bit(n, &vol->flags); +} + +#define isdvdrom(lun) test_media_type((lun), RmmcDVDROM) +#define iscdrom(lun) test_media_type((lun), RmmcCDROM) + +static inline struct rmmc_aux_file *vol_auxfile(struct rmmcio_volume vol[]) +{ + struct auxinfo *auxinfo; + + if (!vol) return NULL; + /*if (!test_bit(RmmcDVDROM, &vol->flags)) + return NULL;*/ + auxinfo = vol->auxinfo; + if (!auxinfo) return NULL; + return auxinfo->auxfile; +} + +/* ---------------------------------------------------------------------- */ +#include "css-auth.h" + +#define CSSKey1Len 5 +#define CSSKey2Len 5 +struct rmmc_css { + u8 authed; + + u8 agid; + u8 variant; + u8 chal[10]; + struct block bkey1, bkey2, bbuskey; +}; + +static inline void swap(unsigned char a[], int i, int j) +{ + unsigned char c; + c = a[i]; + a[i] = a[j]; + a[j] = c; +} + +static inline void rev5(unsigned char a[]) +{ + swap(a, 0, 4); + swap(a, 1, 3); +} + +static inline void rev10(unsigned char a[]) +{ + int i; + for (i = 0; i < 5; i++) + swap(a, i, 9 - i); +} + +static inline u8 *genbuskey(struct rmmc_css css[]) +{ + rev5(css->bkey1.b); + rev5(css->bkey2.b); + memcpy(css->chal, css->bkey1.b, sizeof(css->bkey1.b)); + memcpy(css->chal + sizeof(css->bkey1.b), css->bkey2.b, + sizeof(css->bkey2.b)); + CryptBusKey(css->variant, css->chal, &css->bbuskey); + return css->bbuskey.b; +} + +static inline u8 *genkey1(struct rmmc_css css[]) +{ + rev10(css->chal); + CryptKey1(css->variant, css->chal, &css->bkey1); + rev5(css->bkey1.b); + return css->bkey1.b; +} + +static inline u8 *genkey2(struct rmmc_css css[]) +{ + rev10(css->chal); + CryptKey2(css->variant, css->chal, &css->bkey2); + rev5(css->bkey2.b); + return css->bkey2.b; +} + +static inline int memcmpkey2(struct rmmc_css css[], u8 a[]) +{ + return memcmp(a, css->bkey2.b, sizeof(css->bkey2.b)); +} + +static inline void +encbybuskey(u8 dst[], u8 src[], u32 len, struct rmmc_css css[]) +{ + u32 i; + for (i = 0; i < len; i++) + dst[i] = src[i] ^ css->bbuskey.b[4 - (i % 5)]; +} + +/* ---------------------------------------------------------------------- */ +struct rmmc_conn { + int lasttk; + struct rmmc_css css; + int media_event; +}; + +static inline struct rmmc_css *cmnd_css(struct iscsi_cmnd cmnd[]) +{ + struct iscsi_conn *conn; + struct rmmc_conn *mconn; + + /* if (!cmnd) return NULL; */ + conn = cmnd->conn; + /* if (!conn) return NULL; */ + mconn = conn->private; + if (!mconn) return NULL; + return &mconn->css; +} + +#define set_authed(css, v) \ +do { \ + (css)->authed = (v); \ + /* dprintk(D_RMMC, "authed %d\n", v); */ \ +} while(0) + +#endif /* rmmc_io_h */ Index: iet-0.4.10/kernel/target_disk.c diff -u iet-0.4.10/kernel/target_disk.c:1.1 iet-0.4.10/kernel/target_disk.c:1.7 --- iet-0.4.10/kernel/target_disk.c:1.1 Sat Jun 11 11:30:57 2005 +++ iet-0.4.10/kernel/target_disk.c Thu Jun 16 02:43:04 2005 @@ -139,7 +139,8 @@ return err; } -static int build_inquiry_response(struct iscsi_cmnd *cmnd) +/* static */ +int build_inquiry_response(struct iscsi_cmnd *cmnd) { struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); struct tio *tio = cmnd->tio; @@ -329,6 +330,7 @@ assert(tio); assert(cmnd->lun); + tio_add_pages(tio, tio->need_pages); tio_read(cmnd->lun, tio); return 0; @@ -411,6 +413,5 @@ struct target_type disk_ops = { - .id = 0, .execute_cmnd = disk_execute_cmnd, }; Index: iet-0.4.10/kernel/target_rmmc.c diff -u /dev/null iet-0.4.10/kernel/target_rmmc.c:1.13 --- /dev/null Thu Jun 16 18:47:33 2005 +++ iet-0.4.10/kernel/target_rmmc.c Thu Jun 16 18:22:06 2005 @@ -0,0 +1,939 @@ +/* + * (C) 2004-2005 Junjiro Okajima + * This code is licenced under the GPL. + * + * heavily based on code from *.c under kernel sub directory, which were,,, + * Copyright (C) 2004 Fujita Tomonori + * licensed under the terms of the GPL. + */ + +static char target_rmmc_c[] __attribute__ ((unused, nocommon)) + = "@(#) $Id: target_rmmc.c,v 1.13 2005/06/16 09:22:06 jro Exp $"; + +#include +#include +#include +#include +#include + +#include "iscsi.h" +#include "iscsi_dbg.h" +#include "rmmc-io.h" + +static int rmmc_inquiry(struct iscsi_cmnd *cmnd) +{ + struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); + struct tio *tio; + int ret; + u8 *data; + u8 *scb = req->scb, evpd; + struct iet_volume *lun; + struct rmmc_css *css; + extern int build_inquiry_response(struct iscsi_cmnd *cmnd); // fileio + + evpd = scb[1] & 0x01; +#if RMMC_DEBUG + dprintk(D_RMMC, + "evpd %d, page code %02x, al-len %02x %02x, ctrl %02x\n", evpd, + scb[2], scb[3], scb[4], scb[5]); +#endif + + ret = build_inquiry_response(cmnd); + if (ret) + return ret; + tio = cmnd->tio; + data = page_address(tio->pvec[0]); + + /* lun can be NULL */ + lun = cmnd->lun; + if (lun) { + data[0] = TYPE_ROM; + css = cmnd_css(cmnd); + /* if (!css) return -1; */ + set_authed(css, !isdvdrom(lun)); /* tmp */ + } else + data[0] = TYPE_NO_LUN; + + if (evpd) return 0; + + //assert(tio->length, 64); + data[1] = 0x80; /* rmb */ + data[3] = 0x02; /* norm_aca = 0, hisup = 0, data format(mmc) */ + //data[5] = 0x40; /* sccs = 0, acc = 0, tpgs = 0, 3pc = 0, prot = 0 */ + //data[6] = 0x80; /* bque = 1, encserv = 0, vs = ?, multip = 0, mchnager = 0 */ + //data[7] = 0; /* sync = ?, linked = 0, cmdq = 0, vs = ? */ + + /* product id */ + if (lun) { + if (isdvdrom(lun)) + memcpy(data + 16, "VIRTUAL-DVDROM ", 16); + else if (iscdrom(lun)) + memcpy(data + 16, "VIRTUAL-CDROM ", 16); + } + /* product revision */ + /* memcpy(data + 32, "1 ", 4); */ + +#if RMMC_DEBUG + data[58] = 0x04; /* version descriptor mmc-5 */ + data[59] = 0x20; + data[60] = 0x09; /* iscsi */ + data[61] = 0x60; + data[62] = 0x03; /* spc-3 */ + data[63] = 0x00; +#endif + + return 0; +} + +static int rmmc_capacity(struct iscsi_cmnd *cmnd) +{ + struct tio *tio; + u32 *data32; + struct iet_volume *lun; + + lun = cmnd->lun; + if (!lun) return -1; + + tio = cmnd->tio = tio_alloc(1); + data32 = page_address(tio->pvec[0]); + /* assert(data32); */ + data32[0] = cpu_to_be32(lun->blk_cnt - 1); + data32[1] = cpu_to_be32(RmmcBlkSize); + + tio_set(tio, 8, 0); + + return 0; +} + +/* + * from Ming's vrom patch. + */ +static inline void rmmc_tpa_cdrom(u8 data[], u8 msf) +{ + /* forged for single session data cd only. all iso file fall into this */ + if (msf) { + data[1] = 0x12; + data[2] = 0x01; + data[3] = 0x01; + data[5] = 0x14; + data[6] = 0x01; + data[13] = 0x14; + data[14] = 0xaa; + } else { + data[1] = 0x0a; + data[2] = 0x01; + data[3] = 0x01; + data[5] = 0x14; + data[6] = 0x01; + } +} + +static int rmmc_tpa(struct iscsi_cmnd *cmnd) +{ + struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); + struct tio *tio; + u8 *data, len = 0, fmt, msf; + u8 *scb = req->scb; + struct iet_volume *lun; + + msf = (scb[1] >> 1) & 1; + fmt = scb[2] & 0x0f; +#if RMMC_DEBUG + dprintk(D_RMMC, "time %d, format %x, tr/sess-num %02x, " + "al-len %02x %02x, ctrl %02x\n", + msf, fmt, scb[6], scb[7], scb[8], scb[9]); +#endif + + lun = cmnd->lun; + if (!lun) return -1; + + tio = cmnd->tio = tio_alloc(1); + data = page_address(tio->pvec[0]); + /* assert(data); */ + + if (isdvdrom(lun)) { + switch (fmt) { + case 0: + len = 20; + memset(data, 0, len); + data[1] = 0x12; + data[2] = data[3] = data[6] = 1; + data[5] = data[13] = 0x14; + if (msf) + putu32(data + 8, 0x00000200); + data[14] = 0xaa; + if (msf) + putu32(data + 16, 0x00ff3b4a); + else + putu32(data + 16, lun->blk_cnt); + break; + case 1: + len = 12; + memset(data, 0, len); + data[1] = 0x0a; + data[2] = data[3] = data[6] = 1; + data[5] = 0x14; + if (msf) + putu32(data + 8, 0x00000200); + break; + default: + dprintk(D_RMMC, "Not Implemented Format 0x%02x\n", fmt); + return -1; + } + } else if (iscdrom(lun)) { + len = 20; + memset(data, 0, len); + rmmc_tpa_cdrom(data, msf); + } else { + struct rmmcio_volume *vol; + vol = lun->private; + /* if (!vol) return -1; */ + dprintk(D_RMMC, "unknown media 0x%lx\n", vol->flags); + return -1; + } + + tio_set(tio, min_t(u16, len, getu16(scb + 7)), 0); + return 0; +} + +/* ---------------------------------------------------------------------- */ +static inline struct rmmc_aux_tk* +findtk(struct rmmc_conn mconn[], struct rmmc_aux_rkey rkey[], u32 lba) +{ + struct rmmc_aux_tk *tk, *o; + int n, old; + + o = rkey->data; + n = be32_to_cpu(rkey->ntitle); + old = mconn->lasttk; + + tk = o + mconn->lasttk; + for (; mconn->lasttk < n; mconn->lasttk++, tk++) + if (be32_to_cpu(tk->lba[0]) <= lba + && lba <= be32_to_cpu(tk->lba[1])) + return tk; + + mconn->lasttk = 0; + tk = o; + for (; mconn->lasttk < old; mconn->lasttk++, tk++) + if (be32_to_cpu(tk->lba[0]) <= lba + && lba <= be32_to_cpu(tk->lba[1])) + return tk; + + return NULL; +} + +/* ---------------------------------------------------------------------- */ +static inline int isencrypted(u8 * a, u32 size, int do_warn) +{ + if (a[0x14] & 0x30) + goto end; + /* if (a[0x14] & 0x10) goto end; */ + if (size <= RmmcBlkSize) + return 0; + a += RmmcBlkSize; + if (a[0x14] & 0x30) + goto end; + /* if (a[0x14] & 0x10) goto end; */ + return 0; + end: + if (do_warn) + eprintk("%s\n", + "encrypted blk is going to be read without the authentication"); + return 1; +} + +static inline int +rmmc_readpages(struct iet_volume lun[], struct tio tio[], int need_auth) +{ + int i, ret; + u32 size; + + tio_add_pages(tio, tio->need_pages); + ret = tio_read(lun, tio); + if (ret) { + eprintk("%s\n", "read error"); + /* cmnd->lun->dev_status = -1; */ + return ret; + } + if (!need_auth) + return 0; + + for (size = tio->size, i = 0; i < tio->pg_cnt; i++, size -= PAGE_SIZE) { + struct page *page; + u8 *p; + page = tio->pvec[i]; + /* assert(page); */ + p = page_address(page); + /* assert(p); */ + if (isencrypted(p, size, 1)) + return -1; + } + return 0; +} + +struct rmmc_send_desc { + struct tio *tio; + int i; + int need_auth; + int encrypted; +}; + +static int +rmmc_send_actor(read_descriptor_t *desc, struct page *page, + unsigned long offset, unsigned long size) +{ + unsigned long count = desc->count; + struct rmmc_send_desc *a = desc->arg.data; + struct tio *tio = a->tio; + + /* dprintk(D_RMMC, "size %lu, count %lu\n", size, count); */ + if (size > count) + size = count; + tio->pvec[a->i++] = page; + if (a->need_auth && !a->encrypted) { + /* assert(page); */ + u8 *p = page_address(page); + /* assert(p); */ + if (isencrypted(p, size, 1)) + a->encrypted++; + } + desc->count = count - size; + desc->written += size; + return size; +} + +static inline int +rmmc_sendfile(struct file filp[], loff_t offset, struct tio tio[], int need_auth) +{ + ssize_t written, retval; + int count, ret; + struct rmmc_send_desc a; + + ret = -1; + +#if Exported_rw_verify_area /* linux-2.6.11.7 stopped exporting */ + retval = rw_verify_area(READ, filp, &offset, tio->size); + if (retval) + goto err; +#endif + retval = security_file_permission(filp, MAY_READ); + if (retval) + goto err; + + count = tio->need_pages * sizeof(struct page *); + tio->pvec = kmalloc(count, GFP_KERNEL); + if (!tio->pvec) + goto err; + memset(tio->pvec, 0, count); + + a.tio = tio; + a.i = 0; + a.need_auth = need_auth; + a.encrypted = 0; + written = filp->f_op->sendfile(filp, &offset, tio->size, + rmmc_send_actor, &a); + if ((need_auth && a.encrypted) || written != tio->size) { + kfree(tio->pvec); + tio->pvec = NULL; + goto err; + } + ret = 0; + + err: + //tio->pg_cnt = 0; + /* memset(tio->pvec, 0, count); */ + + return ret; +} + +static inline int +should_auth(struct iscsi_conn conn[], struct rmmcio_volume vol[], loff_t offset) +{ + struct rmmc_conn *mconn; + struct rmmc_css *css; + int ret; + struct rmmc_aux_file *aux; + struct rmmc_aux_rkey *rkey; + u32 len; + + /* if (!conn) goto err; */ + mconn = conn->private; + /* if (!mconn) goto err; */ + css = &mconn->css; + /* if (!css) goto err; */ + ret = !css->authed; + +#if RMMC_DEBUG + /* + * i could not distinguish the legal player or illegal ripper + * after the player. + */ + dprintk(D_RMMC, "conn{cid %x, state %lx, stat_sn %x, exp_stat_sn %x}\n", + conn->cid, conn->state, conn->stat_sn, conn->exp_stat_sn); +#endif + if (!ret) return ret; + + aux = vol_auxfile(vol); + if (!aux) { + set_authed(css, 1); + return 0; + } + + rkey = offlen_rkey(aux, &len); + /* if (!rkey) return -1; */ + + return (findtk(mconn, rkey, offset>>RmmcBlkShift) != NULL); +} + +static int rmmc_read(struct iscsi_cmnd *cmnd) +{ + struct tio *tio = cmnd->tio; + struct iet_volume *lun; + struct rmmcio_volume *vol; + loff_t offset = 0; + int need_auth; + +#if RMMC_DEBUG + struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); + u8 *scb = req->scb; + dprintk(D_RMMC, "op %02x, dpo %d, fua %d, reladr %d, " + "blk{%02x %02x %02x %02x}, " + "len{%02x %02x}, ctrl %02x\n", + scb[0], (scb[1] & 0x10) >> 4, (scb[1] & 0x08) >> 3, + scb[1] & 0x01, scb[2], scb[3], scb[4], scb[5], scb[7], scb[8], + scb[9]); + dprintk(D_RMMC, "idx %lu, pg_cnt %u, offset %u, size %u\n", tio->idx, + tio->pg_cnt, tio->offset, tio->size); +#endif + + lun = cmnd->lun; + if (!lun) return -1; +#if RMMC_DEBUG + if (lun->dev_status) { + dprintk(D_RMMC, "%s\n", "un-recovered error(yet)"); + return -1; + } +#endif + + offset = tio->offset; + offset += (loff_t) tio->idx << PAGE_CACHE_SHIFT; + /* dprintk(D_RMMC, "offset %Lu, size %d\n", offset>>RmmcBlkShift, tio->size); */ + + vol = lun->private; + /* if (!vol) goto err; */ + need_auth = 0; + if (isdvdrom(lun)) + need_auth = should_auth(cmnd->conn, vol, offset); + + if (cmnd->conn->ddigest_type != DIGEST_NONE + || !test_bit(RmmcSendfile, &vol->flags)) + return rmmc_readpages(lun, tio, need_auth); + return rmmc_sendfile(vol->fileio_data->filp, offset, tio, need_auth); +} + +static int rmmc_tur(struct iscsi_cmnd *cmnd) +{ +#if RMMC_DEBUG + struct iet_volume *lun; + struct rmmcio_volume *vol; + struct fileio_data *fio; + struct file *filp; + struct dentry *dent; + struct inode *inode; + struct block_device *bdev; + struct gendisk *gdk; + struct super_block *sb; + + lun = cmnd->lun; + //dprintk(D_RMMC, "lun->dev_status %d\n", lun->dev_status); + //if (!lun->dev_status) return 0; // device is fine. + + vol = lun->private; + fio = vol->fileio_data; + filp = fio->filp; + dent = filp->f_dentry; + inode = dent->d_inode; + bdev = inode->i_bdev; + sb = dent->d_sb; + bdev = sb->s_bdev; + //dprintk(D_RMMC, "lun->dev %08x\n", lun->dev); + //dprintk(D_RMMC, "filp->f_error %08x\n", filp->f_error); + //dprintk(D_RMMC, "bdev %p\n", bdev); + if (0 && bdev) { + dprintk(D_RMMC, "bdev->bd_invalidated %08x\n", + bdev->bd_invalidated); + gdk = bdev->bd_disk; + //dprintk(D_RMMC, "gdk %p\n", gdk); + if (gdk) + dprintk(D_RMMC, "gdk->flags %08x\n", gdk->flags); + } +#endif + return 0; +} + +/* ---------------------------------------------------------------------- */ + +static int rmmc_dvdst(struct iscsi_cmnd *cmnd) +{ + struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); + struct tio *tio; + u8 *data, agid, num; + u8 *scb = req->scb; + struct iet_volume *lun; + struct rmmc_aux_file *aux; + struct rmmc_aux_dvdst *dvdst; + struct rmmc_aux_layer *layer; + struct rmmc_aux_phys *phys; + struct rmmc_aux_cprt *cprt; + u8 *manuf; + struct rmmc_css *css; + u32 len; + enum { Phys, Cprt, DKey, + Burst_Cutting_Area, + Manufacturing, + Cprt_Management, + Media_Identifier, + Media_Key, + ADIP = 0x11, + Disc_Control = 0x30, + READ_SEND_DVD_STRUCTURE = 0xff + }; + + agid = scb[10] >> 6; + num = scb[6]; +#if RMMC_DEBUG + dprintk(D_RMMC, "addr{%02x %02x %02x %02x}, layer %d, format %x, " + "al-len %02x %02x, agid %x, ctrl %02x\n", + scb[2], scb[3], scb[4], scb[5], num, scb[7], + scb[8], scb[9], agid, scb[11]); +#endif + + lun = cmnd->lun; + if (!lun) + return -1; + aux = vol_auxfile(lun->private); + if (!aux) + return -1; + dvdst = offlen_dvdst(aux, &len); + if (!dvdst) + return -1; + layer = offlen_layer(dvdst, num, &len); + if (!layer) + return -1; + + tio = cmnd->tio = tio_alloc(1); + data = page_address(tio->pvec[0]); + /* assert(data); */ + + switch (scb[7]) { + case Phys: + /* dprintk(D_RMMC, "phys%s", "\n"); */ + phys = offlen_phys(layer, &len); + if (!phys) + return -1; + memcpy(data, phys, len); + break; + case Cprt: + /* dprintk(D_RMMC, "copyright%s", "\n"); */ + cprt = offlen_cprt(layer, &len); + if (!cprt) + return -1; + memcpy(data, cprt, len); + break; + case DKey: + /* dprintk(D_RMMC, "disc key%s", "\n"); */ + css = cmnd_css(cmnd); + /* if (!css) return -1; */ + if (!css->authed) + return -1; + len = sizeof(dvdst->dkey); + memcpy(data, dvdst->dkey, 4); + encbybuskey(data + 4, dvdst->dkey + 4, len - 4, css); + break; + case Manufacturing: + dprintk(D_RMMC, "manufacturing%s", "\n"); + manuf = offlen_manuf(layer, &len); + if (!manuf) + return -1; + memcpy(data, manuf, len); + break; + default: + dprintk(D_RMMC, "unknown %02x\n", scb[7]); + return -1; + } + + tio_set(tio, min_t(u16, len, getu16(scb + 8)), 0); + return 0; +} + +static int rmmc_report_key(struct iscsi_cmnd *cmnd) +{ + struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); + struct tio *tio; + u8 *data, len = 4, *p, agid, fmt, class; + u8 *scb = req->scb; + struct rmmc_css *css; + struct iet_volume *lun; + struct rmmc_aux_file *aux; + struct rmmc_aux_rkey *rkey; + struct rmmc_aux_tk *tk; + u32 len32, lba; + enum { Agid_CSS_CPPM, ChalKey, Key1, + TitleKey = 0x04, + ASF, + RPCState = 0x08, + AGID_CPRM = 0x11, + None = 0x3f + }; + + fmt = scb[10] & 0x3f; + class = scb[7]; + agid = scb[10] >> 6; + + /* + * currently, only CSS/CPPM/CPRM Key Class is supported. + */ + if (class) { + dprintk(D_RMMC, "Not Implemented keyclass 0x%02x\n", class); + return -1; + } + +#if RMMC_DEBUG + dprintk(D_RMMC, "CSS/CPPM/CPRM Key Class, addr{%02x %02x %02x %02x}, " + "agid %01x, format %02x, " + "al-len %02x %02x, ctrl %02x\n", + scb[2], scb[3], scb[4], scb[5], + agid, scb[10] & 0x3f, scb[8], scb[9], scb[11]); +#endif + + css = cmnd_css(cmnd); + if (!css) return -1; + + tio = cmnd->tio = tio_alloc(1); + data = page_address(tio->pvec[0]); + /* assert(data); */ + p = data + 4; + + switch (fmt) { + case RPCState: + len += 4; + memset(data, 0, len); + p[0] = 0xc0; /* type = 11h, vra = 0, ucca = 0 */ + p[1] = 0xfd; /* region mask */ + p[2] = 0x01; /* rpc scheme */ + break; + case None: + len = 0; + break; + case Agid_CSS_CPPM: + len += 4; + memset(data, 0, len); + p[3] = css->agid << 6; + break; + case Key1: + len += 8; + memcpy(p, genkey1(css), CSSKey1Len); + break; + case ChalKey: + len += 12; + get_random_bytes(css->chal, sizeof(css->chal)); + memcpy(p, css->chal, sizeof(css->chal)); + break; + case ASF: + len += 4; + memset(data, 0, len); + p[3] = css->authed; + break; + case TitleKey: + if (!css->authed || css->agid != agid) + return -1; + lun = cmnd->lun; + if (!lun) + return -1; + aux = vol_auxfile(lun->private); + if (!aux) + return -1; + rkey = offlen_rkey(aux, &len32); + if (!rkey) + return -1; + lba = getu32(scb + 2); + /* dprintk(D_RMMC, "title key lba=%u\n", lba); */ + tk = findtk(cmnd->conn->private, rkey, lba); + if (!tk) + return -1; + + len += 8; + memset(data, 0, len); + p[0] = tk->cpbits; + encbybuskey(p + 1, tk->tk, sizeof(tk->tk), css); + break; + default: + dprintk(D_RMMC, "Not Implemented fmt 0x%02x\n", fmt); + return -1; + } + + if (len) + putu16(data, len - 2); + tio_set(tio, min_t(u16, len, getu16(scb + 8)), 0); +#if RMMC_DEBUG + dprintk(D_RMMC, + "res{%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x}\n", + data[0], data[1], data[2], data[3], data[4], data[5], data[6], + data[7], data[8], data[9]); +#endif + return 0; +} + +static int rmmc_send_key(struct iscsi_cmnd *cmnd) +{ + struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); + struct tio *tio = cmnd->tio; + u8 *data, len, *p; + u8 *scb = req->scb, kcls, kfmt, agid; + struct rmmc_css *css; + + list_del_init(&cmnd->list); //?? + kcls = scb[7]; +#if RMMC_DEBUG + dprintk(D_RMMC, "key-class %02x, len{%02x %02x}, ctrl %02x\n", + kcls, scb[8], scb[9], scb[11]); + dprintk(D_RMMC, "tio %p\n", tio); + if (tio) + dprintk(D_RMMC, "tio{pg_cnt %d, pvec %p}\n", tio->pg_cnt, + tio->pvec); +#endif + + if (kcls) { + dprintk(D_RMMC, "Not Implemented key-class 0x%02x\n", kcls); + return -1; + } + + /* + * DVD CSS/CPPM or CPRM + */ + kfmt = scb[10] & 0x3f; + agid = scb[10] >> 6; + /* dprintk(D_RMMC, "agid %x, format %02x\n", agid, kfmt); */ + + css = cmnd_css(cmnd); + if (!css) return -1; + + switch (kfmt) { + case 0x01: /* challenge key */ + case 0x03: /* key 2 */ + set_authed(css, 0); + break; + case 0x3f: /* invalidate agid */ + /* dprintk(D_RMMC, "%s\n", "invalidate agid"); */ + return 0; + case 0x06: /* rpc struct */ + /* dprintk(D_RMMC, "rpc struct{region %02x}\n", scb[4]); */ + return 0; + default: + dprintk(D_RMMC, "Not Implemented key-format 0x%02x\n", kfmt); + return -1; + } + + if (!tio || !tio->pvec || !tio->pvec[0]) { + eprintk("%s\n", "no tio or tio->pvec"); + return -1; + } + data = page_address(tio->pvec[0]); + assert(data); + p = data + 4; + len = getu16(data); + + switch (kfmt) { + case 0x01: /* challenge key */ + if (len < sizeof(css->chal) + 2) + return -1; + memcpy(css->chal, p, sizeof(css->chal)); + break; + case 0x03: /* key 2 */ + if (len < CSSKey2Len + 2) + return -1; + genkey2(css); + set_authed(css, !memcmpkey2(css, p)); + if (!css->authed) + break; + genbuskey(css); + break; + } + + return 0; +} + +static int rmmc_error(struct iscsi_cmnd *cmnd) +{ + return -1; +} + +static int rmmc_execute_cmnd(struct iscsi_cmnd *cmnd) +{ + struct iscsi_scsi_cmd_hdr *req = cmnd_hdr(cmnd); + + req->opcode &= ISCSI_OPCODE_MASK; + +#if RMMC_DEBUG + switch (req->scb[0]) { + case TEST_UNIT_READY: + case READ_10: + break; + case GPCMD_REPORT_KEY: + case GPCMD_SEND_KEY: + case READ_CAPACITY: + case INQUIRY: + case GPCMD_MODE_SENSE_10: + case GPCMD_READ_TOC_PMA_ATIP: + //break; + case GPCMD_READ_DVD_STRUCTURE: + case GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL: + //break; + case GPCMD_READ_SUBCHANNEL: + case GPCMD_READ_DISC_INFO: + case GPCMD_GET_EVENT_STATUS_NOTIFICATION: + case GPCMD_READ_TRACK_RZONE_INFO: + case GPCMD_GET_CONFIGURATION: + //break; + default: + dprintk(D_RMMC, "scsi cmd %s(%02x)\n", + opstr(req->scb[0]), req->scb[0]); + } +#endif + + switch (req->scb[0]) { + case INQUIRY: + send_data_rsp(cmnd, rmmc_inquiry); + break; + case READ_CAPACITY: + send_data_rsp(cmnd, rmmc_capacity); + break; + case GPCMD_READ_TOC_PMA_ATIP: + send_data_rsp(cmnd, rmmc_tpa); + break; + case READ_6: + case READ_10: + case READ_16: + send_data_rsp(cmnd, rmmc_read); + break; + case TEST_UNIT_READY: + send_scsi_rsp(cmnd, rmmc_tur); + break; + + /* + * dvd specfic commands + */ + case GPCMD_READ_DVD_STRUCTURE: + if (!isdvdrom(cmnd->lun)) goto err; + send_data_rsp(cmnd, rmmc_dvdst); + break; + case GPCMD_REPORT_KEY: + if (!isdvdrom(cmnd->lun)) goto err; + send_data_rsp(cmnd, rmmc_report_key); + break; + case GPCMD_SEND_KEY: + if (!isdvdrom(cmnd->lun)) goto err; + send_scsi_rsp(cmnd, rmmc_send_key); + break; + + /* + * common to disk ope. + */ + case REPORT_LUNS: + case REQUEST_SENSE: + case SERVICE_ACTION_IN: + case START_STOP: + case SYNCHRONIZE_CACHE: + case VERIFY: + case VERIFY_16: + case RESERVE: + case RELEASE: + case RESERVE_10: + case RELEASE_10: + /* dprintk(D_RMMC, "passing disk_ops %02x\n", req->scb[0]); */ + return disk_ops.execute_cmnd(cmnd); + + default: + do { + struct iscsi_conn *conn; + struct socket *sock; + struct sock *sk; + struct inet_sock *inet; + conn = cmnd->conn; + if (!conn) + break; + sock = conn->sock; + if (!sock) + break; + sk = sock->sk; + if (!sk) + break; + inet = inet_sk(sk); + if (!inet) + break; + dprintk(D_RMMC, "bad op %02x from ip %08x\n", + req->scb[0], inet->daddr); + } while (0); + + /* + * make them errors + */ + case MODE_SENSE: + case GPCMD_MODE_SENSE_10: + case GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL: + case GPCMD_GET_EVENT_STATUS_NOTIFICATION: + case GPCMD_READ_DISC_INFO: + case GPCMD_READ_TRACK_RZONE_INFO: + case GPCMD_GET_CONFIGURATION: + case GPCMD_SEEK: + case GPCMD_READ_CD_MSF: + case GPCMD_READ_CD: + case WRITE_6: + case WRITE_10: + case WRITE_16: + case WRITE_VERIFY: + case GPCMD_READ_SUBCHANNEL: + err: + send_scsi_rsp(cmnd, rmmc_error); + break; + } + + return 0; +} + +/* ---------------------------------------------------------------------- */ + +int rmmc_init_conn(struct iscsi_conn conn[]) +{ + struct rmmc_conn *mconn; + u8 a[2]; + + mconn = kmalloc(sizeof(*mconn), GFP_KERNEL); + if (!mconn) + return -ENOMEM; + /* dprintk(D_RMMC, "rmmc_conn %p\n", mconn); */ + memset(mconn, 0, sizeof(*mconn)); + get_random_bytes(a, 2); + mconn->css.agid = a[0] & 3; + mconn->css.variant = a[1] % 10; + + conn->private = mconn; + return 0; +} + +int rmmc_clean_conn(struct iscsi_conn conn[]) +{ + if (!conn->private) + return 0; + kfree(conn->private); + /* dprintk(D_RMMC, "freed rmmc_conn %p\n", conn->private); */ + conn->private = NULL; + return 0; +} + +struct target_type rmmc_ops = { + .execute_cmnd = rmmc_execute_cmnd, + .init_conn = rmmc_init_conn, + .clean_conn = rmmc_clean_conn +}; Index: iet-0.4.10/kernel/tio.c diff -u iet-0.4.10/kernel/tio.c:1.1 iet-0.4.10/kernel/tio.c:1.2 --- iet-0.4.10/kernel/tio.c:1.1 Sat Jun 11 11:30:57 2005 +++ iet-0.4.10/kernel/tio.c Sat Jun 11 11:44:09 2005 @@ -8,7 +8,8 @@ #include "iscsi_dbg.h" #include "iotype.h" -static int tio_add_pages(struct tio *tio, int count) +/* static */ +int tio_add_pages(struct tio *tio, int count) { int i; struct page *page; @@ -38,13 +39,14 @@ static kmem_cache_t *tio_cache; -struct tio *tio_alloc(int count) +struct tio *_tio_alloc(int count, int add_pages_now) { struct tio *tio; tio = kmem_cache_alloc(tio_cache, GFP_KERNEL | __GFP_NOFAIL); tio->pg_cnt = 0; + tio->need_pages = 0; tio->idx = 0; tio->offset = 0; tio->size = 0; @@ -52,8 +54,10 @@ atomic_set(&tio->count, 1); - if (count) + if (count && add_pages_now) tio_add_pages(tio, count); + else + tio->need_pages = count; return tio; } Index: iet-0.4.10/kernel/wthread.c diff -u iet-0.4.10/kernel/wthread.c:1.1 iet-0.4.10/kernel/wthread.c:1.2 --- iet-0.4.10/kernel/wthread.c:1.1 Sat Jun 11 11:30:57 2005 +++ iet-0.4.10/kernel/wthread.c Sat Jun 11 11:44:09 2005 @@ -50,7 +50,7 @@ static int cmnd_execute(struct iscsi_cmnd *cmnd) { - int type = cmnd->conn->session->target->target_type; + int type = cmnd->conn->session->target->trgt_param.target_type; assert(target_type_array[type]->execute_cmnd); return target_type_array[type]->execute_cmnd(cmnd); Index: iet-0.4.10/usr/Makefile diff -u iet-0.4.10/usr/Makefile:1.1 iet-0.4.10/usr/Makefile:1.3 --- iet-0.4.10/usr/Makefile:1.1 Sat Jun 11 11:30:57 2005 +++ iet-0.4.10/usr/Makefile Sat Jun 11 23:21:15 2005 @@ -1,5 +1,5 @@ CFLAGS += -O2 -fno-inline -Wall -Wstrict-prototypes -g -I../include -PROGRAMS = ietd ietadm +PROGRAMS = ietd ietadm rmmcgen LIBS = -lcrypto all: $(PROGRAMS) @@ -13,3 +13,6 @@ clean: rm -f *.o $(PROGRAMS) + +rmmcgen.o: CPPFLAGS += -I../css-auth -DNDEBUG +rmmcgen: $(addprefix ../css-auth/, $(addsuffix .c, css-auth csstable)) Index: iet-0.4.10/usr/param.c diff -u iet-0.4.10/usr/param.c:1.1 iet-0.4.10/usr/param.c:1.2 --- iet-0.4.10/usr/param.c:1.1 Sat Jun 11 11:30:57 2005 +++ iet-0.4.10/usr/param.c Sat Jun 11 11:44:09 2005 @@ -285,7 +285,7 @@ struct iscsi_key target_keys[] = { {"Wthreads", SET_KEY_VALUES(WTHREADS), &minimum_ops}, - {"Type", 0, 16, 0, &minimum_ops}, + {"Type", 0, 0, 16, &minimum_ops}, {"QueuedCommands", SET_KEY_VALUES(QUEUED_CMNDS), &minimum_ops}, {NULL,}, }; Index: iet-0.4.10/usr/rmmcgen.c diff -u /dev/null iet-0.4.10/usr/rmmcgen.c:1.2 --- /dev/null Thu Jun 16 18:47:33 2005 +++ iet-0.4.10/usr/rmmcgen.c Sat Jun 11 23:21:15 2005 @@ -0,0 +1,1338 @@ + +/* + * based upon tstdvd.c of css-auth tools, which was,,, + * Copyright (C) 1999 Andrew T. Veliath + * See http://www.rpi.edu/~veliaa/linux-dvd for more info. + * + * and arranged by Junjiro Okajima for ietd read-only mmc interface. + * Copyright (C) 2005 Junjiro Okajima + */ + +static char rmmcgen_c[] __attribute__ ((unused, nocommon)) + = "@(#) $Id: rmmcgen.c,v 1.2 2005/06/11 14:21:15 jro Exp $"; + +//#define _LARGEFILE_SOURCE +//#define _LARGEFILE64_SOURCE +#define _FILE_OFFSET_BITS 64 + +/* -------------------- tstdvd.c -------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(__OpenBSD__) +# include +#elif defined(__linux__) +# include +#else +# error "Need the DVD ioctls" +#endif +#include "css-auth.h" + +byte Challenge[10]; +struct block Key1; +struct block Key2; +struct block KeyCheck; +byte DiscKey[10]; +int varient = -1; +int agid = -1; + +#if 0 +void print_challenge(const byte * chal) +{ + int i; + + for (i = 0; i < 10; ++i) + printf(" %02X", chal[9 - i] & 0xff); +} + +void print_key(const byte * key) +{ + int i; + + for (i = 0; i < 5; ++i) + printf(" %02X", key[4 - i] & 0xff); +} + +void print_five(const byte * key) +{ + int i; + + for (i = 0; i < 5; ++i) + printf(" %02X", key[i] & 0xff); +} +#endif + +int authenticate_drive(const byte * key) +{ + int i; + + for (i = 0; i < 5; i++) + Key1.b[i] = key[4 - i]; + + for (i = 0; i < 32; ++i) { + CryptKey1(i, Challenge, &KeyCheck); + if (memcmp(KeyCheck.b, Key1.b, 5) == 0) { + varient = i; + /* printf("Drive Authentic - using varient %d\n", i); */ + return 1; + } + } + + if (varient == -1) + printf("Drive would not Authenticate\n"); + + return 0; +} + +#if 0 +int GetDiscKey(int fd, int agid, char *key) +{ + dvd_struct s; + int index, fdd; + + s.type = DVD_STRUCT_DISCKEY; + s.disckey.agid = agid; + memset(s.disckey.value, 0, 2048); + if (ioctl(fd, DVD_READ_STRUCT, &s) < 0) { + printf("Could not read Disc Key\n"); + return 0; + } + + /* printf ("Received Disc Key:\t"); */ + for (index = 0; index < sizeof s.disckey.value; index++) + s.disckey.value[index] ^= key[4 - (index % 5)]; +#if 0 + for (index = 0; index < 10; index++) { + printf("%02X ", s.disckey.value[index]); + } + printf("\n"); +#endif + + fdd = open("disk-key", O_WRONLY | O_TRUNC | O_CREAT, 0644); + if (fdd < 0) + printf("Can't create \"disk-key\"\n"); + else { + if (write(fdd, s.disckey.value, 2048) != 2048) + printf("Can't write \"disk-key\"\n"); + close(fdd); + } + + return 1; +} + +int GetTitleKey(int fd, int agid, int lba, char *key) +{ + dvd_authinfo ai; + int i, fdd; + + ai.type = DVD_LU_SEND_TITLE_KEY; + + ai.lstk.agid = agid; + ai.lstk.lba = lba; + + if (ioctl(fd, DVD_AUTH, &ai)) { + printf("GetTitleKey failed\n"); + return 0; + } + + /* printf ("Received Title Key:\t"); */ + for (i = 0; i < 5; ++i) { + ai.lstk.title_key[i] ^= key[4 - (i % 5)]; + //printf("%02X ", ai.lstk.title_key[i]); + } + /* putchar('\n'); */ + + /* printf(" CPM=%d, CP_SEC=%d, CGMS=%d\n", ai.lstk.cpm, ai.lstk.cp_sec, ai.lstk.cgms); */ + + fdd = open("title-key", O_WRONLY | O_TRUNC | O_CREAT, 0644); + if (fdd < 0) + printf("Can't create \"title-key\"\n"); + else { + if (write(fdd, ai.lstk.title_key, 5) != 5) + printf("Can't write \"title-key\"\n"); + close(fdd); + } + + return 1; +} +#endif + +int GetASF(int fd) +{ + dvd_authinfo ai; + + ai.type = DVD_LU_SEND_ASF; + ai.lsasf.agid = 0; + ai.lsasf.asf = 0; + + if (ioctl(fd, DVD_AUTH, &ai)) { + printf("GetASF failed\n"); + return 0; + } + + /* printf("%sAuthenticated\n", (ai.lsasf.asf) ? "" : "not "); */ + + return 1; +} + +/* Simulation of a non-CSS compliant host (i.e. the authentication fails, + * but idea is here for a real CSS compliant authentication scheme). */ +int hostauth(dvd_authinfo * ai) +{ + int i; + + switch (ai->type) { + /* Host data receive (host changes state) */ + case DVD_LU_SEND_AGID: + /* printf("AGID %d\n", ai->lsa.agid); */ + ai->type = DVD_HOST_SEND_CHALLENGE; + break; + + case DVD_LU_SEND_KEY1: + /* printf("LU sent key1: "); print_key(ai->lsk.key); printf("\n"); */ + if (!authenticate_drive(ai->lsk.key)) { + ai->type = DVD_AUTH_FAILURE; + return -EINVAL; + } + ai->type = DVD_LU_SEND_CHALLENGE; + break; + + case DVD_LU_SEND_CHALLENGE: + for (i = 0; i < 10; ++i) + Challenge[i] = ai->hsc.chal[9 - i]; + /* printf("LU sent challenge: "); print_challenge(Challenge); printf("\n"); */ + CryptKey2(varient, Challenge, &Key2); + ai->type = DVD_HOST_SEND_KEY2; + break; + + /* Host data send */ + case DVD_HOST_SEND_CHALLENGE: + for (i = 0; i < 10; ++i) + ai->hsc.chal[9 - i] = Challenge[i]; + /* printf("Host sending challenge: "); print_challenge(Challenge); printf("\n"); */ + /* Returning data, let LU change state */ + break; + + case DVD_HOST_SEND_KEY2: + for (i = 0; i < 5; ++i) + ai->hsk.key[4 - i] = Key2.b[i]; + /* printf("Host sending key 2: "); print_key(Key2.b); printf("\n"); */ + /* Returning data, let LU change state */ + break; + + default: + printf("Got invalid state %d\n", ai->type); + return -EINVAL; + } + + return 0; +} + +int authenticate(int fd, int title, int lba) +{ + dvd_authinfo ai; + dvd_struct dvds; + int i, rv, tries; + + memset(&ai, 0, sizeof(ai)); + memset(&dvds, 0, sizeof(dvds)); + + GetASF(fd); + + /* Init sequence, request AGID */ + for (tries = 1, rv = -1; rv == -1 && tries < 4; ++tries) { + /* printf("Request AGID [%d]...\t", tries); */ + ai.type = DVD_LU_SEND_AGID; + ai.lsa.agid = 0; + rv = ioctl(fd, DVD_AUTH, &ai); + if (rv == -1) { + /* perror("N/A, invalidating"); */ + ai.type = DVD_INVALIDATE_AGID; + ai.lsa.agid = 0; + ioctl(fd, DVD_AUTH, &ai); + } + } + if (tries == 4) { + printf("Cannot get AGID\n"); + return -1; + } + + for (i = 0; i < 10; ++i) + Challenge[i] = i; + + /* Send AGID to host */ + if (hostauth(&ai) < 0) { + printf("Send AGID to host failed\n"); + return -1; + } + /* Get challenge from host */ + if (hostauth(&ai) < 0) { + printf("Get challenge from host failed\n"); + return -1; + } + if (agid == -1) + agid = ai.lsa.agid; + else if (agid != ai.lsa.agid) { + printf("AGID have been changed. Try again\n"); + return -1; + } + /* Send challenge to LU */ + if (ioctl(fd, DVD_AUTH, &ai) < 0) { + printf("Send challenge to LU failed\n"); + return -1; + } + /* Get key1 from LU */ + { + struct timespec req; + req.tv_sec = 1; + req.tv_nsec = 0; + nanosleep(&req, NULL); + } + if (ioctl(fd, DVD_AUTH, &ai) < 0) { + printf("Get key1 from LU failed\n"); + return -1; + } + /* Send key1 to host */ + if (hostauth(&ai) < 0) { + printf("Send key1 to host failed\n"); + return -1; + } + /* Get challenge from LU */ + if (ioctl(fd, DVD_AUTH, &ai) < 0) { + printf("Get challenge from LU failed\n"); + return -1; + } + /* Send challenge to host */ + if (hostauth(&ai) < 0) { + printf("Send challenge to host failed\n"); + return -1; + } + /* Get key2 from host */ + if (hostauth(&ai) < 0) { + printf("Get key2 from host failed\n"); + return -1; + } + /* Send key2 to LU */ + if (ioctl(fd, DVD_AUTH, &ai) < 0) { + printf("Send key2 to LU failed (expected)\n"); + return -1; + } + + if (ai.type == DVD_AUTH_ESTABLISHED); /* printf("DVD is authenticated\n"); */ + else if (ai.type == DVD_AUTH_FAILURE) + printf("DVD authentication failed\n"); + + memcpy(Challenge, Key1.b, 5); + memcpy(Challenge + 5, Key2.b, 5); + CryptBusKey(varient, Challenge, &KeyCheck); +#if 0 + printf("Received Session Key:\t"); + for (i = 0; i < 5; i++) { + printf("%02X ", KeyCheck.b[i]); + } + printf("\n"); + + GetASF(fd); + + if (title) + GetTitleKey(fd, agid, lba, KeyCheck.b); + else + GetDiscKey(fd, agid, KeyCheck.b); + + GetASF(fd); +#endif + + return 0; +} + +#ifndef FIBMAP +#define FIBMAP 1 +#endif + +#if 0 +int path_to_lba(char *p) +{ + int fd, lba = 0; + + if ((fd = open(p, O_RDONLY)) == -1) { + perror("DVD vob file:"); + return 0; + } + if (ioctl(fd, FIBMAP, &lba) != 0) { + perror("ioctl FIBMAP failed:"); + close(fd); + return 0; + } + + close(fd); + + return lba; +} +#endif + +/* ---------------------------------------------------------------------- */ +#include +#include +#include +#include +#include +#include + +#include "types.h" +#include "param.h" +#include "config.h" +#include "rmmc_aux.h" + +enum { Device, Img, Aux, LastFile }; +struct f { + char *fname; + int fd; + FILE *fp; +}; + +struct opts { + char genimg:1; + char genaux:1; + char dumpaux:1; + char quiet:1; + char *name; + char *device; + char *mntpnt; +}; + +/* all uppercase. */ +#define VTSDir "VIDEO_TS" + +/* ---------------------------------------- */ + +int openthem(struct f f[], struct opts opts[]) +{ + struct f *p; + int found, n; + struct dirent *de; + DIR *dir; + + if (opts->mntpnt && *opts->mntpnt) { + /* is it udf? */ + dir = opendir(opts->mntpnt); + if (!dir) + return -1; + found = 0; + while (!found && (de = readdir(dir)) != NULL) + found = (strcasecmp(de->d_name, VTSDir) == 0); + errno = ENXIO; + if (!found) + return -1; + } + + if (opts->device && *opts->device) { + p = f + Device; + p->fname = opts->device; + p->fd = open(p->fname, O_RDONLY /*|O_NONBLOCK */ ); + if (p->fd < 0) + return -1; + + if (opts->genimg) { + p->fp = fdopen(p->fd, "r"); + if (!p->fp) + return -1; + + p = f + Img; + p->fname = opts->name; + p->fd = open(p->fname, O_RDWR | O_CREAT | O_EXCL, 0644); + if (p->fd < 0) + return -1; + p->fp = fdopen(p->fd, "r+"); + if (!p->fp) + return -1; + } + } + + p = f + Aux; + if (opts->dumpaux) { + p->fname = opts->name; + p->fd = open(p->fname, O_RDONLY); + if (p->fd < 0) + return -1; + } else if (opts->genaux) { + n = strlen(opts->name); +#define AuxExt ".aux" + p->fname = malloc(n + sizeof(AuxExt)); + if (!p->fname) + return -1; + strcpy(p->fname, opts->name); + strcpy(p->fname + n, AuxExt); +#undef AuxExt + p->fd = open(p->fname, O_RDWR | O_CREAT | O_EXCL, 0644); + if (p->fd < 0) + return -1; + p->fp = fdopen(p->fd, "r+"); + if (!p->fp) + return -1; + } + + return 0; +} + +/* ---------------------------------------- */ + +inline struct cdrom_generic_command *getcgc(u16 len) +{ + static struct cdrom_generic_command cgc; + static u8 a[4096]; + + assert(len <= sizeof(a)); + memset(&cgc, 0, sizeof(cgc)); + cgc.buffer = a; + cgc.buflen = len; + cgc.data_direction = CGC_DATA_READ; + cgc.timeout = 5 * HZ; + return &cgc; +} + +inline u8 *do_ioctl(int fd, struct cdrom_generic_command cgc[]) +{ + int ret; + + ret = ioctl(fd, CDROM_SEND_PACKET, cgc); + if (ret) + return NULL; + return cgc->buffer; +} + +inline u8 *do_dvdst(int fd, u8 num, u8 kind, u16 len, u8 agid) +{ + struct cdrom_generic_command *cgc; + + cgc = getcgc(len); + cgc->cmd[0] = GPCMD_READ_DVD_STRUCTURE; + cgc->cmd[6] = num; + cgc->cmd[7] = kind; + putu16(cgc->cmd + 8, len); + cgc->cmd[10] = agid << 6; + return do_ioctl(fd, cgc); +} + +inline u8 *do_rkey(int fd, u32 lba, u16 len, u8 agid, u8 kind) +{ + struct cdrom_generic_command *cgc; + + cgc = getcgc(len); + cgc->cmd[0] = GPCMD_REPORT_KEY; + putu32(cgc->cmd + 2, lba); + cgc->cmd[7] = 0; + putu16(cgc->cmd + 8, len); + cgc->cmd[10] = agid << 6; + cgc->cmd[10] |= kind; + return do_ioctl(fd, cgc); +} + +/* ---------------------------------------- */ + +int putlayer(FILE fp[], int fd, int num, u8 nlayer[]) +{ + int ret; + u32 start, tlen; + struct rmmc_aux_layer layer; + u16 len; + u8 *p; + + start = ftell(fp); + if (start == -1) + goto err; + ret = fseek(fp, sizeof(layer), SEEK_CUR); + if (ret == -1) + goto err; + + memset(&layer, 0, sizeof(layer)); + tlen = 0; +#define ReqLen 4+2048 + p = do_dvdst(fd, num, DVD_STRUCT_PHYSICAL, ReqLen + 1, agid); + if (!p) + goto err; + if (nlayer) { + *nlayer = (p[4 + 2] >> 5) & 3; + (*nlayer)++; + } + len = getu16(p) + 2; + assert(len <= ReqLen); + ret = fwrite(p, len, 1, fp); + if (ret != 1) + goto err; + set_offlen(layer.offlen + DslPhys, tlen, len); + tlen += len; + + p = do_dvdst(fd, num, DVD_STRUCT_COPYRIGHT, ReqLen + 1, agid); + if (!p) + goto err; + len = getu16(p) + 2; + assert(len <= ReqLen); + ret = fwrite(p, len, 1, fp); + if (ret != 1) + goto err; + set_offlen(layer.offlen + DslCprt, tlen, len); + tlen += len; + + p = do_dvdst(fd, num, DVD_STRUCT_MANUFACT, ReqLen + 1, agid); + if (!p) + goto err; + len = getu16(p) + 2; + assert(len <= ReqLen); +#undef ReqLen + ret = fwrite(p, len, 1, fp); + if (ret != 1) + goto err; + set_offlen(layer.offlen + DslManuf, tlen, len); + tlen += len; + + ret = fseek(fp, start, SEEK_SET); + if (ret == -1) + goto err; + ret = fwrite(&layer, sizeof(layer), 1, fp); + if (ret != 1) + goto err; + ret = fseek(fp, tlen, SEEK_CUR); + if (ret == -1) + goto err; + + return sizeof(layer) + tlen; + err: + return -1; +} + +int putdvdst(FILE fp[], int fd) +{ + int i, ret; + u32 start, tlen; + struct rmmc_aux_dvdst dvdst; + u8 *p; + u16 len; + + start = ftell(fp); + if (start == -1) + goto err; + ret = fseek(fp, sizeof(dvdst), SEEK_CUR); + if (ret == -1) + goto err; + + memset(&dvdst, 0, sizeof(dvdst)); + tlen = 0; + dvdst.nlayer = DVD_LAYERS; + for (i = 0; i < dvdst.nlayer; i++) { + ret = putlayer(fp, fd, i, &dvdst.nlayer); + if (ret < 0) + goto err; + set_offlen(dvdst.offlen + i, tlen, ret); + tlen += ret; + } + + ret = authenticate(fd, 0, 0); + if (ret) + goto err; + p = do_dvdst(fd, 0, DVD_STRUCT_DISCKEY, sizeof(dvdst.dkey) + 1, agid); + if (!p) + goto err; + len = getu16(p) + 2; + assert(len <= sizeof(dvdst.dkey)); + memcpy(dvdst.dkey, p, 4); + p += 4; + for (i = 0; i < sizeof(dvdst.dkey) - 4; i++) + dvdst.dkey[4 + i] = *p++ ^ KeyCheck.b[4 - (i % 5)]; + + ret = fseek(fp, start, SEEK_SET); + if (ret == -1) + goto err; + ret = fwrite(&dvdst, sizeof(dvdst), 1, fp); + if (ret != 1) + goto err; + ret = fseek(fp, tlen, SEEK_CUR); + if (ret == -1) + goto err; + + return sizeof(dvdst) + tlen; + err: + return -1; +} + +int puttitle(FILE fp[], int fd, char name[], int need_to_sort[]) +{ + static int lastlba; + int ret, lba, i, ffd; + struct rmmc_aux_tk tk; + struct stat st; + u8 *p; + u16 len; + + ffd = open(name, O_RDONLY); + if (ffd < 0) + goto err; + ret = fstat(ffd, &st); + if (ret) + goto err; + /* ignore empty files. */ + if (!st.st_size) + return 0; + lba = 0; + ret = ioctl(ffd, FIBMAP, &lba); + /* printf("path %s, lba %d\n", name, lba); */ + if (ret) + goto err; + //if (!lba) goto err; /* lba can be zero. ?? */ + if (lastlba == lba) + goto err; + if (lastlba > lba) + (*need_to_sort)++; + lastlba = lba; + close(ffd); + + ret = authenticate(fd, 0, 0); + if (ret) + goto err; +#define ReqLen 4+8 + p = do_rkey(fd, lba, ReqLen + 1, agid, 4 /* 4 is for title key */ ); + if (!p) + goto err; + len = getu16(p) + 2; + assert(len <= ReqLen); +#undef ReqLen + + memset(&tk, 0, sizeof(tk)); + tk.lba[0] = cpu_to_be32(lba); + /* st_blksize and st_blocks are broken. */ + tk.lba[1] = cpu_to_be32(lba + st.st_size / 2048 - 1); + /* + * printf("%s: lba %u, %u\n", name, + * be32_to_cpu(tk.lba[0]), be32_to_cpu(tk.lba[1])); + */ + tk.cpbits = p[4 + 0]; + for (i = 0; i < sizeof(tk.tk); i++) + tk.tk[i] = p[4 + 1 + i] ^ KeyCheck.b[4 - (i % 5)]; + ret = fwrite(&tk, sizeof(tk), 1, fp); + if (ret != 1) + goto err; + + return sizeof(tk); + err: + return -1; +} + +int compar(const void *aa, const void *bb) +{ + const struct rmmc_aux_tk *a = aa, *b = bb; + /* printf("%d, %d\n", be32_to_cpu(a->lba[0]), be32_to_cpu(b->lba[0])); */ + return be32_to_cpu(a->lba[0]) - be32_to_cpu(b->lba[0]); +} + +int sorttk(FILE fp[], int start, int ntitle) +{ + u8 *p; + int len, ret, pagesize, m, fd; + + ret = fflush(fp); + if (ret) + goto err; + fd = fileno(fp); + if (fd < 0) + goto err; + pagesize = sysconf(_SC_PAGESIZE); + if (!pagesize) + goto err; + m = start % pagesize; + len = ntitle * sizeof(struct rmmc_aux_tk); + p = mmap(NULL, len + m, PROT_READ | PROT_WRITE, MAP_SHARED, fd, + start - m); + if (p == MAP_FAILED) + goto err; + qsort(p + m, ntitle, sizeof(struct rmmc_aux_tk), compar); + /* tiny test */ + { + int i; + struct rmmc_aux_tk *tk; + tk = (void *) p + m; + for (i = 0; i < ntitle - 1; i++) { + assert(be32_to_cpu(tk[i].lba[0]) < + be32_to_cpu(tk[i].lba[1])); + assert(be32_to_cpu(tk[i].lba[1]) < + be32_to_cpu(tk[i + 1].lba[0])); + } + assert(be32_to_cpu(tk[i].lba[0]) < be32_to_cpu(tk[i].lba[1])); + } + ret = munmap(p, len + m); + if (ret) + goto err; + return 0; + err: + return -1; +} + +int putrkey(FILE fp[], int fd) +{ + int ret, ntitle, n, need_to_sort; + u32 start, tlen; + struct rmmc_aux_rkey rkey; + DIR *dir; + struct dirent *de; + + memset(&rkey, 0, sizeof(rkey)); + start = ftell(fp); + if (start == -1) + goto err; + ret = fseek(fp, sizeof(rkey), SEEK_CUR); + if (ret == -1) + goto err; + + need_to_sort = 0; + tlen = 0; + ntitle = 0; + dir = opendir("."); + if (!dir) + goto err; + while ((de = readdir(dir)) != NULL) { + n = strlen(de->d_name); + if (n < 7) + continue; + if (strcasecmp(de->d_name + n - 4, ".VOB")) + continue; + + /* ret can be zero. */ + ret = puttitle(fp, fd, de->d_name, &need_to_sort); + if (ret < 0) + goto err; + if (ret) + ntitle++; + tlen += ret; + } + + if (need_to_sort) { + ret = sorttk(fp, start + sizeof(rkey), ntitle); + if (ret) + goto err; + } + + rkey.ntitle = cpu_to_be32(ntitle); + ret = fseek(fp, start, SEEK_SET); + if (ret == -1) + goto err; + ret = fwrite(&rkey, sizeof(rkey), 1, fp); + if (ret != 1) + goto err; + ret = fseek(fp, tlen, SEEK_CUR); + if (ret == -1) + goto err; + + return sizeof(rkey) + tlen; + err: + return -1; +} + +/* ----------------------------------------------------------------------*/ + +int writeaux(FILE fp[], int fd, struct opts opts[]) +{ + struct rmmc_aux_file aux; + int ret, tlen; + + if (!opts->quiet) { + printf("Generating aux ..."); + fflush(stdout); + } + + /* + * reserve the place for aux as a header + */ + ret = fseek(fp, sizeof(aux), SEEK_SET); + if (ret == -1) + goto err; + + memset(&aux, 0, sizeof(aux)); + tlen = 0; + + ret = putdvdst(fp, fd); + if (ret == -1) + goto err; + set_offlen(aux.offlen + DVD_STRUCTURE, tlen, ret); + tlen += ret; + + ret = putrkey(fp, fd); + if (ret == -1) + goto err; + set_offlen(aux.offlen + REPORT_KEY, tlen, ret); + tlen += ret; + + /* + * write aux as the header + */ + rewind(fp); + strcpy(aux.magic, RmmcAuxMagicStr); + /* aux.version = cpu_to_be32(0); */ + aux.size = cpu_to_be32(tlen); + /* aux.sum = 0; */ + /* aux.salt; */ + ret = fwrite(&aux, sizeof(aux), 1, fp); + if (ret != 1) + goto err; + ret = fflush(fp); + if (ret) + goto err; + fd = fileno(fp); + ret = fsync(fd); + if (ret) + goto err; + + /* set readonly */ + ret = fchmod(fd, 0444); + if (ret) + goto err; + + if (!opts->quiet) + printf(" done\n"); + return 0; + err: + return -1; +} + +/* ---------------------------------------- */ + +int dumpaux(int fd) +{ + struct stat st; + int ret, i; + struct rmmc_aux_file *aux; + u32 len; + struct rmmc_aux_discinfo *disci; + struct rmmc_aux_dvdst *dvdst; + struct rmmc_aux_tpa *tpa; + struct rmmc_aux_rkey *rkey; + + ret = fstat(fd, &st); + if (ret) + goto err; + if (st.st_size < sizeof(*aux)) + goto badfile; + aux = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (aux == MAP_FAILED) + goto err; + + if (memcmp(aux->magic, RmmcAuxMagicStr, sizeof(RmmcAuxMagicStr) - 1)) + goto badfile; + printf("version: %d\n" + "data size: %d\n", + be32_to_cpu(aux->version), be32_to_cpu(aux->size)); + + disci = offlen_discinfo(aux, &len); + if (!disci) + goto badfile; + if (!len) + printf("no discinfo\n"); + else { +#if 0 + struct { + u16 len; + u8 res1:3; + u8 erasable:1; + u8 laststat:2; + u8 discstat:1; + u8 nftrack; + u8 nsess_lsb; + u8 ftrack_lastsess_lsb; + u8 ltrack_lastsess_lsb; + u8 did_v:1; + u8 dbc_v:1; + u8 uru:1; + u8 dac_v:1; + u8 res2:1; + u8 dbit:1; + u8 bg:2; + u8 disctype; + u8 nsess_msb; + u8 ftrack_lastsess_msb; + u8 ltrack_lastsess_msb; + u32 discid; + u32 lin_last; + u32 lout; + u8 barcode[8]; + u8 apcode; + u8 nopc; + u8 opc[0]; + } *di; +#endif + u8 *p; + p = (void *) disci; + printf("discinfo{%02x %02x %02x %02x ...}\n", + p[0], p[1], p[2], p[3]); + } + + dvdst = offlen_dvdst(aux, &len); + if (!dvdst) + goto badfile; + if (!len) + printf("no dvdst\n"); + else { + struct rmmc_aux_phys { + u16 len; + u8 res1[2]; + /* layer descriptor */ + u8 booktype:4; + u8 partver:4; + u8 discsize:4; + u8 maxrate:4; + u8 res2:1; + u8 nlayer:2; + u8 track_path:1; + u8 layertype:4; + u8 lineardensity:4; + u8 trackdensity:4; + u32 startsect; + u32 endsect; + u32 endlayer0; + u8 bca:1; + u8 res3:7; + u8 data[0]; + } *phys; + + struct rmmc_aux_cprt { + u16 len; + u8 res1[2]; + + /* copyright info */ + u8 cpst; + u8 rmt; + u8 res2[2]; + } *cprt; + + printf("dvd structure\nnlayer: %d\n", dvdst->nlayer); + for (i = 0; i < dvdst->nlayer; i++) { + struct rmmc_aux_layer *layer; + layer = offlen_layer(dvdst, i, &len); + if (!layer) + goto badfile; + printf + ("layer %d: physical(%d)+copyright(%d)+manufacture(%d)\n", + i, be32_to_cpu(layer->offlen[DslPhys].length), + be32_to_cpu(layer->offlen[DslCprt].length), + be32_to_cpu(layer->offlen[DslManuf].length)); + + phys = (void *) offlen_phys(layer, &len); + if (!phys) + goto badfile; + printf("phys{\n" + "\tlen: %u\n" + "\tbooktype: %01xh\n" + "\tpartver: %01xh\n" + "\tdiscsize: %01xh\n" + "\tmaxrate: %01xh\n" + "\tnlayer: %01xh\n" + "\ttrack_path: %01xh\n" + "\tlayertype: %01xh\n" + "\tlineardensity: %01xh\n" + "\ttrackdensity: %01xh\n" + "\tstartsect: %u\n" + "\tendsect: %u\n" + "\tendlayer0: %u\n" + "\tbca: %01xh\n" + "}\n", + be16_to_cpu(phys->len), + phys->booktype, + phys->partver, + phys->discsize, + phys->maxrate, + phys->nlayer, + phys->track_path, + phys->layertype, + phys->lineardensity, + phys->trackdensity, + be32_to_cpu(phys->startsect), + be32_to_cpu(phys->endsect), + be32_to_cpu(phys->endlayer0), phys->bca); + + cprt = (void *) offlen_cprt(layer, &len); + if (!cprt) + goto badfile; + printf("copyright{\n" + "\tlen: %04xh\n" + "\tcpst: %02xh\n" + "\trmt: %02xh\n" + "}\n", + be16_to_cpu(cprt->len), cprt->cpst, cprt->rmt); + } + } + + tpa = offlen_tpa(aux, &len); + if (!tpa) + goto badfile; + if (!len) + printf("no toc_pma_atip\n"); + else { + } + + rkey = offlen_rkey(aux, &len); + if (!rkey) + goto badfile; + if (!rkey) + printf("no rkey\n"); + else { + int n; + struct rmmc_aux_tk *tk; + n = be32_to_cpu(rkey->ntitle); + printf("report key{\n" "\tntitle: %d\n", n); + tk = rkey->data; + for (i = 0; i < n; i++) { + printf("\tlba %d - %d, cpbits %02xh\n", + be32_to_cpu(tk->lba[0]), be32_to_cpu(tk->lba[1]), + tk->cpbits); + tk++; + } + printf("}\n"); + } + + return 0; + + badfile: + printf("bad file"); + errno = EBADF; + err: + return -1; +} + +/* ---------------------------------------- */ +#include +#include + +int doprint; +void progress(int sig, siginfo_t si[], void *data) +{ + doprint++; +} + +int +writeimg(FILE fp[], struct f device[], struct statfs stf[], struct opts opts[]) +{ + int ret, n, fd; + u8 a[stf->f_bsize]; + unsigned long long bytes, blks; + struct itimerval it; + + printf("Warning: If the dvd contents is copyright protected,\n" + "\tyou must have a right to copy it.\n" "Are you sure? (y/n) "); + fflush(stdout); + ret = fgetc(stdin); + if (ret != 'y') + return 0; + + ret = authenticate(device->fd, 0, 0); + if (ret) + goto err; + + if (!opts->quiet) { + time_t t; + struct sigaction sa; + + sa.sa_sigaction = progress; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART | SA_SIGINFO; + ret = sigaction(SIGALRM, &sa, NULL); + if (ret) + goto err; + it.it_interval.tv_sec = it.it_value.tv_sec = 1; + it.it_interval.tv_usec = it.it_value.tv_usec = 0; + t = time(NULL); + strftime(a, sizeof(a), "%b %d %I:%M %p", localtime(&t)); + printf("Generating img starts at %s ...\n", a); + ret = setitimer(ITIMER_REAL, &it, NULL); + if (ret) + goto err; + memset(&it, 0, sizeof(it)); + } + + bytes = 0; + do { + n = fread(a, 1, sizeof(a), device->fp); + if (n <= 0 && ferror(device->fp)) + goto err; + if (feof(device->fp)) + break; + if (fwrite(a, 1, n, fp) != n) + goto err; + bytes += n; + if (!doprint) + continue; + + blks = bytes / stf->f_bsize; + printf("\r%Ld/%Lu blks %Ld%%", + blks, stf->f_blocks, 100 * blks / stf->f_blocks); + fflush(stdout); + doprint = 0; + } while (1); + setitimer(ITIMER_REAL, &it, NULL); + ret = fflush(fp); + if (ret) + goto err; + fd = fileno(fp); + ret = fsync(fd); + if (ret) + goto err; + if (!opts->quiet) + printf("\ndone\n"); + + /* set readonly */ + ret = fchmod(fd, 0444); + if (ret) + goto err; + + return 0; + err: + return -1; +} + +/* ---------------------------------------- */ + +int parse(int argc, char *argv[], struct opts opts[]) +{ + int c; + + opts->device = opts->mntpnt = NULL; + while ((c = getopt(argc, argv, "n:iad:vhq")) != -1) { + switch (c) { + case 'n': + opts->name = optarg; + break; + case 'i': + opts->genimg = 1; + opts->genaux = 0; + break; + case 'a': + opts->genimg = 0; + opts->genaux = 1; + break; + case 'd': + /* hidden option */ + opts->genimg = opts->genaux = 0; + opts->dumpaux = 1; + opts->name = optarg; + break; + case 'q': + opts->quiet = 1; + break; + case 'v': + goto version; + case 'h': + default: + goto usage; + } + } + + /* hidden option */ + if (opts->dumpaux) + return 0; + + if (optind + 2 != argc) + goto usage; + opts->device = argv[optind]; + opts->mntpnt = argv[optind + 1]; + return 0; + + usage: + fprintf(stderr, "usage: %s [-n basename] [-iavhq] device mntpnt\n" + "\t-n: img filename.(def: ./img)\n" + "\t-i: generate img only.\n" + "\t-a: generate aux only.\n" + "\t-q: dont show progress info.\n" + "\t-v: show version and exit.\n" + "\t-h: show this help and exit.\n" + "note1: device must be mounted at the mntpnt.\n" + "note2: aux filename is always '.aux'.\n", + argv[0]); + /*FALLTHROUGH*/ + version: + printf("$Id: rmmcgen.c,v 1.2 2005/06/11 14:21:15 jro Exp $\n"); + return -1; + +} + +int main(int argc, char *argv[]) +{ + char *me, *pre; + int ret; + struct f f[LastFile]; + char lower[sizeof(VTSDir)]; + int i; + struct statfs stf; + struct opts opts; + + pre = me = *argv; + memset(&opts, 0, sizeof(opts)); + opts.genimg = opts.genaux = 1; + opts.name = "./img"; + ret = parse(argc, argv, &opts); + if (ret) + return EINVAL; + + /* open files */ + memset(f, 0, sizeof(f)); + pre = "openthem"; + ret = openthem(f, &opts); + if (ret) + goto err; + + /* chdir to the dir where .VOB is */ + memset(&stf, 0, sizeof(stf)); + if (opts.mntpnt) { + pre = opts.mntpnt; + ret = chdir(opts.mntpnt); + if (ret) + goto err; + pre = VTSDir; + ret = chdir(VTSDir); + if (ret) { + if (errno != ENOENT) + goto err; + for (i = 0; i < sizeof(VTSDir); i++) + lower[i] = tolower(VTSDir[i]); + pre = lower; + ret = chdir(lower); + if (ret) + goto err; + } + + ret = statfs(".", &stf); + if (ret) + goto err; + } + + if (opts.dumpaux) { + pre = "dumpaux"; + ret = dumpaux(f[Aux].fd); + if (ret) + goto err; + return 0; + } + + if (opts.genaux) { + pre = "writeaux"; + ret = writeaux(f[Aux].fp, f[Device].fd, &opts); + if (ret) + goto err; + } + + if (opts.genimg) { + pre = "writeimg"; + ret = writeimg(f[Img].fp, f + Device, &stf, &opts); + if (ret) + goto err; + } + + return 0; + err: + ret = errno; + perror(pre); + return ret; +}