• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2003-2010  Marcel Holtmann <marcel@holtmann.org>
6  *
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 
28 #include <stdio.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <string.h>
32 #include <signal.h>
33 #include <sys/socket.h>
34 
35 #include <bluetooth/bluetooth.h>
36 #include <bluetooth/l2cap.h>
37 #include <bluetooth/sdp.h>
38 #include <bluetooth/sdp_lib.h>
39 
40 #include <netinet/in.h>
41 
42 #include "cups.h"
43 
44 #define HCRP_PDU_CREDIT_GRANT		0x0001
45 #define HCRP_PDU_CREDIT_REQUEST		0x0002
46 #define HCRP_PDU_GET_LPT_STATUS		0x0005
47 
48 #define HCRP_STATUS_FEATURE_UNSUPPORTED	0x0000
49 #define HCRP_STATUS_SUCCESS		0x0001
50 #define HCRP_STATUS_CREDIT_SYNC_ERROR	0x0002
51 #define HCRP_STATUS_GENERIC_FAILURE	0xffff
52 
53 struct hcrp_pdu_hdr {
54 	uint16_t pid;
55 	uint16_t tid;
56 	uint16_t plen;
57 } __attribute__ ((packed));
58 #define HCRP_PDU_HDR_SIZE 6
59 
60 struct hcrp_credit_grant_cp {
61 	uint32_t credit;
62 } __attribute__ ((packed));
63 #define HCRP_CREDIT_GRANT_CP_SIZE 4
64 
65 struct hcrp_credit_grant_rp {
66 	uint16_t status;
67 } __attribute__ ((packed));
68 #define HCRP_CREDIT_GRANT_RP_SIZE 2
69 
70 struct hcrp_credit_request_rp {
71 	uint16_t status;
72 	uint32_t credit;
73 } __attribute__ ((packed));
74 #define HCRP_CREDIT_REQUEST_RP_SIZE 6
75 
76 struct hcrp_get_lpt_status_rp {
77 	uint16_t status;
78 	uint8_t  lpt_status;
79 } __attribute__ ((packed));
80 #define HCRP_GET_LPT_STATUS_RP_SIZE 3
81 
hcrp_credit_grant(int sk,uint16_t tid,uint32_t credit)82 static int hcrp_credit_grant(int sk, uint16_t tid, uint32_t credit)
83 {
84 	struct hcrp_pdu_hdr hdr;
85 	struct hcrp_credit_grant_cp cp;
86 	struct hcrp_credit_grant_rp rp;
87 	unsigned char buf[128];
88 	int len;
89 
90 	hdr.pid = htons(HCRP_PDU_CREDIT_GRANT);
91 	hdr.tid = htons(tid);
92 	hdr.plen = htons(HCRP_CREDIT_GRANT_CP_SIZE);
93 	cp.credit = credit;
94 	memcpy(buf, &hdr, HCRP_PDU_HDR_SIZE);
95 	memcpy(buf + HCRP_PDU_HDR_SIZE, &cp, HCRP_CREDIT_GRANT_CP_SIZE);
96 	len = write(sk, buf, HCRP_PDU_HDR_SIZE + HCRP_CREDIT_GRANT_CP_SIZE);
97 
98 	len = read(sk, buf, sizeof(buf));
99 	memcpy(&hdr, buf, HCRP_PDU_HDR_SIZE);
100 	memcpy(&rp, buf + HCRP_PDU_HDR_SIZE, HCRP_CREDIT_GRANT_RP_SIZE);
101 
102 	if (ntohs(rp.status) != HCRP_STATUS_SUCCESS) {
103 		errno = EIO;
104 		return -1;
105 	}
106 
107 	return 0;
108 }
109 
hcrp_credit_request(int sk,uint16_t tid,uint32_t * credit)110 static int hcrp_credit_request(int sk, uint16_t tid, uint32_t *credit)
111 {
112 	struct hcrp_pdu_hdr hdr;
113 	struct hcrp_credit_request_rp rp;
114 	unsigned char buf[128];
115 	int len;
116 
117 	hdr.pid = htons(HCRP_PDU_CREDIT_REQUEST);
118 	hdr.tid = htons(tid);
119 	hdr.plen = htons(0);
120 	memcpy(buf, &hdr, HCRP_PDU_HDR_SIZE);
121 	len = write(sk, buf, HCRP_PDU_HDR_SIZE);
122 
123 	len = read(sk, buf, sizeof(buf));
124 	memcpy(&hdr, buf, HCRP_PDU_HDR_SIZE);
125 	memcpy(&rp, buf + HCRP_PDU_HDR_SIZE, HCRP_CREDIT_REQUEST_RP_SIZE);
126 
127 	if (ntohs(rp.status) != HCRP_STATUS_SUCCESS) {
128 		errno = EIO;
129 		return -1;
130 	}
131 
132 	if (credit)
133 		*credit = ntohl(rp.credit);
134 
135 	return 0;
136 }
137 
hcrp_get_lpt_status(int sk,uint16_t tid,uint8_t * lpt_status)138 static int hcrp_get_lpt_status(int sk, uint16_t tid, uint8_t *lpt_status)
139 {
140 	struct hcrp_pdu_hdr hdr;
141 	struct hcrp_get_lpt_status_rp rp;
142 	unsigned char buf[128];
143 	int len;
144 
145 	hdr.pid = htons(HCRP_PDU_GET_LPT_STATUS);
146 	hdr.tid = htons(tid);
147 	hdr.plen = htons(0);
148 	memcpy(buf, &hdr, HCRP_PDU_HDR_SIZE);
149 	len = write(sk, buf, HCRP_PDU_HDR_SIZE);
150 
151 	len = read(sk, buf, sizeof(buf));
152 	memcpy(&hdr, buf, HCRP_PDU_HDR_SIZE);
153 	memcpy(&rp, buf + HCRP_PDU_HDR_SIZE, HCRP_GET_LPT_STATUS_RP_SIZE);
154 
155 	if (ntohs(rp.status) != HCRP_STATUS_SUCCESS) {
156 		errno = EIO;
157 		return -1;
158 	}
159 
160 	if (lpt_status)
161 		*lpt_status = rp.lpt_status;
162 
163 	return 0;
164 }
165 
hcrp_get_next_tid(int tid)166 static inline int hcrp_get_next_tid(int tid)
167 {
168 	if (tid > 0xf000)
169 		return 0;
170 	else
171 		return tid + 1;
172 }
173 
hcrp_print(bdaddr_t * src,bdaddr_t * dst,unsigned short ctrl_psm,unsigned short data_psm,int fd,int copies,const char * cups_class)174 int hcrp_print(bdaddr_t *src, bdaddr_t *dst, unsigned short ctrl_psm, unsigned short data_psm, int fd, int copies, const char *cups_class)
175 {
176 	struct sockaddr_l2 addr;
177 	struct l2cap_options opts;
178 	socklen_t size;
179 	unsigned char buf[2048];
180 	int i, ctrl_sk, data_sk, count, len, timeout = 0;
181 	unsigned int mtu;
182 	uint8_t status;
183 	uint16_t tid = 0;
184 	uint32_t tmp, credit = 0;
185 
186 	if ((ctrl_sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0) {
187 		perror("ERROR: Can't create socket");
188 		if (cups_class)
189 			return CUPS_BACKEND_FAILED;
190 		else
191 			return CUPS_BACKEND_RETRY;
192 	}
193 
194 	memset(&addr, 0, sizeof(addr));
195 	addr.l2_family = AF_BLUETOOTH;
196 	bacpy(&addr.l2_bdaddr, src);
197 
198 	if (bind(ctrl_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
199 		perror("ERROR: Can't bind socket");
200 		close(ctrl_sk);
201 		if (cups_class)
202 			return CUPS_BACKEND_FAILED;
203 		else
204 			return CUPS_BACKEND_RETRY;
205 	}
206 
207 	memset(&addr, 0, sizeof(addr));
208 	addr.l2_family = AF_BLUETOOTH;
209 	bacpy(&addr.l2_bdaddr, dst);
210 	addr.l2_psm = htobs(ctrl_psm);
211 
212 	if (connect(ctrl_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
213 		perror("ERROR: Can't connect to device");
214 		close(ctrl_sk);
215 		if (cups_class)
216 			return CUPS_BACKEND_FAILED;
217 		else
218 			return CUPS_BACKEND_RETRY;
219 	}
220 
221 	if ((data_sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0) {
222 		perror("ERROR: Can't create socket");
223 		close(ctrl_sk);
224 		if (cups_class)
225 			return CUPS_BACKEND_FAILED;
226 		else
227 			return CUPS_BACKEND_RETRY;
228 	}
229 
230 	memset(&addr, 0, sizeof(addr));
231 	addr.l2_family = AF_BLUETOOTH;
232 	bacpy(&addr.l2_bdaddr, src);
233 
234 	if (bind(data_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
235 		perror("ERROR: Can't bind socket");
236 		close(data_sk);
237 		close(ctrl_sk);
238 		if (cups_class)
239 			return CUPS_BACKEND_FAILED;
240 		else
241 			return CUPS_BACKEND_RETRY;
242 	}
243 
244 	memset(&addr, 0, sizeof(addr));
245 	addr.l2_family = AF_BLUETOOTH;
246 	bacpy(&addr.l2_bdaddr, dst);
247 	addr.l2_psm = htobs(data_psm);
248 
249 	if (connect(data_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
250 		perror("ERROR: Can't connect to device");
251 		close(data_sk);
252 		close(ctrl_sk);
253 		if (cups_class)
254 			return CUPS_BACKEND_FAILED;
255 		else
256 			return CUPS_BACKEND_RETRY;
257 	}
258 
259 	fputs("STATE: -connecting-to-device\n", stderr);
260 
261 	memset(&opts, 0, sizeof(opts));
262 	size = sizeof(opts);
263 
264 	if (getsockopt(data_sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &size) < 0) {
265 		perror("ERROR: Can't get socket options");
266 		close(data_sk);
267 		close(ctrl_sk);
268 		if (cups_class)
269 			return CUPS_BACKEND_FAILED;
270 		else
271 			return CUPS_BACKEND_RETRY;
272 	}
273 
274 	mtu = opts.omtu;
275 
276 	/* Ignore SIGTERM signals if printing from stdin */
277 	if (fd == 0) {
278 #ifdef HAVE_SIGSET
279 		sigset(SIGTERM, SIG_IGN);
280 #elif defined(HAVE_SIGACTION)
281 		memset(&action, 0, sizeof(action));
282 		sigemptyset(&action.sa_mask);
283 		action.sa_handler = SIG_IGN;
284 		sigaction(SIGTERM, &action, NULL);
285 #else
286 		signal(SIGTERM, SIG_IGN);
287 #endif /* HAVE_SIGSET */
288 	}
289 
290 	tid = hcrp_get_next_tid(tid);
291 	if (hcrp_credit_grant(ctrl_sk, tid, 0) < 0) {
292 		fprintf(stderr, "ERROR: Can't grant initial credits\n");
293 		close(data_sk);
294 		close(ctrl_sk);
295 		if (cups_class)
296 			return CUPS_BACKEND_FAILED;
297 		else
298 			return CUPS_BACKEND_RETRY;
299 	}
300 
301 	for (i = 0; i < copies; i++) {
302 
303 		if (fd != 0) {
304 			fprintf(stderr, "PAGE: 1 1\n");
305 			lseek(fd, 0, SEEK_SET);
306 		}
307 
308 		while (1) {
309 			if (credit < mtu) {
310 				tid = hcrp_get_next_tid(tid);
311 				if (!hcrp_credit_request(ctrl_sk, tid, &tmp)) {
312 					credit += tmp;
313 					timeout = 0;
314 				}
315 			}
316 
317 			if (!credit) {
318 				if (timeout++ > 300) {
319 					tid = hcrp_get_next_tid(tid);
320 					if (!hcrp_get_lpt_status(ctrl_sk, tid, &status))
321 						fprintf(stderr, "ERROR: LPT status 0x%02x\n", status);
322 					break;
323 				}
324 
325 				sleep(1);
326 				continue;
327 			}
328 
329 			count = read(fd, buf, (credit > mtu) ? mtu : credit);
330 			if (count <= 0)
331 				break;
332 
333 			len = write(data_sk, buf, count);
334 			if (len < 0) {
335 				perror("ERROR: Error writing to device");
336 				close(data_sk);
337 				close(ctrl_sk);
338 				return CUPS_BACKEND_FAILED;
339 			}
340 
341 			if (len != count)
342 				fprintf(stderr, "ERROR: Can't send complete data\n");
343 
344 			credit -= len;
345 		}
346 
347 	}
348 
349 	close(data_sk);
350 	close(ctrl_sk);
351 
352 	return CUPS_BACKEND_OK;
353 }
354