@@ -395,36 +395,34 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
395395 * mei_ioctl_connect_client - the connect to fw client IOCTL function
396396 *
397397 * @file: private data of the file object
398- * @data: IOCTL connect data, input and output parameters
398+ * @in_client_uuid: requested UUID for connection
399+ * @client: IOCTL connect data, output parameters
399400 *
400401 * Locking: called under "dev->device_lock" lock
401402 *
402403 * Return: 0 on success, <0 on failure.
403404 */
404405static int mei_ioctl_connect_client (struct file * file ,
405- struct mei_connect_client_data * data )
406+ const uuid_le * in_client_uuid ,
407+ struct mei_client * client )
406408{
407409struct mei_device * dev ;
408- struct mei_client * client ;
409410struct mei_me_client * me_cl ;
410411struct mei_cl * cl ;
411412int rets ;
412413
413414cl = file -> private_data ;
414415dev = cl -> dev ;
415416
416- if (dev -> dev_state != MEI_DEV_ENABLED )
417- return - ENODEV ;
418-
419417if (cl -> state != MEI_FILE_INITIALIZING &&
420418cl -> state != MEI_FILE_DISCONNECTED )
421419return - EBUSY ;
422420
423421/* find ME client we're trying to connect to */
424- me_cl = mei_me_cl_by_uuid (dev ,& data -> in_client_uuid );
422+ me_cl = mei_me_cl_by_uuid (dev ,in_client_uuid );
425423if (!me_cl ) {
426424dev_dbg (dev -> dev ,"Cannot connect to FW Client UUID = %pUl\n" ,
427- & data -> in_client_uuid );
425+ in_client_uuid );
428426rets = - ENOTTY ;
429427gotoend ;
430428}
@@ -434,7 +432,7 @@ static int mei_ioctl_connect_client(struct file *file,
434432 !dev -> allow_fixed_address : !dev -> hbm_f_fa_supported ;
435433if (forbidden ) {
436434dev_dbg (dev -> dev ,"Connection forbidden to FW Client UUID = %pUl\n" ,
437- & data -> in_client_uuid );
435+ in_client_uuid );
438436rets = - ENOTTY ;
439437gotoend ;
440438}
@@ -448,7 +446,6 @@ static int mei_ioctl_connect_client(struct file *file,
448446me_cl -> props .max_msg_length );
449447
450448/* prepare the output buffer */
451- client = & data -> out_client_properties ;
452449client -> max_msg_length = me_cl -> props .max_msg_length ;
453450client -> protocol_version = me_cl -> props .protocol_version ;
454451dev_dbg (dev -> dev ,"Can connect?\n" );
@@ -460,6 +457,135 @@ static int mei_ioctl_connect_client(struct file *file,
460457return rets ;
461458}
462459
460+ /**
461+ * mei_vt_support_check - check if client support vtags
462+ *
463+ * Locking: called under "dev->device_lock" lock
464+ *
465+ * @dev: mei_device
466+ * @uuid: client UUID
467+ *
468+ * Return:
469+ *0 - supported
470+ *-ENOTTY - no such client
471+ *-EOPNOTSUPP - vtags are not supported by client
472+ */
473+ static int mei_vt_support_check (struct mei_device * dev ,const uuid_le * uuid )
474+ {
475+ struct mei_me_client * me_cl ;
476+ int ret ;
477+
478+ if (!dev -> hbm_f_vt_supported )
479+ return - EOPNOTSUPP ;
480+
481+ me_cl = mei_me_cl_by_uuid (dev ,uuid );
482+ if (!me_cl ) {
483+ dev_dbg (dev -> dev ,"Cannot connect to FW Client UUID = %pUl\n" ,
484+ uuid );
485+ return - ENOTTY ;
486+ }
487+ ret = me_cl -> props .vt_supported ?0 :- EOPNOTSUPP ;
488+ mei_me_cl_put (me_cl );
489+
490+ return ret ;
491+ }
492+
493+ /**
494+ * mei_ioctl_connect_vtag - connect to fw client with vtag IOCTL function
495+ *
496+ * @file: private data of the file object
497+ * @in_client_uuid: requested UUID for connection
498+ * @client: IOCTL connect data, output parameters
499+ * @vtag: vm tag
500+ *
501+ * Locking: called under "dev->device_lock" lock
502+ *
503+ * Return: 0 on success, <0 on failure.
504+ */
505+ static int mei_ioctl_connect_vtag (struct file * file ,
506+ const uuid_le * in_client_uuid ,
507+ struct mei_client * client ,
508+ u8 vtag )
509+ {
510+ struct mei_device * dev ;
511+ struct mei_cl * cl ;
512+ struct mei_cl * pos ;
513+ struct mei_cl_vtag * cl_vtag ;
514+
515+ cl = file -> private_data ;
516+ dev = cl -> dev ;
517+
518+ dev_dbg (dev -> dev ,"FW Client %pUl vtag %d\n" ,in_client_uuid ,vtag );
519+
520+ switch (cl -> state ) {
521+ case MEI_FILE_DISCONNECTED :
522+ if (mei_cl_vtag_by_fp (cl ,file )!= vtag ) {
523+ dev_err (dev -> dev ,"reconnect with different vtag\n" );
524+ return - EINVAL ;
525+ }
526+ break ;
527+ case MEI_FILE_INITIALIZING :
528+ /* malicious connect from another thread may push vtag */
529+ if (!IS_ERR (mei_cl_fp_by_vtag (cl ,vtag ))) {
530+ dev_err (dev -> dev ,"vtag already filled\n" );
531+ return - EINVAL ;
532+ }
533+
534+ list_for_each_entry (pos ,& dev -> file_list ,link ) {
535+ if (pos == cl )
536+ continue ;
537+ if (!pos -> me_cl )
538+ continue ;
539+
540+ /* only search for same UUID */
541+ if (uuid_le_cmp (* mei_cl_uuid (pos ),* in_client_uuid ))
542+ continue ;
543+
544+ /* if tag already exist try another fp */
545+ if (!IS_ERR (mei_cl_fp_by_vtag (pos ,vtag )))
546+ continue ;
547+
548+ /* replace cl with acquired one */
549+ dev_dbg (dev -> dev ,"replacing with existing cl\n" );
550+ mei_cl_unlink (cl );
551+ kfree (cl );
552+ file -> private_data = pos ;
553+ cl = pos ;
554+ break ;
555+ }
556+
557+ cl_vtag = mei_cl_vtag_alloc (file ,vtag );
558+ if (IS_ERR (cl_vtag ))
559+ return - ENOMEM ;
560+
561+ list_add_tail (& cl_vtag -> list ,& cl -> vtag_map );
562+ break ;
563+ default :
564+ return - EBUSY ;
565+ }
566+
567+ while (cl -> state != MEI_FILE_INITIALIZING &&
568+ cl -> state != MEI_FILE_DISCONNECTED &&
569+ cl -> state != MEI_FILE_CONNECTED ) {
570+ mutex_unlock (& dev -> device_lock );
571+ wait_event_timeout (cl -> wait ,
572+ (cl -> state == MEI_FILE_CONNECTED ||
573+ cl -> state == MEI_FILE_DISCONNECTED ||
574+ cl -> state == MEI_FILE_DISCONNECT_REQUIRED ||
575+ cl -> state == MEI_FILE_DISCONNECT_REPLY ),
576+ mei_secs_to_jiffies (MEI_CL_CONNECT_TIMEOUT ));
577+ mutex_lock (& dev -> device_lock );
578+ }
579+
580+ if (!mei_cl_is_connected (cl ))
581+ return mei_ioctl_connect_client (file ,in_client_uuid ,client );
582+
583+ client -> max_msg_length = cl -> me_cl -> props .max_msg_length ;
584+ client -> protocol_version = cl -> me_cl -> props .protocol_version ;
585+
586+ return 0 ;
587+ }
588+
463589/**
464590 * mei_ioctl_client_notify_request -
465591 * propagate event notification request to client
@@ -516,7 +642,11 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data)
516642{
517643struct mei_device * dev ;
518644struct mei_cl * cl = file -> private_data ;
519- struct mei_connect_client_data connect_data ;
645+ struct mei_connect_client_data conn ;
646+ struct mei_connect_client_data_vtag conn_vtag ;
647+ const uuid_le * cl_uuid ;
648+ struct mei_client * props ;
649+ u8 vtag ;
520650u32 notify_get ,notify_req ;
521651int rets ;
522652
@@ -537,20 +667,68 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data)
537667switch (cmd ) {
538668case IOCTL_MEI_CONNECT_CLIENT :
539669dev_dbg (dev -> dev ,": IOCTL_MEI_CONNECT_CLIENT.\n" );
540- if (copy_from_user (& connect_data , (char __user * )data ,
541- sizeof (connect_data ))) {
670+ if (copy_from_user (& conn , (char __user * )data ,sizeof (conn ))) {
671+ dev_dbg (dev -> dev ,"failed to copy data from userland\n" );
672+ rets = - EFAULT ;
673+ gotoout ;
674+ }
675+ cl_uuid = & conn .in_client_uuid ;
676+ props = & conn .out_client_properties ;
677+ vtag = 0 ;
678+
679+ rets = mei_vt_support_check (dev ,cl_uuid );
680+ if (rets == - ENOTTY )
681+ gotoout ;
682+ if (!rets )
683+ rets = mei_ioctl_connect_vtag (file ,cl_uuid ,props ,
684+ vtag );
685+ else
686+ rets = mei_ioctl_connect_client (file ,cl_uuid ,props );
687+ if (rets )
688+ gotoout ;
689+
690+ /* if all is ok, copying the data back to user. */
691+ if (copy_to_user ((char __user * )data ,& conn ,sizeof (conn ))) {
692+ dev_dbg (dev -> dev ,"failed to copy data to userland\n" );
693+ rets = - EFAULT ;
694+ gotoout ;
695+ }
696+
697+ break ;
698+
699+ case IOCTL_MEI_CONNECT_CLIENT_VTAG :
700+ dev_dbg (dev -> dev ,"IOCTL_MEI_CONNECT_CLIENT_VTAG\n" );
701+ if (copy_from_user (& conn_vtag , (char __user * )data ,
702+ sizeof (conn_vtag ))) {
542703dev_dbg (dev -> dev ,"failed to copy data from userland\n" );
543704rets = - EFAULT ;
544705gotoout ;
545706}
546707
547- rets = mei_ioctl_connect_client (file ,& connect_data );
708+ cl_uuid = & conn_vtag .connect .in_client_uuid ;
709+ props = & conn_vtag .out_client_properties ;
710+ vtag = conn_vtag .connect .vtag ;
711+
712+ rets = mei_vt_support_check (dev ,cl_uuid );
713+ if (rets == - EOPNOTSUPP )
714+ dev_dbg (dev -> dev ,"FW Client %pUl does not support vtags\n" ,
715+ cl_uuid );
716+ if (rets )
717+ gotoout ;
718+
719+ if (!vtag ) {
720+ dev_dbg (dev -> dev ,"vtag can't be zero\n" );
721+ rets = - EINVAL ;
722+ gotoout ;
723+ }
724+
725+ rets = mei_ioctl_connect_vtag (file ,cl_uuid ,props ,vtag );
548726if (rets )
549727gotoout ;
550728
551729/* if all is ok, copying the data back to user. */
552- if (copy_to_user ((char __user * )data ,& connect_data ,
553- sizeof (connect_data ))) {
730+ if (copy_to_user ((char __user * )data ,& conn_vtag ,
731+ sizeof (conn_vtag ))) {
554732dev_dbg (dev -> dev ,"failed to copy data to userland\n" );
555733rets = - EFAULT ;
556734gotoout ;