ng_cisco.c revision 138009
1240116Smarcel 2240116Smarcel/* 3240116Smarcel * ng_cisco.c 4240116Smarcel * 5240116Smarcel * Copyright (c) 1996-1999 Whistle Communications, Inc. 6240116Smarcel * All rights reserved. 7240116Smarcel * 8240116Smarcel * Subject to the following obligations and disclaimer of warranty, use and 9240116Smarcel * redistribution of this software, in source or object code forms, with or 10240116Smarcel * without modifications are expressly permitted by Whistle Communications; 11240116Smarcel * provided, however, that: 12240116Smarcel * 1. Any and all reproductions of the source or object code must include the 13240116Smarcel * copyright notice above and the following disclaimer of warranties; and 14240116Smarcel * 2. No rights are granted, in any manner or form, to use Whistle 15240116Smarcel * Communications, Inc. trademarks, including the mark "WHISTLE 16240116Smarcel * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 17240116Smarcel * such appears in the above copyright notice or in the software. 18240116Smarcel * 19240116Smarcel * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 20240116Smarcel * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 21240116Smarcel * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 22240116Smarcel * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 23240116Smarcel * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 24240116Smarcel * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 25240116Smarcel * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 26240116Smarcel * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 27240116Smarcel * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 28240116Smarcel * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 29240116Smarcel * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 30240116Smarcel * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 31240116Smarcel * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 32240116Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33240116Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34240116Smarcel * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 35240116Smarcel * OF SUCH DAMAGE. 36240116Smarcel * 37240116Smarcel * Author: Julian Elischer <julian@freebsd.org> 38240116Smarcel * 39240116Smarcel * $FreeBSD: head/sys/netgraph/ng_cisco.c 138009 2004-11-23 09:30:27Z glebius $ 40240116Smarcel * $Whistle: ng_cisco.c,v 1.25 1999/11/01 09:24:51 julian Exp $ 41240116Smarcel */ 42240116Smarcel 43240116Smarcel#include <sys/param.h> 44240116Smarcel#include <sys/systm.h> 45240116Smarcel#include <sys/errno.h> 46240116Smarcel#include <sys/kernel.h> 47240116Smarcel#include <sys/socket.h> 48240116Smarcel#include <sys/malloc.h> 49240116Smarcel#include <sys/mbuf.h> 50240116Smarcel#include <sys/syslog.h> 51240116Smarcel 52240116Smarcel#include <net/if.h> 53240116Smarcel 54240116Smarcel#include <netinet/in.h> 55240116Smarcel#include <netinet/if_ether.h> 56240116Smarcel 57240116Smarcel#include <netatalk/at.h> 58240116Smarcel 59240116Smarcel#include <netipx/ipx.h> 60240116Smarcel#include <netipx/ipx_if.h> 61240116Smarcel 62240116Smarcel#include <netgraph/ng_message.h> 63240116Smarcel#include <netgraph/netgraph.h> 64240116Smarcel#include <netgraph/ng_parse.h> 65240116Smarcel#include <netgraph/ng_cisco.h> 66240116Smarcel 67240116Smarcel#define CISCO_MULTICAST 0x8f /* Cisco multicast address */ 68240116Smarcel#define CISCO_UNICAST 0x0f /* Cisco unicast address */ 69240116Smarcel#define CISCO_KEEPALIVE 0x8035 /* Cisco keepalive protocol */ 70240116Smarcel#define CISCO_ADDR_REQ 0 /* Cisco address request */ 71240116Smarcel#define CISCO_ADDR_REPLY 1 /* Cisco address reply */ 72240116Smarcel#define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */ 73240116Smarcel 74240116Smarcel#define KEEPALIVE_SECS 10 75240116Smarcel 76240116Smarcelstruct cisco_header { 77240116Smarcel u_char address; 78240116Smarcel u_char control; 79240116Smarcel u_short protocol; 80240116Smarcel}; 81240116Smarcel 82240116Smarcel#define CISCO_HEADER_LEN sizeof (struct cisco_header) 83240116Smarcel 84240116Smarcelstruct cisco_packet { 85240116Smarcel u_long type; 86240116Smarcel u_long par1; 87240116Smarcel u_long par2; 88240116Smarcel u_short rel; 89240116Smarcel u_short time0; 90240116Smarcel u_short time1; 91240116Smarcel}; 92240116Smarcel 93240116Smarcel#define CISCO_PACKET_LEN (sizeof(struct cisco_packet)) 94240116Smarcel 95240116Smarcelstruct protoent { 96240116Smarcel hook_p hook; /* the hook for this proto */ 97240116Smarcel u_short af; /* address family, -1 = downstream */ 98240116Smarcel}; 99240116Smarcel 100240116Smarcelstruct cisco_priv { 101240116Smarcel u_long local_seq; 102240116Smarcel u_long remote_seq; 103240116Smarcel u_long seqRetries; /* how many times we've been here throwing out 104240116Smarcel * the same sequence number without ack */ 105240116Smarcel node_p node; 106240116Smarcel struct callout handle; 107240116Smarcel struct protoent downstream; 108240116Smarcel struct protoent inet; /* IP information */ 109240116Smarcel struct in_addr localip; 110240116Smarcel struct in_addr localmask; 111240116Smarcel struct protoent inet6; /* IPv6 information */ 112240116Smarcel struct protoent atalk; /* AppleTalk information */ 113240116Smarcel struct protoent ipx; /* IPX information */ 114240116Smarcel}; 115240116Smarceltypedef struct cisco_priv *sc_p; 116240116Smarcel 117240116Smarcel/* Netgraph methods */ 118240116Smarcelstatic ng_constructor_t cisco_constructor; 119240116Smarcelstatic ng_rcvmsg_t cisco_rcvmsg; 120240116Smarcelstatic ng_shutdown_t cisco_shutdown; 121240116Smarcelstatic ng_newhook_t cisco_newhook; 122240116Smarcelstatic ng_rcvdata_t cisco_rcvdata; 123240116Smarcelstatic ng_disconnect_t cisco_disconnect; 124240116Smarcel 125240116Smarcel/* Other functions */ 126240116Smarcelstatic int cisco_input(sc_p sc, item_p item); 127240116Smarcelstatic void cisco_keepalive(node_p node, hook_p hook, void *arg1, int arg2); 128240116Smarcelstatic int cisco_send(sc_p sc, int type, long par1, long par2); 129240116Smarcelstatic void cisco_notify(sc_p sc, uint32_t cmd); 130240116Smarcel 131240116Smarcel/* Parse type for struct ng_cisco_ipaddr */ 132240116Smarcelstatic const struct ng_parse_struct_field ng_cisco_ipaddr_type_fields[] 133240116Smarcel = NG_CISCO_IPADDR_TYPE_INFO; 134240116Smarcelstatic const struct ng_parse_type ng_cisco_ipaddr_type = { 135240116Smarcel &ng_parse_struct_type, 136240116Smarcel &ng_cisco_ipaddr_type_fields 137240116Smarcel}; 138240116Smarcel 139240116Smarcel/* Parse type for struct ng_async_stat */ 140240116Smarcelstatic const struct ng_parse_struct_field ng_cisco_stats_type_fields[] 141240116Smarcel = NG_CISCO_STATS_TYPE_INFO; 142240116Smarcelstatic const struct ng_parse_type ng_cisco_stats_type = { 143240116Smarcel &ng_parse_struct_type, 144240116Smarcel &ng_cisco_stats_type_fields 145240116Smarcel}; 146240116Smarcel 147240116Smarcel/* List of commands and how to convert arguments to/from ASCII */ 148240116Smarcelstatic const struct ng_cmdlist ng_cisco_cmdlist[] = { 149240116Smarcel { 150240116Smarcel NGM_CISCO_COOKIE, 151240116Smarcel NGM_CISCO_SET_IPADDR, 152240116Smarcel "setipaddr", 153240116Smarcel &ng_cisco_ipaddr_type, 154240116Smarcel NULL 155240116Smarcel }, 156240116Smarcel { 157240116Smarcel NGM_CISCO_COOKIE, 158240116Smarcel NGM_CISCO_GET_IPADDR, 159240116Smarcel "getipaddr", 160240116Smarcel NULL, 161240116Smarcel &ng_cisco_ipaddr_type 162240116Smarcel }, 163240116Smarcel { 164240116Smarcel NGM_CISCO_COOKIE, 165240116Smarcel NGM_CISCO_GET_STATUS, 166240116Smarcel "getstats", 167240116Smarcel NULL, 168240116Smarcel &ng_cisco_stats_type 169240116Smarcel }, 170240116Smarcel { 0 } 171240116Smarcel}; 172240116Smarcel 173240116Smarcel/* Node type */ 174240116Smarcelstatic struct ng_type typestruct = { 175240116Smarcel .version = NG_ABI_VERSION, 176240116Smarcel .name = NG_CISCO_NODE_TYPE, 177240116Smarcel .constructor = cisco_constructor, 178240116Smarcel .rcvmsg = cisco_rcvmsg, 179240116Smarcel .shutdown = cisco_shutdown, 180240116Smarcel .newhook = cisco_newhook, 181240116Smarcel .rcvdata = cisco_rcvdata, 182240116Smarcel .disconnect = cisco_disconnect, 183240116Smarcel .cmdlist = ng_cisco_cmdlist, 184240116Smarcel}; 185240116SmarcelNETGRAPH_INIT(cisco, &typestruct); 186240116Smarcel 187240116Smarcel/* 188240116Smarcel * Node constructor 189240116Smarcel */ 190240116Smarcelstatic int 191240116Smarcelcisco_constructor(node_p node) 192240116Smarcel{ 193240116Smarcel sc_p sc; 194240116Smarcel 195240116Smarcel MALLOC(sc, sc_p, sizeof(*sc), M_NETGRAPH, M_NOWAIT | M_ZERO); 196240116Smarcel if (sc == NULL) 197240116Smarcel return (ENOMEM); 198240116Smarcel 199240116Smarcel ng_callout_init(&sc->handle); 200240116Smarcel NG_NODE_SET_PRIVATE(node, sc); 201240116Smarcel sc->node = node; 202240116Smarcel 203240116Smarcel /* Initialise the varous protocol hook holders */ 204240116Smarcel sc->downstream.af = 0xffff; 205240116Smarcel sc->inet.af = AF_INET; 206240116Smarcel sc->inet6.af = AF_INET6; 207240116Smarcel sc->atalk.af = AF_APPLETALK; 208240116Smarcel sc->ipx.af = AF_IPX; 209240116Smarcel return (0); 210240116Smarcel} 211240116Smarcel 212240116Smarcel/* 213240116Smarcel * Check new hook 214240116Smarcel */ 215240116Smarcelstatic int 216240116Smarcelcisco_newhook(node_p node, hook_p hook, const char *name) 217240116Smarcel{ 218240116Smarcel const sc_p sc = NG_NODE_PRIVATE(node); 219240116Smarcel 220240116Smarcel if (strcmp(name, NG_CISCO_HOOK_DOWNSTREAM) == 0) { 221240116Smarcel sc->downstream.hook = hook; 222240116Smarcel NG_HOOK_SET_PRIVATE(hook, &sc->downstream); 223240116Smarcel 224240116Smarcel /* Start keepalives */ 225240116Smarcel ng_timeout(&sc->handle, node, NULL, (hz * KEEPALIVE_SECS), 226240116Smarcel &cisco_keepalive, (void *)sc, 0); 227240116Smarcel } else if (strcmp(name, NG_CISCO_HOOK_INET) == 0) { 228240116Smarcel sc->inet.hook = hook; 229240116Smarcel NG_HOOK_SET_PRIVATE(hook, &sc->inet); 230240116Smarcel } else if (strcmp(name, NG_CISCO_HOOK_APPLETALK) == 0) { 231240116Smarcel sc->atalk.hook = hook; 232240116Smarcel NG_HOOK_SET_PRIVATE(hook, &sc->atalk); 233240116Smarcel } else if (strcmp(name, NG_CISCO_HOOK_IPX) == 0) { 234240116Smarcel sc->ipx.hook = hook; 235240116Smarcel NG_HOOK_SET_PRIVATE(hook, &sc->ipx); 236240116Smarcel } else if (strcmp(name, NG_CISCO_HOOK_DEBUG) == 0) { 237240116Smarcel NG_HOOK_SET_PRIVATE(hook, NULL); /* unimplemented */ 238240116Smarcel } else 239240116Smarcel return (EINVAL); 240240116Smarcel return 0; 241240116Smarcel} 242240116Smarcel 243240116Smarcel/* 244240116Smarcel * Receive control message. 245240116Smarcel */ 246240116Smarcelstatic int 247240116Smarcelcisco_rcvmsg(node_p node, item_p item, hook_p lasthook) 248240116Smarcel{ 249240116Smarcel struct ng_mesg *msg; 250240116Smarcel const sc_p sc = NG_NODE_PRIVATE(node); 251240116Smarcel struct ng_mesg *resp = NULL; 252240116Smarcel int error = 0; 253240116Smarcel 254240116Smarcel NGI_GET_MSG(item, msg); 255240116Smarcel switch (msg->header.typecookie) { 256240116Smarcel case NGM_GENERIC_COOKIE: 257240116Smarcel switch (msg->header.cmd) { 258240116Smarcel case NGM_TEXT_STATUS: 259240116Smarcel { 260240116Smarcel char *arg; 261240116Smarcel int pos; 262240116Smarcel 263240116Smarcel NG_MKRESPONSE(resp, msg, sizeof(struct ng_mesg) 264240116Smarcel + NG_TEXTRESPONSE, M_NOWAIT); 265240116Smarcel if (resp == NULL) { 266240116Smarcel error = ENOMEM; 267240116Smarcel break; 268240116Smarcel } 269240116Smarcel arg = (char *) resp->data; 270240116Smarcel pos = sprintf(arg, 271240116Smarcel "keepalive period: %d sec; ", KEEPALIVE_SECS); 272240116Smarcel pos += sprintf(arg + pos, 273240116Smarcel "unacknowledged keepalives: %ld", sc->seqRetries); 274240116Smarcel resp->header.arglen = pos + 1; 275240116Smarcel break; 276240116Smarcel } 277240116Smarcel default: 278240116Smarcel error = EINVAL; 279240116Smarcel break; 280240116Smarcel } 281240116Smarcel break; 282240116Smarcel case NGM_CISCO_COOKIE: 283240116Smarcel switch (msg->header.cmd) { 284240116Smarcel case NGM_CISCO_GET_IPADDR: /* could be a late reply! */ 285240116Smarcel if ((msg->header.flags & NGF_RESP) == 0) { 286240116Smarcel struct in_addr *ips; 287240116Smarcel 288240116Smarcel NG_MKRESPONSE(resp, msg, 289240116Smarcel 2 * sizeof(*ips), M_NOWAIT); 290240116Smarcel if (!resp) { 291240116Smarcel error = ENOMEM; 292240116Smarcel break; 293240116Smarcel } 294240116Smarcel ips = (struct in_addr *) resp->data; 295240116Smarcel ips[0] = sc->localip; 296240116Smarcel ips[1] = sc->localmask; 297240116Smarcel break; 298240116Smarcel } 299240116Smarcel /* FALLTHROUGH */ /* ...if it's a reply */ 300240116Smarcel case NGM_CISCO_SET_IPADDR: 301240116Smarcel { 302240116Smarcel struct in_addr *const ips = (struct in_addr *)msg->data; 303240116Smarcel 304240116Smarcel if (msg->header.arglen < 2 * sizeof(*ips)) { 305240116Smarcel error = EINVAL; 306240116Smarcel break; 307240116Smarcel } 308240116Smarcel sc->localip = ips[0]; 309240116Smarcel sc->localmask = ips[1]; 310240116Smarcel break; 311240116Smarcel } 312240116Smarcel case NGM_CISCO_GET_STATUS: 313240116Smarcel { 314240116Smarcel struct ng_cisco_stats *stat; 315240116Smarcel 316240116Smarcel NG_MKRESPONSE(resp, msg, sizeof(*stat), M_NOWAIT); 317240116Smarcel if (!resp) { 318240116Smarcel error = ENOMEM; 319240116Smarcel break; 320240116Smarcel } 321240116Smarcel stat = (struct ng_cisco_stats *)resp->data; 322240116Smarcel stat->seqRetries = sc->seqRetries; 323240116Smarcel stat->keepAlivePeriod = KEEPALIVE_SECS; 324240116Smarcel break; 325240116Smarcel } 326240116Smarcel default: 327240116Smarcel error = EINVAL; 328240116Smarcel break; 329240116Smarcel } 330240116Smarcel break; 331240116Smarcel default: 332240116Smarcel error = EINVAL; 333240116Smarcel break; 334240116Smarcel } 335240116Smarcel NG_RESPOND_MSG(error, node, item, resp); 336240116Smarcel NG_FREE_MSG(msg); 337240116Smarcel return (error); 338240116Smarcel} 339240116Smarcel 340240116Smarcel/* 341240116Smarcel * Receive data 342240116Smarcel */ 343240116Smarcelstatic int 344240116Smarcelcisco_rcvdata(hook_p hook, item_p item) 345240116Smarcel{ 346240116Smarcel const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 347240116Smarcel struct protoent *pep; 348240116Smarcel struct cisco_header *h; 349240116Smarcel struct mbuf *m; 350240116Smarcel int error = 0; 351240116Smarcel 352240116Smarcel if ((pep = NG_HOOK_PRIVATE(hook)) == NULL) 353240116Smarcel goto out; 354240116Smarcel 355240116Smarcel /* If it came from our downlink, deal with it separately */ 356240116Smarcel if (pep->af == 0xffff) 357240116Smarcel return (cisco_input(sc, item)); 358240116Smarcel 359240116Smarcel /* OK so it came from a protocol, heading out. Prepend general data 360240116Smarcel packet header. For now, IP,IPX only */ 361240116Smarcel m = NGI_M(item); /* still associated with item */ 362240116Smarcel M_PREPEND(m, CISCO_HEADER_LEN, M_DONTWAIT); 363240116Smarcel if (!m) { 364240116Smarcel error = ENOBUFS; 365240116Smarcel goto out; 366240116Smarcel } 367240116Smarcel h = mtod(m, struct cisco_header *); 368240116Smarcel h->address = CISCO_UNICAST; 369240116Smarcel h->control = 0; 370240116Smarcel 371240116Smarcel switch (pep->af) { 372240116Smarcel case AF_INET: /* Internet Protocol */ 373240116Smarcel h->protocol = htons(ETHERTYPE_IP); 374240116Smarcel break; 375240116Smarcel case AF_INET6: 376240116Smarcel h->protocol = htons(ETHERTYPE_IPV6); 377240116Smarcel break; 378240116Smarcel case AF_APPLETALK: /* AppleTalk Protocol */ 379240116Smarcel h->protocol = htons(ETHERTYPE_AT); 380240116Smarcel break; 381240116Smarcel case AF_IPX: /* Novell IPX Protocol */ 382240116Smarcel h->protocol = htons(ETHERTYPE_IPX); 383240116Smarcel break; 384240116Smarcel default: 385240116Smarcel error = EAFNOSUPPORT; 386240116Smarcel goto out; 387240116Smarcel } 388240116Smarcel 389240116Smarcel /* Send it */ 390240116Smarcel NG_FWD_NEW_DATA(error, item, sc->downstream.hook, m); 391240116Smarcel return (error); 392240116Smarcel 393240116Smarcelout: 394240116Smarcel NG_FREE_ITEM(item); 395240116Smarcel return (error); 396240116Smarcel} 397240116Smarcel 398240116Smarcel/* 399240116Smarcel * Shutdown node 400240116Smarcel */ 401240116Smarcelstatic int 402240116Smarcelcisco_shutdown(node_p node) 403240116Smarcel{ 404240116Smarcel const sc_p sc = NG_NODE_PRIVATE(node); 405240116Smarcel 406240116Smarcel NG_NODE_SET_PRIVATE(node, NULL); 407240116Smarcel NG_NODE_UNREF(sc->node); 408240116Smarcel FREE(sc, M_NETGRAPH); 409240116Smarcel return (0); 410240116Smarcel} 411240116Smarcel 412240116Smarcel/* 413240116Smarcel * Disconnection of a hook 414240116Smarcel * 415240116Smarcel * For this type, removal of the last link destroys the node 416240116Smarcel */ 417240116Smarcelstatic int 418240116Smarcelcisco_disconnect(hook_p hook) 419240116Smarcel{ 420240116Smarcel const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 421240116Smarcel struct protoent *pep; 422240116Smarcel 423240116Smarcel /* Check it's not the debug hook */ 424240116Smarcel if ((pep = NG_HOOK_PRIVATE(hook))) { 425 pep->hook = NULL; 426 if (pep->af == 0xffff) 427 /* If it is the downstream hook, stop the timers */ 428 ng_untimeout(&sc->handle, NG_HOOK_NODE(hook)); 429 } 430 431 /* If no more hooks, remove the node */ 432 if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) 433 && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) 434 ng_rmnode_self(NG_HOOK_NODE(hook)); 435 return (0); 436} 437 438/* 439 * Receive data 440 */ 441static int 442cisco_input(sc_p sc, item_p item) 443{ 444 const struct cisco_header *h; 445 struct cisco_header hdrbuf; 446 struct protoent *pep; 447 struct mbuf *m; 448 int error = 0; 449 450 /* Get data */ 451 m = NGI_M(item); 452 453 /* Sanity check header length */ 454 if (m->m_pkthdr.len < sizeof(*h)) { 455 error = EINVAL; 456 goto drop; 457 } 458 459 /* Get cisco header */ 460 if (m->m_len >= sizeof(*h)) /* the common case */ 461 h = mtod(m, const struct cisco_header *); 462 else { 463 m_copydata(m, 0, sizeof(*h), (caddr_t)&hdrbuf); 464 h = &hdrbuf; 465 } 466 m_adj(m, sizeof(*h)); 467 468 /* Check header address */ 469 switch (h->address) { 470 default: /* Invalid Cisco packet. */ 471 goto drop; 472 case CISCO_UNICAST: 473 case CISCO_MULTICAST: 474 /* Don't check the control field here (RFC 1547). */ 475 switch (ntohs(h->protocol)) { 476 default: 477 goto drop; 478 case CISCO_KEEPALIVE: 479 { 480 const struct cisco_packet *p; 481 struct cisco_packet pktbuf; 482 483 /* Sanity check packet length */ 484 if (m->m_pkthdr.len < sizeof(*p)) { 485 error = EINVAL; 486 goto drop; 487 } 488 489 /* Get cisco packet */ 490 if (m->m_len >= sizeof(*p)) /* the common case */ 491 p = mtod(m, const struct cisco_packet *); 492 else { 493 m_copydata(m, 0, sizeof(*p), (caddr_t)&pktbuf); 494 p = &pktbuf; 495 } 496 497 /* Check packet type */ 498 switch (ntohl(p->type)) { 499 default: 500 log(LOG_WARNING, 501 "cisco: unknown cisco packet type: 0x%lx\n", 502 (long)ntohl(p->type)); 503 break; 504 case CISCO_ADDR_REPLY: 505 /* Reply on address request, ignore */ 506 break; 507 case CISCO_KEEPALIVE_REQ: 508 sc->remote_seq = ntohl(p->par1); 509 if (sc->local_seq == ntohl(p->par2)) { 510 sc->local_seq++; 511 if (sc->seqRetries > 1) 512 cisco_notify(sc, NGM_LINK_IS_UP); 513 sc->seqRetries = 0; 514 } 515 break; 516 case CISCO_ADDR_REQ: 517 { 518 struct ng_mesg *msg; 519 int dummy_error = 0; 520 521 /* Ask inet peer for IP address information */ 522 if (sc->inet.hook == NULL) 523 goto nomsg; 524 NG_MKMESSAGE(msg, NGM_CISCO_COOKIE, 525 NGM_CISCO_GET_IPADDR, 0, M_NOWAIT); 526 if (msg == NULL) 527 goto nomsg; 528 NG_SEND_MSG_HOOK(dummy_error, 529 sc->node, msg, sc->inet.hook, 0); 530 /* 531 * XXX Now maybe we should set a flag telling 532 * our receiver to send this message when the response comes in 533 * instead of now when the data may be bad. 534 */ 535 nomsg: 536 /* Send reply to peer device */ 537 error = cisco_send(sc, CISCO_ADDR_REPLY, 538 ntohl(sc->localip.s_addr), 539 ntohl(sc->localmask.s_addr)); 540 break; 541 } 542 } 543 goto drop; 544 } 545 case ETHERTYPE_IP: 546 pep = &sc->inet; 547 break; 548 case ETHERTYPE_IPV6: 549 pep = &sc->inet6; 550 break; 551 case ETHERTYPE_AT: 552 pep = &sc->atalk; 553 break; 554 case ETHERTYPE_IPX: 555 pep = &sc->ipx; 556 break; 557 } 558 break; 559 } 560 561 /* Drop if payload is empty */ 562 if (m->m_pkthdr.len == 0) { 563 error = EINVAL; 564 goto drop; 565 } 566 567 /* Send it on */ 568 if (pep->hook == NULL) 569 goto drop; 570 NG_FWD_NEW_DATA(error, item, pep->hook, m); 571 return (error); 572 573drop: 574 NG_FREE_ITEM(item); 575 return (error); 576} 577 578 579/* 580 * Send keepalive packets, every 10 seconds. 581 */ 582static void 583cisco_keepalive(node_p node, hook_p hook, void *arg1, int arg2) 584{ 585 const sc_p sc = arg1; 586 587 cisco_send(sc, CISCO_KEEPALIVE_REQ, sc->local_seq, sc->remote_seq); 588 if (sc->seqRetries++ > 1) 589 cisco_notify(sc, NGM_LINK_IS_DOWN); 590 ng_timeout(&sc->handle, node, NULL, (hz * KEEPALIVE_SECS), 591 &cisco_keepalive, (void *)sc, 0); 592} 593 594/* 595 * Send Cisco keepalive packet. 596 */ 597static int 598cisco_send(sc_p sc, int type, long par1, long par2) 599{ 600 struct cisco_header *h; 601 struct cisco_packet *ch; 602 struct mbuf *m; 603 struct timeval time; 604 u_long t; 605 int error = 0; 606 607 getmicrouptime(&time); 608 609 MGETHDR(m, M_DONTWAIT, MT_DATA); 610 if (!m) 611 return (ENOBUFS); 612 613 t = time.tv_sec * 1000 + time.tv_usec / 1000; 614 m->m_pkthdr.len = m->m_len = CISCO_HEADER_LEN + CISCO_PACKET_LEN; 615 m->m_pkthdr.rcvif = 0; 616 617 h = mtod(m, struct cisco_header *); 618 h->address = CISCO_MULTICAST; 619 h->control = 0; 620 h->protocol = htons(CISCO_KEEPALIVE); 621 622 ch = (struct cisco_packet *) (h + 1); 623 ch->type = htonl(type); 624 ch->par1 = htonl(par1); 625 ch->par2 = htonl(par2); 626 ch->rel = -1; 627 ch->time0 = htons((u_short) (t >> 16)); 628 ch->time1 = htons((u_short) t); 629 630 NG_SEND_DATA_ONLY(error, sc->downstream.hook, m); 631 return (error); 632} 633 634/* 635 * Send linkstate to upstream node. 636 */ 637static void 638cisco_notify(sc_p sc, uint32_t cmd) 639{ 640 struct ng_mesg *msg; 641 int dummy_error = 0; 642 643 if (sc->inet.hook == NULL) /* nothing to notify */ 644 return; 645 646 NG_MKMESSAGE(msg, NGM_FLOW_COOKIE, cmd, 0, M_NOWAIT); 647 if (msg != NULL) 648 NG_SEND_MSG_HOOK(dummy_error, sc->node, msg, sc->inet.hook, 0); 649} 650