Home | History | Annotate | Download | only in cups
      1 /*
      2  *
      3  *  BlueZ - Bluetooth protocol stack for Linux
      4  *
      5  *  Copyright (C) 2003-2010  Marcel Holtmann <marcel (at) 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 
     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 	if (len < 0)
     98 		return len;
     99 
    100 	len = read(sk, buf, sizeof(buf));
    101 	if (len < 0)
    102 		return len;
    103 
    104 	memcpy(&hdr, buf, HCRP_PDU_HDR_SIZE);
    105 	memcpy(&rp, buf + HCRP_PDU_HDR_SIZE, HCRP_CREDIT_GRANT_RP_SIZE);
    106 
    107 	if (ntohs(rp.status) != HCRP_STATUS_SUCCESS) {
    108 		errno = EIO;
    109 		return -1;
    110 	}
    111 
    112 	return 0;
    113 }
    114 
    115 static int hcrp_credit_request(int sk, uint16_t tid, uint32_t *credit)
    116 {
    117 	struct hcrp_pdu_hdr hdr;
    118 	struct hcrp_credit_request_rp rp;
    119 	unsigned char buf[128];
    120 	int len;
    121 
    122 	hdr.pid = htons(HCRP_PDU_CREDIT_REQUEST);
    123 	hdr.tid = htons(tid);
    124 	hdr.plen = htons(0);
    125 	memcpy(buf, &hdr, HCRP_PDU_HDR_SIZE);
    126 	len = write(sk, buf, HCRP_PDU_HDR_SIZE);
    127 	if (len < 0)
    128 		return len;
    129 
    130 	len = read(sk, buf, sizeof(buf));
    131 	if (len < 0)
    132 		return len;
    133 
    134 	memcpy(&hdr, buf, HCRP_PDU_HDR_SIZE);
    135 	memcpy(&rp, buf + HCRP_PDU_HDR_SIZE, HCRP_CREDIT_REQUEST_RP_SIZE);
    136 
    137 	if (ntohs(rp.status) != HCRP_STATUS_SUCCESS) {
    138 		errno = EIO;
    139 		return -1;
    140 	}
    141 
    142 	if (credit)
    143 		*credit = ntohl(rp.credit);
    144 
    145 	return 0;
    146 }
    147 
    148 static int hcrp_get_lpt_status(int sk, uint16_t tid, uint8_t *lpt_status)
    149 {
    150 	struct hcrp_pdu_hdr hdr;
    151 	struct hcrp_get_lpt_status_rp rp;
    152 	unsigned char buf[128];
    153 	int len;
    154 
    155 	hdr.pid = htons(HCRP_PDU_GET_LPT_STATUS);
    156 	hdr.tid = htons(tid);
    157 	hdr.plen = htons(0);
    158 	memcpy(buf, &hdr, HCRP_PDU_HDR_SIZE);
    159 	len = write(sk, buf, HCRP_PDU_HDR_SIZE);
    160 	if (len < 0)
    161 		return len;
    162 
    163 	len = read(sk, buf, sizeof(buf));
    164 	if (len < 0)
    165 		return len;
    166 
    167 	memcpy(&hdr, buf, HCRP_PDU_HDR_SIZE);
    168 	memcpy(&rp, buf + HCRP_PDU_HDR_SIZE, HCRP_GET_LPT_STATUS_RP_SIZE);
    169 
    170 	if (ntohs(rp.status) != HCRP_STATUS_SUCCESS) {
    171 		errno = EIO;
    172 		return -1;
    173 	}
    174 
    175 	if (lpt_status)
    176 		*lpt_status = rp.lpt_status;
    177 
    178 	return 0;
    179 }
    180 
    181 static inline int hcrp_get_next_tid(int tid)
    182 {
    183 	if (tid > 0xf000)
    184 		return 0;
    185 	else
    186 		return tid + 1;
    187 }
    188 
    189 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)
    190 {
    191 	struct sockaddr_l2 addr;
    192 	struct l2cap_options opts;
    193 	socklen_t size;
    194 	unsigned char buf[2048];
    195 	int i, ctrl_sk, data_sk, count, len, timeout = 0;
    196 	unsigned int mtu;
    197 	uint8_t status;
    198 	uint16_t tid = 0;
    199 	uint32_t tmp, credit = 0;
    200 
    201 	if ((ctrl_sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0) {
    202 		perror("ERROR: Can't create socket");
    203 		if (cups_class)
    204 			return CUPS_BACKEND_FAILED;
    205 		else
    206 			return CUPS_BACKEND_RETRY;
    207 	}
    208 
    209 	memset(&addr, 0, sizeof(addr));
    210 	addr.l2_family = AF_BLUETOOTH;
    211 	bacpy(&addr.l2_bdaddr, src);
    212 
    213 	if (bind(ctrl_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
    214 		perror("ERROR: Can't bind socket");
    215 		close(ctrl_sk);
    216 		if (cups_class)
    217 			return CUPS_BACKEND_FAILED;
    218 		else
    219 			return CUPS_BACKEND_RETRY;
    220 	}
    221 
    222 	memset(&addr, 0, sizeof(addr));
    223 	addr.l2_family = AF_BLUETOOTH;
    224 	bacpy(&addr.l2_bdaddr, dst);
    225 	addr.l2_psm = htobs(ctrl_psm);
    226 
    227 	if (connect(ctrl_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
    228 		perror("ERROR: Can't connect to device");
    229 		close(ctrl_sk);
    230 		if (cups_class)
    231 			return CUPS_BACKEND_FAILED;
    232 		else
    233 			return CUPS_BACKEND_RETRY;
    234 	}
    235 
    236 	if ((data_sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0) {
    237 		perror("ERROR: Can't create socket");
    238 		close(ctrl_sk);
    239 		if (cups_class)
    240 			return CUPS_BACKEND_FAILED;
    241 		else
    242 			return CUPS_BACKEND_RETRY;
    243 	}
    244 
    245 	memset(&addr, 0, sizeof(addr));
    246 	addr.l2_family = AF_BLUETOOTH;
    247 	bacpy(&addr.l2_bdaddr, src);
    248 
    249 	if (bind(data_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
    250 		perror("ERROR: Can't bind socket");
    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 	memset(&addr, 0, sizeof(addr));
    260 	addr.l2_family = AF_BLUETOOTH;
    261 	bacpy(&addr.l2_bdaddr, dst);
    262 	addr.l2_psm = htobs(data_psm);
    263 
    264 	if (connect(data_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
    265 		perror("ERROR: Can't connect to device");
    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 	fputs("STATE: -connecting-to-device\n", stderr);
    275 
    276 	memset(&opts, 0, sizeof(opts));
    277 	size = sizeof(opts);
    278 
    279 	if (getsockopt(data_sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &size) < 0) {
    280 		perror("ERROR: Can't get socket options");
    281 		close(data_sk);
    282 		close(ctrl_sk);
    283 		if (cups_class)
    284 			return CUPS_BACKEND_FAILED;
    285 		else
    286 			return CUPS_BACKEND_RETRY;
    287 	}
    288 
    289 	mtu = opts.omtu;
    290 
    291 	/* Ignore SIGTERM signals if printing from stdin */
    292 	if (fd == 0) {
    293 #ifdef HAVE_SIGSET
    294 		sigset(SIGTERM, SIG_IGN);
    295 #elif defined(HAVE_SIGACTION)
    296 		memset(&action, 0, sizeof(action));
    297 		sigemptyset(&action.sa_mask);
    298 		action.sa_handler = SIG_IGN;
    299 		sigaction(SIGTERM, &action, NULL);
    300 #else
    301 		signal(SIGTERM, SIG_IGN);
    302 #endif /* HAVE_SIGSET */
    303 	}
    304 
    305 	tid = hcrp_get_next_tid(tid);
    306 	if (hcrp_credit_grant(ctrl_sk, tid, 0) < 0) {
    307 		fprintf(stderr, "ERROR: Can't grant initial credits\n");
    308 		close(data_sk);
    309 		close(ctrl_sk);
    310 		if (cups_class)
    311 			return CUPS_BACKEND_FAILED;
    312 		else
    313 			return CUPS_BACKEND_RETRY;
    314 	}
    315 
    316 	for (i = 0; i < copies; i++) {
    317 
    318 		if (fd != 0) {
    319 			fprintf(stderr, "PAGE: 1 1\n");
    320 			lseek(fd, 0, SEEK_SET);
    321 		}
    322 
    323 		while (1) {
    324 			if (credit < mtu) {
    325 				tid = hcrp_get_next_tid(tid);
    326 				if (!hcrp_credit_request(ctrl_sk, tid, &tmp)) {
    327 					credit += tmp;
    328 					timeout = 0;
    329 				}
    330 			}
    331 
    332 			if (!credit) {
    333 				if (timeout++ > 300) {
    334 					tid = hcrp_get_next_tid(tid);
    335 					if (!hcrp_get_lpt_status(ctrl_sk, tid, &status))
    336 						fprintf(stderr, "ERROR: LPT status 0x%02x\n", status);
    337 					break;
    338 				}
    339 
    340 				sleep(1);
    341 				continue;
    342 			}
    343 
    344 			count = read(fd, buf, (credit > mtu) ? mtu : credit);
    345 			if (count <= 0)
    346 				break;
    347 
    348 			len = write(data_sk, buf, count);
    349 			if (len < 0) {
    350 				perror("ERROR: Error writing to device");
    351 				close(data_sk);
    352 				close(ctrl_sk);
    353 				return CUPS_BACKEND_FAILED;
    354 			}
    355 
    356 			if (len != count)
    357 				fprintf(stderr, "ERROR: Can't send complete data\n");
    358 
    359 			credit -= len;
    360 		}
    361 
    362 	}
    363 
    364 	close(data_sk);
    365 	close(ctrl_sk);
    366 
    367 	return CUPS_BACKEND_OK;
    368 }
    369