xref: /aosp_15_r20/external/autotest/client/cros/cellular/pseudomodem/sim.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1*9c5db199SXin Li# Lint as: python2, python3
2*9c5db199SXin Li# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
3*9c5db199SXin Li# Use of this source code is governed by a BSD-style license that can be
4*9c5db199SXin Li# found in the LICENSE file.
5*9c5db199SXin Li
6*9c5db199SXin Lifrom __future__ import absolute_import
7*9c5db199SXin Lifrom __future__ import division
8*9c5db199SXin Lifrom __future__ import print_function
9*9c5db199SXin Li
10*9c5db199SXin Liimport dbus
11*9c5db199SXin Liimport dbus.service
12*9c5db199SXin Liimport logging
13*9c5db199SXin Li
14*9c5db199SXin Liimport six
15*9c5db199SXin Li
16*9c5db199SXin Lifrom autotest_lib.client.cros.cellular import mm1_constants
17*9c5db199SXin Lifrom autotest_lib.client.cros.cellular.pseudomodem import dbus_std_ifaces
18*9c5db199SXin Lifrom autotest_lib.client.cros.cellular.pseudomodem import pm_constants
19*9c5db199SXin Lifrom autotest_lib.client.cros.cellular.pseudomodem import pm_errors
20*9c5db199SXin Lifrom autotest_lib.client.cros.cellular.pseudomodem import utils
21*9c5db199SXin Li
22*9c5db199SXin Liclass IncorrectPasswordError(pm_errors.MMMobileEquipmentError):
23*9c5db199SXin Li    """ Wrapper around MM_MOBILE_EQUIPMENT_ERROR_INCORRECT_PASSWORD. """
24*9c5db199SXin Li
25*9c5db199SXin Li    def __init__(self):
26*9c5db199SXin Li        pm_errors.MMMobileEquipmentError.__init__(
27*9c5db199SXin Li                self, pm_errors.MMMobileEquipmentError.INCORRECT_PASSWORD,
28*9c5db199SXin Li                'Incorrect password')
29*9c5db199SXin Li
30*9c5db199SXin Liclass SimPukError(pm_errors.MMMobileEquipmentError):
31*9c5db199SXin Li    """ Wrapper around MM_MOBILE_EQUIPMENT_ERROR_SIM_PUK. """
32*9c5db199SXin Li
33*9c5db199SXin Li    def __init__(self):
34*9c5db199SXin Li        pm_errors.MMMobileEquipmentError.__init__(
35*9c5db199SXin Li                self, pm_errors.MMMobileEquipmentError.SIM_PUK,
36*9c5db199SXin Li                'SIM PUK required')
37*9c5db199SXin Li
38*9c5db199SXin Liclass SimFailureError(pm_errors.MMMobileEquipmentError):
39*9c5db199SXin Li    """ Wrapper around MM_MOBILE_EQUIPMENT_ERROR_SIM_FAILURE. """
40*9c5db199SXin Li
41*9c5db199SXin Li    def __init__(self):
42*9c5db199SXin Li        pm_errors.MMMobileEquipmentError.__init__(
43*9c5db199SXin Li                self, pm_errors.MMMobileEquipmentError.SIM_FAILURE,
44*9c5db199SXin Li                'SIM failure')
45*9c5db199SXin Li
46*9c5db199SXin Liclass SIM(dbus_std_ifaces.DBusProperties):
47*9c5db199SXin Li    """
48*9c5db199SXin Li    Pseudomodem implementation of the org.freedesktop.ModemManager1.Sim
49*9c5db199SXin Li    interface.
50*9c5db199SXin Li
51*9c5db199SXin Li    Broadband modems usually need a SIM card to operate. Each Modem object will
52*9c5db199SXin Li    therefore expose up to one SIM object, which allows SIM-specific actions
53*9c5db199SXin Li    such as PIN unlocking.
54*9c5db199SXin Li
55*9c5db199SXin Li    The SIM interface handles communication with SIM, USIM, and RUIM (CDMA SIM)
56*9c5db199SXin Li    cards.
57*9c5db199SXin Li
58*9c5db199SXin Li    """
59*9c5db199SXin Li
60*9c5db199SXin Li    # Multiple object paths needs to be supported so that the SIM can be
61*9c5db199SXin Li    # "reset". This allows the object to reappear on a new path as if it has
62*9c5db199SXin Li    # been reset.
63*9c5db199SXin Li    SUPPORTS_MULTIPLE_OBJECT_PATHS = True
64*9c5db199SXin Li
65*9c5db199SXin Li    DEFAULT_MSIN = '1234567890'
66*9c5db199SXin Li    DEFAULT_IMSI = '888999111'
67*9c5db199SXin Li    DEFAULT_PIN = '1111'
68*9c5db199SXin Li    DEFAULT_PUK = '12345678'
69*9c5db199SXin Li    DEFAULT_PIN_RETRIES = 3
70*9c5db199SXin Li    DEFAULT_PUK_RETRIES = 10
71*9c5db199SXin Li
72*9c5db199SXin Li    class Carrier:
73*9c5db199SXin Li        """
74*9c5db199SXin Li        Represents a 3GPP carrier that can be stored by a SIM object.
75*9c5db199SXin Li
76*9c5db199SXin Li        """
77*9c5db199SXin Li        MCC_LIST = {
78*9c5db199SXin Li            'test' : '001',
79*9c5db199SXin Li            'us': '310',
80*9c5db199SXin Li            'de': '262',
81*9c5db199SXin Li            'es': '214',
82*9c5db199SXin Li            'fr': '208',
83*9c5db199SXin Li            'gb': '234',
84*9c5db199SXin Li            'it': '222',
85*9c5db199SXin Li            'nl': '204'
86*9c5db199SXin Li        }
87*9c5db199SXin Li
88*9c5db199SXin Li        CARRIER_LIST = {
89*9c5db199SXin Li            'test' : ('test', '000', pm_constants.DEFAULT_TEST_NETWORK_PREFIX),
90*9c5db199SXin Li            'banana' : ('us', '001', 'Banana-Comm'),
91*9c5db199SXin Li            'att': ('us', '090', 'AT&T'),
92*9c5db199SXin Li            'tmobile': ('us', '026', 'T-Mobile'),
93*9c5db199SXin Li            'simyo': ('de', '03', 'simyo'),
94*9c5db199SXin Li            'movistar': ('es', '07', 'Movistar'),
95*9c5db199SXin Li            'sfr': ('fr', '10', 'SFR'),
96*9c5db199SXin Li            'three': ('gb', '20', '3'),
97*9c5db199SXin Li            'threeita': ('it', '99', '3ITA'),
98*9c5db199SXin Li            'kpn': ('nl', '08', 'KPN')
99*9c5db199SXin Li        }
100*9c5db199SXin Li
101*9c5db199SXin Li        def __init__(self, carrier='test'):
102*9c5db199SXin Li           carrier = self.CARRIER_LIST.get(carrier, self.CARRIER_LIST['test'])
103*9c5db199SXin Li
104*9c5db199SXin Li           self.mcc = self.MCC_LIST[carrier[0]]
105*9c5db199SXin Li           self.mnc = carrier[1]
106*9c5db199SXin Li           self.operator_name = carrier[2]
107*9c5db199SXin Li           if self.operator_name != 'Banana-Comm':
108*9c5db199SXin Li              self.operator_name = self.operator_name + ' - Fake'
109*9c5db199SXin Li           self.operator_id = self.mcc + self.mnc
110*9c5db199SXin Li
111*9c5db199SXin Li
112*9c5db199SXin Li    def __init__(self,
113*9c5db199SXin Li                 carrier,
114*9c5db199SXin Li                 access_technology,
115*9c5db199SXin Li                 index=0,
116*9c5db199SXin Li                 pin=DEFAULT_PIN,
117*9c5db199SXin Li                 puk=DEFAULT_PUK,
118*9c5db199SXin Li                 pin_retries=DEFAULT_PIN_RETRIES,
119*9c5db199SXin Li                 puk_retries=DEFAULT_PUK_RETRIES,
120*9c5db199SXin Li                 locked=False,
121*9c5db199SXin Li                 msin=DEFAULT_MSIN,
122*9c5db199SXin Li                 imsi=DEFAULT_IMSI,
123*9c5db199SXin Li                 config=None):
124*9c5db199SXin Li        if not carrier:
125*9c5db199SXin Li            raise TypeError('A carrier is required.')
126*9c5db199SXin Li        path = mm1_constants.MM1 + '/SIM/' + str(index)
127*9c5db199SXin Li        self.msin = msin
128*9c5db199SXin Li        self._carrier = carrier
129*9c5db199SXin Li        self.imsi = carrier.operator_id + imsi
130*9c5db199SXin Li        self._index = 0
131*9c5db199SXin Li        self._total_pin_retries = pin_retries
132*9c5db199SXin Li        self._total_puk_retries = puk_retries
133*9c5db199SXin Li        self._lock_data = {
134*9c5db199SXin Li            mm1_constants.MM_MODEM_LOCK_SIM_PIN : {
135*9c5db199SXin Li                'code' : pin,
136*9c5db199SXin Li                'retries' : pin_retries
137*9c5db199SXin Li            },
138*9c5db199SXin Li            mm1_constants.MM_MODEM_LOCK_SIM_PUK : {
139*9c5db199SXin Li                'code' : puk,
140*9c5db199SXin Li                'retries' : puk_retries
141*9c5db199SXin Li            }
142*9c5db199SXin Li        }
143*9c5db199SXin Li        self._lock_enabled = locked
144*9c5db199SXin Li        self._show_retries = locked
145*9c5db199SXin Li        if locked:
146*9c5db199SXin Li            self._lock_type = mm1_constants.MM_MODEM_LOCK_SIM_PIN
147*9c5db199SXin Li        else:
148*9c5db199SXin Li            self._lock_type = mm1_constants.MM_MODEM_LOCK_NONE
149*9c5db199SXin Li        self._modem = None
150*9c5db199SXin Li        self.access_technology = access_technology
151*9c5db199SXin Li        dbus_std_ifaces.DBusProperties.__init__(self, path, None, config)
152*9c5db199SXin Li
153*9c5db199SXin Li
154*9c5db199SXin Li    def IncrementPath(self):
155*9c5db199SXin Li        """
156*9c5db199SXin Li        Increments the current index at which this modem is exposed on DBus.
157*9c5db199SXin Li        E.g. if the current path is org/freedesktop/ModemManager/Modem/0, the
158*9c5db199SXin Li        path will change to org/freedesktop/ModemManager/Modem/1.
159*9c5db199SXin Li
160*9c5db199SXin Li        Calling this method does not remove the object from its current path,
161*9c5db199SXin Li        which means that it will be available via both the old and the new
162*9c5db199SXin Li        paths. This is currently only used by Reset, in conjunction with
163*9c5db199SXin Li        dbus_std_ifaces.DBusObjectManager.[Add|Remove].
164*9c5db199SXin Li
165*9c5db199SXin Li        """
166*9c5db199SXin Li        self._index += 1
167*9c5db199SXin Li        path = mm1_constants.MM1 + '/SIM/' + str(self._index)
168*9c5db199SXin Li        logging.info('SIM coming back as: ' + path)
169*9c5db199SXin Li        self.SetPath(path)
170*9c5db199SXin Li
171*9c5db199SXin Li
172*9c5db199SXin Li    def Reset(self):
173*9c5db199SXin Li        """ Resets the SIM. This will lock the SIM if locks are enabled. """
174*9c5db199SXin Li        self.IncrementPath()
175*9c5db199SXin Li        if not self.locked and self._lock_enabled:
176*9c5db199SXin Li            self._lock_type = mm1_constants.MM_MODEM_LOCK_SIM_PIN
177*9c5db199SXin Li
178*9c5db199SXin Li
179*9c5db199SXin Li    @property
180*9c5db199SXin Li    def lock_type(self):
181*9c5db199SXin Li        """
182*9c5db199SXin Li        Returns the current lock type of the SIM. Can be used to determine
183*9c5db199SXin Li        whether or not the SIM is locked.
184*9c5db199SXin Li
185*9c5db199SXin Li        @returns: The lock type, as a MMModemLock value.
186*9c5db199SXin Li
187*9c5db199SXin Li        """
188*9c5db199SXin Li        return self._lock_type
189*9c5db199SXin Li
190*9c5db199SXin Li
191*9c5db199SXin Li    @property
192*9c5db199SXin Li    def unlock_retries(self):
193*9c5db199SXin Li        """
194*9c5db199SXin Li        Returns the number of unlock retries left.
195*9c5db199SXin Li
196*9c5db199SXin Li        @returns: The number of unlock retries for each lock type the SIM
197*9c5db199SXin Li                supports as a dictionary.
198*9c5db199SXin Li
199*9c5db199SXin Li        """
200*9c5db199SXin Li        retries = dbus.Dictionary(signature='uu')
201*9c5db199SXin Li        if not self._show_retries:
202*9c5db199SXin Li            return retries
203*9c5db199SXin Li        for k, v in six.iteritems(self._lock_data):
204*9c5db199SXin Li            retries[dbus.types.UInt32(k)] = dbus.types.UInt32(v['retries'])
205*9c5db199SXin Li        return retries
206*9c5db199SXin Li
207*9c5db199SXin Li
208*9c5db199SXin Li    @property
209*9c5db199SXin Li    def enabled_locks(self):
210*9c5db199SXin Li        """
211*9c5db199SXin Li        Returns the currently enabled facility locks.
212*9c5db199SXin Li
213*9c5db199SXin Li        @returns: The currently enabled facility locks, as a MMModem3gppFacility
214*9c5db199SXin Li                value.
215*9c5db199SXin Li
216*9c5db199SXin Li        """
217*9c5db199SXin Li        if self._lock_enabled:
218*9c5db199SXin Li            return mm1_constants.MM_MODEM_3GPP_FACILITY_SIM
219*9c5db199SXin Li        return mm1_constants.MM_MODEM_3GPP_FACILITY_NONE
220*9c5db199SXin Li
221*9c5db199SXin Li
222*9c5db199SXin Li    @property
223*9c5db199SXin Li    def locked(self):
224*9c5db199SXin Li        """ @returns: True, if the SIM is locked. False, otherwise. """
225*9c5db199SXin Li        return not (self._lock_type == mm1_constants.MM_MODEM_LOCK_NONE or
226*9c5db199SXin Li            self._lock_type == mm1_constants.MM_MODEM_LOCK_UNKNOWN)
227*9c5db199SXin Li
228*9c5db199SXin Li
229*9c5db199SXin Li    @property
230*9c5db199SXin Li    def modem(self):
231*9c5db199SXin Li        """
232*9c5db199SXin Li        @returns: the modem object that this SIM is currently plugged into.
233*9c5db199SXin Li
234*9c5db199SXin Li        """
235*9c5db199SXin Li        return self._modem
236*9c5db199SXin Li
237*9c5db199SXin Li
238*9c5db199SXin Li    @modem.setter
239*9c5db199SXin Li    def modem(self, modem):
240*9c5db199SXin Li        """
241*9c5db199SXin Li        Assigns a modem object to this SIM, so that the modem knows about it.
242*9c5db199SXin Li        This should only be called directly by a modem object.
243*9c5db199SXin Li
244*9c5db199SXin Li        @param modem: The modem to be associated with this SIM.
245*9c5db199SXin Li
246*9c5db199SXin Li        """
247*9c5db199SXin Li        self._modem = modem
248*9c5db199SXin Li
249*9c5db199SXin Li
250*9c5db199SXin Li    @property
251*9c5db199SXin Li    def carrier(self):
252*9c5db199SXin Li        """
253*9c5db199SXin Li        @returns: An instance of SIM.Carrier that contains the carrier
254*9c5db199SXin Li                information assigned to this SIM.
255*9c5db199SXin Li
256*9c5db199SXin Li        """
257*9c5db199SXin Li        return self._carrier
258*9c5db199SXin Li
259*9c5db199SXin Li
260*9c5db199SXin Li    def _DBusPropertiesDict(self):
261*9c5db199SXin Li        imsi = self.imsi
262*9c5db199SXin Li        if self.locked:
263*9c5db199SXin Li            msin = ''
264*9c5db199SXin Li            op_id = ''
265*9c5db199SXin Li            op_name = ''
266*9c5db199SXin Li        else:
267*9c5db199SXin Li            msin = self.msin
268*9c5db199SXin Li            op_id = self._carrier.operator_id
269*9c5db199SXin Li            op_name = self._carrier.operator_name
270*9c5db199SXin Li        return {
271*9c5db199SXin Li            'SimIdentifier' : msin,
272*9c5db199SXin Li            'Imsi' : imsi,
273*9c5db199SXin Li            'OperatorIdentifier' : op_id,
274*9c5db199SXin Li            'OperatorName' : op_name
275*9c5db199SXin Li        }
276*9c5db199SXin Li
277*9c5db199SXin Li
278*9c5db199SXin Li    def _InitializeProperties(self):
279*9c5db199SXin Li        return { mm1_constants.I_SIM : self._DBusPropertiesDict() }
280*9c5db199SXin Li
281*9c5db199SXin Li
282*9c5db199SXin Li    def _UpdateProperties(self):
283*9c5db199SXin Li        self.SetAll(mm1_constants.I_SIM, self._DBusPropertiesDict())
284*9c5db199SXin Li
285*9c5db199SXin Li
286*9c5db199SXin Li    def _CheckCode(self, code, lock_data, next_lock, error_to_raise):
287*9c5db199SXin Li        # Checks |code| against |lock_data['code']|. If the codes don't match:
288*9c5db199SXin Li        #
289*9c5db199SXin Li        #   - if the number of retries left for |lock_data| drops down to 0,
290*9c5db199SXin Li        #     the current lock type gets set to |next_lock| and
291*9c5db199SXin Li        #     |error_to_raise| is raised.
292*9c5db199SXin Li        #
293*9c5db199SXin Li        #   - otherwise, IncorrectPasswordError is raised.
294*9c5db199SXin Li        #
295*9c5db199SXin Li        # If the codes match, no error is raised.
296*9c5db199SXin Li
297*9c5db199SXin Li        if code == lock_data['code']:
298*9c5db199SXin Li            # Codes match, nothing to do.
299*9c5db199SXin Li            return
300*9c5db199SXin Li
301*9c5db199SXin Li        # Codes didn't match. Figure out which error to raise based on
302*9c5db199SXin Li        # remaining retries.
303*9c5db199SXin Li        lock_data['retries'] -= 1
304*9c5db199SXin Li        self._show_retries = True
305*9c5db199SXin Li        if lock_data['retries'] == 0:
306*9c5db199SXin Li            logging.info('Retries exceeded the allowed number.')
307*9c5db199SXin Li            if next_lock:
308*9c5db199SXin Li                self._lock_type = next_lock
309*9c5db199SXin Li                self._lock_enabled = True
310*9c5db199SXin Li        else:
311*9c5db199SXin Li            error_to_raise = IncorrectPasswordError()
312*9c5db199SXin Li        self._modem.UpdateLockStatus()
313*9c5db199SXin Li        raise error_to_raise
314*9c5db199SXin Li
315*9c5db199SXin Li
316*9c5db199SXin Li    def _ResetRetries(self, lock_type):
317*9c5db199SXin Li        if lock_type == mm1_constants.MM_MODEM_LOCK_SIM_PIN:
318*9c5db199SXin Li            value = self._total_pin_retries
319*9c5db199SXin Li        elif lock_type == mm1_constants.MM_MODEM_LOCK_SIM_PUK:
320*9c5db199SXin Li            value = self._total_puk_retries
321*9c5db199SXin Li        else:
322*9c5db199SXin Li            raise TypeError('Invalid SIM lock type')
323*9c5db199SXin Li        self._lock_data[lock_type]['retries'] = value
324*9c5db199SXin Li
325*9c5db199SXin Li
326*9c5db199SXin Li    @utils.log_dbus_method()
327*9c5db199SXin Li    @dbus.service.method(mm1_constants.I_SIM, in_signature='s')
328*9c5db199SXin Li    def SendPin(self, pin):
329*9c5db199SXin Li        """
330*9c5db199SXin Li        Sends the PIN to unlock the SIM card.
331*9c5db199SXin Li
332*9c5db199SXin Li        @param pin: A string containing the PIN code.
333*9c5db199SXin Li
334*9c5db199SXin Li        """
335*9c5db199SXin Li        if not self.locked:
336*9c5db199SXin Li            logging.info('SIM is not locked. Nothing to do.')
337*9c5db199SXin Li            return
338*9c5db199SXin Li
339*9c5db199SXin Li        if self._lock_type == mm1_constants.MM_MODEM_LOCK_SIM_PUK:
340*9c5db199SXin Li            if self._lock_data[self._lock_type]['retries'] == 0:
341*9c5db199SXin Li                raise SimFailureError()
342*9c5db199SXin Li            else:
343*9c5db199SXin Li                raise SimPukError()
344*9c5db199SXin Li
345*9c5db199SXin Li        lock_data = self._lock_data.get(self._lock_type, None)
346*9c5db199SXin Li        if not lock_data:
347*9c5db199SXin Li            raise pm_errors.MMCoreError(
348*9c5db199SXin Li                pm_errors.MMCoreError.FAILED,
349*9c5db199SXin Li                'Current lock type does not match the SIM lock capabilities.')
350*9c5db199SXin Li
351*9c5db199SXin Li        self._CheckCode(pin, lock_data, mm1_constants.MM_MODEM_LOCK_SIM_PUK,
352*9c5db199SXin Li                        SimPukError())
353*9c5db199SXin Li
354*9c5db199SXin Li        logging.info('Entered correct PIN.')
355*9c5db199SXin Li        self._ResetRetries(mm1_constants.MM_MODEM_LOCK_SIM_PIN)
356*9c5db199SXin Li        self._lock_type = mm1_constants.MM_MODEM_LOCK_NONE
357*9c5db199SXin Li        self._modem.UpdateLockStatus()
358*9c5db199SXin Li        self._modem.Expose3GPPProperties()
359*9c5db199SXin Li        self._UpdateProperties()
360*9c5db199SXin Li
361*9c5db199SXin Li
362*9c5db199SXin Li    @utils.log_dbus_method()
363*9c5db199SXin Li    @dbus.service.method(mm1_constants.I_SIM, in_signature='ss')
364*9c5db199SXin Li    def SendPuk(self, puk, pin):
365*9c5db199SXin Li        """
366*9c5db199SXin Li        Sends the PUK and a new PIN to unlock the SIM card.
367*9c5db199SXin Li
368*9c5db199SXin Li        @param puk: A string containing the PUK code.
369*9c5db199SXin Li        @param pin: A string containing the PIN code.
370*9c5db199SXin Li
371*9c5db199SXin Li        """
372*9c5db199SXin Li        if self._lock_type != mm1_constants.MM_MODEM_LOCK_SIM_PUK:
373*9c5db199SXin Li            logging.info('No PUK lock in place. Nothing to do.')
374*9c5db199SXin Li            return
375*9c5db199SXin Li
376*9c5db199SXin Li        lock_data = self._lock_data.get(self._lock_type, None)
377*9c5db199SXin Li        if not lock_data:
378*9c5db199SXin Li            raise pm_errors.MMCoreError(
379*9c5db199SXin Li                    pm_errors.MMCoreError.FAILED,
380*9c5db199SXin Li                    'Current lock type does not match the SIM locks in place.')
381*9c5db199SXin Li
382*9c5db199SXin Li        if lock_data['retries'] == 0:
383*9c5db199SXin Li            raise SimFailureError()
384*9c5db199SXin Li
385*9c5db199SXin Li        self._CheckCode(puk, lock_data, None, SimFailureError())
386*9c5db199SXin Li
387*9c5db199SXin Li        logging.info('Entered correct PUK.')
388*9c5db199SXin Li        self._ResetRetries(mm1_constants.MM_MODEM_LOCK_SIM_PIN)
389*9c5db199SXin Li        self._ResetRetries(mm1_constants.MM_MODEM_LOCK_SIM_PUK)
390*9c5db199SXin Li        self._lock_data[mm1_constants.MM_MODEM_LOCK_SIM_PIN]['code'] = pin
391*9c5db199SXin Li        self._lock_type = mm1_constants.MM_MODEM_LOCK_NONE
392*9c5db199SXin Li        self._modem.UpdateLockStatus()
393*9c5db199SXin Li        self._modem.Expose3GPPProperties()
394*9c5db199SXin Li        self._UpdateProperties()
395*9c5db199SXin Li
396*9c5db199SXin Li
397*9c5db199SXin Li    @utils.log_dbus_method()
398*9c5db199SXin Li    @dbus.service.method(mm1_constants.I_SIM, in_signature='sb')
399*9c5db199SXin Li    def EnablePin(self, pin, enabled):
400*9c5db199SXin Li        """
401*9c5db199SXin Li        Enables or disables PIN checking.
402*9c5db199SXin Li
403*9c5db199SXin Li        @param pin: A string containing the PIN code.
404*9c5db199SXin Li        @param enabled: True to enable PIN, False otherwise.
405*9c5db199SXin Li
406*9c5db199SXin Li        """
407*9c5db199SXin Li        if enabled:
408*9c5db199SXin Li            self._EnablePin(pin)
409*9c5db199SXin Li        else:
410*9c5db199SXin Li            self._DisablePin(pin)
411*9c5db199SXin Li
412*9c5db199SXin Li
413*9c5db199SXin Li    def _EnablePin(self, pin):
414*9c5db199SXin Li        # Operation fails if the SIM is locked or PIN lock is already
415*9c5db199SXin Li        # enabled.
416*9c5db199SXin Li        if self.locked or self._lock_enabled:
417*9c5db199SXin Li            raise SimFailureError()
418*9c5db199SXin Li
419*9c5db199SXin Li        lock_data = self._lock_data[mm1_constants.MM_MODEM_LOCK_SIM_PIN]
420*9c5db199SXin Li        self._CheckCode(pin, lock_data, mm1_constants.MM_MODEM_LOCK_SIM_PUK,
421*9c5db199SXin Li                        SimPukError())
422*9c5db199SXin Li        self._lock_enabled = True
423*9c5db199SXin Li        self._show_retries = True
424*9c5db199SXin Li        self._ResetRetries(mm1_constants.MM_MODEM_LOCK_SIM_PIN)
425*9c5db199SXin Li        self._UpdateProperties()
426*9c5db199SXin Li        self.modem.UpdateLockStatus()
427*9c5db199SXin Li
428*9c5db199SXin Li
429*9c5db199SXin Li    def _DisablePin(self, pin):
430*9c5db199SXin Li        if not self._lock_enabled:
431*9c5db199SXin Li            raise SimFailureError()
432*9c5db199SXin Li
433*9c5db199SXin Li        if self.locked:
434*9c5db199SXin Li            self.SendPin(pin)
435*9c5db199SXin Li        else:
436*9c5db199SXin Li            lock_data = self._lock_data[mm1_constants.MM_MODEM_LOCK_SIM_PIN]
437*9c5db199SXin Li            self._CheckCode(pin, lock_data,
438*9c5db199SXin Li                            mm1_constants.MM_MODEM_LOCK_SIM_PUK, SimPukError())
439*9c5db199SXin Li            self._ResetRetries(mm1_constants.MM_MODEM_LOCK_SIM_PIN)
440*9c5db199SXin Li        self._lock_enabled = False
441*9c5db199SXin Li        self._UpdateProperties()
442*9c5db199SXin Li        self.modem.UpdateLockStatus()
443*9c5db199SXin Li
444*9c5db199SXin Li
445*9c5db199SXin Li    @utils.log_dbus_method()
446*9c5db199SXin Li    @dbus.service.method(mm1_constants.I_SIM, in_signature='ss')
447*9c5db199SXin Li    def ChangePin(self, old_pin, new_pin):
448*9c5db199SXin Li        """
449*9c5db199SXin Li        Changes the PIN code.
450*9c5db199SXin Li
451*9c5db199SXin Li        @param old_pin: A string containing the old PIN code.
452*9c5db199SXin Li        @param new_pin: A string containing the new PIN code.
453*9c5db199SXin Li
454*9c5db199SXin Li        """
455*9c5db199SXin Li        if not self._lock_enabled or self.locked:
456*9c5db199SXin Li            raise SimFailureError()
457*9c5db199SXin Li
458*9c5db199SXin Li        lock_data = self._lock_data[mm1_constants.MM_MODEM_LOCK_SIM_PIN]
459*9c5db199SXin Li        self._CheckCode(old_pin, lock_data,
460*9c5db199SXin Li                        mm1_constants.MM_MODEM_LOCK_SIM_PUK, SimPukError())
461*9c5db199SXin Li        self._ResetRetries(mm1_constants.MM_MODEM_LOCK_SIM_PIN)
462*9c5db199SXin Li        self._lock_data[mm1_constants.MM_MODEM_LOCK_SIM_PIN]['code'] = new_pin
463*9c5db199SXin Li        self._UpdateProperties()
464*9c5db199SXin Li        self.modem.UpdateLockStatus()
465