11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Generic HDLC support routines for Linux 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Frame Relay support 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa * Copyright (C) 1999 - 2006 Krzysztof Halasa <khc@pm.waw.pl> 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify it 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * under the terms of version 2 of the GNU General Public License 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as published by the Free Software Foundation. 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Theory of PVC state 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DCE mode: 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (exist,new) -> 0,0 when "PVC create" or if "link unreliable" 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0,x -> 1,1 if "link reliable" when sending FULL STATUS 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1,1 -> 1,0 if received FULL STATUS ACK 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (active) -> 0 when "ifconfig PVC down" or "link unreliable" or "PVC create" 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds -> 1 when "PVC up" and (exist,new) = 1,0 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DTE mode: 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (exist,new,active) = FULL STATUS if "link reliable" 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds = 0, 0, 0 if "link unreliable" 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds No LMI: 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds active = open and "link reliable" 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds exist = new = not used 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa CCITT LMI: ITU-T Q.933 Annex A 31b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa ANSI LMI: ANSI T1.617 Annex D 32b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa CISCO LMI: the original, aka "Gang of Four" LMI 33b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 374dfce4075aa4e2eee35e52a78dbabfe37d94c908Krzysztof Hałasa#include <linux/etherdevice.h> 384dfce4075aa4e2eee35e52a78dbabfe37d94c908Krzysztof Hałasa#include <linux/hdlc.h> 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/if_arp.h> 404dfce4075aa4e2eee35e52a78dbabfe37d94c908Krzysztof Hałasa#include <linux/inetdevice.h> 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 424dfce4075aa4e2eee35e52a78dbabfe37d94c908Krzysztof Hałasa#include <linux/kernel.h> 434dfce4075aa4e2eee35e52a78dbabfe37d94c908Krzysztof Hałasa#include <linux/module.h> 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pkt_sched.h> 454dfce4075aa4e2eee35e52a78dbabfe37d94c908Krzysztof Hałasa#include <linux/poll.h> 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/rtnetlink.h> 474dfce4075aa4e2eee35e52a78dbabfe37d94c908Krzysztof Hałasa#include <linux/skbuff.h> 484dfce4075aa4e2eee35e52a78dbabfe37d94c908Krzysztof Hałasa#include <linux/slab.h> 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef DEBUG_PKT 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef DEBUG_ECN 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef DEBUG_LINK 53eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa#undef DEBUG_PROTO 54eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa#undef DEBUG_PVC 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 56b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa#define FR_UI 0x03 57b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa#define FR_PAD 0x00 58b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa 59b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa#define NLPID_IP 0xCC 60b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa#define NLPID_IPV6 0x8E 61b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa#define NLPID_SNAP 0x80 62b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa#define NLPID_PAD 0x00 63b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa#define NLPID_CCITT_ANSI_LMI 0x08 64b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa#define NLPID_CISCO_LMI 0x09 65b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa 66b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa 67b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa#define LMI_CCITT_ANSI_DLCI 0 /* LMI DLCI */ 68b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa#define LMI_CISCO_DLCI 1023 69b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa 70b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa#define LMI_CALLREF 0x00 /* Call Reference */ 71b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa#define LMI_ANSI_LOCKSHIFT 0x95 /* ANSI locking shift */ 72b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa#define LMI_ANSI_CISCO_REPTYPE 0x01 /* report type */ 73b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa#define LMI_CCITT_REPTYPE 0x51 74b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa#define LMI_ANSI_CISCO_ALIVE 0x03 /* keep alive */ 75b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa#define LMI_CCITT_ALIVE 0x53 76b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa#define LMI_ANSI_CISCO_PVCSTAT 0x07 /* PVC status */ 77b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa#define LMI_CCITT_PVCSTAT 0x57 78b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa 79b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa#define LMI_FULLREP 0x00 /* full report */ 80b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa#define LMI_INTEGRITY 0x01 /* link integrity report */ 81b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa#define LMI_SINGLE 0x02 /* single PVC report */ 82b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LMI_STATUS_ENQUIRY 0x75 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LMI_STATUS 0x7D /* reply */ 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LMI_REPT_LEN 1 /* report type element length */ 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LMI_INTEG_LEN 2 /* link integrity element length */ 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 89b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa#define LMI_CCITT_CISCO_LENGTH 13 /* LMI frame lengths */ 90b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa#define LMI_ANSI_LENGTH 14 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstypedef struct { 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if defined(__LITTLE_ENDIAN_BITFIELD) 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned ea1: 1; 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned cr: 1; 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned dlcih: 6; 984dfce4075aa4e2eee35e52a78dbabfe37d94c908Krzysztof Hałasa 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned ea2: 1; 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned de: 1; 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned becn: 1; 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned fecn: 1; 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned dlcil: 4; 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned dlcih: 6; 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned cr: 1; 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned ea1: 1; 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned dlcil: 4; 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned fecn: 1; 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned becn: 1; 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned de: 1; 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned ea2: 1; 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 115ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet}__packed fr_hdr; 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 118eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasatypedef struct pvc_device_struct { 119eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa struct net_device *frad; 120eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa struct net_device *main; 121eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa struct net_device *ether; /* bridged Ethernet interface */ 122eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa struct pvc_device_struct *next; /* Sorted in ascending DLCI order */ 123eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa int dlci; 124eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa int open_count; 125eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa 126eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa struct { 127eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa unsigned int new: 1; 128eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa unsigned int active: 1; 129eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa unsigned int exist: 1; 130eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa unsigned int deleted: 1; 131eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa unsigned int fecn: 1; 132eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa unsigned int becn: 1; 133eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa unsigned int bandwidth; /* Cisco LMI reporting only */ 134eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa }state; 135eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa}pvc_device; 136eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa 137eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasastruct frad_state { 138eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa fr_proto settings; 139eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa pvc_device *first_pvc; 140eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa int dce_pvc_count; 141eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa 142eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa struct timer_list timer; 143eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa unsigned long last_poll; 144eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa int reliable; 145eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa int dce_changed; 146eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa int request; 147eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa int fullrep_sent; 148eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa u32 last_errors; /* last errors bit list */ 149eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa u8 n391cnt; 150eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa u8 txseq; /* TX sequence number */ 151eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa u8 rxseq; /* RX sequence number */ 152eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa}; 153eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa 154eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa 155eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasastatic int fr_ioctl(struct net_device *dev, struct ifreq *ifr); 156eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa 157eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u16 q922_to_dlci(u8 *hdr) 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ((hdr[0] & 0xFC) << 2) | ((hdr[1] & 0xF0) >> 4); 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void dlci_to_q922(u8 *hdr, u16 dlci) 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdr[0] = (dlci >> 2) & 0xFC; 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdr[1] = ((dlci << 4) & 0xF0) | 0x01; 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 171983e23041b28abb113862b2935a85cfb9aab4f5aKrzysztof Halasastatic inline struct frad_state* state(hdlc_device *hdlc) 172eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa{ 173eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa return(struct frad_state *)(hdlc->state); 174eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa} 175eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa 176eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci) 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 179eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa pvc_device *pvc = state(hdlc)->first_pvc; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (pvc) { 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pvc->dlci == dlci) 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return pvc; 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pvc->dlci > dlci) 185870571a2ef6fb2d6306673b4376fec93d441e013Rudy Matela return NULL; /* the list is sorted */ 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc = pvc->next; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 193eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasastatic pvc_device* add_pvc(struct net_device *dev, u16 dlci) 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlc_device *hdlc = dev_to_hdlc(dev); 196eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa pvc_device *pvc, **pvc_p = &state(hdlc)->first_pvc; 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (*pvc_p) { 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((*pvc_p)->dlci == dlci) 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return *pvc_p; 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((*pvc_p)->dlci > dlci) 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; /* the list is sorted */ 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc_p = &(*pvc_p)->next; 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2061ee325438cdbe374ebea6e3d2f19204072c15038Mariusz Kozlowski pvc = kzalloc(sizeof(pvc_device), GFP_ATOMIC); 207eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa#ifdef DEBUG_PVC 208eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa printk(KERN_DEBUG "add_pvc: allocated pvc %p, frad %p\n", pvc, dev); 209eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa#endif 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!pvc) 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc->dlci = dlci; 214eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa pvc->frad = dev; 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc->next = *pvc_p; /* Put it in the chain */ 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *pvc_p = pvc; 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return pvc; 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int pvc_is_used(pvc_device *pvc) 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 223eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa return pvc->main || pvc->ether; 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void pvc_carrier(int on, pvc_device *pvc) 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (on) { 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pvc->main) 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!netif_carrier_ok(pvc->main)) 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_carrier_on(pvc->main); 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pvc->ether) 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!netif_carrier_ok(pvc->ether)) 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_carrier_on(pvc->ether); 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pvc->main) 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (netif_carrier_ok(pvc->main)) 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_carrier_off(pvc->main); 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pvc->ether) 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (netif_carrier_ok(pvc->ether)) 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_carrier_off(pvc->ether); 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void delete_unused_pvcs(hdlc_device *hdlc) 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 249eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa pvc_device **pvc_p = &state(hdlc)->first_pvc; 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (*pvc_p) { 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!pvc_is_used(*pvc_p)) { 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc_device *pvc = *pvc_p; 254eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa#ifdef DEBUG_PVC 255eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa printk(KERN_DEBUG "freeing unused pvc: %p\n", pvc); 256eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa#endif 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *pvc_p = pvc->next; 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(pvc); 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc_p = &(*pvc_p)->next; 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct net_device** get_dev_p(pvc_device *pvc, int type) 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (type == ARPHRD_ETHER) 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return &pvc->ether; 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return &pvc->main; 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int fr_hard_header(struct sk_buff **skb_p, u16 dlci) 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 head_len; 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb = *skb_p; 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (skb->protocol) { 28109640e6365c679b5642b1c41b6d7078f51689ddfHarvey Harrison case cpu_to_be16(NLPID_CCITT_ANSI_LMI): 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds head_len = 4; 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_push(skb, head_len); 284b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa skb->data[3] = NLPID_CCITT_ANSI_LMI; 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28709640e6365c679b5642b1c41b6d7078f51689ddfHarvey Harrison case cpu_to_be16(NLPID_CISCO_LMI): 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds head_len = 4; 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_push(skb, head_len); 290b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa skb->data[3] = NLPID_CISCO_LMI; 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29309640e6365c679b5642b1c41b6d7078f51689ddfHarvey Harrison case cpu_to_be16(ETH_P_IP): 294b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa head_len = 4; 295b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa skb_push(skb, head_len); 296b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa skb->data[3] = NLPID_IP; 297b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa break; 298b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa 29909640e6365c679b5642b1c41b6d7078f51689ddfHarvey Harrison case cpu_to_be16(ETH_P_IPV6): 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds head_len = 4; 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_push(skb, head_len); 302b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa skb->data[3] = NLPID_IPV6; 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30509640e6365c679b5642b1c41b6d7078f51689ddfHarvey Harrison case cpu_to_be16(ETH_P_802_3): 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds head_len = 10; 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb_headroom(skb) < head_len) { 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb2 = skb_realloc_headroom(skb, 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds head_len); 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!skb2) 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOBUFS; 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb(skb); 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb = *skb_p = skb2; 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_push(skb, head_len); 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->data[3] = FR_PAD; 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->data[4] = NLPID_SNAP; 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->data[5] = FR_PAD; 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->data[6] = 0x80; 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->data[7] = 0xC2; 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->data[8] = 0x00; 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->data[9] = 0x07; /* bridged Ethernet frame w/out FCS */ 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds head_len = 10; 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_push(skb, head_len); 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->data[3] = FR_PAD; 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->data[4] = NLPID_SNAP; 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->data[5] = FR_PAD; 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->data[6] = FR_PAD; 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->data[7] = FR_PAD; 333abf17ffda7b7b6c83a29d7ccea91d46065c6ca3eKrzysztof Halasa *(__be16*)(skb->data + 8) = skb->protocol; 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dlci_to_q922(skb->data, dlci); 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->data[2] = FR_UI; 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pvc_open(struct net_device *dev) 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3452baf8a2daab65cdd3f20bfeb4676a2f6aff7c3bfWang Chen pvc_device *pvc = dev->ml_priv; 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 347eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa if ((pvc->frad->flags & IFF_UP) == 0) 348eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa return -EIO; /* Frad must be UP in order to activate PVC */ 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pvc->open_count++ == 0) { 351eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa hdlc_device *hdlc = dev_to_hdlc(pvc->frad); 352eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa if (state(hdlc)->settings.lmi == LMI_NONE) 353eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa pvc->state.active = netif_carrier_ok(pvc->frad); 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc_carrier(pvc->state.active, pvc); 356eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->dce_changed = 1; 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pvc_close(struct net_device *dev) 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3652baf8a2daab65cdd3f20bfeb4676a2f6aff7c3bfWang Chen pvc_device *pvc = dev->ml_priv; 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (--pvc->open_count == 0) { 368eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa hdlc_device *hdlc = dev_to_hdlc(pvc->frad); 369eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa if (state(hdlc)->settings.lmi == LMI_NONE) 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc->state.active = 0; 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 372eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa if (state(hdlc)->settings.dce) { 373eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->dce_changed = 1; 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc->state.active = 0; 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3827665a08928f241247afe8c76865cdbe4ef5489bfAdrian Bunkstatic int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3842baf8a2daab65cdd3f20bfeb4676a2f6aff7c3bfWang Chen pvc_device *pvc = dev->ml_priv; 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fr_proto_pvc_info info; 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ifr->ifr_settings.type == IF_GET_PROTO) { 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->type == ARPHRD_ETHER) 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ifr->ifr_settings.type = IF_PROTO_FR_ETH_PVC; 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ifr->ifr_settings.type = IF_PROTO_FR_PVC; 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ifr->ifr_settings.size < sizeof(info)) { 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* data size wanted */ 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ifr->ifr_settings.size = sizeof(info); 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOBUFS; 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds info.dlci = pvc->dlci; 400eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa memcpy(info.master, pvc->frad->name, IFNAMSIZ); 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_to_user(ifr->ifr_settings.ifs_ifsu.fr_pvc_info, 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &info, sizeof(info))) 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 410d71a674922e7519edb477ecb585e7d29d69c7aa7Stephen Hemmingerstatic netdev_tx_t pvc_xmit(struct sk_buff *skb, struct net_device *dev) 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4122baf8a2daab65cdd3f20bfeb4676a2f6aff7c3bfWang Chen pvc_device *pvc = dev->ml_priv; 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pvc->state.active) { 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->type == ARPHRD_ETHER) { 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int pad = ETH_ZLEN - skb->len; 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pad > 0) { /* Pad the frame with zeros */ 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int len = skb->len; 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb_tailroom(skb) < pad) 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pskb_expand_head(skb, 0, pad, 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds GFP_ATOMIC)) { 422198191c4a7ce4daba379608fb38b9bc5a4eedc61Krzysztof Halasa dev->stats.tx_dropped++; 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb(skb); 4246ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy return NETDEV_TX_OK; 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_put(skb, pad); 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(skb->data + len, 0, pad); 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 42909640e6365c679b5642b1c41b6d7078f51689ddfHarvey Harrison skb->protocol = cpu_to_be16(ETH_P_802_3); 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!fr_hard_header(&skb, pvc->dlci)) { 432198191c4a7ce4daba379608fb38b9bc5a4eedc61Krzysztof Halasa dev->stats.tx_bytes += skb->len; 433198191c4a7ce4daba379608fb38b9bc5a4eedc61Krzysztof Halasa dev->stats.tx_packets++; 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pvc->state.fecn) /* TX Congestion counter */ 435198191c4a7ce4daba379608fb38b9bc5a4eedc61Krzysztof Halasa dev->stats.tx_compressed++; 436eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa skb->dev = pvc->frad; 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_queue_xmit(skb); 4386ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy return NETDEV_TX_OK; 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 442198191c4a7ce4daba379608fb38b9bc5a4eedc61Krzysztof Halasa dev->stats.tx_dropped++; 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb(skb); 4446ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy return NETDEV_TX_OK; 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void fr_log_dlci_active(pvc_device *pvc) 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 44912a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches netdev_info(pvc->frad, "DLCI %d [%s%s%s]%s %s\n", 45012a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches pvc->dlci, 45112a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches pvc->main ? pvc->main->name : "", 45212a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches pvc->main && pvc->ether ? " " : "", 45312a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches pvc->ether ? pvc->ether->name : "", 45412a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches pvc->state.new ? " new" : "", 45512a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches !pvc->state.exist ? "deleted" : 45612a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches pvc->state.active ? "active" : "inactive"); 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u8 fr_lmi_nextseq(u8 x) 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds x++; 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return x ? x : 1; 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void fr_lmi_send(struct net_device *dev, int fullrep) 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlc_device *hdlc = dev_to_hdlc(dev); 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 472eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa pvc_device *pvc = state(hdlc)->first_pvc; 473eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa int lmi = state(hdlc)->settings.lmi; 474eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa int dce = state(hdlc)->settings.dce; 475b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa int len = lmi == LMI_ANSI ? LMI_ANSI_LENGTH : LMI_CCITT_CISCO_LENGTH; 476b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa int stat_len = (lmi == LMI_CISCO) ? 6 : 3; 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 *data; 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i = 0; 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 480b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa if (dce && fullrep) { 481eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa len += state(hdlc)->dce_pvc_count * (2 + stat_len); 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (len > HDLC_MAX_MRU) { 48312a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches netdev_warn(dev, "Too many PVCs while sending LMI full report\n"); 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb = dev_alloc_skb(len); 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!skb) { 49012a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches netdev_warn(dev, "Memory squeeze on fr_lmi_send()\n"); 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(skb->data, 0, len); 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_reserve(skb, 4); 495b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa if (lmi == LMI_CISCO) { 49609640e6365c679b5642b1c41b6d7078f51689ddfHarvey Harrison skb->protocol = cpu_to_be16(NLPID_CISCO_LMI); 497b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa fr_hard_header(&skb, LMI_CISCO_DLCI); 498b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa } else { 49909640e6365c679b5642b1c41b6d7078f51689ddfHarvey Harrison skb->protocol = cpu_to_be16(NLPID_CCITT_ANSI_LMI); 500b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa fr_hard_header(&skb, LMI_CCITT_ANSI_DLCI); 501b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa } 50227a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo data = skb_tail_pointer(skb); 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data[i++] = LMI_CALLREF; 504b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa data[i++] = dce ? LMI_STATUS : LMI_STATUS_ENQUIRY; 505b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa if (lmi == LMI_ANSI) 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data[i++] = LMI_ANSI_LOCKSHIFT; 507b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa data[i++] = lmi == LMI_CCITT ? LMI_CCITT_REPTYPE : 508b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa LMI_ANSI_CISCO_REPTYPE; 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data[i++] = LMI_REPT_LEN; 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data[i++] = fullrep ? LMI_FULLREP : LMI_INTEGRITY; 511b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa data[i++] = lmi == LMI_CCITT ? LMI_CCITT_ALIVE : LMI_ANSI_CISCO_ALIVE; 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data[i++] = LMI_INTEG_LEN; 513eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa data[i++] = state(hdlc)->txseq = 514eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa fr_lmi_nextseq(state(hdlc)->txseq); 515eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa data[i++] = state(hdlc)->rxseq; 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 517b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa if (dce && fullrep) { 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (pvc) { 519b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa data[i++] = lmi == LMI_CCITT ? LMI_CCITT_PVCSTAT : 520b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa LMI_ANSI_CISCO_PVCSTAT; 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data[i++] = stat_len; 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* LMI start/restart */ 524eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa if (state(hdlc)->reliable && !pvc->state.exist) { 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc->state.exist = pvc->state.new = 1; 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fr_log_dlci_active(pvc); 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* ifconfig PVC up */ 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pvc->open_count && !pvc->state.active && 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc->state.exist && !pvc->state.new) { 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc_carrier(1, pvc); 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc->state.active = 1; 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fr_log_dlci_active(pvc); 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 537b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa if (lmi == LMI_CISCO) { 538b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa data[i] = pvc->dlci >> 8; 539b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa data[i + 1] = pvc->dlci & 0xFF; 540b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa } else { 541b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa data[i] = (pvc->dlci >> 4) & 0x3F; 542b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa data[i + 1] = ((pvc->dlci << 3) & 0x78) | 0x80; 543b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa data[i + 2] = 0x80; 544b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa } 545b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa 546b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa if (pvc->state.new) 547b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa data[i + 2] |= 0x08; 548b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa else if (pvc->state.active) 549b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa data[i + 2] |= 0x02; 550b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i += stat_len; 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc = pvc->next; 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_put(skb, i); 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->priority = TC_PRIO_CONTROL; 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->dev = dev; 559c1d2bbe1cd6c7bbdc6d532cefebb66c7efb789ceArnaldo Carvalho de Melo skb_reset_network_header(skb); 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_queue_xmit(skb); 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void fr_set_link_state(int reliable, struct net_device *dev) 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlc_device *hdlc = dev_to_hdlc(dev); 569eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa pvc_device *pvc = state(hdlc)->first_pvc; 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 571eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->reliable = reliable; 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reliable) { 573c2ce920468624d87ec5f91f080ea99681dae6d88Krzysztof Halasa netif_dormant_off(dev); 574eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->n391cnt = 0; /* Request full status */ 575eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->dce_changed = 1; 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 577eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa if (state(hdlc)->settings.lmi == LMI_NONE) { 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (pvc) { /* Activate all PVCs */ 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc_carrier(1, pvc); 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc->state.exist = pvc->state.active = 1; 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc->state.new = 0; 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc = pvc->next; 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 586c2ce920468624d87ec5f91f080ea99681dae6d88Krzysztof Halasa netif_dormant_on(dev); 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (pvc) { /* Deactivate all PVCs */ 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc_carrier(0, pvc); 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc->state.exist = pvc->state.active = 0; 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc->state.new = 0; 591eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa if (!state(hdlc)->settings.dce) 592b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa pvc->state.bandwidth = 0; 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc = pvc->next; 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void fr_timer(unsigned long arg) 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev = (struct net_device *)arg; 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlc_device *hdlc = dev_to_hdlc(dev); 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, cnt = 0, reliable; 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 list; 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 606eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa if (state(hdlc)->settings.dce) { 607eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa reliable = state(hdlc)->request && 608eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa time_before(jiffies, state(hdlc)->last_poll + 609eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->settings.t392 * HZ); 610eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->request = 0; 611b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa } else { 612eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->last_errors <<= 1; /* Shift the list */ 613eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa if (state(hdlc)->request) { 614eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa if (state(hdlc)->reliable) 61512a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches netdev_info(dev, "No LMI status reply received\n"); 616eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->last_errors |= 1; 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 619eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa list = state(hdlc)->last_errors; 620eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa for (i = 0; i < state(hdlc)->settings.n393; i++, list >>= 1) 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cnt += (list & 1); /* errors count */ 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 623eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa reliable = (cnt < state(hdlc)->settings.n392); 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 626eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa if (state(hdlc)->reliable != reliable) { 62712a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches netdev_info(dev, "Link %sreliable\n", reliable ? "" : "un"); 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fr_set_link_state(reliable, dev); 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 631eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa if (state(hdlc)->settings.dce) 632eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->timer.expires = jiffies + 633eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->settings.t392 * HZ; 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 635eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa if (state(hdlc)->n391cnt) 636eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->n391cnt--; 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 638eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa fr_lmi_send(dev, state(hdlc)->n391cnt == 0); 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 640eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->last_poll = jiffies; 641eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->request = 1; 642eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->timer.expires = jiffies + 643eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->settings.t391 * HZ; 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 646eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->timer.function = fr_timer; 647eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->timer.data = arg; 648eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa add_timer(&state(hdlc)->timer); 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb) 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlc_device *hdlc = dev_to_hdlc(dev); 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc_device *pvc; 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 rxseq, txseq; 657eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa int lmi = state(hdlc)->settings.lmi; 658eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa int dce = state(hdlc)->settings.dce; 659b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa int stat_len = (lmi == LMI_CISCO) ? 6 : 3, reptype, error, no_ram, i; 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 661b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa if (skb->len < (lmi == LMI_ANSI ? LMI_ANSI_LENGTH : 662b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa LMI_CCITT_CISCO_LENGTH)) { 66312a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches netdev_info(dev, "Short LMI frame\n"); 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 667b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa if (skb->data[3] != (lmi == LMI_CISCO ? NLPID_CISCO_LMI : 668b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa NLPID_CCITT_ANSI_LMI)) { 66912a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches netdev_info(dev, "Received non-LMI frame with LMI DLCI\n"); 670b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa return 1; 671b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa } 672b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa 673b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa if (skb->data[4] != LMI_CALLREF) { 67412a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches netdev_info(dev, "Invalid LMI Call reference (0x%02X)\n", 67512a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches skb->data[4]); 676b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa return 1; 677b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa } 678b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa 679b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa if (skb->data[5] != (dce ? LMI_STATUS_ENQUIRY : LMI_STATUS)) { 68012a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches netdev_info(dev, "Invalid LMI Message type (0x%02X)\n", 68112a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches skb->data[5]); 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 685b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa if (lmi == LMI_ANSI) { 686b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa if (skb->data[6] != LMI_ANSI_LOCKSHIFT) { 68712a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches netdev_info(dev, "Not ANSI locking shift in LMI message (0x%02X)\n", 68812a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches skb->data[6]); 689b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa return 1; 690b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa } 691b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa i = 7; 692b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa } else 693b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa i = 6; 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 695b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa if (skb->data[i] != (lmi == LMI_CCITT ? LMI_CCITT_REPTYPE : 696b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa LMI_ANSI_CISCO_REPTYPE)) { 69712a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches netdev_info(dev, "Not an LMI Report type IE (0x%02X)\n", 69812a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches skb->data[i]); 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 702b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa if (skb->data[++i] != LMI_REPT_LEN) { 70312a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches netdev_info(dev, "Invalid LMI Report type IE length (%u)\n", 70412a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches skb->data[i]); 705b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa return 1; 706b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa } 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 708b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa reptype = skb->data[++i]; 709b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa if (reptype != LMI_INTEGRITY && reptype != LMI_FULLREP) { 71012a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches netdev_info(dev, "Unsupported LMI Report type (0x%02X)\n", 71112a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches reptype); 712b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa return 1; 713b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa } 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 715b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa if (skb->data[++i] != (lmi == LMI_CCITT ? LMI_CCITT_ALIVE : 716b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa LMI_ANSI_CISCO_ALIVE)) { 71712a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches netdev_info(dev, "Not an LMI Link integrity verification IE (0x%02X)\n", 71812a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches skb->data[i]); 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 722b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa if (skb->data[++i] != LMI_INTEG_LEN) { 72312a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches netdev_info(dev, "Invalid LMI Link integrity verification IE length (%u)\n", 72412a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches skb->data[i]); 725b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa return 1; 726b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa } 727b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa i++; 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 729eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->rxseq = skb->data[i++]; /* TX sequence from peer */ 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rxseq = skb->data[i++]; /* Should confirm our sequence */ 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 732eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa txseq = state(hdlc)->txseq; 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 734b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa if (dce) 735eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->last_poll = jiffies; 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = 0; 738eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa if (!state(hdlc)->reliable) 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = 1; 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 741eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa if (rxseq == 0 || rxseq != txseq) { /* Ask for full report next time */ 742eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->n391cnt = 0; 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = 1; 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 746b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa if (dce) { 747eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa if (state(hdlc)->fullrep_sent && !error) { 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Stop sending full report - the last one has been confirmed by DTE */ 749eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->fullrep_sent = 0; 750eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa pvc = state(hdlc)->first_pvc; 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (pvc) { 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pvc->state.new) { 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc->state.new = 0; 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Tell DTE that new PVC is now active */ 756eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->dce_changed = 1; 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc = pvc->next; 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 762eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa if (state(hdlc)->dce_changed) { 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reptype = LMI_FULLREP; 764eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->fullrep_sent = 1; 765eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->dce_changed = 0; 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 768eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->request = 1; /* got request */ 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fr_lmi_send(dev, reptype == LMI_FULLREP ? 1 : 0); 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* DTE */ 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 775eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->request = 0; /* got response, no request pending */ 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error) 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reptype != LMI_FULLREP) 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 783eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa pvc = state(hdlc)->first_pvc; 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (pvc) { 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc->state.deleted = 1; 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc = pvc->next; 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds no_ram = 0; 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (skb->len >= i + 2 + stat_len) { 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 dlci; 793b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa u32 bw; 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int active, new; 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 796b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa if (skb->data[i] != (lmi == LMI_CCITT ? LMI_CCITT_PVCSTAT : 797b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa LMI_ANSI_CISCO_PVCSTAT)) { 79812a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches netdev_info(dev, "Not an LMI PVC status IE (0x%02X)\n", 79912a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches skb->data[i]); 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 803b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa if (skb->data[++i] != stat_len) { 80412a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches netdev_info(dev, "Invalid LMI PVC status IE length (%u)\n", 80512a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches skb->data[i]); 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i++; 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 810b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa new = !! (skb->data[i + 2] & 0x08); 811b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa active = !! (skb->data[i + 2] & 0x02); 812b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa if (lmi == LMI_CISCO) { 813b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa dlci = (skb->data[i] << 8) | skb->data[i + 1]; 814b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa bw = (skb->data[i + 3] << 16) | 815b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa (skb->data[i + 4] << 8) | 816b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa (skb->data[i + 5]); 817b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa } else { 818b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa dlci = ((skb->data[i] & 0x3F) << 4) | 819b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa ((skb->data[i + 1] & 0x78) >> 3); 820b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa bw = 0; 821b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa } 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc = add_pvc(dev, dlci); 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!pvc && !no_ram) { 82612a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches netdev_warn(dev, "Memory squeeze on fr_lmi_recv()\n"); 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds no_ram = 1; 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pvc) { 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc->state.exist = 1; 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc->state.deleted = 0; 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (active != pvc->state.active || 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new != pvc->state.new || 835b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa bw != pvc->state.bandwidth || 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !pvc->state.exist) { 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc->state.new = new; 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc->state.active = active; 839b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa pvc->state.bandwidth = bw; 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc_carrier(active, pvc); 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fr_log_dlci_active(pvc); 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i += stat_len; 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 848eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa pvc = state(hdlc)->first_pvc; 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (pvc) { 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pvc->state.deleted && pvc->state.exist) { 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc_carrier(0, pvc); 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc->state.active = pvc->state.new = 0; 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc->state.exist = 0; 855b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa pvc->state.bandwidth = 0; 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fr_log_dlci_active(pvc); 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc = pvc->next; 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Next full report after N391 polls */ 862eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->n391cnt = state(hdlc)->settings.n391; 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int fr_rx(struct sk_buff *skb) 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 870eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa struct net_device *frad = skb->dev; 871eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa hdlc_device *hdlc = dev_to_hdlc(frad); 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fr_hdr *fh = (fr_hdr*)skb->data; 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 *data = skb->data; 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 dlci; 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc_device *pvc; 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev = NULL; 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb->len <= 4 || fh->ea1 || data[2] != FR_UI) 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto rx_error; 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dlci = q922_to_dlci(skb->data); 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 883b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa if ((dlci == LMI_CCITT_ANSI_DLCI && 884eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa (state(hdlc)->settings.lmi == LMI_ANSI || 885eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->settings.lmi == LMI_CCITT)) || 886b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa (dlci == LMI_CISCO_DLCI && 887eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->settings.lmi == LMI_CISCO)) { 888eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa if (fr_lmi_recv(frad, skb)) 889b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa goto rx_error; 890b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa dev_kfree_skb_any(skb); 891b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa return NET_RX_SUCCESS; 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc = find_pvc(hdlc, dlci); 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!pvc) { 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_PKT 89712a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches netdev_info(frad, "No PVC for received frame's DLCI %d\n", 89812a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches dlci); 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb_any(skb); 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NET_RX_DROP; 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pvc->state.fecn != fh->fecn) { 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_ECN 906eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa printk(KERN_DEBUG "%s: DLCI %d FECN O%s\n", frad->name, 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dlci, fh->fecn ? "N" : "FF"); 9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc->state.fecn ^= 1; 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pvc->state.becn != fh->becn) { 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_ECN 914eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa printk(KERN_DEBUG "%s: DLCI %d BECN O%s\n", frad->name, 9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dlci, fh->becn ? "N" : "FF"); 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc->state.becn ^= 1; 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { 922198191c4a7ce4daba379608fb38b9bc5a4eedc61Krzysztof Halasa frad->stats.rx_dropped++; 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NET_RX_DROP; 9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data[3] == NLPID_IP) { 9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */ 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev = pvc->main; 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->protocol = htons(ETH_P_IP); 9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (data[3] == NLPID_IPV6) { 9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */ 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev = pvc->main; 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->protocol = htons(ETH_P_IPV6); 9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (skb->len > 10 && data[3] == FR_PAD && 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data[4] == NLPID_SNAP && data[5] == FR_PAD) { 938abf17ffda7b7b6c83a29d7ccea91d46065c6ca3eKrzysztof Halasa u16 oui = ntohs(*(__be16*)(data + 6)); 939abf17ffda7b7b6c83a29d7ccea91d46065c6ca3eKrzysztof Halasa u16 pid = ntohs(*(__be16*)(data + 8)); 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_pull(skb, 10); 9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch ((((u32)oui) << 16) | pid) { 9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ETH_P_ARP: /* routed frame with SNAP */ 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ETH_P_IPX: 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ETH_P_IP: /* a long variant */ 9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ETH_P_IPV6: 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev = pvc->main; 9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->protocol = htons(pid); 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x80C20007: /* bridged Ethernet frame */ 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((dev = pvc->ether) != NULL) 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->protocol = eth_type_trans(skb, dev); 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 95712a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches netdev_info(frad, "Unsupported protocol, OUI=%x PID=%x\n", 95812a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches oui, pid); 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb_any(skb); 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NET_RX_DROP; 9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 96312a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches netdev_info(frad, "Unsupported protocol, NLPID=%x length=%i\n", 96412a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches data[3], skb->len); 9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb_any(skb); 9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NET_RX_DROP; 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev) { 970198191c4a7ce4daba379608fb38b9bc5a4eedc61Krzysztof Halasa dev->stats.rx_packets++; /* PVC traffic */ 971198191c4a7ce4daba379608fb38b9bc5a4eedc61Krzysztof Halasa dev->stats.rx_bytes += skb->len; 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pvc->state.becn) 973198191c4a7ce4daba379608fb38b9bc5a4eedc61Krzysztof Halasa dev->stats.rx_compressed++; 97454364b752ef0c91fe92684df000cc4593d1e8963Krzysztof Halasa skb->dev = dev; 9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_rx(skb); 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NET_RX_SUCCESS; 9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb_any(skb); 9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NET_RX_DROP; 9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_error: 983198191c4a7ce4daba379608fb38b9bc5a4eedc61Krzysztof Halasa frad->stats.rx_errors++; /* Mark error */ 9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb_any(skb); 9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NET_RX_DROP; 9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void fr_start(struct net_device *dev) 9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlc_device *hdlc = dev_to_hdlc(dev); 9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_LINK 9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "fr_start\n"); 9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 996eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa if (state(hdlc)->settings.lmi != LMI_NONE) { 997eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->reliable = 0; 998eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->dce_changed = 1; 999eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->request = 0; 1000eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->fullrep_sent = 0; 1001eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->last_errors = 0xFFFFFFFF; 1002eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->n391cnt = 0; 1003eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->txseq = state(hdlc)->rxseq = 0; 1004eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa 1005eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa init_timer(&state(hdlc)->timer); 10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* First poll after 1 s */ 1007eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->timer.expires = jiffies + HZ; 1008eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->timer.function = fr_timer; 1009eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->timer.data = (unsigned long)dev; 1010eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa add_timer(&state(hdlc)->timer); 10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fr_set_link_state(1, dev); 10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void fr_stop(struct net_device *dev) 10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlc_device *hdlc = dev_to_hdlc(dev); 10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_LINK 10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "fr_stop\n"); 10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1022eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa if (state(hdlc)->settings.lmi != LMI_NONE) 1023eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa del_timer_sync(&state(hdlc)->timer); 10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fr_set_link_state(0, dev); 10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void fr_close(struct net_device *dev) 10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlc_device *hdlc = dev_to_hdlc(dev); 1031eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa pvc_device *pvc = state(hdlc)->first_pvc; 10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (pvc) { /* Shutdown all PVCs for this FRAD */ 10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pvc->main) 10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_close(pvc->main); 10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pvc->ether) 10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_close(pvc->ether); 10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc = pvc->next; 10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1042eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa 1043eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasastatic void pvc_setup(struct net_device *dev) 10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->type = ARPHRD_DLCI; 10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->flags = IFF_POINTOPOINT; 10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->hard_header_len = 10; 10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->addr_len = 2; 104993f154b594fe47e4a7e5358b309add449a046cd3Eric Dumazet dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; 10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1052991990a12de42281f81b4e3a6471586d2d0caf6aKrzysztof Hałasastatic const struct net_device_ops pvc_ops = { 1053991990a12de42281f81b4e3a6471586d2d0caf6aKrzysztof Hałasa .ndo_open = pvc_open, 1054991990a12de42281f81b4e3a6471586d2d0caf6aKrzysztof Hałasa .ndo_stop = pvc_close, 1055991990a12de42281f81b4e3a6471586d2d0caf6aKrzysztof Hałasa .ndo_change_mtu = hdlc_change_mtu, 1056991990a12de42281f81b4e3a6471586d2d0caf6aKrzysztof Hałasa .ndo_start_xmit = pvc_xmit, 1057991990a12de42281f81b4e3a6471586d2d0caf6aKrzysztof Hałasa .ndo_do_ioctl = pvc_ioctl, 1058991990a12de42281f81b4e3a6471586d2d0caf6aKrzysztof Hałasa}; 1059991990a12de42281f81b4e3a6471586d2d0caf6aKrzysztof Hałasa 1060eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasastatic int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type) 10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1062eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa hdlc_device *hdlc = dev_to_hdlc(frad); 1063141766cf9755e773b980238da52f5f5da5c69abeKrzysztof Halasa pvc_device *pvc; 10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 10651c5cae815d19ffe02bdfda1260949ef2b1806171Jiri Pirko int used; 10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1067eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa if ((pvc = add_pvc(frad, dlci)) == NULL) { 106812a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches netdev_warn(frad, "Memory squeeze on fr_add_pvc()\n"); 10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOBUFS; 10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*get_dev_p(pvc, type)) 10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EEXIST; 10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds used = pvc_is_used(pvc); 10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1077550fd08c2cebad61c548def135f67aba284c6162Neil Horman if (type == ARPHRD_ETHER) { 1078141766cf9755e773b980238da52f5f5da5c69abeKrzysztof Halasa dev = alloc_netdev(0, "pvceth%d", ether_setup); 1079550fd08c2cebad61c548def135f67aba284c6162Neil Horman dev->priv_flags &= ~IFF_TX_SKB_SHARING; 1080550fd08c2cebad61c548def135f67aba284c6162Neil Horman } else 1081141766cf9755e773b980238da52f5f5da5c69abeKrzysztof Halasa dev = alloc_netdev(0, "pvc%d", pvc_setup); 10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dev) { 108412a3bfefc8c1e43ddb50950cb74f8a11d680567aJoe Perches netdev_warn(frad, "Memory squeeze on fr_pvc()\n"); 10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds delete_unused_pvcs(hdlc); 10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOBUFS; 10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 108947eaa267a5db1729d238f977364e297b8963e115Krzysztof Halasa if (type == ARPHRD_ETHER) 1090f2cedb63df14342ad40a8b5b324fc5d94a60b665Danny Kukawka eth_hw_addr_random(dev); 109147eaa267a5db1729d238f977364e297b8963e115Krzysztof Halasa else { 1092abf17ffda7b7b6c83a29d7ccea91d46065c6ca3eKrzysztof Halasa *(__be16*)dev->dev_addr = htons(dlci); 10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dlci_to_q922(dev->broadcast, dlci); 10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1095991990a12de42281f81b4e3a6471586d2d0caf6aKrzysztof Hałasa dev->netdev_ops = &pvc_ops; 10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->mtu = HDLC_MAX_MTU; 10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_queue_len = 0; 10982baf8a2daab65cdd3f20bfeb4676a2f6aff7c3bfWang Chen dev->ml_priv = pvc; 10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (register_netdevice(dev) != 0) { 11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_netdev(dev); 11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds delete_unused_pvcs(hdlc); 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->destructor = free_netdev; 11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *get_dev_p(pvc, type) = dev; 11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!used) { 1109eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->dce_changed = 1; 1110eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->dce_pvc_count++; 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int fr_del_pvc(hdlc_device *hdlc, unsigned int dlci, int type) 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc_device *pvc; 11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((pvc = find_pvc(hdlc, dlci)) == NULL) 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOENT; 11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((dev = *get_dev_p(pvc, type)) == NULL) 11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOENT; 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->flags & IFF_UP) 11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; /* PVC in use */ 11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unregister_netdevice(dev); /* the destructor will free_netdev(dev) */ 11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *get_dev_p(pvc, type) = NULL; 11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!pvc_is_used(pvc)) { 1135eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->dce_pvc_count--; 1136eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->dce_changed = 1; 11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds delete_unused_pvcs(hdlc); 11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1144eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasastatic void fr_destroy(struct net_device *frad) 11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1146eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa hdlc_device *hdlc = dev_to_hdlc(frad); 1147eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa pvc_device *pvc = state(hdlc)->first_pvc; 1148eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->first_pvc = NULL; /* All PVCs destroyed */ 1149eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->dce_pvc_count = 0; 1150eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->dce_changed = 1; 11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (pvc) { 11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc_device *next = pvc->next; 11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* destructors will free_netdev() main and ether */ 11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pvc->main) 11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unregister_netdevice(pvc->main); 11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pvc->ether) 11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unregister_netdevice(pvc->ether); 11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(pvc); 11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pvc = next; 11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1167eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasastatic struct hdlc_proto proto = { 1168eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa .close = fr_close, 1169eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa .start = fr_start, 1170eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa .stop = fr_stop, 1171eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa .detach = fr_destroy, 1172eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa .ioctl = fr_ioctl, 117340d25142f2ef27084fc317ac8bb5bae460c8ea72Krzysztof Halasa .netif_rx = fr_rx, 1174eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa .module = THIS_MODULE, 1175eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa}; 1176eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa 11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1178eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasastatic int fr_ioctl(struct net_device *dev, struct ifreq *ifr) 11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fr_proto __user *fr_s = ifr->ifr_settings.ifs_ifsu.fr; 11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const size_t size = sizeof(fr_proto); 11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fr_proto new_settings; 11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlc_device *hdlc = dev_to_hdlc(dev); 11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fr_proto_pvc pvc; 11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (ifr->ifr_settings.type) { 11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IF_GET_PROTO: 1189eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa if (dev_to_hdlc(dev)->proto != &proto) /* Different proto */ 1190eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa return -EINVAL; 11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ifr->ifr_settings.type = IF_PROTO_FR; 11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ifr->ifr_settings.size < size) { 11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ifr->ifr_settings.size = size; /* data size wanted */ 11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOBUFS; 11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1196eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa if (copy_to_user(fr_s, &state(hdlc)->settings, size)) 11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IF_PROTO_FR: 12016f7ad1e3a24a64923538557b686d24c37b26f9d8Rudy Matela if (!capable(CAP_NET_ADMIN)) 12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12046f7ad1e3a24a64923538557b686d24c37b26f9d8Rudy Matela if (dev->flags & IFF_UP) 12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&new_settings, fr_s, size)) 12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (new_settings.lmi == LMI_DEFAULT) 12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_settings.lmi = LMI_ANSI; 12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((new_settings.lmi != LMI_NONE && 12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_settings.lmi != LMI_ANSI && 1215b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa new_settings.lmi != LMI_CCITT && 1216b3dd65f958354226275522b5a64157834bdc5415Krzysztof Halasa new_settings.lmi != LMI_CISCO) || 12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_settings.t391 < 1 || 12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_settings.t392 < 2 || 12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_settings.n391 < 1 || 12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_settings.n392 < 1 || 12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_settings.n393 < new_settings.n392 || 12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_settings.n393 > 32 || 12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (new_settings.dce != 0 && 12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_settings.dce != 1)) 12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT); 12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1231eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa if (dev_to_hdlc(dev)->proto != &proto) { /* Different proto */ 123240d25142f2ef27084fc317ac8bb5bae460c8ea72Krzysztof Halasa result = attach_hdlc_protocol(dev, &proto, 1233eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa sizeof(struct frad_state)); 1234eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa if (result) 1235eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa return result; 1236eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->first_pvc = NULL; 1237eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa state(hdlc)->dce_pvc_count = 0; 12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1239eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa memcpy(&state(hdlc)->settings, &new_settings, size); 12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->type = ARPHRD_FRAD; 12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IF_PROTO_FR_ADD_PVC: 12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IF_PROTO_FR_DEL_PVC: 12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IF_PROTO_FR_ADD_ETH_PVC: 12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IF_PROTO_FR_DEL_ETH_PVC: 1247eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa if (dev_to_hdlc(dev)->proto != &proto) /* Different proto */ 1248eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa return -EINVAL; 1249eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa 12506f7ad1e3a24a64923538557b686d24c37b26f9d8Rudy Matela if (!capable(CAP_NET_ADMIN)) 12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&pvc, ifr->ifr_settings.ifs_ifsu.fr_pvc, 12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(fr_proto_pvc))) 12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pvc.dlci <= 0 || pvc.dlci >= 1024) 12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; /* Only 10 bits, DLCI 0 reserved */ 12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ifr->ifr_settings.type == IF_PROTO_FR_ADD_ETH_PVC || 12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ifr->ifr_settings.type == IF_PROTO_FR_DEL_ETH_PVC) 12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = ARPHRD_ETHER; /* bridged Ethernet device */ 12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = ARPHRD_DLCI; 12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ifr->ifr_settings.type == IF_PROTO_FR_ADD_PVC || 12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ifr->ifr_settings.type == IF_PROTO_FR_ADD_ETH_PVC) 12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return fr_add_pvc(dev, pvc.dlci, result); 12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return fr_del_pvc(hdlc, pvc.dlci, result); 12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1275eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa 1276eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa 1277eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasastatic int __init mod_init(void) 1278eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa{ 1279eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa register_hdlc_protocol(&proto); 1280eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa return 0; 1281eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa} 1282eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa 1283eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa 1284eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasastatic void __exit mod_exit(void) 1285eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa{ 1286eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa unregister_hdlc_protocol(&proto); 1287eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa} 1288eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa 1289eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa 1290eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasamodule_init(mod_init); 1291eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasamodule_exit(mod_exit); 1292eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof Halasa 1293eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof HalasaMODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); 1294eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof HalasaMODULE_DESCRIPTION("Frame-Relay protocol support for generic HDLC"); 1295eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfbKrzysztof HalasaMODULE_LICENSE("GPL v2"); 1296