From owner-freebsd-bugs Fri Nov 12 8: 0:28 1999 Delivered-To: freebsd-bugs@freebsd.org Received: from freefall.freebsd.org (freefall.FreeBSD.ORG [204.216.27.21]) by hub.freebsd.org (Postfix) with ESMTP id 821E414F27 for ; Fri, 12 Nov 1999 08:00:01 -0800 (PST) (envelope-from gnats@FreeBSD.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.9.3/8.9.2) id IAA85897; Fri, 12 Nov 1999 08:00:01 -0800 (PST) (envelope-from gnats@FreeBSD.org) Received: from crox.cronyx.ru (crox.cronyx.ru [144.206.181.72]) by hub.freebsd.org (Postfix) with ESMTP id D528714E38 for ; Fri, 12 Nov 1999 07:59:01 -0800 (PST) (envelope-from vak@crox.cronyx.ru) Received: (from vak@localhost) by crox.cronyx.ru (8.9.3/8.9.3) id TAA00364; Fri, 12 Nov 1999 19:02:06 +0300 (MSK) (envelope-from vak) Message-Id: <199911121602.TAA00364@crox.cronyx.ru> Date: Fri, 12 Nov 1999 19:02:06 +0300 (MSK) From: vak@cronyx.ru To: FreeBSD-gnats-submit@freebsd.org X-Send-Pr-Version: 3.2 Subject: kern/14843: Added Frame Relay support Sender: owner-freebsd-bugs@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.org >Number: 14843 >Category: kern >Synopsis: Added support of Frame Relay protocol >Confidential: no >Severity: serious >Priority: medium >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: change-request >Submitter-Id: current-users >Arrival-Date: Fri Nov 12 08:00:01 PST 1999 >Closed-Date: >Last-Modified: >Originator: Serge V.Vakulenko >Release: FreeBSD 3.3-RELEASE i386 >Organization: Cronyx >Environment: FreeBSD router with serial adapters installed. >Description: The in-kernel implementation of point-to-point protocols supported only PPP and Cisco/HDLC protocols. This patch adds Frame Relay support, with ANSI T1.617 signaling. >How-To-Repeat: >Fix: --- if_sppp33.h Fri Nov 12 17:09:39 1999 +++ if_sppp.h Fri Nov 12 17:10:20 1999 @@ -99,6 +99,8 @@ struct sipcp ipcp; /* IPCP params */ struct sauth myauth; /* auth params, i'm peer */ struct sauth hisauth; /* auth params, i'm authenticator */ + u_short fr_dlci; /* Frame Relay DLCI number, 16..1023 */ + u_char fr_status; /* PVC status, active/new/delete */ /* * These functions are filled in by sppp_attach(), and are * expected to be used by the lower layer (hardware) drivers @@ -133,7 +135,7 @@ #define PP_KEEPALIVE 0x01 /* use keepalive protocol */ #define PP_CISCO 0x02 /* use Cisco protocol instead of PPP */ - /* 0x04 was PP_TIMO */ +#define PP_FR 0x04 /* use Frame Relay protocol instead of PPP */ #define PP_CALLIN 0x08 /* we are being called */ #define PP_NEEDAUTH 0x10 /* remote requested authentication */ --- if_sppps33.c Fri Nov 12 18:21:18 1999 +++ if_spppsubr.c Fri Nov 12 18:50:57 1999 @@ -1,8 +1,12 @@ /* - * Synchronous PPP/Cisco link level subroutines. + * Synchronous PPP/Cisco/Frame Relay link level subroutines. * Keepalive protocol implemented in both Cisco and PPP modes. + * ANSI T1.617-compaible link management signaling + * implemented for Frame Relay mode. + * Cisco-type Frame Relay framing added, thanks Alex Tutubalin. + * Only one DLCI per channel for now. * - * Copyright (C) 1994-1996 Cronyx Engineering Ltd. + * Copyright (C) 1994-1999 Cronyx Engineering Ltd. * Author: Serge Vakulenko, * * Heavily revamped to conform to RFC 1661. @@ -226,6 +230,63 @@ #define CISCO_PACKET_LEN 18 /* + * Frame Relay. + */ +#define FR_IP 0xCC /* IP protocol identifier */ +#define FR_PADDING 0x00 /* NLPID padding */ +#define FR_SIGNALING 0x08 /* Q.933/T1.617 signaling identifier */ +#define FR_SNAP 0x80 /* NLPID snap */ + +/* + * Header flags. + */ +#define FR_DE 0x02 /* discard eligibility */ +#define FR_FECN 0x04 /* forward notification */ +#define FR_BECN 0x08 /* backward notification */ + +/* + * Signaling message types. + */ +#define FR_MSG_ENQUIRY 0x75 /* status enquiry */ +#define FR_MSG_STATUS 0x7d /* status */ + +#define FR_ENQUIRY_SIZE 14 + +/* + * Message field types. + */ +#define FR_FLD_RTYPE 0x01 /* report type */ +#define FR_FLD_VERIFY 0x03 /* link verification */ +#define FR_FLD_PVC 0x07 /* PVC status */ +#define FR_FLD_LSHIFT5 0x95 /* locking shift 5 */ + +/* + * Report types. + */ +#define FR_RTYPE_FULL 0 /* full status */ +#define FR_RTYPE_SHORT 1 /* link verification only */ +#define FR_RTYPE_SINGLE 2 /* single PVC status */ + +/* PVC status field. */ +#define FR_DLCI_DELETE 0x04 /* PVC is deleted */ +#define FR_DLCI_ACTIVE 0x02 /* PVC is operational */ +#define FR_DLCI_NEW 0x08 /* PVC is new */ + +struct arp_req { + unsigned short htype; /* hardware type = ARPHRD_FRELAY */ + unsigned short ptype; /* protocol type = ETHERTYPE_IP */ + unsigned char halen; /* hardware address length = 2 */ + unsigned char palen; /* protocol address length = 4 */ + unsigned short op; /* ARP/RARP/InARP request/reply */ + unsigned short hsource; /* hardware source address */ + unsigned short psource1; /* protocol source */ + unsigned short psource2; + unsigned short htarget; /* hardware target address */ + unsigned short ptarget1; /* protocol target */ + unsigned short ptarget2; +}; + +/* * We follow the spelling and capitalization of RFC 1661 here, to make * it easier comparing with the standard. Please refer to this RFC in * case you can't make sense out of these abbreviation; it will also @@ -295,6 +356,12 @@ static void sppp_cisco_send(struct sppp *sp, int type, long par1, long par2); static void sppp_cisco_input(struct sppp *sp, struct mbuf *m); +static void sppp_fr_input (struct sppp *sp, struct mbuf *m); +static struct mbuf *sppp_fr_header (struct sppp *sp, struct mbuf *m, int fam); +static void sppp_fr_keepalive (struct sppp *sp); +static void sppp_fr_arp (struct sppp *sp, struct arp_req *req, u_short addr); +static void sppp_fr_signal (struct sppp *sp, unsigned char *h, int len); + static void sppp_cp_input(const struct cp *cp, struct sppp *sp, struct mbuf *m); static void sppp_cp_send(struct sppp *sp, u_short proto, u_char type, @@ -458,6 +525,11 @@ return; } + if (sp->pp_flags & PP_FR) { + sppp_fr_input (sp, m); + return; + } + /* Get PPP header. */ h = mtod (m, struct ppp_header*); m_adj (m, PPP_HEADER_LEN); @@ -663,7 +735,7 @@ * become invalid. So we * - don't let packets with src ip addr 0 thru * - we flag TCP packets with src ip 0 as an error - */ + */ if(ip->ip_src.s_addr == INADDR_ANY) /* -hm */ { @@ -674,7 +746,7 @@ else return(0); } - + /* * Put low delay, telnet, rlogin and ftp control packets * in front of the queue. @@ -694,12 +766,20 @@ } #endif + if (sp->pp_flags & PP_FR) { + /* Add frame relay header. */ + m = sppp_fr_header (sp, m, dst->sa_family); + if (! m) + goto nobufs; + goto out; + } + /* * Prepend general data packet PPP header. For now, IP only. */ M_PREPEND (m, PPP_HEADER_LEN, M_DONTWAIT); if (! m) { - if (debug) +nobufs: if (debug) log(LOG_DEBUG, SPP_FMT "no memory for transmit header\n", SPP_ARGS(ifp)); ++ifp->if_oerrors; @@ -771,7 +851,7 @@ * Queue message on interface, and start output if interface * not yet active. */ - if (IF_QFULL (ifq)) { +out: if (IF_QFULL (ifq)) { IF_DROP (&ifp->if_snd); m_freem (m); ++ifp->if_oerrors; @@ -898,7 +978,8 @@ */ IF_DEQUEUE(&sp->pp_cpq, m); if (m == NULL && - (sppp_ncp_check(sp) || (sp->pp_flags & PP_CISCO) != 0)) { + (sppp_ncp_check(sp) || (sp->pp_flags & PP_CISCO) != 0 || + (sp->pp_flags & PP_FR) != 0)) { IF_DEQUEUE(&sp->pp_fastq, m); if (m == NULL) IF_DEQUEUE (&sp->pp_if.if_snd, m); @@ -922,7 +1003,8 @@ m = sp->pp_cpq.ifq_head; if (m == NULL && (sp->pp_phase == PHASE_NETWORK || - (sp->pp_flags & PP_CISCO) != 0)) + (sp->pp_flags & PP_CISCO) != 0 || + (sp->pp_flags & PP_FR) != 0)) if ((m = sp->pp_fastq.ifq_head) == NULL) m = sp->pp_if.if_snd.ifq_head; splx (s); @@ -963,11 +1045,14 @@ } if (going_up || going_down) - lcp.Close(sp); + if (! (sp->pp_flags & PP_CISCO) && + ! (sp->pp_flags & PP_FR)) + lcp.Close(sp); if (going_up && newmode == 0) { /* neither auto-dial nor passive */ ifp->if_flags |= IFF_RUNNING; - if (!(sp->pp_flags & PP_CISCO)) + if (! (sp->pp_flags & PP_CISCO) && + ! (sp->pp_flags & PP_FR)) lcp.Open(sp); } else if (going_down) { sppp_flush(ifp); @@ -1117,7 +1202,7 @@ #if defined(__FreeBSD__) && __FreeBSD__ >= 3 getmicrouptime(&tv); #endif - + MGETHDR (m, M_DONTWAIT, MT_DATA); if (! m) return; @@ -1738,7 +1823,7 @@ case STATE_STOPPING: sppp_cp_send(sp, cp->proto, TERM_REQ, ++sp->pp_seq, 0, 0); - TIMEOUT(cp->TO, (void *)sp, sp->lcp.timeout, + TIMEOUT(cp->TO, (void *)sp, sp->lcp.timeout, sp->ch[cp->protoidx]); break; case STATE_REQ_SENT: @@ -1779,7 +1864,7 @@ case STATE_REQ_SENT: case STATE_ACK_RCVD: case STATE_ACK_SENT: - TIMEOUT(cp->TO, (void *)sp, sp->lcp.timeout, + TIMEOUT(cp->TO, (void *)sp, sp->lcp.timeout, sp->ch[cp->protoidx]); break; } @@ -2322,7 +2407,7 @@ /* notify low-level driver of state change */ if (sp->pp_chg) sp->pp_chg(sp, (int)sp->pp_phase); - + if (sp->pp_phase == PHASE_NETWORK) /* if no NCP is starting, close down */ sppp_lcp_check_and_close(sp); @@ -2641,7 +2726,7 @@ (hisaddr == 1 && desiredaddr != 0)) { /* * Peer's address is same as our value, - * or we have set it to 0.0.0.1 to + * or we have set it to 0.0.0.1 to * indicate that we do not really care, * this is agreeable. Gonna conf-ack * it. @@ -3026,7 +3111,7 @@ } break; } - + if (debug) { log(LOG_DEBUG, SPP_FMT "chap input <%s id=0x%x len=%d name=", @@ -3136,7 +3221,7 @@ sppp_print_string(sp->hisauth.name, sppp_strnlen(sp->hisauth.name, AUTHNAMELEN)); addlog("\n"); - } + } if (debug) { log(LOG_DEBUG, SPP_FMT "chap input(%s) " "<%s id=0x%x len=%d name=", @@ -3812,6 +3897,11 @@ ! (ifp->if_flags & IFF_RUNNING)) continue; + if (sp->pp_flags & PP_FR) { + sppp_fr_keepalive (sp); + continue; + } + /* No keepalive in PPP mode if LCP not opened yet. */ if (! (sp->pp_flags & PP_CISCO) && sp->pp_phase < PHASE_AUTHENTICATE) @@ -3958,7 +4048,7 @@ si->sin_addr.s_addr = htonl(src); /* add new route */ - error = rtinit(ifa, (int)RTM_ADD, RTF_HOST); + error = rtinit(ifa, (int)RTM_ADD, RTF_HOST); if (debug && error) { log(LOG_DEBUG, SPP_FMT "sppp_set_ip_addr: rtinit ADD failed, error=%d", @@ -3966,7 +4056,7 @@ } #endif } -} +} static int sppp_params(struct sppp *sp, u_long cmd, void *data) @@ -4098,7 +4188,7 @@ /* if no NCP is starting, all this was in vain, close down */ sppp_lcp_check_and_close(sp); } - + static const char * sppp_cp_type_name(u_char type) @@ -4271,4 +4361,500 @@ sppp_null(struct sppp *unused) { /* do just nothing */ +} + +/* + * Frame Relay link level subroutines. + * ANSI T1.617-compatible link management signaling implemented. + * Only one DLCI per channel for now. + * Copyright (C) 1994-1999 Cronyx Engineering Ltd. + * Author: Serge Vakulenko, + */ +static void sppp_fr_input (struct sppp *sp, struct mbuf *m) +{ + STDDCL; + u_char *h = mtod (m, u_char*); + struct ifqueue *inq; + int dlci, hlen, proto, s; + + /* Get the DLCI number. */ + if (m->m_pkthdr.len < 10) { +bad: m_freem (m); + return; + } + dlci = (h[0] << 2 & 0x3f0) | (h[1] >> 4 & 0x0f); + + /* Process signaling packets. */ + if (dlci == 0) { + sppp_fr_signal (sp, h, m->m_pkthdr.len); + m_freem (m); + return; + } + + if (dlci != sp->fr_dlci) { + if (debug) + printf ("%s%d: Received packet from invalid DLCI %d\n", + ifp->if_name, ifp->if_unit, dlci); + goto bad; + } + + /* Process the packet. */ + if (ntohs (*(short*) (h+2)) == ETHERTYPE_IP) + goto proto_ip; /* cisco framing */ + if (h[2] != PPP_UI) { + if (debug) + printf ("%s%d: Invalid frame relay header flag 0x%02x\n", + ifp->if_name, ifp->if_unit, h[2]); + goto bad; + } + switch (h[3]) { + default: + if (debug) + printf ("%s%d: Unsupported NLPID 0x%02x\n", + ifp->if_name, ifp->if_unit, h[3]); + goto bad; + + case FR_PADDING: + if (h[4] != FR_SNAP) { + if (debug) + printf ("%s%d: Bad NLPID 0x%02x\n", + ifp->if_name, ifp->if_unit, h[4]); + goto bad; + } + if (h[5] || h[6] || h[7]) { + if (debug) + printf ("%s%d: Bad OID 0x%02x-0x%02x-0x%02x\n", + ifp->if_name, ifp->if_unit, + h[5], h[6], h[7]); + goto bad; + } + proto = ntohs (*(short*) (h+8)); + if (proto == ETHERTYPE_ARP) { + /* Process the ARP request. */ + if (m->m_pkthdr.len != 10 + sizeof (struct arp_req)) { + if (debug) + printf ("%s%d: Bad ARP request size = %d bytes\n", + ifp->if_name, ifp->if_unit, + m->m_pkthdr.len); + goto bad; + } + sppp_fr_arp (sp, (struct arp_req*) (h + 10), + h[0] << 8 | h[1]); + m_freem (m); + return; + } + hlen = 10; + break; + + case FR_IP: +proto_ip: proto = ETHERTYPE_IP; + hlen = 4; + break; + } + + /* Remove frame relay header. */ + m_adj (m, hlen); + + switch (proto) { + default: + ++ifp->if_noproto; +drop: ++ifp->if_ierrors; + ++ifp->if_iqdrops; + m_freem (m); + return; +#ifdef INET + case ETHERTYPE_IP: + schednetisr (NETISR_IP); + inq = &ipintrq; + break; +#endif +#ifdef IPX + case ETHERTYPE_IPX: + schednetisr (NETISR_IPX); + inq = &ipxintrq; + break; +#endif +#ifdef NS + case 0x8137: /* Novell Ethernet_II Ethernet TYPE II */ + schednetisr (NETISR_NS); + inq = &nsintrq; + break; +#endif +#ifdef NETATALK + case ETHERTYPE_AT: + schednetisr (NETISR_ATALK); + inq = &atintrq1; + break; +#endif + } + + if (! (ifp->if_flags & IFF_UP)) + goto drop; + + /* Check queue. */ + s = splimp(); + if (IF_QFULL (inq)) { + /* Queue overflow. */ + IF_DROP(inq); + splx(s); + if (debug) + log(LOG_DEBUG, SPP_FMT "protocol queue overflow\n", + SPP_ARGS(ifp)); + goto drop; + } + IF_ENQUEUE(inq, m); + splx(s); +} + +/* + * Add the frame relay header to the packet. + * For IP the header length is 4 bytes, + * for all other protocols - 10 bytes (RFC 1490). + */ +static struct mbuf *sppp_fr_header (struct sppp *sp, struct mbuf *m, + int family) +{ + STDDCL; + u_char *h; + int type, hlen; + + /* Prepend the space for Frame Relay header. */ + hlen = (family == AF_INET) ? 4 : 10; + M_PREPEND (m, hlen, M_DONTWAIT); + if (! m) + return 0; + h = mtod (m, u_char*); + + /* Fill the header. */ + h[0] = sp->fr_dlci >> 2 & 0xfc; + h[1] = sp->fr_dlci << 4 | 1; + h[2] = PPP_UI; + + switch (family) { + default: + if (debug) + printf ("%s%d: cannot handle address family %d\n", + ifp->if_name, ifp->if_unit, family); + m_freem (m); + return 0; +#ifdef INET + case AF_INET: +#if 0 /* Crashes on fragmented packets */ + /* + * Set the discard eligibility bit, if: + * 1) no fragmentation + * 2) length > 400 bytes + * 3a) the protocol is UDP or + * 3b) TCP data (no control bits) + */ + { + struct ip *ip = (struct ip*) (h + hlen); + struct tcphdr *tcp = (struct tcphdr*) ((long*)ip + ip->ip_hl); + + if (! (ip->ip_off & ~IP_DF) && ip->ip_len > 400 && + (ip->ip_p == IPPROTO_UDP || + ip->ip_p == IPPROTO_TCP && ! tcp->th_flags)) + h[1] |= FR_DE; + } +#endif + h[3] = FR_IP; + return m; +#endif +#ifdef IPX + case AF_IPX: + type = ETHERTYPE_IPX; + break; +#endif +#ifdef NS + case AF_NS: + type = 0x8137; + break; +#endif +#ifdef NETATALK + case AF_APPLETALK: + type = ETHERTYPE_AT; + break; +#endif + } + h[3] = FR_PADDING; + h[4] = FR_SNAP; + h[5] = 0; + h[6] = 0; + h[7] = 0; + *(short*) (h+8) = htons(type); + return m; +} + +/* + * Send periodical frame relay link verification messages via DLCI 0. + * Called every 10 seconds (default value of T391 timer is 10 sec). + * Every 6-th message is a full status request + * (default value of N391 counter is 6). + */ +static void sppp_fr_keepalive (struct sppp *sp) +{ + STDDCL; + unsigned char *h, *p; + struct mbuf *m; + + MGETHDR (m, M_DONTWAIT, MT_DATA); + if (! m) + return; + m->m_pkthdr.rcvif = 0; + + h = mtod (m, u_char*); + p = h; + *p++ = 0; /* DLCI = 0 */ + *p++ = 1; + *p++ = PPP_UI; + *p++ = FR_SIGNALING; /* NLPID = UNI call control */ + + *p++ = 0; /* call reference length = 0 */ + *p++ = FR_MSG_ENQUIRY; /* message type = status enquiry */ + + *p++ = FR_FLD_LSHIFT5; /* locking shift 5 */ + + *p++ = FR_FLD_RTYPE; /* report type field */ + *p++ = 1; /* report type length = 1 */ + if (sp->pp_seq % 6) + *p++ = FR_RTYPE_SHORT; /* link verification only */ + else + *p++ = FR_RTYPE_FULL; /* full status needed */ + + *p++ = FR_FLD_VERIFY; /* link verification type field */ + *p++ = 2; /* link verification field length = 2 */ + *p++ = ++sp->pp_seq; /* our sequence number */ + *p++ = sp->pp_rseq; /* last received sequence number */ + + m->m_pkthdr.len = m->m_len = p - h; + if (debug) + printf ("%s%d: send lmi packet, seq=%d, rseq=%d\n", + ifp->if_name, ifp->if_unit, (u_char) sp->pp_seq, + (u_char) sp->pp_rseq); + + if (IF_QFULL (&sp->pp_fastq)) { + IF_DROP (&ifp->if_snd); + m_freem (m); + } else + IF_ENQUEUE (&sp->pp_fastq, m); + if (! (ifp->if_flags & IFF_OACTIVE)) + (*ifp->if_start) (ifp); + ifp->if_obytes += m->m_pkthdr.len + 3; +} + +/* + * Process the frame relay Inverse ARP request. + */ +static void sppp_fr_arp (struct sppp *sp, struct arp_req *req, + u_short his_hardware_address) +{ + STDDCL; + struct mbuf *m; + struct arp_req *reply; + u_char *h; + u_short my_hardware_address; + u_long his_ip_address, my_ip_address; + + if ((ntohs (req->htype) != ARPHRD_FRELAY || + ntohs (req->htype) != 16) || /* for BayNetworks routers */ + ntohs (req->ptype) != ETHERTYPE_IP) { + if (debug) + printf ("%s%d: Invalid ARP hardware/protocol type = 0x%x/0x%x\n", + ifp->if_name, ifp->if_unit, + ntohs (req->htype), ntohs (req->ptype)); + return; + } + if (req->halen != 2 || req->palen != 4) { + if (debug) + printf ("%s%d: Invalid ARP hardware/protocol address length = %d/%d\n", + ifp->if_name, ifp->if_unit, + req->halen, req->palen); + return; + } + switch (ntohs (req->op)) { + default: + if (debug) + printf ("%s%d: Invalid ARP op = 0x%x\n", + ifp->if_name, ifp->if_unit, ntohs (req->op)); + return; + + case ARPOP_INVREPLY: + /* Ignore. */ + return; + + case ARPOP_INVREQUEST: + sppp_get_ip_addrs (sp, &my_ip_address, 0, 0); + if (! my_ip_address) + return; /* nothing to reply */ + my_hardware_address = ntohs (req->htarget); + his_ip_address = ntohs (req->psource1) << 16 | + ntohs (req->psource2); + my_ip_address = ntohs (req->ptarget1) << 16 | + ntohs (req->ptarget2); + break; + } + if (debug) { + printf ("%s%d: got ARP request, source=0x%04x/%d.%d.%d.%d, target=0x%04x/%d.%d.%d.%d\n", + ifp->if_name, ifp->if_unit, ntohs (req->hsource), + (unsigned char) (his_ip_address >> 24), + (unsigned char) (his_ip_address >> 16), + (unsigned char) (his_ip_address >> 8), + (unsigned char) his_ip_address, + my_hardware_address, + (unsigned char) (my_ip_address >> 24), + (unsigned char) (my_ip_address >> 16), + (unsigned char) (my_ip_address >> 8), + (unsigned char) my_ip_address); + printf ("%s%d: send ARP reply, source=0x%04x/%d.%d.%d.%d, target=0x%04x/%d.%d.%d.%d\n", + ifp->if_name, ifp->if_unit, my_hardware_address, + (unsigned char) (my_ip_address >> 24), + (unsigned char) (my_ip_address >> 16), + (unsigned char) (my_ip_address >> 8), + (unsigned char) my_ip_address, + his_hardware_address, + (unsigned char) (his_ip_address >> 24), + (unsigned char) (his_ip_address >> 16), + (unsigned char) (his_ip_address >> 8), + (unsigned char) his_ip_address); + } + + /* Send the Inverse ARP reply. */ + MGETHDR (m, M_DONTWAIT, MT_DATA); + if (! m) + return; + m->m_pkthdr.len = m->m_len = 10 + sizeof (*reply); + m->m_pkthdr.rcvif = 0; + + h = mtod (m, u_char*); + reply = (struct arp_req*) (h + 10); + + h[0] = his_hardware_address >> 8; + h[1] = his_hardware_address; + h[2] = PPP_UI; + h[3] = FR_PADDING; + h[4] = FR_SNAP; + h[5] = 0; + h[6] = 0; + h[7] = 0; + *(short*) (h+8) = htons (ETHERTYPE_ARP); + + reply->htype = htons (ARPHRD_FRELAY); + reply->ptype = htons (ETHERTYPE_IP); + reply->halen = 2; + reply->palen = 4; + reply->op = htons (ARPOP_INVREPLY); + reply->hsource = htons (my_hardware_address); + reply->psource1 = htonl (my_ip_address); + reply->psource2 = htonl (my_ip_address) >> 16; + reply->htarget = htons (his_hardware_address); + reply->ptarget1 = htonl (his_ip_address); + reply->ptarget2 = htonl (his_ip_address) >> 16; + + if (IF_QFULL (&sp->pp_fastq)) { + IF_DROP (&ifp->if_snd); + m_freem (m); + } else + IF_ENQUEUE (&sp->pp_fastq, m); + if (! (ifp->if_flags & IFF_OACTIVE)) + (*ifp->if_start) (ifp); + ifp->if_obytes += m->m_pkthdr.len + 3; +} + +/* + * Process the input signaling packet (DLCI 0). + * The implemented protocol is ANSI T1.617 Annex D. + */ +static void sppp_fr_signal (struct sppp *sp, unsigned char *h, int len) +{ + STDDCL; + u_char *p; + int dlci; + + if (h[2] != PPP_UI || h[3] != FR_SIGNALING || h[4] != 0) { + if (debug) + printf ("%s%d: Invalid signaling header\n", + ifp->if_name, ifp->if_unit); +bad: if (debug) { + printf ("%02x", *h++); + while (--len > 0) + printf ("-%02x", *h++); + printf ("\n"); + } + return; + } + if (h[5] == FR_MSG_ENQUIRY) { + if (len == FR_ENQUIRY_SIZE && + h[12] == (u_char) sp->pp_seq) { + sp->pp_seq = random(); + printf ("%s%d: loopback detected\n", + ifp->if_name, ifp->if_unit); + } + return; + } + if (h[5] != FR_MSG_STATUS) { + if (debug) + printf ("%s%d: Unknown signaling message: 0x%02x\n", + ifp->if_name, ifp->if_unit, h[5]); + goto bad; + } + + /* Parse message fields. */ + for (p=h+6; pif_name, ifp->if_unit, *p); + break; + case FR_FLD_LSHIFT5: + case FR_FLD_RTYPE: + /* Ignore. */ + break; + case FR_FLD_VERIFY: + if (p[1] != 2) { + if (debug) + printf ("%s%d: Invalid signaling verify field length %d\n", + ifp->if_name, ifp->if_unit, p[1]); + break; + } + sp->pp_rseq = p[2]; + if (debug) { + printf ("%s%d: got lmi reply rseq=%d, seq=%d", + ifp->if_name, ifp->if_unit, p[2], p[3]); + if (p[3] != (u_char) sp->pp_seq) + printf (" (really %d)", + (u_char) sp->pp_seq); + printf ("\n"); + } + break; + case FR_FLD_PVC: + if (p[1] < 3) { + if (debug) + printf ("%s%d: Invalid PVC status length %d\n", + ifp->if_name, ifp->if_unit, p[1]); + break; + } + dlci = (p[2] << 4 & 0x3f0) | (p[3] >> 3 & 0x0f); + if (! sp->fr_dlci) + sp->fr_dlci = dlci; + if (sp->fr_status != p[4]) + printf ("%s%d: DLCI %d %s%s\n", + ifp->if_name, ifp->if_unit, dlci, + p[4] & FR_DLCI_DELETE ? "deleted" : + p[4] & FR_DLCI_ACTIVE ? "active" : "passive", + p[4] & FR_DLCI_NEW ? ", new" : ""); + sp->fr_status = p[4]; + break; + } + if (*p & 0x80) + ++p; + else if (p < h+len+1 && p[1]) + p += 2 + p[1]; + else { + if (debug) + printf ("%s%d: Invalid signaling field 0x%x\n", + ifp->if_name, ifp->if_unit, *p); + goto bad; + } + } } >Release-Note: >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message