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