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