1f7d24e3fSHanoh Haim## This file is part of Scapy
2f7d24e3fSHanoh Haim## See http://www.secdev.org/projects/scapy for more informations
3f7d24e3fSHanoh Haim## Copyright (C) Philippe Biondi <phil@secdev.org>
4f7d24e3fSHanoh Haim## This program is published under a GPLv2 license
5f7d24e3fSHanoh Haim
6f7d24e3fSHanoh Haim"""
7f7d24e3fSHanoh HaimBluetooth layers, sockets and send/receive functions.
8f7d24e3fSHanoh Haim"""
9f7d24e3fSHanoh Haim
10f7d24e3fSHanoh Haimimport socket,struct
11f7d24e3fSHanoh Haim
12f7d24e3fSHanoh Haimfrom scapy.config import conf
13f7d24e3fSHanoh Haimfrom scapy.packet import *
14f7d24e3fSHanoh Haimfrom scapy.fields import *
15f7d24e3fSHanoh Haimfrom scapy.supersocket import SuperSocket
16f7d24e3fSHanoh Haimfrom scapy.data import MTU
17f7d24e3fSHanoh Haim
18f7d24e3fSHanoh Haim
19f7d24e3fSHanoh Haimclass HCI_Hdr(Packet):
20f7d24e3fSHanoh Haim    name = "HCI header"
21f7d24e3fSHanoh Haim    fields_desc = [ ByteEnumField("type",2,{1:"command",2:"ACLdata",3:"SCOdata",4:"event",5:"vendor"}),]
22f7d24e3fSHanoh Haim
23f7d24e3fSHanoh Haim    def mysummary(self):
24f7d24e3fSHanoh Haim        return self.sprintf("HCI %type%")
25f7d24e3fSHanoh Haim
26f7d24e3fSHanoh Haimclass HCI_ACL_Hdr(Packet):
27f7d24e3fSHanoh Haim    name = "HCI ACL header"
28f7d24e3fSHanoh Haim    fields_desc = [ ByteField("handle",0), # Actually, handle is 12 bits and flags is 4.
29f7d24e3fSHanoh Haim                    ByteField("flags",0),  # I wait to write a LEBitField
30f7d24e3fSHanoh Haim                    LEShortField("len",None), ]
31f7d24e3fSHanoh Haim    def post_build(self, p, pay):
32f7d24e3fSHanoh Haim        p += pay
33f7d24e3fSHanoh Haim        if self.len is None:
34f7d24e3fSHanoh Haim            l = len(p)-4
35f7d24e3fSHanoh Haim            p = p[:2]+chr(l&0xff)+chr((l>>8)&0xff)+p[4:]
36f7d24e3fSHanoh Haim        return p
37f7d24e3fSHanoh Haim
38f7d24e3fSHanoh Haim
39f7d24e3fSHanoh Haimclass L2CAP_Hdr(Packet):
40f7d24e3fSHanoh Haim    name = "L2CAP header"
41f7d24e3fSHanoh Haim    fields_desc = [ LEShortField("len",None),
42f7d24e3fSHanoh Haim                    LEShortEnumField("cid",0,{1:"control"}),]
43f7d24e3fSHanoh Haim
44f7d24e3fSHanoh Haim    def post_build(self, p, pay):
45f7d24e3fSHanoh Haim        p += pay
46f7d24e3fSHanoh Haim        if self.len is None:
47f7d24e3fSHanoh Haim            l = len(p)-4
48f7d24e3fSHanoh Haim            p = p[:2]+chr(l&0xff)+chr((l>>8)&0xff)+p[4:]
49f7d24e3fSHanoh Haim        return p
50f7d24e3fSHanoh Haim
51f7d24e3fSHanoh Haim
52f7d24e3fSHanoh Haim
53f7d24e3fSHanoh Haimclass L2CAP_CmdHdr(Packet):
54f7d24e3fSHanoh Haim    name = "L2CAP command header"
55f7d24e3fSHanoh Haim    fields_desc = [
56f7d24e3fSHanoh Haim        ByteEnumField("code",8,{1:"rej",2:"conn_req",3:"conn_resp",
57f7d24e3fSHanoh Haim                                4:"conf_req",5:"conf_resp",6:"disconn_req",
58f7d24e3fSHanoh Haim                                7:"disconn_resp",8:"echo_req",9:"echo_resp",
59f7d24e3fSHanoh Haim                                10:"info_req",11:"info_resp"}),
60f7d24e3fSHanoh Haim        ByteField("id",0),
61f7d24e3fSHanoh Haim        LEShortField("len",None) ]
62f7d24e3fSHanoh Haim    def post_build(self, p, pay):
63f7d24e3fSHanoh Haim        p += pay
64f7d24e3fSHanoh Haim        if self.len is None:
65f7d24e3fSHanoh Haim            l = len(p)-4
66f7d24e3fSHanoh Haim            p = p[:2]+chr(l&0xff)+chr((l>>8)&0xff)+p[4:]
67f7d24e3fSHanoh Haim        return p
68f7d24e3fSHanoh Haim    def answers(self, other):
69f7d24e3fSHanoh Haim        if other.id == self.id:
70f7d24e3fSHanoh Haim            if self.code == 1:
71f7d24e3fSHanoh Haim                return 1
72f7d24e3fSHanoh Haim            if other.code in [2,4,6,8,10] and self.code == other.code+1:
73f7d24e3fSHanoh Haim                if other.code == 8:
74f7d24e3fSHanoh Haim                    return 1
75f7d24e3fSHanoh Haim                return self.payload.answers(other.payload)
76f7d24e3fSHanoh Haim        return 0
77f7d24e3fSHanoh Haim
78f7d24e3fSHanoh Haimclass L2CAP_ConnReq(Packet):
79f7d24e3fSHanoh Haim    name = "L2CAP Conn Req"
80f7d24e3fSHanoh Haim    fields_desc = [ LEShortEnumField("psm",0,{1:"SDP",3:"RFCOMM",5:"telephony control"}),
81f7d24e3fSHanoh Haim                    LEShortField("scid",0),
82f7d24e3fSHanoh Haim                    ]
83f7d24e3fSHanoh Haim
84f7d24e3fSHanoh Haimclass L2CAP_ConnResp(Packet):
85f7d24e3fSHanoh Haim    name = "L2CAP Conn Resp"
86f7d24e3fSHanoh Haim    fields_desc = [ LEShortField("dcid",0),
87f7d24e3fSHanoh Haim                    LEShortField("scid",0),
88f7d24e3fSHanoh Haim                    LEShortEnumField("result",0,["no_info","authen_pend","author_pend"]),
89f7d24e3fSHanoh Haim                    LEShortEnumField("status",0,["success","pend","bad_psm",
90f7d24e3fSHanoh Haim                                               "cr_sec_block","cr_no_mem"]),
91f7d24e3fSHanoh Haim                    ]
92f7d24e3fSHanoh Haim    def answers(self, other):
93f7d24e3fSHanoh Haim        return self.scid == other.scid
94f7d24e3fSHanoh Haim
95f7d24e3fSHanoh Haimclass L2CAP_CmdRej(Packet):
96f7d24e3fSHanoh Haim    name = "L2CAP Command Rej"
97f7d24e3fSHanoh Haim    fields_desc = [ LEShortField("reason",0),
98f7d24e3fSHanoh Haim                    ]
99f7d24e3fSHanoh Haim
100f7d24e3fSHanoh Haim
101f7d24e3fSHanoh Haimclass L2CAP_ConfReq(Packet):
102f7d24e3fSHanoh Haim    name = "L2CAP Conf Req"
103f7d24e3fSHanoh Haim    fields_desc = [ LEShortField("dcid",0),
104f7d24e3fSHanoh Haim                    LEShortField("flags",0),
105f7d24e3fSHanoh Haim                    ]
106f7d24e3fSHanoh Haim
107f7d24e3fSHanoh Haimclass L2CAP_ConfResp(Packet):
108f7d24e3fSHanoh Haim    name = "L2CAP Conf Resp"
109f7d24e3fSHanoh Haim    fields_desc = [ LEShortField("scid",0),
110f7d24e3fSHanoh Haim                    LEShortField("flags",0),
111f7d24e3fSHanoh Haim                    LEShortEnumField("result",0,["success","unaccept","reject","unknown"]),
112f7d24e3fSHanoh Haim                    ]
113f7d24e3fSHanoh Haim    def answers(self, other):
114f7d24e3fSHanoh Haim        return self.scid == other.scid
115f7d24e3fSHanoh Haim
116f7d24e3fSHanoh Haim
117f7d24e3fSHanoh Haimclass L2CAP_DisconnReq(Packet):
118f7d24e3fSHanoh Haim    name = "L2CAP Disconn Req"
119f7d24e3fSHanoh Haim    fields_desc = [ LEShortField("dcid",0),
120f7d24e3fSHanoh Haim                    LEShortField("scid",0), ]
121f7d24e3fSHanoh Haim
122f7d24e3fSHanoh Haimclass L2CAP_DisconnResp(Packet):
123f7d24e3fSHanoh Haim    name = "L2CAP Disconn Resp"
124f7d24e3fSHanoh Haim    fields_desc = [ LEShortField("dcid",0),
125f7d24e3fSHanoh Haim                    LEShortField("scid",0), ]
126f7d24e3fSHanoh Haim    def answers(self, other):
127f7d24e3fSHanoh Haim        return self.scid == other.scid
128f7d24e3fSHanoh Haim
129f7d24e3fSHanoh Haim
130f7d24e3fSHanoh Haim
131f7d24e3fSHanoh Haimclass L2CAP_InfoReq(Packet):
132f7d24e3fSHanoh Haim    name = "L2CAP Info Req"
133f7d24e3fSHanoh Haim    fields_desc = [ LEShortEnumField("type",0,{1:"CL_MTU",2:"FEAT_MASK"}),
134f7d24e3fSHanoh Haim                    StrField("data","")
135f7d24e3fSHanoh Haim                    ]
136f7d24e3fSHanoh Haim
137f7d24e3fSHanoh Haim
138f7d24e3fSHanoh Haimclass L2CAP_InfoResp(Packet):
139f7d24e3fSHanoh Haim    name = "L2CAP Info Resp"
140f7d24e3fSHanoh Haim    fields_desc = [ LEShortField("type",0),
141f7d24e3fSHanoh Haim                    LEShortEnumField("result",0,["success","not_supp"]),
142f7d24e3fSHanoh Haim                    StrField("data",""), ]
143f7d24e3fSHanoh Haim    def answers(self, other):
144f7d24e3fSHanoh Haim        return self.type == other.type
145f7d24e3fSHanoh Haim
146f7d24e3fSHanoh Haim
147f7d24e3fSHanoh Haim
148f7d24e3fSHanoh Haimbind_layers( HCI_Hdr,       HCI_ACL_Hdr,   type=2)
149f7d24e3fSHanoh Haimbind_layers( HCI_Hdr,       conf.raw_layer,           )
150f7d24e3fSHanoh Haimbind_layers( HCI_ACL_Hdr,   L2CAP_Hdr,     )
151f7d24e3fSHanoh Haimbind_layers( L2CAP_Hdr,     L2CAP_CmdHdr,      cid=1)
152f7d24e3fSHanoh Haimbind_layers( L2CAP_CmdHdr,  L2CAP_CmdRej,      code=1)
153f7d24e3fSHanoh Haimbind_layers( L2CAP_CmdHdr,  L2CAP_ConnReq,     code=2)
154f7d24e3fSHanoh Haimbind_layers( L2CAP_CmdHdr,  L2CAP_ConnResp,    code=3)
155f7d24e3fSHanoh Haimbind_layers( L2CAP_CmdHdr,  L2CAP_ConfReq,     code=4)
156f7d24e3fSHanoh Haimbind_layers( L2CAP_CmdHdr,  L2CAP_ConfResp,    code=5)
157f7d24e3fSHanoh Haimbind_layers( L2CAP_CmdHdr,  L2CAP_DisconnReq,  code=6)
158f7d24e3fSHanoh Haimbind_layers( L2CAP_CmdHdr,  L2CAP_DisconnResp, code=7)
159f7d24e3fSHanoh Haimbind_layers( L2CAP_CmdHdr,  L2CAP_InfoReq,     code=10)
160f7d24e3fSHanoh Haimbind_layers( L2CAP_CmdHdr,  L2CAP_InfoResp,    code=11)
161f7d24e3fSHanoh Haim
162f7d24e3fSHanoh Haimclass BluetoothL2CAPSocket(SuperSocket):
163f7d24e3fSHanoh Haim    desc = "read/write packets on a connected L2CAP socket"
164f7d24e3fSHanoh Haim    def __init__(self, peer):
165f7d24e3fSHanoh Haim        s = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW,
166f7d24e3fSHanoh Haim                          socket.BTPROTO_L2CAP)
167f7d24e3fSHanoh Haim        s.connect((peer,0))
168f7d24e3fSHanoh Haim
169f7d24e3fSHanoh Haim        self.ins = self.outs = s
170f7d24e3fSHanoh Haim
171f7d24e3fSHanoh Haim    def recv(self, x=MTU):
172f7d24e3fSHanoh Haim        return L2CAP_CmdHdr(self.ins.recv(x))
173f7d24e3fSHanoh Haim
174f7d24e3fSHanoh Haim
175f7d24e3fSHanoh Haimclass BluetoothHCISocket(SuperSocket):
176f7d24e3fSHanoh Haim    desc = "read/write on a BlueTooth HCI socket"
177f7d24e3fSHanoh Haim    def __init__(self, iface=0x10000, type=None):
178f7d24e3fSHanoh Haim        s = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW, socket.BTPROTO_HCI)
179f7d24e3fSHanoh Haim        s.setsockopt(socket.SOL_HCI, socket.HCI_DATA_DIR,1)
180f7d24e3fSHanoh Haim        s.setsockopt(socket.SOL_HCI, socket.HCI_TIME_STAMP,1)
181f7d24e3fSHanoh Haim        s.setsockopt(socket.SOL_HCI, socket.HCI_FILTER, struct.pack("IIIh2x", 0xffffffffL,0xffffffffL,0xffffffffL,0)) #type mask, event mask, event mask, opcode
182f7d24e3fSHanoh Haim        s.bind((iface,))
183f7d24e3fSHanoh Haim        self.ins = self.outs = s
184f7d24e3fSHanoh Haim#        s.connect((peer,0))
185f7d24e3fSHanoh Haim
186f7d24e3fSHanoh Haim
187f7d24e3fSHanoh Haim    def recv(self, x):
188f7d24e3fSHanoh Haim        return HCI_Hdr(self.ins.recv(x))
189f7d24e3fSHanoh Haim
190f7d24e3fSHanoh Haim## Bluetooth
191f7d24e3fSHanoh Haim
192f7d24e3fSHanoh Haim
193f7d24e3fSHanoh Haim@conf.commands.register
194f7d24e3fSHanoh Haimdef srbt(peer, pkts, inter=0.1, *args, **kargs):
195f7d24e3fSHanoh Haim    """send and receive using a bluetooth socket"""
196f7d24e3fSHanoh Haim    s = conf.BTsocket(peer=peer)
197f7d24e3fSHanoh Haim    a,b = sndrcv(s,pkts,inter=inter,*args,**kargs)
198f7d24e3fSHanoh Haim    s.close()
199f7d24e3fSHanoh Haim    return a,b
200f7d24e3fSHanoh Haim
201f7d24e3fSHanoh Haim@conf.commands.register
202f7d24e3fSHanoh Haimdef srbt1(peer, pkts, *args, **kargs):
203f7d24e3fSHanoh Haim    """send and receive 1 packet using a bluetooth socket"""
204f7d24e3fSHanoh Haim    a,b = srbt(peer, pkts, *args, **kargs)
205f7d24e3fSHanoh Haim    if len(a) > 0:
206f7d24e3fSHanoh Haim        return a[0][1]
207f7d24e3fSHanoh Haim
208f7d24e3fSHanoh Haim
209f7d24e3fSHanoh Haim
210f7d24e3fSHanoh Haimconf.BTsocket = BluetoothL2CAPSocket
211