if_spppfr.c revision 147256
1/*- 2 * Synchronous Frame Relay link level subroutines. 3 * ANSI T1.617-compaible link management signaling 4 * implemented for Frame Relay mode. 5 * Cisco-type Frame Relay framing added, thanks Alex Tutubalin. 6 * Only one DLCI per channel for now. 7 * 8 * Copyright (C) 1994-2000 Cronyx Engineering. 9 * Author: Serge Vakulenko, <vak@cronyx.ru> 10 * 11 * Copyright (C) 1999-2004 Cronyx Engineering. 12 * Author: Kurakin Roman, <rik@cronyx.ru> 13 * 14 * This software is distributed with NO WARRANTIES, not even the implied 15 * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 16 * 17 * Authors grant any other persons or organisations a permission to use, 18 * modify and redistribute this software in source and binary forms, 19 * as long as this message is kept with the software, all derivative 20 * works or modified versions. 21 * 22 * $Cronyx Id: if_spppfr.c,v 1.1.2.10 2004/06/29 09:02:30 rik Exp $ 23 * $FreeBSD: head/sys/net/if_spppfr.c 147256 2005-06-10 16:49:24Z brooks $ 24 */ 25 26#include <sys/param.h> 27 28#if defined(__FreeBSD__) && __FreeBSD__ >= 3 29#include "opt_inet.h" 30#include "opt_inet6.h" 31#include "opt_ipx.h" 32#endif 33 34#ifdef NetBSD1_3 35# if NetBSD1_3 > 6 36# include "opt_inet.h" 37# include "opt_inet6.h" 38# include "opt_iso.h" 39# endif 40#endif 41 42#include <sys/systm.h> 43#include <sys/kernel.h> 44#include <sys/module.h> 45#include <sys/sockio.h> 46#include <sys/socket.h> 47#include <sys/syslog.h> 48#if defined(__FreeBSD__) && __FreeBSD__ >= 3 49#include <sys/random.h> 50#endif 51#include <sys/malloc.h> 52#include <sys/mbuf.h> 53 54#if defined (__OpenBSD__) 55#include <sys/md5k.h> 56#else 57#include <sys/md5.h> 58#endif 59 60#include <net/if.h> 61#include <net/netisr.h> 62#include <net/if_types.h> 63#include <net/route.h> 64#include <netinet/in.h> 65#include <netinet/in_systm.h> 66#include <netinet/ip.h> 67#include <net/slcompress.h> 68 69#if defined (__NetBSD__) || defined (__OpenBSD__) 70#include <machine/cpu.h> /* XXX for softnet */ 71#endif 72 73#include <machine/stdarg.h> 74 75#include <netinet/in_var.h> 76#ifdef INET 77#include <netinet/ip.h> 78#include <netinet/tcp.h> 79#endif 80 81#if defined (__FreeBSD__) || defined (__OpenBSD__) 82# include <netinet/if_ether.h> 83#else 84# include <net/ethertypes.h> 85#endif 86 87#ifdef IPX 88#include <netipx/ipx.h> 89#include <netipx/ipx_if.h> 90#endif 91 92#include <net/if_sppp.h> 93 94/* 95 * Frame Relay. 96 */ 97#define FR_UI 0x03 /* Unnumbered Information */ 98#define FR_IP 0xCC /* IP protocol identifier */ 99#define FR_PADDING 0x00 /* NLPID padding */ 100#define FR_SIGNALING 0x08 /* Q.933/T1.617 signaling identifier */ 101#define FR_SNAP 0x80 /* NLPID snap */ 102 103/* 104 * Header flags. 105 */ 106#define FR_DE 0x02 /* discard eligibility */ 107#define FR_FECN 0x04 /* forward notification */ 108#define FR_BECN 0x08 /* backward notification */ 109 110/* 111 * Signaling message types. 112 */ 113#define FR_MSG_ENQUIRY 0x75 /* status enquiry */ 114#define FR_MSG_STATUS 0x7d /* status */ 115 116#define FR_ENQUIRY_SIZE 14 117 118/* 119 * Message field types. 120 */ 121#define FR_FLD_RTYPE 0x01 /* report type */ 122#define FR_FLD_VERIFY 0x03 /* link verification */ 123#define FR_FLD_PVC 0x07 /* PVC status */ 124#define FR_FLD_LSHIFT5 0x95 /* locking shift 5 */ 125 126/* 127 * Report types. 128 */ 129#define FR_RTYPE_FULL 0 /* full status */ 130#define FR_RTYPE_SHORT 1 /* link verification only */ 131#define FR_RTYPE_SINGLE 2 /* single PVC status */ 132 133/* PVC status field. */ 134#define FR_DLCI_DELETE 0x04 /* PVC is deleted */ 135#define FR_DLCI_ACTIVE 0x02 /* PVC is operational */ 136#define FR_DLCI_NEW 0x08 /* PVC is new */ 137 138struct arp_req { 139 unsigned short htype; /* hardware type = ARPHRD_FRELAY */ 140 unsigned short ptype; /* protocol type = ETHERTYPE_IP */ 141 unsigned char halen; /* hardware address length = 2 */ 142 unsigned char palen; /* protocol address length = 4 */ 143 unsigned short op; /* ARP/RARP/InARP request/reply */ 144 unsigned short hsource; /* hardware source address */ 145 unsigned short psource1; /* protocol source */ 146 unsigned short psource2; 147 unsigned short htarget; /* hardware target address */ 148 unsigned short ptarget1; /* protocol target */ 149 unsigned short ptarget2; 150} __packed; 151 152#if defined(__FreeBSD__) && __FreeBSD__ >= 3 && __FreeBSD_version < 501113 153#define SPP_FMT "%s%d: " 154#define SPP_ARGS(ifp) (ifp)->if_name, (ifp)->if_unit 155#else 156#define SPP_FMT "%s: " 157#define SPP_ARGS(ifp) (ifp)->if_xname 158#endif 159 160/* almost every function needs these */ 161#define STDDCL \ 162 struct ifnet *ifp = SP2IFP(sp); \ 163 int debug = ifp->if_flags & IFF_DEBUG 164 165static void sppp_fr_arp (struct sppp *sp, struct arp_req *req, u_short addr); 166static void sppp_fr_signal (struct sppp *sp, unsigned char *h, int len); 167 168void sppp_fr_input (struct sppp *sp, struct mbuf *m) 169{ 170 STDDCL; 171 u_char *h = mtod (m, u_char*); 172 int isr = -1; 173 int dlci, hlen, proto; 174 175 /* Get the DLCI number. */ 176 if (m->m_pkthdr.len < 10) { 177bad: m_freem (m); 178 return; 179 } 180 dlci = (h[0] << 2 & 0x3f0) | (h[1] >> 4 & 0x0f); 181 182 /* Process signaling packets. */ 183 if (dlci == 0) { 184 sppp_fr_signal (sp, h, m->m_pkthdr.len); 185 m_freem (m); 186 return; 187 } 188 189 if (dlci != sp->fr_dlci) { 190 if (debug) 191 printf (SPP_FMT "Received packet from invalid DLCI %d\n", 192 SPP_ARGS(ifp), dlci); 193 goto bad; 194 } 195 196 /* Process the packet. */ 197 if (ntohs (*(short*) (h+2)) == ETHERTYPE_IP) { 198 /* Prehistoric IP framing? */ 199 h[2] = FR_UI; 200 h[3] = FR_IP; 201 } 202 if (h[2] != FR_UI) { 203 if (debug) 204 printf (SPP_FMT "Invalid frame relay header flag 0x%02x\n", 205 SPP_ARGS(ifp), h[2]); 206 goto bad; 207 } 208 switch (h[3]) { 209 default: 210 if (debug) 211 printf (SPP_FMT "Unsupported NLPID 0x%02x\n", 212 SPP_ARGS(ifp), h[3]); 213 goto bad; 214 215 case FR_PADDING: 216 if (h[4] != FR_SNAP) { 217 if (debug) 218 printf (SPP_FMT "Bad NLPID 0x%02x\n", 219 SPP_ARGS(ifp), h[4]); 220 goto bad; 221 } 222 if (h[5] || h[6] || h[7]) { 223 if (debug) 224 printf (SPP_FMT "Bad OID 0x%02x-0x%02x-0x%02x\n", 225 SPP_ARGS(ifp), 226 h[5], h[6], h[7]); 227 goto bad; 228 } 229 proto = ntohs (*(short*) (h+8)); 230 if (proto == ETHERTYPE_ARP) { 231 /* Process the ARP request. */ 232 if (m->m_pkthdr.len != 10 + sizeof (struct arp_req)) { 233 if (debug) 234 printf (SPP_FMT "Bad ARP request size = %d bytes\n", 235 SPP_ARGS(ifp), 236 m->m_pkthdr.len); 237 goto bad; 238 } 239 sppp_fr_arp (sp, (struct arp_req*) (h + 10), 240 h[0] << 8 | h[1]); 241 m_freem (m); 242 return; 243 } 244 hlen = 10; 245 break; 246 247 case FR_IP: 248 proto = ETHERTYPE_IP; 249 hlen = 4; 250 break; 251 } 252 253 /* Remove frame relay header. */ 254 m_adj (m, hlen); 255 256 switch (proto) { 257 default: 258 ++ifp->if_noproto; 259drop: ++ifp->if_ierrors; 260 ++ifp->if_iqdrops; 261 m_freem (m); 262 return; 263#ifdef INET 264 case ETHERTYPE_IP: 265 isr = NETISR_IP; 266 break; 267#endif 268#ifdef IPX 269 case ETHERTYPE_IPX: 270 isr = NETISR_IPX; 271 break; 272#endif 273#ifdef NETATALK 274 case ETHERTYPE_AT: 275 isr = NETISR_ATALK; 276 break; 277#endif 278 } 279 280 if (! (ifp->if_flags & IFF_UP)) 281 goto drop; 282 283 /* Check queue. */ 284 if (netisr_queue(isr, m)) { /* (0) on success. */ 285 if (debug) 286 log(LOG_DEBUG, SPP_FMT "protocol queue overflow\n", 287 SPP_ARGS(ifp)); 288 } 289} 290 291/* 292 * Add the frame relay header to the packet. 293 * For IP the header length is 4 bytes, 294 * for all other protocols - 10 bytes (RFC 1490). 295 */ 296struct mbuf *sppp_fr_header (struct sppp *sp, struct mbuf *m, 297 int family) 298{ 299 STDDCL; 300 u_char *h; 301 int type, hlen; 302 303 /* Prepend the space for Frame Relay header. */ 304 hlen = (family == AF_INET) ? 4 : 10; 305 M_PREPEND (m, hlen, M_DONTWAIT); 306 if (! m) 307 return 0; 308 h = mtod (m, u_char*); 309 310 /* Fill the header. */ 311 h[0] = sp->fr_dlci >> 2 & 0xfc; 312 h[1] = sp->fr_dlci << 4 | 1; 313 h[2] = FR_UI; 314 315 switch (family) { 316 default: 317 if (debug) 318 printf (SPP_FMT "Cannot handle address family %d\n", 319 SPP_ARGS(ifp), family); 320 m_freem (m); 321 return 0; 322#ifdef INET 323 case AF_INET: 324#if 0 /* Crashes on fragmented packets */ 325 /* 326 * Set the discard eligibility bit, if: 327 * 1) no fragmentation 328 * 2) length > 400 bytes 329 * 3a) the protocol is UDP or 330 * 3b) TCP data (no control bits) 331 */ 332 { 333 struct ip *ip = (struct ip*) (h + hlen); 334 struct tcphdr *tcp = (struct tcphdr*) ((long*)ip + ip->ip_hl); 335 336 if (! (ip->ip_off & ~IP_DF) && ip->ip_len > 400 && 337 (ip->ip_p == IPPROTO_UDP || 338 ip->ip_p == IPPROTO_TCP && ! tcp->th_flags)) 339 h[1] |= FR_DE; 340 } 341#endif 342 h[3] = FR_IP; 343 return m; 344#endif 345#ifdef IPX 346 case AF_IPX: 347 type = ETHERTYPE_IPX; 348 break; 349#endif 350#ifdef NS 351 case AF_NS: 352 type = 0x8137; 353 break; 354#endif 355#ifdef NETATALK 356 case AF_APPLETALK: 357 type = ETHERTYPE_AT; 358 break; 359#endif 360 } 361 h[3] = FR_PADDING; 362 h[4] = FR_SNAP; 363 h[5] = 0; 364 h[6] = 0; 365 h[7] = 0; 366 *(short*) (h+8) = htons(type); 367 return m; 368} 369 370/* 371 * Send periodical frame relay link verification messages via DLCI 0. 372 * Called every 10 seconds (default value of T391 timer is 10 sec). 373 * Every 6-th message is a full status request 374 * (default value of N391 counter is 6). 375 */ 376void sppp_fr_keepalive (struct sppp *sp) 377{ 378 STDDCL; 379 unsigned char *h, *p; 380 struct mbuf *m; 381 382 MGETHDR (m, M_DONTWAIT, MT_DATA); 383 if (! m) 384 return; 385 m->m_pkthdr.rcvif = 0; 386 387 h = mtod (m, u_char*); 388 p = h; 389 *p++ = 0; /* DLCI = 0 */ 390 *p++ = 1; 391 *p++ = FR_UI; 392 *p++ = FR_SIGNALING; /* NLPID = UNI call control */ 393 394 *p++ = 0; /* call reference length = 0 */ 395 *p++ = FR_MSG_ENQUIRY; /* message type = status enquiry */ 396 397 *p++ = FR_FLD_LSHIFT5; /* locking shift 5 */ 398 399 *p++ = FR_FLD_RTYPE; /* report type field */ 400 *p++ = 1; /* report type length = 1 */ 401 if (sp->pp_seq[IDX_LCP] % 6) 402 *p++ = FR_RTYPE_SHORT; /* link verification only */ 403 else 404 *p++ = FR_RTYPE_FULL; /* full status needed */ 405 406 if (sp->pp_seq[IDX_LCP] >= 255) 407 sp->pp_seq[IDX_LCP] = 0; 408 *p++ = FR_FLD_VERIFY; /* link verification type field */ 409 *p++ = 2; /* link verification field length = 2 */ 410 *p++ = ++sp->pp_seq[IDX_LCP]; /* our sequence number */ 411 *p++ = sp->pp_rseq[IDX_LCP]; /* last received sequence number */ 412 413 m->m_pkthdr.len = m->m_len = p - h; 414 if (debug) 415 printf (SPP_FMT "send lmi packet, seq=%d, rseq=%d\n", 416 SPP_ARGS(ifp), (u_char) sp->pp_seq[IDX_LCP], 417 (u_char) sp->pp_rseq[IDX_LCP]); 418 419 if (! IF_HANDOFF_ADJ(&sp->pp_cpq, m, ifp, 3)) 420 ++ifp->if_oerrors; 421} 422 423/* 424 * Process the frame relay Inverse ARP request. 425 */ 426static void sppp_fr_arp (struct sppp *sp, struct arp_req *req, 427 u_short his_hardware_address) 428{ 429 STDDCL; 430 struct mbuf *m; 431 struct arp_req *reply; 432 u_char *h; 433 u_short my_hardware_address; 434 u_long his_ip_address, my_ip_address; 435 436 if ((ntohs (req->htype) != ARPHRD_FRELAY || 437 ntohs (req->htype) != 16) || /* for BayNetworks routers */ 438 ntohs (req->ptype) != ETHERTYPE_IP) { 439 if (debug) 440 printf (SPP_FMT "Invalid ARP hardware/protocol type = 0x%x/0x%x\n", 441 SPP_ARGS(ifp), 442 ntohs (req->htype), ntohs (req->ptype)); 443 return; 444 } 445 if (req->halen != 2 || req->palen != 4) { 446 if (debug) 447 printf (SPP_FMT "Invalid ARP hardware/protocol address length = %d/%d\n", 448 SPP_ARGS(ifp), 449 req->halen, req->palen); 450 return; 451 } 452 switch (ntohs (req->op)) { 453 default: 454 if (debug) 455 printf (SPP_FMT "Invalid ARP op = 0x%x\n", 456 SPP_ARGS(ifp), ntohs (req->op)); 457 return; 458 459 case ARPOP_INVREPLY: 460 /* Ignore. */ 461 return; 462 463 case ARPOP_INVREQUEST: 464 my_hardware_address = ntohs (req->htarget); 465 his_ip_address = ntohs (req->psource1) << 16 | 466 ntohs (req->psource2); 467 my_ip_address = ntohs (req->ptarget1) << 16 | 468 ntohs (req->ptarget2); 469 break; 470 } 471 if (debug) 472 printf (SPP_FMT "got ARP request, source=0x%04x/%d.%d.%d.%d, target=0x%04x/%d.%d.%d.%d\n", 473 SPP_ARGS(ifp), ntohs (req->hsource), 474 (unsigned char) (his_ip_address >> 24), 475 (unsigned char) (his_ip_address >> 16), 476 (unsigned char) (his_ip_address >> 8), 477 (unsigned char) his_ip_address, 478 my_hardware_address, 479 (unsigned char) (my_ip_address >> 24), 480 (unsigned char) (my_ip_address >> 16), 481 (unsigned char) (my_ip_address >> 8), 482 (unsigned char) my_ip_address); 483 484 sppp_get_ip_addrs (sp, &my_ip_address, 0, 0); 485 if (! my_ip_address) 486 return; /* nothing to reply */ 487 488 if (debug) 489 printf (SPP_FMT "send ARP reply, source=0x%04x/%d.%d.%d.%d, target=0x%04x/%d.%d.%d.%d\n", 490 SPP_ARGS(ifp), my_hardware_address, 491 (unsigned char) (my_ip_address >> 24), 492 (unsigned char) (my_ip_address >> 16), 493 (unsigned char) (my_ip_address >> 8), 494 (unsigned char) my_ip_address, 495 his_hardware_address, 496 (unsigned char) (his_ip_address >> 24), 497 (unsigned char) (his_ip_address >> 16), 498 (unsigned char) (his_ip_address >> 8), 499 (unsigned char) his_ip_address); 500 501 /* Send the Inverse ARP reply. */ 502 MGETHDR (m, M_DONTWAIT, MT_DATA); 503 if (! m) 504 return; 505 m->m_pkthdr.len = m->m_len = 10 + sizeof (*reply); 506 m->m_pkthdr.rcvif = 0; 507 508 h = mtod (m, u_char*); 509 reply = (struct arp_req*) (h + 10); 510 511 h[0] = his_hardware_address >> 8; 512 h[1] = his_hardware_address; 513 h[2] = FR_UI; 514 h[3] = FR_PADDING; 515 h[4] = FR_SNAP; 516 h[5] = 0; 517 h[6] = 0; 518 h[7] = 0; 519 *(short*) (h+8) = htons (ETHERTYPE_ARP); 520 521 reply->htype = htons (ARPHRD_FRELAY); 522 reply->ptype = htons (ETHERTYPE_IP); 523 reply->halen = 2; 524 reply->palen = 4; 525 reply->op = htons (ARPOP_INVREPLY); 526 reply->hsource = htons (my_hardware_address); 527 reply->psource1 = htonl (my_ip_address); 528 reply->psource2 = htonl (my_ip_address) >> 16; 529 reply->htarget = htons (his_hardware_address); 530 reply->ptarget1 = htonl (his_ip_address); 531 reply->ptarget2 = htonl (his_ip_address) >> 16; 532 533 if (! IF_HANDOFF_ADJ(&sp->pp_cpq, m, ifp, 3)) 534 ++ifp->if_oerrors; 535} 536 537/* 538 * Process the input signaling packet (DLCI 0). 539 * The implemented protocol is ANSI T1.617 Annex D. 540 */ 541static void sppp_fr_signal (struct sppp *sp, unsigned char *h, int len) 542{ 543 STDDCL; 544 u_char *p; 545 int dlci; 546 547 if (h[2] != FR_UI || h[3] != FR_SIGNALING || h[4] != 0) { 548 if (debug) 549 printf (SPP_FMT "Invalid signaling header\n", 550 SPP_ARGS(ifp)); 551bad: if (debug) { 552 printf ("%02x", *h++); 553 while (--len > 0) 554 printf ("-%02x", *h++); 555 printf ("\n"); 556 } 557 return; 558 } 559 if (h[5] == FR_MSG_ENQUIRY) { 560 if (len == FR_ENQUIRY_SIZE && 561 h[12] == (u_char) sp->pp_seq[IDX_LCP]) { 562 sp->pp_seq[IDX_LCP] = random(); 563 printf (SPP_FMT "loopback detected\n", 564 SPP_ARGS(ifp)); 565 } 566 return; 567 } 568 if (h[5] != FR_MSG_STATUS) { 569 if (debug) 570 printf (SPP_FMT "Unknown signaling message: 0x%02x\n", 571 SPP_ARGS(ifp), h[5]); 572 goto bad; 573 } 574 575 /* Parse message fields. */ 576 for (p=h+6; p<h+len; ) { 577 switch (*p) { 578 default: 579 if (debug) 580 printf (SPP_FMT "Unknown signaling field 0x%x\n", 581 SPP_ARGS(ifp), *p); 582 break; 583 case FR_FLD_LSHIFT5: 584 case FR_FLD_RTYPE: 585 /* Ignore. */ 586 break; 587 case FR_FLD_VERIFY: 588 if (p[1] != 2) { 589 if (debug) 590 printf (SPP_FMT "Invalid signaling verify field length %d\n", 591 SPP_ARGS(ifp), p[1]); 592 break; 593 } 594 sp->pp_rseq[IDX_LCP] = p[2]; 595 if (debug) { 596 printf (SPP_FMT "got lmi reply rseq=%d, seq=%d", 597 SPP_ARGS(ifp), p[2], p[3]); 598 if (p[3] != (u_char) sp->pp_seq[IDX_LCP]) 599 printf (" (really %d)", 600 (u_char) sp->pp_seq[IDX_LCP]); 601 printf ("\n"); 602 } 603 break; 604 case FR_FLD_PVC: 605 if (p[1] < 3) { 606 if (debug) 607 printf (SPP_FMT "Invalid PVC status length %d\n", 608 SPP_ARGS(ifp), p[1]); 609 break; 610 } 611 dlci = (p[2] << 4 & 0x3f0) | (p[3] >> 3 & 0x0f); 612 if (! sp->fr_dlci) 613 sp->fr_dlci = dlci; 614 if (sp->fr_status != p[4]) 615 printf (SPP_FMT "DLCI %d %s%s\n", 616 SPP_ARGS(ifp), dlci, 617 p[4] & FR_DLCI_DELETE ? "deleted" : 618 p[4] & FR_DLCI_ACTIVE ? "active" : "passive", 619 p[4] & FR_DLCI_NEW ? ", new" : ""); 620 sp->fr_status = p[4]; 621 break; 622 } 623 if (*p & 0x80) 624 ++p; 625 else if (p < h+len+1 && p[1]) 626 p += 2 + p[1]; 627 else { 628 if (debug) 629 printf (SPP_FMT "Invalid signaling field 0x%x\n", 630 SPP_ARGS(ifp), *p); 631 goto bad; 632 } 633 } 634} 635