1 /*****************************************************************************
2 * ioctl.c: DVD ioctl replacement function
3 *****************************************************************************
4 * Copyright (C) 1999-2001 VideoLAN
5 *
6 * Authors: Markus Kuespert <ltlBeBoy@beosmail.com>
7 * Sam Hocevar <sam@zoy.org>
8 * Jon Lech Johansen <jon-vl@nanocrew.net>
9 * Håkan Hjort <d95hjort@dtek.chalmers.se>
10 * Eugenio Jarosiewicz <ej0@cise.ufl.edu>
11 * David Siebörger <drs-videolan@rucus.ru.ac.za>
12 * Alex Strelnikov <lelik@os2.ru>
13 * Gildas Bazin <gbazin@netcourrier.com>
14 *
15 * libdvdcss is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * libdvdcss is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License along
26 * with libdvdcss; if not, write to the Free Software Foundation, Inc.,
27 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 *****************************************************************************/
29
30 /*****************************************************************************
31 * Preamble
32 *****************************************************************************/
33 #include "config.h"
34
35 #include <stdio.h>
36
37 #include <string.h> /* memcpy(), memset() */
38 #include <sys/types.h>
39
40 #if defined( _WIN32 )
41 # include <windows.h>
42 # include <winioctl.h>
43 #elif defined ( __OS2__ )
44 # define INCL_DOSFILEMGR
45 # define INCL_DOSDEVICES
46 # define INCL_DOSDEVIOCTL
47 # define INCL_DOSERRORS
48 # include <os2.h>
49 # include <sys/ioctl.h>
50 #else
51 # include <netinet/in.h>
52 # include <sys/ioctl.h>
53 #endif
54
55 #ifdef DVD_STRUCT_IN_SYS_CDIO_H
56 # include <sys/cdio.h>
57 #endif
58 #ifdef DVD_STRUCT_IN_SYS_DVDIO_H
59 # include <sys/dvdio.h>
60 #endif
61 #ifdef DVD_STRUCT_IN_LINUX_CDROM_H
62 # include <linux/cdrom.h>
63 #endif
64 #ifdef DVD_STRUCT_IN_DVD_H
65 # include <dvd.h>
66 #endif
67 #ifdef __HAIKU__
68 # include <malloc.h>
69 # include <scsi.h>
70 #endif
71 #ifdef SOLARIS_USCSI
72 # include <dlfcn.h>
73 # include <unistd.h>
74 # include <stropts.h>
75 # include <sys/scsi/scsi_types.h>
76 # include <sys/scsi/impl/uscsi.h>
77 #endif
78 #ifdef DARWIN_DVD_IOCTL
79 # include <IOKit/storage/IODVDMediaBSDClient.h>
80 #endif
81 #ifdef __QNXNTO__
82 # include <sys/mman.h>
83 # include <sys/dcmd_cam.h>
84 #endif
85
86 #include "dvdcss/dvdcss.h"
87 #include "common.h"
88 #include "css.h"
89 #include "ioctl.h"
90
91 #define DVD_CHALLENGE_SIZE 10
92
93 /*****************************************************************************
94 * Local prototypes, OS-specific
95 *****************************************************************************/
96 #if defined( __HAIKU__ )
97 static void BeInitRDC ( raw_device_command *, int );
98 #elif defined( SOLARIS_USCSI )
99 static void SolarisInitUSCSI( struct uscsi_cmd *p_sc, int i_type );
100 static int SolarisSendUSCSI( int fd, struct uscsi_cmd *p_sc );
101 #elif defined( _WIN32 )
102 static void WinInitSPTD ( SCSI_PASS_THROUGH_DIRECT *, int );
103 #elif defined( __QNXNTO__ )
104 static void QNXInitCPT ( CAM_PASS_THRU *, int );
105 #elif defined( __OS2__ )
106 static void OS2InitSDC( struct OS2_ExecSCSICmd *, int );
107 #endif
108
109 /*****************************************************************************
110 * ioctl_ReadCopyright: check whether the disc is encrypted or not
111 *****************************************************************************/
ioctl_ReadCopyright(int i_fd,int i_layer,int * pi_copyright)112 int ioctl_ReadCopyright( int i_fd, int i_layer, int *pi_copyright )
113 {
114 int i_ret;
115
116 #if defined( HAVE_LINUX_DVD_STRUCT )
117 dvd_struct dvd = { 0 };
118
119 dvd.type = DVD_STRUCT_COPYRIGHT;
120 dvd.copyright.layer_num = i_layer;
121
122 i_ret = ioctl( i_fd, DVD_READ_STRUCT, &dvd );
123
124 *pi_copyright = dvd.copyright.cpst;
125
126 #elif defined( HAVE_BSD_DVD_STRUCT )
127 struct dvd_struct dvd = { 0 };
128
129 dvd.format = DVD_STRUCT_COPYRIGHT;
130 dvd.layer_num = i_layer;
131
132 i_ret = ioctl( i_fd, DVDIOCREADSTRUCTURE, &dvd );
133
134 *pi_copyright = dvd.cpst;
135
136 #elif defined( __HAIKU__ )
137 INIT_RDC( GPCMD_READ_DVD_STRUCTURE, 8 );
138
139 rdc.command[ 6 ] = i_layer;
140 rdc.command[ 7 ] = DVD_STRUCT_COPYRIGHT;
141
142 i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
143
144 *pi_copyright = p_buffer[ 4 ];
145
146 #elif defined( SOLARIS_USCSI )
147 INIT_USCSI( GPCMD_READ_DVD_STRUCTURE, 8 );
148
149 rs_cdb.cdb_opaque[ 6 ] = i_layer;
150 rs_cdb.cdb_opaque[ 7 ] = DVD_STRUCT_COPYRIGHT;
151
152 i_ret = SolarisSendUSCSI(i_fd, &sc);
153
154 if( i_ret < 0 || sc.uscsi_status ) {
155 i_ret = -1;
156 }
157
158 *pi_copyright = p_buffer[ 4 ];
159 /* s->copyright.rmi = p_buffer[ 5 ]; */
160
161 #elif defined( DARWIN_DVD_IOCTL )
162 INIT_DVDIOCTL( dk_dvd_read_structure_t, DVDCopyrightInfo,
163 kDVDStructureFormatCopyrightInfo );
164
165 dvd.layer = i_layer;
166
167 i_ret = ioctl( i_fd, DKIOCDVDREADSTRUCTURE, &dvd );
168
169 *pi_copyright = dvdbs.copyrightProtectionSystemType;
170
171 #elif defined( _WIN32 )
172 DWORD tmp;
173 SCSI_PASS_THROUGH_DIRECT sptd = { 0 };
174 uint8_t p_buffer[8];
175 sptd.Length = sizeof( SCSI_PASS_THROUGH_DIRECT );
176 sptd.DataBuffer = p_buffer;
177 sptd.DataTransferLength = sizeof( p_buffer );
178 WinInitSPTD( &sptd, GPCMD_READ_DVD_STRUCTURE );
179
180 /* When using IOCTL_DVD_READ_STRUCTURE and
181 DVD_COPYRIGHT_DESCRIPTOR, CopyrightProtectionType
182 seems to be always 6 ???
183 To work around this MS bug we try to send a raw SCSI command
184 instead (if we've got enough privileges to do so). */
185
186 sptd.Cdb[ 6 ] = i_layer;
187 sptd.Cdb[ 7 ] = DVD_STRUCT_COPYRIGHT;
188
189 i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_SCSI_PASS_THROUGH_DIRECT,
190 &sptd, sizeof( SCSI_PASS_THROUGH_DIRECT ),
191 &sptd, sizeof( SCSI_PASS_THROUGH_DIRECT ),
192 &tmp, NULL ) ? 0 : -1;
193
194 if( i_ret == 0 )
195 {
196 *pi_copyright = p_buffer[ 4 ];
197 }
198
199 #elif defined( __QNXNTO__ )
200
201 INIT_CPT( GPCMD_READ_DVD_STRUCTURE, 8 );
202
203 p_cpt->cam_cdb[ 6 ] = i_layer;
204 p_cpt->cam_cdb[ 7 ] = DVD_STRUCT_COPYRIGHT;
205
206 i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL);
207
208 *pi_copyright = p_buffer[4];
209
210 #elif defined( __OS2__ )
211 INIT_SSC( GPCMD_READ_DVD_STRUCTURE, 8 );
212
213 sdc.command[ 6 ] = i_layer;
214 sdc.command[ 7 ] = DVD_STRUCT_COPYRIGHT;
215
216 i_ret = DosDevIOCtl(i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD,
217 &sdc, sizeof(sdc), &ulParamLen,
218 p_buffer, sizeof(p_buffer), &ulDataLen);
219
220 *pi_copyright = p_buffer[ 4 ];
221
222 #else
223 # error "DVD ioctls are unavailable on this system"
224
225 #endif
226 return i_ret;
227 }
228
229 /*****************************************************************************
230 * ioctl_ReadDiscKey: get the disc key
231 *****************************************************************************/
ioctl_ReadDiscKey(int i_fd,const int * pi_agid,uint8_t * p_key)232 int ioctl_ReadDiscKey( int i_fd, const int *pi_agid, uint8_t *p_key )
233 {
234 int i_ret;
235
236 #if defined( HAVE_LINUX_DVD_STRUCT )
237 dvd_struct dvd = { 0 };
238
239 dvd.type = DVD_STRUCT_DISCKEY;
240 dvd.disckey.agid = *pi_agid;
241
242 i_ret = ioctl( i_fd, DVD_READ_STRUCT, &dvd );
243
244 if( i_ret < 0 )
245 {
246 return i_ret;
247 }
248
249 memcpy( p_key, dvd.disckey.value, DVD_DISCKEY_SIZE );
250
251 #elif defined( HAVE_BSD_DVD_STRUCT )
252 struct dvd_struct dvd = { 0 };
253
254 dvd.format = DVD_STRUCT_DISCKEY;
255 dvd.agid = *pi_agid;
256
257 i_ret = ioctl( i_fd, DVDIOCREADSTRUCTURE, &dvd );
258
259 if( i_ret < 0 )
260 {
261 return i_ret;
262 }
263
264 memcpy( p_key, dvd.data, DVD_DISCKEY_SIZE );
265
266 #elif defined( __HAIKU__ )
267 INIT_RDC( GPCMD_READ_DVD_STRUCTURE, DVD_DISCKEY_SIZE + 4 );
268
269 rdc.command[ 7 ] = DVD_STRUCT_DISCKEY;
270 rdc.command[ 10 ] = *pi_agid << 6;
271
272 i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
273
274 if( i_ret < 0 )
275 {
276 return i_ret;
277 }
278
279 memcpy( p_key, p_buffer + 4, DVD_DISCKEY_SIZE );
280
281 #elif defined( SOLARIS_USCSI )
282 INIT_USCSI( GPCMD_READ_DVD_STRUCTURE, DVD_DISCKEY_SIZE + 4 );
283
284 rs_cdb.cdb_opaque[ 7 ] = DVD_STRUCT_DISCKEY;
285 rs_cdb.cdb_opaque[ 10 ] = *pi_agid << 6;
286
287 i_ret = SolarisSendUSCSI( i_fd, &sc );
288
289 if( i_ret < 0 || sc.uscsi_status )
290 {
291 i_ret = -1;
292 return i_ret;
293 }
294
295 memcpy( p_key, p_buffer + 4, DVD_DISCKEY_SIZE );
296
297 #elif defined( DARWIN_DVD_IOCTL )
298 INIT_DVDIOCTL( dk_dvd_read_structure_t, DVDDiscKeyInfo,
299 kDVDStructureFormatDiscKeyInfo );
300
301 dvd.grantID = *pi_agid;
302
303 i_ret = ioctl( i_fd, DKIOCDVDREADSTRUCTURE, &dvd );
304
305 memcpy( p_key, dvdbs.discKeyStructures, DVD_DISCKEY_SIZE );
306
307 #elif defined( _WIN32 )
308 DWORD tmp;
309 uint8_t buffer[DVD_DISK_KEY_LENGTH] = { 0 };
310 PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
311
312 key->KeyLength = DVD_DISK_KEY_LENGTH;
313 key->SessionId = *pi_agid;
314 key->KeyType = DvdDiskKey;
315 key->KeyFlags = 0;
316
317 i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key,
318 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
319
320 if( i_ret < 0 )
321 {
322 return i_ret;
323 }
324
325 memcpy( p_key, key->KeyData, DVD_DISCKEY_SIZE );
326
327 #elif defined( __QNXNTO__ )
328
329 INIT_CPT( GPCMD_READ_DVD_STRUCTURE, DVD_DISCKEY_SIZE + 4 );
330
331 p_cpt->cam_cdb[ 7 ] = DVD_STRUCT_DISCKEY;
332 p_cpt->cam_cdb[ 10 ] = *pi_agid << 6;
333
334 i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL);
335
336 memcpy( p_key, p_buffer + 4, DVD_DISCKEY_SIZE );
337
338 #elif defined ( __OS2__ )
339 INIT_SSC( GPCMD_READ_DVD_STRUCTURE, DVD_DISCKEY_SIZE + 4 );
340
341 sdc.command[ 7 ] = DVD_STRUCT_DISCKEY;
342 sdc.command[ 10 ] = *pi_agid << 6;
343
344 i_ret = DosDevIOCtl(i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD,
345 &sdc, sizeof(sdc), &ulParamLen,
346 p_buffer, sizeof(p_buffer), &ulDataLen);
347
348 if( i_ret < 0 )
349 {
350 return i_ret;
351 }
352
353 memcpy( p_key, p_buffer + 4, DVD_DISCKEY_SIZE );
354
355 #else
356 # error "DVD ioctls are unavailable on this system"
357
358 #endif
359 return i_ret;
360 }
361
362 /*****************************************************************************
363 * ioctl_ReadTitleKey: get the title key
364 *****************************************************************************/
ioctl_ReadTitleKey(int i_fd,const int * pi_agid,int i_pos,uint8_t * p_key)365 int ioctl_ReadTitleKey( int i_fd, const int *pi_agid, int i_pos, uint8_t *p_key )
366 {
367 int i_ret;
368
369 #if defined( HAVE_LINUX_DVD_STRUCT )
370 dvd_authinfo auth_info = { 0 };
371
372 auth_info.type = DVD_LU_SEND_TITLE_KEY;
373 auth_info.lstk.agid = *pi_agid;
374 auth_info.lstk.lba = i_pos;
375
376 i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
377
378 memcpy( p_key, auth_info.lstk.title_key, DVD_KEY_SIZE );
379
380 #elif defined( HAVE_BSD_DVD_STRUCT )
381 struct dvd_authinfo auth_info = { 0 };
382
383 auth_info.format = DVD_REPORT_TITLE_KEY;
384 auth_info.agid = *pi_agid;
385 auth_info.lba = i_pos;
386
387 i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
388
389 memcpy( p_key, auth_info.keychal, DVD_KEY_SIZE );
390
391 #elif defined( __HAIKU__ )
392 INIT_RDC( GPCMD_REPORT_KEY, 12 );
393
394 rdc.command[ 2 ] = ( i_pos >> 24 ) & 0xff;
395 rdc.command[ 3 ] = ( i_pos >> 16 ) & 0xff;
396 rdc.command[ 4 ] = ( i_pos >> 8 ) & 0xff;
397 rdc.command[ 5 ] = ( i_pos ) & 0xff;
398 rdc.command[ 10 ] = DVD_REPORT_TITLE_KEY | (*pi_agid << 6);
399
400 i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
401
402 memcpy( p_key, p_buffer + 5, DVD_KEY_SIZE );
403
404 #elif defined( SOLARIS_USCSI )
405 INIT_USCSI( GPCMD_REPORT_KEY, 12 );
406
407 rs_cdb.cdb_opaque[ 2 ] = ( i_pos >> 24 ) & 0xff;
408 rs_cdb.cdb_opaque[ 3 ] = ( i_pos >> 16 ) & 0xff;
409 rs_cdb.cdb_opaque[ 4 ] = ( i_pos >> 8 ) & 0xff;
410 rs_cdb.cdb_opaque[ 5 ] = ( i_pos ) & 0xff;
411 rs_cdb.cdb_opaque[ 10 ] = DVD_REPORT_TITLE_KEY | (*pi_agid << 6);
412
413 i_ret = SolarisSendUSCSI( i_fd, &sc );
414
415 if( i_ret < 0 || sc.uscsi_status )
416 {
417 i_ret = -1;
418 }
419
420 /* Do we want to return the cp_sec flag perhaps? */
421 /* a->lstk.cpm = (buf[ 4 ] >> 7) & 1; */
422 /* a->lstk.cp_sec = (buf[ 4 ] >> 6) & 1; */
423 /* a->lstk.cgms = (buf[ 4 ] >> 4) & 3; */
424
425 memcpy( p_key, p_buffer + 5, DVD_KEY_SIZE );
426
427 #elif defined( DARWIN_DVD_IOCTL )
428 INIT_DVDIOCTL( dk_dvd_report_key_t, DVDTitleKeyInfo,
429 kDVDKeyFormatTitleKey );
430
431 dvd.address = i_pos;
432 dvd.grantID = *pi_agid;
433 dvd.keyClass = kDVDKeyClassCSS_CPPM_CPRM;
434
435 i_ret = ioctl( i_fd, DKIOCDVDREPORTKEY, &dvd );
436
437 memcpy( p_key, dvdbs.titleKeyValue, DVD_KEY_SIZE );
438
439 #elif defined( _WIN32 )
440 DWORD tmp;
441 uint8_t buffer[DVD_TITLE_KEY_LENGTH] = { 0 };
442 PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
443
444 key->KeyLength = DVD_TITLE_KEY_LENGTH;
445 key->SessionId = *pi_agid;
446 key->KeyType = DvdTitleKey;
447 key->KeyFlags = 0;
448 key->Parameters.TitleOffset.QuadPart = (LONGLONG) i_pos *
449 DVDCSS_BLOCK_SIZE;
450
451 i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key,
452 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
453
454 memcpy( p_key, key->KeyData, DVD_KEY_SIZE );
455
456 #elif defined( __QNXNTO__ )
457
458 INIT_CPT( GPCMD_REPORT_KEY, 12 );
459
460 p_cpt->cam_cdb[ 2 ] = ( i_pos >> 24 ) & 0xff;
461 p_cpt->cam_cdb[ 3 ] = ( i_pos >> 16 ) & 0xff;
462 p_cpt->cam_cdb[ 4 ] = ( i_pos >> 8 ) & 0xff;
463 p_cpt->cam_cdb[ 5 ] = ( i_pos ) & 0xff;
464 p_cpt->cam_cdb[ 10 ] = DVD_REPORT_TITLE_KEY | (*pi_agid << 6);
465
466 i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL);
467
468 memcpy( p_key, p_buffer + 5, DVD_KEY_SIZE );
469
470 #elif defined( __OS2__ )
471 INIT_SSC( GPCMD_REPORT_KEY, 12 );
472
473 sdc.command[ 2 ] = ( i_pos >> 24 ) & 0xff;
474 sdc.command[ 3 ] = ( i_pos >> 16 ) & 0xff;
475 sdc.command[ 4 ] = ( i_pos >> 8 ) & 0xff;
476 sdc.command[ 5 ] = ( i_pos ) & 0xff;
477 sdc.command[ 10 ] = DVD_REPORT_TITLE_KEY | (*pi_agid << 6);
478
479 i_ret = DosDevIOCtl(i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD,
480 &sdc, sizeof(sdc), &ulParamLen,
481 p_buffer, sizeof(p_buffer), &ulDataLen);
482
483 memcpy( p_key, p_buffer + 5, DVD_KEY_SIZE );
484
485 #else
486 # error "DVD ioctls are unavailable on this system"
487
488 #endif
489
490 return i_ret;
491 }
492
493
494 /*****************************************************************************
495 * ioctl_ReportAgid: get AGID from the drive
496 *****************************************************************************/
ioctl_ReportAgid(int i_fd,int * pi_agid)497 int ioctl_ReportAgid( int i_fd, int *pi_agid )
498 {
499 int i_ret;
500
501 #if defined( HAVE_LINUX_DVD_STRUCT )
502 dvd_authinfo auth_info = { 0 };
503
504 auth_info.type = DVD_LU_SEND_AGID;
505 auth_info.lsa.agid = *pi_agid;
506
507 i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
508
509 *pi_agid = auth_info.lsa.agid;
510
511 #elif defined( HAVE_BSD_DVD_STRUCT )
512 struct dvd_authinfo auth_info = { 0 };
513
514 auth_info.format = DVD_REPORT_AGID;
515 auth_info.agid = *pi_agid;
516
517 i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
518
519 *pi_agid = auth_info.agid;
520
521 #elif defined( __HAIKU__ )
522 INIT_RDC( GPCMD_REPORT_KEY, 8 );
523
524 rdc.command[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
525
526 i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
527
528 *pi_agid = p_buffer[ 7 ] >> 6;
529
530 #elif defined( SOLARIS_USCSI )
531 INIT_USCSI( GPCMD_REPORT_KEY, 8 );
532
533 rs_cdb.cdb_opaque[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
534
535 i_ret = SolarisSendUSCSI( i_fd, &sc );
536
537 if( i_ret < 0 || sc.uscsi_status )
538 {
539 i_ret = -1;
540 }
541
542 *pi_agid = p_buffer[ 7 ] >> 6;
543
544 #elif defined( DARWIN_DVD_IOCTL )
545 INIT_DVDIOCTL( dk_dvd_report_key_t, DVDAuthenticationGrantIDInfo,
546 kDVDKeyFormatAGID_CSS );
547
548 dvd.grantID = *pi_agid;
549 dvd.keyClass = kDVDKeyClassCSS_CPPM_CPRM;
550
551 i_ret = ioctl( i_fd, DKIOCDVDREPORTKEY, &dvd );
552
553 *pi_agid = dvdbs.grantID;
554
555 #elif defined( _WIN32 )
556 DWORD tmp = 0;
557
558 i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_START_SESSION, &tmp, 4,
559 pi_agid, sizeof( *pi_agid ), &tmp, NULL ) ? 0 : -1;
560
561 #elif defined( __QNXNTO__ )
562
563 INIT_CPT( GPCMD_REPORT_KEY, 8 );
564
565 p_cpt->cam_cdb[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
566
567 i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL);
568
569 *pi_agid = p_buffer[ 7 ] >> 6;
570
571 #elif defined( __OS2__ )
572 INIT_SSC( GPCMD_REPORT_KEY, 8 );
573
574 sdc.command[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
575
576 i_ret = DosDevIOCtl(i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD,
577 &sdc, sizeof(sdc), &ulParamLen,
578 p_buffer, sizeof(p_buffer), &ulDataLen);
579
580 *pi_agid = p_buffer[ 7 ] >> 6;
581
582 #else
583 # error "DVD ioctls are unavailable on this system"
584
585 #endif
586 return i_ret;
587 }
588
589 /*****************************************************************************
590 * ioctl_ReportChallenge: get challenge from the drive
591 *****************************************************************************/
ioctl_ReportChallenge(int i_fd,const int * pi_agid,uint8_t * p_challenge)592 int ioctl_ReportChallenge( int i_fd, const int *pi_agid, uint8_t *p_challenge )
593 {
594 int i_ret;
595
596 #if defined( HAVE_LINUX_DVD_STRUCT )
597 dvd_authinfo auth_info = { 0 };
598
599 auth_info.type = DVD_LU_SEND_CHALLENGE;
600 auth_info.lsc.agid = *pi_agid;
601
602 i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
603
604 memcpy( p_challenge, auth_info.lsc.chal, DVD_CHALLENGE_SIZE );
605
606 #elif defined( HAVE_BSD_DVD_STRUCT )
607 struct dvd_authinfo auth_info = { 0 };
608
609 auth_info.format = DVD_REPORT_CHALLENGE;
610 auth_info.agid = *pi_agid;
611
612 i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
613
614 memcpy( p_challenge, auth_info.keychal, DVD_CHALLENGE_SIZE );
615
616 #elif defined( __HAIKU__ )
617 INIT_RDC( GPCMD_REPORT_KEY, 16 );
618
619 rdc.command[ 10 ] = DVD_REPORT_CHALLENGE | (*pi_agid << 6);
620
621 i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
622
623 memcpy( p_challenge, p_buffer + 4, DVD_CHALLENGE_SIZE );
624
625 #elif defined( SOLARIS_USCSI )
626 INIT_USCSI( GPCMD_REPORT_KEY, 16 );
627
628 rs_cdb.cdb_opaque[ 10 ] = DVD_REPORT_CHALLENGE | (*pi_agid << 6);
629
630 i_ret = SolarisSendUSCSI( i_fd, &sc );
631
632 if( i_ret < 0 || sc.uscsi_status )
633 {
634 i_ret = -1;
635 }
636
637 memcpy( p_challenge, p_buffer + 4, DVD_CHALLENGE_SIZE );
638
639 #elif defined( DARWIN_DVD_IOCTL )
640 INIT_DVDIOCTL( dk_dvd_report_key_t, DVDChallengeKeyInfo,
641 kDVDKeyFormatChallengeKey );
642
643 dvd.grantID = *pi_agid;
644
645 i_ret = ioctl( i_fd, DKIOCDVDREPORTKEY, &dvd );
646
647 memcpy( p_challenge, dvdbs.challengeKeyValue, DVD_CHALLENGE_SIZE );
648
649 #elif defined( _WIN32 )
650 DWORD tmp;
651 uint8_t buffer[DVD_CHALLENGE_KEY_LENGTH] = { 0 };
652 PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
653
654 key->KeyLength = DVD_CHALLENGE_KEY_LENGTH;
655 key->SessionId = *pi_agid;
656 key->KeyType = DvdChallengeKey;
657 key->KeyFlags = 0;
658
659 i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key,
660 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
661
662 if( i_ret < 0 )
663 {
664 return i_ret;
665 }
666
667 memcpy( p_challenge, key->KeyData, DVD_CHALLENGE_SIZE );
668
669 #elif defined( __QNXNTO__ )
670
671 INIT_CPT( GPCMD_REPORT_KEY, 16 );
672
673 p_cpt->cam_cdb[ 10 ] = DVD_REPORT_CHALLENGE | (*pi_agid << 6);
674
675 i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL);
676
677 memcpy( p_challenge, p_buffer + 4, DVD_CHALLENGE_SIZE );
678
679 #elif defined( __OS2__ )
680 INIT_SSC( GPCMD_REPORT_KEY, 16 );
681
682 sdc.command[ 10 ] = DVD_REPORT_CHALLENGE | (*pi_agid << 6);
683
684 i_ret = DosDevIOCtl(i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD,
685 &sdc, sizeof(sdc), &ulParamLen,
686 p_buffer, sizeof(p_buffer), &ulDataLen);
687
688 memcpy( p_challenge, p_buffer + 4, DVD_CHALLENGE_SIZE );
689
690 #else
691 # error "DVD ioctls are unavailable on this system"
692
693 #endif
694 return i_ret;
695 }
696
697 /*****************************************************************************
698 * ioctl_ReportASF: get ASF from the drive
699 *****************************************************************************/
ioctl_ReportASF(int i_fd,int * pi_asf)700 int ioctl_ReportASF( int i_fd, int *pi_asf )
701 {
702 int i_ret;
703
704 #if defined( HAVE_LINUX_DVD_STRUCT )
705 dvd_authinfo auth_info = { 0 };
706
707 auth_info.type = DVD_LU_SEND_ASF;
708 auth_info.lsasf.asf = *pi_asf;
709
710 i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
711
712 *pi_asf = auth_info.lsasf.asf;
713
714 #elif defined( HAVE_BSD_DVD_STRUCT )
715 struct dvd_authinfo auth_info = { 0 };
716
717 auth_info.format = DVD_REPORT_ASF;
718 auth_info.asf = *pi_asf;
719
720 i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
721
722 *pi_asf = auth_info.asf;
723
724 #elif defined( __HAIKU__ )
725 INIT_RDC( GPCMD_REPORT_KEY, 8 );
726
727 rdc.command[ 10 ] = DVD_REPORT_ASF;
728
729 i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
730
731 *pi_asf = p_buffer[ 7 ] & 1;
732
733 #elif defined( SOLARIS_USCSI )
734 INIT_USCSI( GPCMD_REPORT_KEY, 8 );
735
736 rs_cdb.cdb_opaque[ 10 ] = DVD_REPORT_ASF;
737
738 i_ret = SolarisSendUSCSI( i_fd, &sc );
739
740 if( i_ret < 0 || sc.uscsi_status )
741 {
742 i_ret = -1;
743 }
744
745 *pi_asf = p_buffer[ 7 ] & 1;
746
747 #elif defined( DARWIN_DVD_IOCTL )
748 INIT_DVDIOCTL( dk_dvd_report_key_t, DVDAuthenticationSuccessFlagInfo,
749 kDVDKeyFormatASF );
750
751 i_ret = ioctl( i_fd, DKIOCDVDREPORTKEY, &dvd );
752
753 *pi_asf = dvdbs.successFlag;
754
755 #elif defined( _WIN32 )
756 DWORD tmp;
757 uint8_t buffer[DVD_ASF_LENGTH] = { 0 };
758 PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
759 PDVD_ASF keyData;
760
761 key->KeyLength = DVD_ASF_LENGTH;
762 key->KeyType = DvdAsf;
763 key->KeyFlags = 0;
764
765 keyData = (PDVD_ASF)key->KeyData;
766 keyData->SuccessFlag = *pi_asf;
767
768 i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key,
769 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
770
771 if( i_ret < 0 )
772 {
773 return i_ret;
774 }
775
776 keyData = (PDVD_ASF)key->KeyData;
777 *pi_asf = keyData->SuccessFlag;
778
779 #elif defined( __QNXNTO__ )
780
781 INIT_CPT( GPCMD_REPORT_KEY, 8 );
782
783 p_cpt->cam_cdb[ 10 ] = DVD_REPORT_ASF;
784
785 i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL);
786
787 *pi_asf = p_buffer[ 7 ] & 1;
788
789 #elif defined( __OS2__ )
790 INIT_SSC( GPCMD_REPORT_KEY, 8 );
791
792 sdc.command[ 10 ] = DVD_REPORT_ASF;
793
794 i_ret = DosDevIOCtl(i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD,
795 &sdc, sizeof(sdc), &ulParamLen,
796 p_buffer, sizeof(p_buffer), &ulDataLen);
797
798 *pi_asf = p_buffer[ 7 ] & 1;
799
800 #else
801 # error "DVD ioctls are unavailable on this system"
802
803 #endif
804 return i_ret;
805 }
806
807 /*****************************************************************************
808 * ioctl_ReportKey1: get the first key from the drive
809 *****************************************************************************/
ioctl_ReportKey1(int i_fd,const int * pi_agid,uint8_t * p_key)810 int ioctl_ReportKey1( int i_fd, const int *pi_agid, uint8_t *p_key )
811 {
812 int i_ret;
813
814 #if defined( HAVE_LINUX_DVD_STRUCT )
815 dvd_authinfo auth_info = { 0 };
816
817 auth_info.type = DVD_LU_SEND_KEY1;
818 auth_info.lsk.agid = *pi_agid;
819
820 i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
821
822 memcpy( p_key, auth_info.lsk.key, DVD_KEY_SIZE );
823
824 #elif defined( HAVE_BSD_DVD_STRUCT )
825 struct dvd_authinfo auth_info = { 0 };
826
827 auth_info.format = DVD_REPORT_KEY1;
828 auth_info.agid = *pi_agid;
829
830 i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
831
832 memcpy( p_key, auth_info.keychal, DVD_KEY_SIZE );
833
834 #elif defined( __HAIKU__ )
835 INIT_RDC( GPCMD_REPORT_KEY, 12 );
836
837 rdc.command[ 10 ] = DVD_REPORT_KEY1 | (*pi_agid << 6);
838
839 i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
840
841 memcpy( p_key, p_buffer + 4, DVD_KEY_SIZE );
842
843 #elif defined( SOLARIS_USCSI )
844 INIT_USCSI( GPCMD_REPORT_KEY, 12 );
845
846 rs_cdb.cdb_opaque[ 10 ] = DVD_REPORT_KEY1 | (*pi_agid << 6);
847
848 i_ret = SolarisSendUSCSI( i_fd, &sc );
849
850 if( i_ret < 0 || sc.uscsi_status )
851 {
852 i_ret = -1;
853 }
854
855 memcpy( p_key, p_buffer + 4, DVD_KEY_SIZE );
856
857 #elif defined( DARWIN_DVD_IOCTL )
858 INIT_DVDIOCTL( dk_dvd_report_key_t, DVDKey1Info,
859 kDVDKeyFormatKey1 );
860
861 dvd.grantID = *pi_agid;
862
863 i_ret = ioctl( i_fd, DKIOCDVDREPORTKEY, &dvd );
864
865 memcpy( p_key, dvdbs.key1Value, DVD_KEY_SIZE );
866
867 #elif defined( _WIN32 )
868 DWORD tmp;
869 uint8_t buffer[DVD_BUS_KEY_LENGTH] = { 0 };
870 PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
871
872 key->KeyLength = DVD_BUS_KEY_LENGTH;
873 key->SessionId = *pi_agid;
874 key->KeyType = DvdBusKey1;
875 key->KeyFlags = 0;
876
877 i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key,
878 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
879
880 memcpy( p_key, key->KeyData, DVD_KEY_SIZE );
881
882 #elif defined( __QNXNTO__ )
883
884 INIT_CPT( GPCMD_REPORT_KEY, 12 );
885
886 p_cpt->cam_cdb[ 10 ] = DVD_REPORT_KEY1 | (*pi_agid << 6);
887
888 i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL);
889
890 memcpy( p_key, p_buffer + 4, DVD_KEY_SIZE );
891
892 #elif defined( __OS2__ )
893 INIT_SSC( GPCMD_REPORT_KEY, 12 );
894
895 sdc.command[ 10 ] = DVD_REPORT_KEY1 | (*pi_agid << 6);
896
897 i_ret = DosDevIOCtl(i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD,
898 &sdc, sizeof(sdc), &ulParamLen,
899 p_buffer, sizeof(p_buffer), &ulDataLen);
900
901 memcpy( p_key, p_buffer + 4, DVD_KEY_SIZE );
902
903 #else
904 # error "DVD ioctls are unavailable on this system"
905
906 #endif
907 return i_ret;
908 }
909
910 /*****************************************************************************
911 * ioctl_InvalidateAgid: invalidate the current AGID
912 *****************************************************************************/
ioctl_InvalidateAgid(int i_fd,int * pi_agid)913 int ioctl_InvalidateAgid( int i_fd, int *pi_agid )
914 {
915 int i_ret;
916
917 #if defined( HAVE_LINUX_DVD_STRUCT )
918 dvd_authinfo auth_info = { 0 };
919
920 auth_info.type = DVDCSS_INVALIDATE_AGID;
921 auth_info.lsa.agid = *pi_agid;
922
923 i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
924
925 #elif defined( HAVE_BSD_DVD_STRUCT )
926 struct dvd_authinfo auth_info = { 0 };
927
928 auth_info.format = DVDCSS_INVALIDATE_AGID;
929 auth_info.agid = *pi_agid;
930
931 i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
932
933 #elif defined( __HAIKU__ )
934 INIT_RDC( GPCMD_REPORT_KEY, 0 );
935
936 rdc.command[ 10 ] = DVDCSS_INVALIDATE_AGID | (*pi_agid << 6);
937
938 i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
939
940 #elif defined( SOLARIS_USCSI )
941 INIT_USCSI( GPCMD_REPORT_KEY, 0 );
942
943 rs_cdb.cdb_opaque[ 10 ] = DVDCSS_INVALIDATE_AGID | (*pi_agid << 6);
944
945 i_ret = SolarisSendUSCSI( i_fd, &sc );
946
947 if( i_ret < 0 || sc.uscsi_status )
948 {
949 i_ret = -1;
950 }
951
952 #elif defined( DARWIN_DVD_IOCTL )
953 INIT_DVDIOCTL( dk_dvd_send_key_t, DVDAuthenticationGrantIDInfo,
954 kDVDKeyFormatAGID_Invalidate );
955
956 dvd.grantID = *pi_agid;
957
958 i_ret = ioctl( i_fd, DKIOCDVDSENDKEY, &dvd );
959
960 #elif defined( _WIN32 )
961 DWORD tmp;
962
963 i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_END_SESSION,
964 pi_agid, sizeof( *pi_agid ), NULL, 0, &tmp, NULL ) ? 0 : -1;
965
966 #elif defined( __QNXNTO__ )
967
968 INIT_CPT( GPCMD_REPORT_KEY, 0 );
969
970 p_cpt->cam_cdb[ 10 ] = DVDCSS_INVALIDATE_AGID | (*pi_agid << 6);
971
972 i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL);
973
974 #elif defined( __OS2__ )
975 INIT_SSC( GPCMD_REPORT_KEY, 1 );
976
977 sdc.data_length = 0;
978 sdc.command[ 8 ] = 0;
979 sdc.command[ 9 ] = 0;
980
981 sdc.command[ 10 ] = DVDCSS_INVALIDATE_AGID | (*pi_agid << 6);
982
983 i_ret = DosDevIOCtl(i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD,
984 &sdc, sizeof(sdc), &ulParamLen,
985 NULL, 0, &ulDataLen);
986 #else
987 # error "DVD ioctls are unavailable on this system"
988
989 #endif
990 return i_ret;
991 }
992
993 /*****************************************************************************
994 * ioctl_SendChallenge: send challenge to the drive
995 *****************************************************************************/
ioctl_SendChallenge(int i_fd,const int * pi_agid,const uint8_t * p_challenge)996 int ioctl_SendChallenge( int i_fd, const int *pi_agid, const uint8_t *p_challenge )
997 {
998 int i_ret;
999
1000 #if defined( HAVE_LINUX_DVD_STRUCT )
1001 dvd_authinfo auth_info = { 0 };
1002
1003 auth_info.type = DVD_HOST_SEND_CHALLENGE;
1004 auth_info.hsc.agid = *pi_agid;
1005
1006 memcpy( auth_info.hsc.chal, p_challenge, DVD_CHALLENGE_SIZE );
1007
1008 i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
1009
1010 #elif defined( HAVE_BSD_DVD_STRUCT )
1011 struct dvd_authinfo auth_info = { 0 };
1012
1013 auth_info.format = DVD_SEND_CHALLENGE;
1014 auth_info.agid = *pi_agid;
1015
1016 memcpy( auth_info.keychal, p_challenge, DVD_CHALLENGE_SIZE );
1017
1018 i_ret = ioctl( i_fd, DVDIOCSENDKEY, &auth_info );
1019
1020 #elif defined( __HAIKU__ )
1021 INIT_RDC( GPCMD_SEND_KEY, 16 );
1022
1023 rdc.command[ 10 ] = DVD_SEND_CHALLENGE | (*pi_agid << 6);
1024
1025 p_buffer[ 1 ] = 0xe;
1026 memcpy( p_buffer + 4, p_challenge, DVD_CHALLENGE_SIZE );
1027
1028 i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
1029
1030 #elif defined( SOLARIS_USCSI )
1031 INIT_USCSI( GPCMD_SEND_KEY, 16 );
1032
1033 rs_cdb.cdb_opaque[ 10 ] = DVD_SEND_CHALLENGE | (*pi_agid << 6);
1034
1035 p_buffer[ 1 ] = 0xe;
1036 memcpy( p_buffer + 4, p_challenge, DVD_CHALLENGE_SIZE );
1037
1038 if( SolarisSendUSCSI( i_fd, &sc ) < 0 || sc.uscsi_status )
1039 {
1040 return -1;
1041 }
1042
1043 i_ret = 0;
1044
1045 #elif defined( DARWIN_DVD_IOCTL )
1046 INIT_DVDIOCTL( dk_dvd_send_key_t, DVDChallengeKeyInfo,
1047 kDVDKeyFormatChallengeKey );
1048
1049 dvd.grantID = *pi_agid;
1050 dvd.keyClass = kDVDKeyClassCSS_CPPM_CPRM;
1051
1052 dvdbs.dataLength[ 1 ] = 0xe;
1053 memcpy( dvdbs.challengeKeyValue, p_challenge, DVD_CHALLENGE_SIZE );
1054
1055 i_ret = ioctl( i_fd, DKIOCDVDSENDKEY, &dvd );
1056
1057 #elif defined( _WIN32 )
1058 DWORD tmp;
1059 uint8_t buffer[DVD_CHALLENGE_KEY_LENGTH] = { 0 };
1060 PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
1061
1062 key->KeyLength = DVD_CHALLENGE_KEY_LENGTH;
1063 key->SessionId = *pi_agid;
1064 key->KeyType = DvdChallengeKey;
1065 key->KeyFlags = 0;
1066
1067 memcpy( key->KeyData, p_challenge, DVD_CHALLENGE_SIZE );
1068
1069 i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_SEND_KEY, key,
1070 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
1071
1072 #elif defined( __QNXNTO__ )
1073
1074 INIT_CPT( GPCMD_SEND_KEY, 16 );
1075
1076 p_cpt->cam_cdb[ 10 ] = DVD_SEND_CHALLENGE | (*pi_agid << 6);
1077
1078 p_buffer[ 1 ] = 0xe;
1079 memcpy( p_buffer + 4, p_challenge, DVD_CHALLENGE_SIZE );
1080
1081 i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL);
1082
1083 #elif defined( __OS2__ )
1084 INIT_SSC( GPCMD_SEND_KEY, 16 );
1085
1086 sdc.command[ 10 ] = DVD_SEND_CHALLENGE | (*pi_agid << 6);
1087
1088 p_buffer[ 1 ] = 0xe;
1089 memcpy( p_buffer + 4, p_challenge, DVD_CHALLENGE_SIZE );
1090
1091 i_ret = DosDevIOCtl( i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD,
1092 &sdc, sizeof(sdc), &ulParamLen,
1093 p_buffer, sizeof(p_buffer), &ulDataLen );
1094
1095 #else
1096 # error "DVD ioctls are unavailable on this system"
1097
1098 #endif
1099 return i_ret;
1100 }
1101
1102 /*****************************************************************************
1103 * ioctl_SendKey2: send the second key to the drive
1104 *****************************************************************************/
ioctl_SendKey2(int i_fd,const int * pi_agid,const uint8_t * p_key)1105 int ioctl_SendKey2( int i_fd, const int *pi_agid, const uint8_t *p_key )
1106 {
1107 int i_ret;
1108
1109 #if defined( HAVE_LINUX_DVD_STRUCT )
1110 dvd_authinfo auth_info = { 0 };
1111
1112 auth_info.type = DVD_HOST_SEND_KEY2;
1113 auth_info.hsk.agid = *pi_agid;
1114
1115 memcpy( auth_info.hsk.key, p_key, DVD_KEY_SIZE );
1116
1117 i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
1118
1119 #elif defined( HAVE_BSD_DVD_STRUCT )
1120 struct dvd_authinfo auth_info = { 0 };
1121
1122 auth_info.format = DVD_SEND_KEY2;
1123 auth_info.agid = *pi_agid;
1124
1125 memcpy( auth_info.keychal, p_key, DVD_KEY_SIZE );
1126
1127 i_ret = ioctl( i_fd, DVDIOCSENDKEY, &auth_info );
1128
1129 #elif defined( __HAIKU__ )
1130 INIT_RDC( GPCMD_SEND_KEY, 12 );
1131
1132 rdc.command[ 10 ] = DVD_SEND_KEY2 | (*pi_agid << 6);
1133
1134 p_buffer[ 1 ] = 0xa;
1135 memcpy( p_buffer + 4, p_key, DVD_KEY_SIZE );
1136
1137 i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
1138
1139 #elif defined( SOLARIS_USCSI )
1140 INIT_USCSI( GPCMD_SEND_KEY, 12 );
1141
1142 rs_cdb.cdb_opaque[ 10 ] = DVD_SEND_KEY2 | (*pi_agid << 6);
1143
1144 p_buffer[ 1 ] = 0xa;
1145 memcpy( p_buffer + 4, p_key, DVD_KEY_SIZE );
1146
1147 if( SolarisSendUSCSI( i_fd, &sc ) < 0 || sc.uscsi_status )
1148 {
1149 return -1;
1150 }
1151
1152 i_ret = 0;
1153
1154 #elif defined( DARWIN_DVD_IOCTL )
1155 INIT_DVDIOCTL( dk_dvd_send_key_t, DVDKey2Info,
1156 kDVDKeyFormatKey2 );
1157
1158 dvd.grantID = *pi_agid;
1159 dvd.keyClass = kDVDKeyClassCSS_CPPM_CPRM;
1160
1161 dvdbs.dataLength[ 1 ] = 0xa;
1162 memcpy( dvdbs.key2Value, p_key, DVD_KEY_SIZE );
1163
1164 i_ret = ioctl( i_fd, DKIOCDVDSENDKEY, &dvd );
1165
1166 #elif defined( _WIN32 )
1167 DWORD tmp;
1168 uint8_t buffer[DVD_BUS_KEY_LENGTH] = { 0 };
1169 PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
1170
1171 key->KeyLength = DVD_BUS_KEY_LENGTH;
1172 key->SessionId = *pi_agid;
1173 key->KeyType = DvdBusKey2;
1174 key->KeyFlags = 0;
1175
1176 memcpy( key->KeyData, p_key, DVD_KEY_SIZE );
1177
1178 i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_SEND_KEY, key,
1179 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
1180
1181 #elif defined( __QNXNTO__ )
1182
1183 INIT_CPT( GPCMD_SEND_KEY, 12 );
1184
1185 p_cpt->cam_cdb[ 10 ] = DVD_SEND_KEY2 | (*pi_agid << 6);
1186
1187 p_buffer[ 1 ] = 0xa;
1188 memcpy( p_buffer + 4, p_key, DVD_KEY_SIZE );
1189
1190 i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL);
1191
1192 #elif defined( __OS2__ )
1193 INIT_SSC( GPCMD_SEND_KEY, 12 );
1194
1195 sdc.command[ 10 ] = DVD_SEND_KEY2 | (*pi_agid << 6);
1196
1197 p_buffer[ 1 ] = 0xa;
1198 memcpy( p_buffer + 4, p_key, DVD_KEY_SIZE );
1199
1200 i_ret = DosDevIOCtl( i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD,
1201 &sdc, sizeof(sdc), &ulParamLen,
1202 p_buffer, sizeof(p_buffer), &ulDataLen );
1203
1204 #else
1205 # error "DVD ioctls are unavailable on this system"
1206
1207 #endif
1208 return i_ret;
1209 }
1210
1211 /*****************************************************************************
1212 * ioctl_ReportRPC: get RPC (Regional Playback Control) status for the drive
1213 *****************************************************************************/
ioctl_ReportRPC(int i_fd,int * p_type,int * p_mask,int * p_scheme)1214 int ioctl_ReportRPC( int i_fd, int *p_type, int *p_mask, int *p_scheme )
1215 {
1216 int i_ret;
1217
1218 #if defined( HAVE_LINUX_DVD_STRUCT ) && defined( DVD_LU_SEND_RPC_STATE )
1219 dvd_authinfo auth_info = { 0 };
1220
1221 auth_info.type = DVD_LU_SEND_RPC_STATE;
1222
1223 i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
1224
1225 *p_type = auth_info.lrpcs.type;
1226 *p_mask = auth_info.lrpcs.region_mask;
1227 *p_scheme = auth_info.lrpcs.rpc_scheme;
1228
1229 #elif defined( HAVE_LINUX_DVD_STRUCT )
1230 /* FIXME: OpenBSD doesn't know this */
1231 i_ret = -1;
1232
1233 #elif defined( HAVE_BSD_DVD_STRUCT )
1234 struct dvd_authinfo auth_info = { 0 };
1235
1236 auth_info.format = DVD_REPORT_RPC;
1237
1238 i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
1239
1240 *p_type = auth_info.reg_type;
1241 *p_mask = auth_info.region; // ??
1242 *p_scheme = auth_info.rpc_scheme;
1243
1244 #elif defined( __HAIKU__ )
1245 INIT_RDC( GPCMD_REPORT_KEY, 8 );
1246
1247 rdc.command[ 10 ] = DVD_REPORT_RPC;
1248
1249 i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
1250
1251 *p_type = p_buffer[ 4 ] >> 6;
1252 *p_mask = p_buffer[ 5 ];
1253 *p_scheme = p_buffer[ 6 ];
1254
1255 #elif defined( SOLARIS_USCSI )
1256 INIT_USCSI( GPCMD_REPORT_KEY, 8 );
1257
1258 rs_cdb.cdb_opaque[ 10 ] = DVD_REPORT_RPC;
1259
1260 i_ret = SolarisSendUSCSI( i_fd, &sc );
1261
1262 if( i_ret < 0 || sc.uscsi_status )
1263 {
1264 i_ret = -1;
1265 }
1266
1267 *p_type = p_buffer[ 4 ] >> 6;
1268 *p_mask = p_buffer[ 5 ];
1269 *p_scheme = p_buffer[ 6 ];
1270
1271 #elif defined( DARWIN_DVD_IOCTL )
1272 INIT_DVDIOCTL( dk_dvd_report_key_t, DVDRegionPlaybackControlInfo,
1273 kDVDKeyFormatRegionState );
1274
1275 dvd.keyClass = kDVDKeyClassCSS_CPPM_CPRM;
1276
1277 i_ret = ioctl( i_fd, DKIOCDVDREPORTKEY, &dvd );
1278
1279 *p_type = dvdbs.typeCode;
1280 *p_mask = dvdbs.driveRegion;
1281 *p_scheme = dvdbs.rpcScheme;
1282
1283 #elif defined( _WIN32 )
1284 DWORD tmp;
1285 uint8_t buffer[DVD_RPC_KEY_LENGTH] = { 0 };
1286 PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
1287 PDVD_RPC_KEY keyData;
1288
1289 key->KeyLength = DVD_RPC_KEY_LENGTH;
1290 key->KeyType = DvdGetRpcKey;
1291 key->KeyFlags = 0;
1292
1293 i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key,
1294 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
1295
1296 if( i_ret < 0 )
1297 {
1298 return i_ret;
1299 }
1300
1301 keyData = (PDVD_RPC_KEY)key->KeyData;
1302 *p_type = keyData->TypeCode;
1303 *p_mask = keyData->RegionMask;
1304 *p_scheme = keyData->RpcScheme;
1305
1306 #elif defined( __QNXNTO__ )
1307
1308 INIT_CPT( GPCMD_REPORT_KEY, 8 );
1309
1310 p_cpt->cam_cdb[ 10 ] = DVD_REPORT_RPC;
1311
1312 i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL);
1313
1314 *p_type = p_buffer[ 4 ] >> 6;
1315 *p_mask = p_buffer[ 5 ];
1316 *p_scheme = p_buffer[ 6 ];
1317
1318 #elif defined( __OS2__ )
1319 INIT_SSC( GPCMD_REPORT_KEY, 8 );
1320
1321 sdc.command[ 10 ] = DVD_REPORT_RPC;
1322
1323 i_ret = DosDevIOCtl(i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD,
1324 &sdc, sizeof(sdc), &ulParamLen,
1325 p_buffer, sizeof(p_buffer), &ulDataLen);
1326
1327 *p_type = p_buffer[ 4 ] >> 6;
1328 *p_mask = p_buffer[ 5 ];
1329 *p_scheme = p_buffer[ 6 ];
1330
1331 #else
1332 # error "DVD ioctls are unavailable on this system"
1333
1334 #endif
1335 return i_ret;
1336 }
1337
1338 /* Local prototypes */
1339
1340 #if defined( __HAIKU__ )
1341 /*****************************************************************************
1342 * BeInitRDC: initialize a RDC structure for the Haiku kernel
1343 *****************************************************************************
1344 * This function initializes a Haiku raw device command structure for future
1345 * use, either a read command or a write command.
1346 *****************************************************************************/
BeInitRDC(raw_device_command * p_rdc,int i_type)1347 static void BeInitRDC( raw_device_command *p_rdc, int i_type )
1348 {
1349 memset( p_rdc->data, 0, p_rdc->data_length );
1350
1351 switch( i_type )
1352 {
1353 case GPCMD_SEND_KEY:
1354 /* leave the flags to 0 */
1355 break;
1356
1357 case GPCMD_READ_DVD_STRUCTURE: case GPCMD_REPORT_KEY:
1358 p_rdc->flags = B_RAW_DEVICE_DATA_IN; break; }
1359
1360 p_rdc->command[ 0 ] = i_type;
1361
1362 p_rdc->command[ 8 ] = (p_rdc->data_length >> 8) & 0xff;
1363 p_rdc->command[ 9 ] = p_rdc->data_length & 0xff;
1364 p_rdc->command_length = 12;
1365
1366 p_rdc->sense_data = NULL;
1367 p_rdc->sense_data_length = 0;
1368
1369 p_rdc->timeout = 1000000;
1370 }
1371 #endif
1372
1373 #if defined( SOLARIS_USCSI )
1374 /*****************************************************************************
1375 * SolarisInitUSCSI: initialize a USCSICMD structure for the Solaris kernel
1376 *****************************************************************************
1377 * This function initializes a Solaris userspace SCSI command structure for
1378 * future use, either a read command or a write command.
1379 *****************************************************************************/
SolarisInitUSCSI(struct uscsi_cmd * p_sc,int i_type)1380 static void SolarisInitUSCSI( struct uscsi_cmd *p_sc, int i_type )
1381 {
1382 union scsi_cdb *rs_cdb;
1383 memset( p_sc->uscsi_cdb, 0, sizeof( union scsi_cdb ) );
1384 memset( p_sc->uscsi_bufaddr, 0, p_sc->uscsi_buflen );
1385
1386 switch( i_type )
1387 {
1388 case GPCMD_SEND_KEY:
1389 p_sc->uscsi_flags = USCSI_ISOLATE | USCSI_WRITE;
1390 break;
1391
1392 case GPCMD_READ_DVD_STRUCTURE:
1393 case GPCMD_REPORT_KEY:
1394 p_sc->uscsi_flags = USCSI_ISOLATE | USCSI_READ;
1395 break;
1396 }
1397
1398 rs_cdb = (union scsi_cdb *)p_sc->uscsi_cdb;
1399
1400 rs_cdb->scc_cmd = i_type;
1401
1402 rs_cdb->cdb_opaque[ 8 ] = (p_sc->uscsi_buflen >> 8) & 0xff;
1403 rs_cdb->cdb_opaque[ 9 ] = p_sc->uscsi_buflen & 0xff;
1404 p_sc->uscsi_cdblen = 12;
1405 p_sc->uscsi_timeout = 15;
1406 }
1407
1408 /*****************************************************************************
1409 * SolarisSendUSCSI: send a USCSICMD structure to the Solaris kernel
1410 * for execution
1411 *****************************************************************************
1412 * When available, this function uses the function smedia_uscsi_cmd()
1413 * from Solaris' libsmedia library (Solaris 9 or newer) to execute the
1414 * USCSI command. smedia_uscsi_cmd() allows USCSI commands for
1415 * non-root users on removable media devices on Solaris 9; sending the
1416 * USCSI command directly to the device using the USCSICMD ioctl fails
1417 * with an EPERM error on Solaris 9.
1418 *
1419 * The code will fall back to the USCSICMD ioctl method, when
1420 * libsmedia.so is not available or does not export the
1421 * smedia_uscsi_cmd() function (on Solaris releases up to and including
1422 * Solaris 8). Fortunately, on these old releases non-root users are
1423 * allowed to perform USCSICMD ioctls on removable media devices.
1424 *****************************************************************************/
SolarisSendUSCSI(int i_fd,struct uscsi_cmd * p_sc)1425 static int SolarisSendUSCSI( int i_fd, struct uscsi_cmd *p_sc )
1426 {
1427 void *p_handle;
1428
1429 /* We use static variables to keep track of the libsmedia symbols, which
1430 * is harmless even in a multithreaded program because the library and
1431 * its symbols will always be mapped at the same address. */
1432 static int b_tried = 0;
1433 static int b_have_sm = 0;
1434 static void * (*p_get_handle) ( int32_t );
1435 static int (*p_uscsi_cmd) ( void *, struct uscsi_cmd * );
1436 static int (*p_release_handle) ( void * );
1437
1438 if( !b_tried )
1439 {
1440 void *p_lib;
1441
1442 p_lib = dlopen( "libsmedia.so", RTLD_NOW );
1443 if( p_lib )
1444 {
1445 p_get_handle = dlsym( p_lib, "smedia_get_handle" );
1446 p_uscsi_cmd = dlsym( p_lib, "smedia_uscsi_cmd" );
1447 p_release_handle = dlsym( p_lib, "smedia_release_handle" );
1448
1449 if( p_get_handle && p_uscsi_cmd && p_release_handle )
1450 {
1451 b_have_sm = 1;
1452 }
1453 else
1454 {
1455 dlclose( p_lib );
1456 }
1457 }
1458
1459 b_tried = 1;
1460 }
1461
1462 if( b_have_sm && (p_handle = p_get_handle(i_fd)) )
1463 {
1464 int i_ret = p_uscsi_cmd( p_handle, p_sc );
1465 p_release_handle( p_handle );
1466 return i_ret;
1467 }
1468
1469 return ioctl( i_fd, USCSICMD, p_sc );
1470 }
1471 #endif /* defined( SOLARIS_USCSI ) */
1472
1473 #if defined( _WIN32 )
1474 /*****************************************************************************
1475 * WinInitSPTD: initialize a sptd structure
1476 *****************************************************************************
1477 * This function initializes a SCSI pass through command structure for future
1478 * use, either a read command or a write command.
1479 *****************************************************************************/
WinInitSPTD(SCSI_PASS_THROUGH_DIRECT * p_sptd,int i_type)1480 static void WinInitSPTD( SCSI_PASS_THROUGH_DIRECT *p_sptd, int i_type )
1481 {
1482 memset( p_sptd->DataBuffer, 0, p_sptd->DataTransferLength );
1483
1484 switch( i_type )
1485 {
1486 case GPCMD_SEND_KEY:
1487 p_sptd->DataIn = SCSI_IOCTL_DATA_OUT;
1488 break;
1489
1490 case GPCMD_READ_DVD_STRUCTURE:
1491 case GPCMD_REPORT_KEY:
1492 p_sptd->DataIn = SCSI_IOCTL_DATA_IN;
1493 break;
1494 }
1495
1496 p_sptd->Cdb[ 0 ] = i_type;
1497 p_sptd->Cdb[ 8 ] = (uint8_t)(p_sptd->DataTransferLength >> 8) & 0xff;
1498 p_sptd->Cdb[ 9 ] = (uint8_t) p_sptd->DataTransferLength & 0xff;
1499 p_sptd->CdbLength = 12;
1500
1501 p_sptd->TimeOutValue = 2;
1502 }
1503 #endif /* defined( _WIN32 ) */
1504
1505 #if defined( __QNXNTO__ )
1506 /*****************************************************************************
1507 * QNXInitCPT: initialize a CPT structure for QNX Neutrino
1508 *****************************************************************************
1509 * This function initializes a cpt command structure for future use,
1510 * either a read command or a write command.
1511 *****************************************************************************/
QNXInitCPT(CAM_PASS_THRU * p_cpt,int i_type)1512 static void QNXInitCPT( CAM_PASS_THRU * p_cpt, int i_type )
1513 {
1514 switch( i_type )
1515 {
1516 case GPCMD_SEND_KEY:
1517 p_cpt->cam_flags = CAM_DIR_OUT;
1518 break;
1519
1520 case GPCMD_READ_DVD_STRUCTURE:
1521 case GPCMD_REPORT_KEY:
1522 p_cpt->cam_flags = CAM_DIR_IN;
1523 break;
1524 }
1525
1526 p_cpt->cam_cdb[0] = i_type;
1527
1528 p_cpt->cam_cdb[ 8 ] = (p_cpt->cam_dxfer_len >> 8) & 0xff;
1529 p_cpt->cam_cdb[ 9 ] = p_cpt->cam_dxfer_len & 0xff;
1530 p_cpt->cam_cdb_len = 12;
1531
1532 p_cpt->cam_timeout = CAM_TIME_DEFAULT;
1533 }
1534 #endif /* defined( __QNXNTO__ ) */
1535
1536 #if defined( __OS2__ )
1537 /*****************************************************************************
1538 * OS2InitSDC: initialize a SDC structure for the Execute SCSI-command
1539 *****************************************************************************
1540 * This function initializes an OS/2 'execute SCSI command' structure for
1541 * future use, either a read command or a write command.
1542 *****************************************************************************/
OS2InitSDC(struct OS2_ExecSCSICmd * p_sdc,int i_type)1543 static void OS2InitSDC( struct OS2_ExecSCSICmd *p_sdc, int i_type )
1544 {
1545 switch( i_type )
1546 {
1547 case GPCMD_SEND_KEY:
1548 p_sdc->flags = 0;
1549 break;
1550
1551 case GPCMD_READ_DVD_STRUCTURE:
1552 case GPCMD_REPORT_KEY:
1553 p_sdc->flags = EX_DIRECTION_IN;
1554 break;
1555 }
1556
1557 p_sdc->command[ 0 ] = i_type;
1558 p_sdc->command[ 8 ] = (p_sdc->data_length >> 8) & 0xff;
1559 p_sdc->command[ 9 ] = p_sdc->data_length & 0xff;
1560 p_sdc->id_code = 0x31304443; // 'CD01'
1561 p_sdc->cmd_length = 12;
1562 }
1563 #endif /* defined( __OS2__ ) */
1564