Home | History | Annotate | Download | only in cups
      1 /*
      2  *
      3  *  BlueZ - Bluetooth protocol stack for Linux
      4  *
      5  *  Copyright (C) 2003-2009  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 
     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 
    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 
    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 
    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 
    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