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