1 /* $OpenBSD: virtual.c,v 1.21 2005/04/08 23:15:26 hshoexer Exp $ */ 2 3 /* 4 * Copyright (c) 2004 H�kan Olsson. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <sys/types.h> 28 #include <sys/ioctl.h> 29 #include <sys/socket.h> 30 #include <sys/sockio.h> 31 #include <net/if.h> 32 #include <netinet/in.h> 33 #include <arpa/inet.h> 34 #include <ctype.h> 35 #include <limits.h> 36 #include <netdb.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <unistd.h> 40 41 #include "conf.h" 42 #include "if.h" 43 #include "exchange.h" 44 #include "log.h" 45 #include "message.h" 46 #include "nat_traversal.h" 47 #include "transport.h" 48 #include "virtual.h" 49 #include "udp.h" 50 #include "util.h" 51 52 #include "udp_encap.h" 53 54 static struct transport *virtual_bind(const struct sockaddr *); 55 static struct transport *virtual_bind_ADDR_ANY(sa_family_t); 56 static int virtual_bind_if(char *, struct sockaddr *, void *); 57 static struct transport *virtual_clone(struct transport *, struct sockaddr *); 58 static struct transport *virtual_create(char *); 59 static char *virtual_decode_ids (struct transport *); 60 static void virtual_get_dst(struct transport *, 61 struct sockaddr **); 62 static struct msg_head *virtual_get_queue(struct message *); 63 static void virtual_get_src(struct transport *, 64 struct sockaddr **); 65 static void virtual_handle_message(struct transport *); 66 static void virtual_reinit(void); 67 static void virtual_remove(struct transport *); 68 static void virtual_report(struct transport *); 69 static int virtual_send_message(struct message *, 70 struct transport *); 71 72 static struct transport_vtbl virtual_transport_vtbl = { 73 { 0 }, "udp", 74 virtual_create, 75 virtual_reinit, 76 virtual_remove, 77 virtual_report, 78 0, 79 0, 80 virtual_handle_message, 81 virtual_send_message, 82 virtual_get_dst, 83 virtual_get_src, 84 virtual_decode_ids, 85 virtual_clone, 86 virtual_get_queue 87 }; 88 89 static LIST_HEAD (virtual_listen_list, virtual_transport) virtual_listen_list; 90 static struct transport *default_transport, *default_transport6; 91 92 void 93 virtual_init(void) 94 { 95 struct conf_list *listen_on; 96 97 LIST_INIT(&virtual_listen_list); 98 99 transport_method_add(&virtual_transport_vtbl); 100 101 /* Bind the ISAKMP port(s) on all network interfaces we have. */ 102 if (if_map(virtual_bind_if, 0) == -1) 103 log_fatal("virtual_init: " 104 "could not bind the ISAKMP port(s) on all interfaces"); 105 106 /* Only listen to the specified address if Listen-on is configured */ 107 listen_on = conf_get_list("General", "Listen-on"); 108 if (listen_on) { 109 LOG_DBG((LOG_TRANSPORT, 50, 110 "virtual_init: not binding ISAKMP port(s) to ADDR_ANY")); 111 conf_free_list(listen_on); 112 return; 113 } 114 115 /* 116 * Bind to INADDR_ANY in case of new addresses popping up. 117 * Packet reception on this transport is taken as a hint to reprobe the 118 * interface list. 119 */ 120 if (!bind_family || (bind_family & BIND_FAMILY_INET4)) { 121 default_transport = virtual_bind_ADDR_ANY(AF_INET); 122 if (!default_transport) 123 return; 124 LIST_INSERT_HEAD(&virtual_listen_list, 125 (struct virtual_transport *)default_transport, link); 126 transport_reference(default_transport); 127 } 128 129 if (!bind_family || (bind_family & BIND_FAMILY_INET6)) { 130 default_transport6 = virtual_bind_ADDR_ANY(AF_INET6); 131 if (!default_transport6) 132 return; 133 LIST_INSERT_HEAD(&virtual_listen_list, 134 (struct virtual_transport *)default_transport6, link); 135 transport_reference(default_transport6); 136 } 137 } 138 139 struct virtual_transport * 140 virtual_get_default(sa_family_t af) 141 { 142 switch (af) { 143 case AF_INET: 144 return (struct virtual_transport *)default_transport; 145 case AF_INET6: 146 return (struct virtual_transport *)default_transport6; 147 default: 148 return 0; 149 } 150 } 151 152 /* 153 * Probe the interface list and determine what new interfaces have 154 * appeared. 155 * 156 * At the same time, we try to determine whether existing interfaces have 157 * been rendered invalid; we do this by marking all virtual transports before 158 * we call virtual_bind_if () through if_map (), and then releasing those 159 * transports that have not been unmarked. 160 */ 161 void 162 virtual_reinit(void) 163 { 164 struct virtual_transport *v, *v2; 165 166 /* Mark all UDP transports, except the default ones. */ 167 for (v = LIST_FIRST(&virtual_listen_list); v; v = LIST_NEXT(v, link)) 168 if (&v->transport != default_transport && 169 &v->transport != default_transport6) 170 v->transport.flags |= TRANSPORT_MARK; 171 172 /* Re-probe interface list. */ 173 if (if_map(virtual_bind_if, 0) == -1) 174 log_print("virtual_init: " 175 "could not bind the ISAKMP port(s) on all interfaces"); 176 177 /* 178 * Release listening transports for local addresses that no 179 * longer exist. virtual_bind_if () will have left those still marked. 180 */ 181 v = LIST_FIRST(&virtual_listen_list); 182 while (v) { 183 v2 = LIST_NEXT(v, link); 184 if (v->transport.flags & TRANSPORT_MARK) { 185 LIST_REMOVE(v, link); 186 transport_release(&v->transport); 187 } 188 v = v2; 189 } 190 } 191 192 struct virtual_transport * 193 virtual_listen_lookup(struct sockaddr *addr) 194 { 195 struct virtual_transport *v; 196 struct udp_transport *u; 197 198 for (v = LIST_FIRST(&virtual_listen_list); v; 199 v = LIST_NEXT(v, link)) { 200 if (!(u = (struct udp_transport *)v->main)) 201 if (!(u = (struct udp_transport *)v->encap)) { 202 log_print("virtual_listen_lookup: " 203 "virtual %p has no low-level transports", 204 v); 205 continue; 206 } 207 208 if (u->src->sa_family == addr->sa_family && 209 sockaddr_addrlen(u->src) == sockaddr_addrlen(addr) && 210 memcmp(sockaddr_addrdata (u->src), sockaddr_addrdata(addr), 211 sockaddr_addrlen(addr)) == 0) 212 return v; 213 } 214 215 LOG_DBG((LOG_TRANSPORT, 40, "virtual_listen_lookup: no match")); 216 return 0; 217 } 218 219 /* 220 * Initialize an object of the VIRTUAL transport class. 221 */ 222 static struct transport * 223 virtual_bind(const struct sockaddr *addr) 224 { 225 struct virtual_transport *v; 226 struct sockaddr_storage tmp_sa; 227 char *stport; 228 in_port_t port; 229 230 v = (struct virtual_transport *)calloc(1, sizeof *v); 231 if (!v) { 232 log_error("virtual_bind: calloc(1, %lu) failed", 233 (unsigned long)sizeof *v); 234 return 0; 235 } 236 237 v->transport.vtbl = &virtual_transport_vtbl; 238 239 memcpy(&tmp_sa, addr, SA_LEN(addr)); 240 241 /* Get port. */ 242 stport = udp_default_port ? udp_default_port : UDP_DEFAULT_PORT_STR; 243 port = text2port(stport); 244 if (port == 0) { 245 log_print("virtual_bind: bad port \"%s\"", stport); 246 free(v); 247 return 0; 248 } 249 250 sockaddr_set_port((struct sockaddr *)&tmp_sa, port); 251 v->main = udp_bind((struct sockaddr *)&tmp_sa); 252 if (!v->main) { 253 free(v); 254 return 0; 255 } 256 v->main->virtual = (struct transport *)v; 257 258 if (!disable_nat_t) { 259 memcpy(&tmp_sa, addr, SA_LEN(addr)); 260 261 /* Get port. */ 262 stport = udp_encap_default_port 263 ? udp_encap_default_port : UDP_ENCAP_DEFAULT_PORT_STR; 264 port = text2port(stport); 265 if (port == 0) { 266 log_print("virtual_bind: bad encap port \"%s\"", 267 stport); 268 v->main->vtbl->remove(v->main); 269 free(v); 270 return 0; 271 } 272 273 sockaddr_set_port((struct sockaddr *)&tmp_sa, port); 274 v->encap = udp_encap_bind((struct sockaddr *)&tmp_sa); 275 if (!v->encap) { 276 v->main->vtbl->remove(v->main); 277 free(v); 278 return 0; 279 } 280 v->encap->virtual = (struct transport *)v; 281 } 282 v->encap_is_active = 0; 283 284 transport_setup(&v->transport, 1); 285 v->transport.flags |= TRANSPORT_LISTEN; 286 287 return (struct transport *)v; 288 } 289 290 static struct transport * 291 virtual_bind_ADDR_ANY(sa_family_t af) 292 { 293 struct sockaddr_storage dflt_stor; 294 struct sockaddr_in *d4 = (struct sockaddr_in *)&dflt_stor; 295 struct sockaddr_in6 *d6 = (struct sockaddr_in6 *)&dflt_stor; 296 struct transport *t; 297 struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; 298 299 bzero(&dflt_stor, sizeof dflt_stor); 300 switch (af) { 301 case AF_INET: 302 d4->sin_family = af; 303 d4->sin_len = sizeof(struct sockaddr_in); 304 d4->sin_addr.s_addr = INADDR_ANY; 305 break; 306 307 case AF_INET6: 308 d6->sin6_family = af; 309 d6->sin6_len = sizeof(struct sockaddr_in6); 310 memcpy(&d6->sin6_addr.s6_addr, &in6addr_any, 311 sizeof in6addr_any); 312 break; 313 } 314 315 t = virtual_bind((struct sockaddr *)&dflt_stor); 316 if (!t) 317 log_error("virtual_bind_ADDR_ANY: " 318 "could not allocate default IPv%s ISAKMP port(s)", 319 af == AF_INET ? "4" : "6"); 320 return t; 321 } 322 323 static int 324 virtual_bind_if(char *ifname, struct sockaddr *if_addr, void *arg) 325 { 326 struct conf_list *listen_on; 327 struct virtual_transport *v; 328 struct conf_list_node *address; 329 struct sockaddr *addr; 330 struct transport *t; 331 struct ifreq flags_ifr; 332 char *addr_str; 333 int s, error; 334 335 if (sockaddr2text(if_addr, &addr_str, 0)) 336 addr_str = 0; 337 338 LOG_DBG((LOG_TRANSPORT, 90, 339 "virtual_bind_if: interface %s family %s address %s", 340 ifname ? ifname : "<unknown>", 341 if_addr->sa_family == AF_INET ? "v4" : 342 (if_addr->sa_family == AF_INET6 ? "v6" : "<unknown>"), 343 addr_str ? addr_str : "<invalid>")); 344 if (addr_str) 345 free(addr_str); 346 347 /* 348 * Drop non-Internet stuff. 349 */ 350 if ((if_addr->sa_family != AF_INET || 351 SA_LEN(if_addr) != sizeof (struct sockaddr_in)) && 352 (if_addr->sa_family != AF_INET6 || 353 SA_LEN(if_addr) != sizeof (struct sockaddr_in6))) 354 return 0; 355 356 /* 357 * Only create sockets for families we should listen to. 358 */ 359 if (bind_family) 360 switch (if_addr->sa_family) { 361 case AF_INET: 362 if ((bind_family & BIND_FAMILY_INET4) == 0) 363 return 0; 364 break; 365 case AF_INET6: 366 if ((bind_family & BIND_FAMILY_INET6) == 0) 367 return 0; 368 break; 369 default: 370 return 0; 371 } 372 373 /* 374 * These special addresses are not useable as they have special meaning 375 * in the IP stack. 376 */ 377 if (if_addr->sa_family == AF_INET && 378 (((struct sockaddr_in *)if_addr)->sin_addr.s_addr == INADDR_ANY || 379 (((struct sockaddr_in *)if_addr)->sin_addr.s_addr == INADDR_NONE))) 380 return 0; 381 382 /* 383 * Go through the list of transports and see if we already have this 384 * address bound. If so, unmark the transport and skip it; this allows 385 * us to call this function when we suspect a new address has appeared. 386 */ 387 if ((v = virtual_listen_lookup(if_addr)) != 0) { 388 LOG_DBG ((LOG_TRANSPORT, 90, "virtual_bind_if: " 389 "already bound")); 390 v->transport.flags &= ~TRANSPORT_MARK; 391 return 0; 392 } 393 394 /* 395 * Don't bother with interfaces that are down. 396 * Note: This socket is only used to collect the interface status. 397 */ 398 s = socket(if_addr->sa_family, SOCK_DGRAM, 0); 399 if (s == -1) { 400 log_error("virtual_bind_if: " 401 "socket (%d, SOCK_DGRAM, 0) failed", if_addr->sa_family); 402 return -1; 403 } 404 strlcpy(flags_ifr.ifr_name, ifname, sizeof flags_ifr.ifr_name); 405 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&flags_ifr) == -1) { 406 log_error("virtual_bind_if: " 407 "ioctl (%d, SIOCGIFFLAGS, ...) failed", s); 408 close(s); 409 return -1; 410 } 411 close(s); 412 if (!(flags_ifr.ifr_flags & IFF_UP)) 413 return 0; 414 415 /* Set the port number to zero. */ 416 switch (if_addr->sa_family) { 417 case AF_INET: 418 ((struct sockaddr_in *)if_addr)->sin_port = htons(0); 419 break; 420 case AF_INET6: 421 ((struct sockaddr_in6 *)if_addr)->sin6_port = htons(0); 422 break; 423 default: 424 log_print("virtual_bind_if: unsupported protocol family %d", 425 if_addr->sa_family); 426 break; 427 } 428 429 /* 430 * If we are explicit about what addresses we can listen to, be sure 431 * to respect that option. 432 * This is quite wasteful redoing the list-run for every interface, 433 * but who cares? This is not an operation that needs to be fast. 434 */ 435 listen_on = conf_get_list("General", "Listen-on"); 436 if (listen_on) { 437 for (address = TAILQ_FIRST(&listen_on->fields); address; 438 address = TAILQ_NEXT(address, link)) { 439 if (text2sockaddr(address->field, 0, &addr, 0, 0)) { 440 log_print("virtual_bind_if: " 441 "invalid address %s in \"Listen-on\"", 442 address->field); 443 continue; 444 } 445 446 /* If found, take the easy way out. */ 447 if (memcmp(addr, if_addr, SA_LEN(addr)) == 0) { 448 free(addr); 449 break; 450 } 451 free(addr); 452 } 453 conf_free_list(listen_on); 454 455 /* 456 * If address is zero then we did not find the address among 457 * the ones we should listen to. 458 * XXX We do not discover if we do not find our listen 459 * addresses. Maybe this should be the other way round. 460 */ 461 if (!address) 462 return 0; 463 } 464 465 t = virtual_bind(if_addr); 466 if (!t) { 467 error = sockaddr2text(if_addr, &addr_str, 0); 468 log_print("virtual_bind_if: failed to create a socket on %s", 469 error ? "unknown" : addr_str); 470 if (!error) 471 free(addr_str); 472 return -1; 473 } 474 LIST_INSERT_HEAD(&virtual_listen_list, (struct virtual_transport *)t, 475 link); 476 transport_reference(t); 477 return 0; 478 } 479 480 static struct transport * 481 virtual_clone(struct transport *vt, struct sockaddr *raddr) 482 { 483 struct virtual_transport *v = (struct virtual_transport *)vt; 484 struct virtual_transport *v2; 485 struct transport *t; 486 char *stport; 487 in_port_t port; 488 489 t = malloc(sizeof *v); 490 if (!t) { 491 log_error("virtual_clone: malloc(%lu) failed", 492 (unsigned long)sizeof *v); 493 return 0; 494 } 495 v2 = (struct virtual_transport *)t; 496 497 memcpy(v2, v, sizeof *v); 498 /* Remove the copy's links into virtual_listen_list. */ 499 v2->link.le_next = 0; 500 v2->link.le_prev = 0; 501 502 if (v->encap_is_active) 503 v2->main = 0; /* No need to clone this. */ 504 else { 505 v2->main = v->main->vtbl->clone(v->main, raddr); 506 v2->main->virtual = (struct transport *)v2; 507 } 508 if (!disable_nat_t) { 509 stport = udp_encap_default_port ? udp_encap_default_port : 510 UDP_ENCAP_DEFAULT_PORT_STR; 511 port = text2port(stport); 512 if (port == 0) { 513 log_print("virtual_clone: port string \"%s\" not convertible " 514 "to in_port_t", stport); 515 free(t); 516 return 0; 517 } 518 sockaddr_set_port(raddr, port); 519 v2->encap = v->encap->vtbl->clone(v->encap, raddr); 520 v2->encap->virtual = (struct transport *)v2; 521 } 522 LOG_DBG((LOG_TRANSPORT, 50, "virtual_clone: old %p new %p (%s is %p)", 523 v, t, v->encap_is_active ? "encap" : "main", 524 v->encap_is_active ? v2->encap : v2->main)); 525 526 t->flags &= ~TRANSPORT_LISTEN; 527 transport_setup(t, 1); 528 return t; 529 } 530 531 static struct transport * 532 virtual_create(char *name) 533 { 534 struct virtual_transport *v; 535 struct transport *t, *t2 = 0; 536 537 t = transport_create("udp_physical", name); 538 if (!t) 539 return 0; 540 541 if (!disable_nat_t) { 542 t2 = transport_create("udp_encap", name); 543 if (!t2) { 544 t->vtbl->remove(t); 545 return 0; 546 } 547 } 548 549 v = (struct virtual_transport *)calloc(1, sizeof *v); 550 if (!v) { 551 log_error("virtual_create: calloc(1, %lu) failed", 552 (unsigned long)sizeof *v); 553 t->vtbl->remove(t); 554 if (t2) 555 t2->vtbl->remove(t2); 556 return 0; 557 } 558 559 memcpy(v, t, sizeof *t); 560 v->transport.virtual = 0; 561 v->main = t; 562 v->encap = t2; 563 v->transport.vtbl = &virtual_transport_vtbl; 564 t->virtual = (struct transport *)v; 565 if (t2) 566 t2->virtual = (struct transport *)v; 567 transport_setup(&v->transport, 1); 568 return (struct transport *)v; 569 } 570 571 static void 572 virtual_remove(struct transport *t) 573 { 574 struct virtual_transport *v = (struct virtual_transport *)t; 575 576 if (v->encap) 577 v->encap->vtbl->remove(v->encap); 578 if (v->main) 579 v->main->vtbl->remove(v->main); 580 if (v->link.le_prev) 581 LIST_REMOVE(v, link); 582 583 LOG_DBG((LOG_TRANSPORT, 90, "virtual_remove: removed %p", v)); 584 free(t); 585 } 586 587 static void 588 virtual_report(struct transport *t) 589 { 590 } 591 592 static void 593 virtual_handle_message(struct transport *t) 594 { 595 if (t->virtual == default_transport || 596 t->virtual == default_transport6) { 597 /* XXX drain pending message. See udp_handle_message(). */ 598 599 virtual_reinit(); 600 601 /* 602 * As we don't know the actual destination address of the 603 * packet, we can't really deal with it. So, just ignore it 604 * and hope we catch the retransmission. 605 */ 606 return; 607 } 608 609 /* 610 * As per the NAT-T draft, in case we have already switched ports, 611 * any messages recieved on the old (500) port SHOULD be discarded. 612 * (Actually, while phase 1 messages should be discarded, 613 * informational exchanges MAY be processed normally. For now, we 614 * discard them all.) 615 */ 616 if (((struct virtual_transport *)t->virtual)->encap_is_active && 617 ((struct virtual_transport *)t->virtual)->main == t) { 618 LOG_DBG((LOG_MESSAGE, 10, "virtual_handle_message: " 619 "message on old port discarded")); 620 return; 621 } 622 623 t->vtbl->handle_message(t); 624 } 625 626 static int 627 virtual_send_message(struct message *msg, struct transport *t) 628 { 629 struct virtual_transport *v = 630 (struct virtual_transport *)msg->transport; 631 struct sockaddr *dst; 632 in_port_t port, default_port; 633 634 /* 635 * Activate NAT-T Encapsulation if 636 * - the exchange says we can, and 637 * - in ID_PROT, after step 4 (draft-ietf-ipsec-nat-t-ike-03), or 638 * - in other exchange (Aggressive, ), asap 639 * XXX ISAKMP_EXCH_BASE etc? 640 */ 641 if (v->encap_is_active == 0 && 642 (msg->exchange->flags & EXCHANGE_FLAG_NAT_T_ENABLE) && 643 (msg->exchange->type != ISAKMP_EXCH_ID_PROT || 644 msg->exchange->step > 4)) { 645 LOG_DBG((LOG_MESSAGE, 10, "virtual_send_message: " 646 "enabling NAT-T encapsulation for this exchange")); 647 v->encap_is_active++; 648 649 /* Copy destination port if it is translated (NAT). */ 650 v->main->vtbl->get_dst(v->main, &dst); 651 port = ntohs(sockaddr_port(dst)); 652 653 if (udp_default_port) 654 default_port = text2port(udp_default_port); 655 else 656 default_port = UDP_DEFAULT_PORT; 657 if (port != default_port) { 658 v->main->vtbl->get_dst(v->encap, &dst); 659 sockaddr_set_port(dst, port); 660 } 661 } 662 663 if (v->encap_is_active) 664 return v->encap->vtbl->send_message(msg, v->encap); 665 else 666 return v->main->vtbl->send_message(msg, v->main); 667 } 668 669 static void 670 virtual_get_src(struct transport *t, struct sockaddr **s) 671 { 672 struct virtual_transport *v = (struct virtual_transport *)t; 673 674 if (v->encap_is_active) 675 v->encap->vtbl->get_src(v->encap, s); 676 else 677 v->main->vtbl->get_src(v->main, s); 678 } 679 680 static void 681 virtual_get_dst(struct transport *t, struct sockaddr **s) 682 { 683 struct virtual_transport *v = (struct virtual_transport *)t; 684 685 if (v->encap_is_active) 686 v->encap->vtbl->get_dst(v->encap, s); 687 else 688 v->main->vtbl->get_dst(v->main, s); 689 } 690 691 static char * 692 virtual_decode_ids(struct transport *t) 693 { 694 struct virtual_transport *v = (struct virtual_transport *)t; 695 696 if (v->encap_is_active) 697 return v->encap->vtbl->decode_ids(t); 698 else 699 return v->main->vtbl->decode_ids(t); 700 } 701 702 static struct msg_head * 703 virtual_get_queue(struct message *msg) 704 { 705 if (msg->flags & MSG_PRIORITIZED) 706 return &msg->transport->prio_sendq; 707 else 708 return &msg->transport->sendq; 709 } 710