From e7c2a72e2680827d6a733931273a93461c0d8d1b Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 14 Nov 1995 08:00:00 +0000 Subject: Import of Linux/MIPS 1.3.0 --- net/802/Makefile | 55 ++++++++ net/802/llc.c | 412 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ net/802/p8022.c | 98 +++++++++++++ net/802/p8023.c | 35 +++++ net/802/psnap.c | 123 +++++++++++++++++ net/802/tr.c | 285 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 1008 insertions(+) create mode 100644 net/802/Makefile create mode 100644 net/802/llc.c create mode 100644 net/802/p8022.c create mode 100644 net/802/p8023.c create mode 100644 net/802/psnap.c create mode 100644 net/802/tr.c (limited to 'net/802') diff --git a/net/802/Makefile b/net/802/Makefile new file mode 100644 index 000000000..a81249c91 --- /dev/null +++ b/net/802/Makefile @@ -0,0 +1,55 @@ +# +# Makefile for the Linux 802.x protocol layers. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definition is now in the main makefile... + +.c.o: + $(CC) $(CFLAGS) -c $< +.s.o: + $(AS) -o $*.o $< +.c.s: + $(CC) $(CFLAGS) -S $< + + +OBJS := p8023.o + +ifdef CONFIG_TR + +OBJS := $(OBJS) tr.o + +endif + +ifdef CONFIG_IPX + +OBJS := $(OBJS) p8022.o psnap.o + +endif + +ifdef CONFIG_ATALK +ifndef CONFIG_IPX + +OBJS := $(OBJS) p8022.o psnap.o + +endif +endif + +802.o: $(OBJS) + $(LD) -r -o 802.o $(OBJS) + + +dep: + $(CPP) -M *.c > .depend + +tar: + tar -cvf /dev/f1 . + +# +# include a dependency file if one exists +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif diff --git a/net/802/llc.c b/net/802/llc.c new file mode 100644 index 000000000..d280fb38f --- /dev/null +++ b/net/802/llc.c @@ -0,0 +1,412 @@ +/* + * 802.2 Class 2 LLC service. + */ + + +int llc_rx_adm(struct sock *sk,struct sk_buff *skb, int type, int cmd, int pf, int nr, int ns) +{ + if(type==CMD) + { + if(cmd==DISC) + send_response(sk,DM|pf); + else if(cmd==SABM) + { + if(sk->state!=TCP_LISTEN) + send_response(sk. DM|pf); + else + { + sk=ll_rx_accept(sk); + if(sk!=NULL) + { + send_response(sk, UA|pf); + sk->llc.vs=0; + sk->llc.vr=0; + sk->llc.p_flag=0; + sk->llc.remote_busy=0; + llc_state(sk,LLC_NORMAL); + } + } + } + else if(pf) + send_response(sk, DM|PF); + } + return 0; +} + +int llc_rx_setup(struct sock *sk, struct sk_buff *skb, int type, int cmd, int pf, int nr, int ns) +{ + if(type==CMD) + { + if(cmd==SABM) + { + sk->llc.vs=0; + sk->llc.vr=0; + send_response(sk, UA|pf); + } + if(cmd==DISC) + { + send_response(sk, DM|pf); + llc_error(sk,ECONNRESET); + llc_state(sk, LLC_ADM); + } + } + else + { + if(cmd==UA && pf==sk->llc.p_flag) + { + del_timer(&sk->llc.t1); + sk->llc.vs=0; + llc_update_p_flag(sk,pf); + llc_state(sk,LLC_NORMAL); + } + if(cmd==DM) + { + llc_error(sk, ECONNRESET); + llc_state(sk, LLC_ADM); + } + } +} + +int llc_rx_reset(struct sock *sk, struct sk_buff *skb, int type, int cmd, int pf, int nr, int ns) +{ + if(type==CMD) + { + if(cmd==SABM) + { + sk->llc.vr=0; + sk->llc.vs=0; + send_response(sk, UA|pf); + } + else if(cmd==DISC) + { + if(sk->llc.cause_flag==1) + llc_shutdown(sk,SHUTDOWN_MASK); + else + llc_eror(sk, ECONNREFUSED); + send_response(sk, DM|pf); + llc_state(sk, LLC_ADM); + } + } + else + { + if(cmd==UA) + { + if(sk->llc.p_flag==pf) + { + del_timer(&sk->llc.t1); + sk->llc.vs=0; + sk->llc.vr=0; + llc_update_p_flag(sk,pf); + llc_confirm_reset(sk, sk->llc.cause_flag); + sk->llc.remote_busy=0; + llc_state(sk, LLC_NORMAL); + } + } + if(cmd==DM) + { /* Should check cause_flag */ + llc_shutdown(sk, SHUTDOWN_MASK); + llc_state(sk, LLC_ADM); + } + } + return 0; +} + +int llc_rx_d_conn(struct sock *sk, struct sk_buff *skb, int type, int cmd, int pf, int nr, int ns) +{ + if(type==CMD) + { + if(cmd==SABM) + { + llc_error(sk, ECONNRESET); + llc_state(sk, ADM); + } + else if(cmd==DISC) + { + send_response(UA|pf); + llc_state(sk, LLC_D_CONN); + } + else if(pf) + send_response(sk, DM|PF); + } + else + { + if(cmd==UA && pf==sk->llc.p_flag) + { + del_timer(&sk->llc.t1); + llc_state(sk, ADM); + llc_confirm_reset(sk, sk->llc.cause_flag); + } + if(cmd==DM) + { + del_timer(&sk->llc.t1); + /*if(sk->llc.cause_flag)*/ + llc_shutdown(sk, SHUTDOWN_MASK); + } + + } + return 0; +} + +int llc_rx_error(struct sock *sk, struct sk_buff *skb, int type, int cmd, int pf, int nr, int ns) +{ + if(type==CMD) + { + if(cmd==SABM) + { + sk->llc.vs=0; + sk->llc.vr=0; + send_response(sk, UA|pf); + llc_error(sk,ECONNRESET); + sk->llc.p_flag=0; + sk->llc.remote_busy=0; + llc_state(sk, LLC_NORMAL); + } + else if(cmd==DISC) + { + send_response(sk, UA|pf); + llc_shutdown(sk, SHUTDOWN_MASK); + llc_state(sk, LLC_ADM); + } + else + llc_resend_frmr_rsp(sk,pf); + } + else + { + if(cmd==DM) + { + llc_error(sk, ECONNRESET); + del_timer(&sk->llc.t1); + llc_state(sk, LLC_ADM); + } + if(cmd==FRMR) + { + send_command(sk, SABM); + sk->llc.p_flag=pf; + llc_start_t1(); + sk->llc.retry_count=0; + sk->llc.cause_flag=0; + llc_error(sk, EPROTO); + llc_state(sk, LLC_RESET); + } + } +} + + +/* + * Subroutine for handling the shared cases of the data modes. + */ + +int llc_rx_nr_shared(struct sock *sk, struct sk_buff *skb, int type, int cmd, int pf, int nr, int ns) +{ + if(type==CMD) + { + if(cmd==SABM) + { + /* + * Optional reset processing. We decline resets. + */ + send_response(sk,DM|pf); + llc_error(sk, ECONNRESET); + llc_state(sk, LLC_ADM); + } + else if(cmd==DISC) + { + send_response(sk,UA|pf); + llc_state(sk, LLC_ADM); + llc_shutdown(sk, SHUTDOWN_MASK); + } + /* + * We only ever use windows of 7, so there is no illegal NR/NS value + * otherwise we would FRMR here and go to ERROR state + */ + else if(cmd==ILLEGAL) + { + llc_send_frmr_response(sk, ILLEGAL_TYPE,pf); + llc_state(sk, LLC_ERROR); + llc_error(sk, EPROTO); + } + else + /* + * Not covered by general rule + */ + return 0; + } + else + { + /* + * We close on errors + */ + if(cmd==FRMR) + { + send_command(sk, DM|pf); + sk->llc.p_flag=pf; + llc_start_t1(sk); + llc_error(sk, EPROTO); + sk->llc.cause_flag=0; + llc_state(sk, LLC_D_CONN): + } + else if(cmd==DM) + { + llc_state(sk, LLC_ADM); + llc_error(sk, ECONNREFUSED); + } + /* + * We always use a window of 7 so can't get I resp + * with invalid NS, or any resp with invalid NR. If + * we add this they do the same as.. + */ + else if(cmd==UA) + { + llc_send_frmr_response(sk, UNEXPECTED_CONTROL, pf); + llc_state(sk, LLC_ERROR); + llc_error(sk, EPROTO); + } + else if(pf==1 && sk->llc.p_flag==0) + { + llc_send_frmr_response(sk, UNEXPECTED_RESPONSE, pf); + llc_state(sk, LLC_ERROR); + llc_error(sk, EPROTO); + } + else if(cmd==ILLEGAL) + { + llc_send_frmr_response(sk, ILLEGAL_TYPE,pf); + llc_state(sk, LLC_ERROR); + llc_error(sk, EPROTO); + } + else + /* + * Not covered by general rule + */ + return 0 + } + /* + * Processed. + */ + return 1; +} + +int llc_rx_normal(struct sock *sk, struct sk_buff *skb, int type, int cmd, int pf, int nr, int ns) +{ + if(llc_rx_nr_shared(sk, skb, type, cmd, pf, nr, ns)) + return 0; + if(cmd==I) + { + if(llc_invalid_ns(sk,ns)) + { + if((type==RESP && sk->llc.p_flag==pf)||(type==CMD && pf==0 && sk->llc.p_flag==0)) + { + llc_command(sk, REJ|PF); + llc_ack_frames(sk,nr); /* Ack frames and update N(R) */ + sk->llc.p_flag=PF; + llc_state(sk, LLC_REJECT); + sk->llc.retry_count=0; + llc_start_t1(sk); + sk->llc.remote_busy=0; + } + else if((type==CMD && !pf && sk->llc.p_flag==1) || (type==RESP && !pf && sk->llc.p_flag==1)) + { + if(type==CMD) + llc_response(sk, REJ); + else + llc_command(sk, REJ); + llc_ack_frames(sk,nr); + sk->llc.retry_count=0; + llc_state(sk, LLC_REJECT); + llc_start_t1(sk); + } + else if(pf && type==CMD) + { + llc_response(sk, REJ|PF); + llc_ack_frames(sk,nr); + sk->llc.retry_count=0; + llc_start_t1(sk); + } + } + else + { + /* + * Valid I frame cases + */ + + if(sk->llc.p_flag==pf && !(type==CMD && pf)) + { + sk->llc.vr=(sk->llc.vr+1)&7; + llc_queue_rr_cmd(sk, PF); + sk->llc.retry_count=0; + llc_start_t1(sk); + sk->llc.p_flag=1; + llc_ack_frames(sk,nr); + sk->llc.remote_busy=0; + } + else if(sk->ppc.p_flag!=pf) + { + sk->llc.vr=(sk->llc.vr+1)&7; + if(type==CMD) + llc_queue_rr_resp(sk, 0); + else + llc_queue_rr_cmd(sk, 0); + if(sk->llc.nr!=nr) + { + llc_ack_frames(sk,nr); + llc_reset_t1(sk); + } + } + else if(pf) + { + sk->llc.vr=(sk->llc.vr+1)&7; + llc_queue_rr_resp(sk,PF); + if(sk->llc.nr!=nr) + { + llc_ack_frames(sk,nr); + llc_reset_t1(sk); + } + } + llc_queue_data(sk,skb); + return 1; + } + } + else if(cmd==RR||cmd==RNR) + { + if(type==CMD || (type==RESP && (!pf || pf==1 && sk->llc.p_flag==1))) + { + llc_update_p_flag(sk,pf); + if(sk->llc.nr!=nr) + { + llc_ack_frames(sk,nr); + llc_reset_t1(sk); + } + if(cmd==RR) + sk->llc.remote_busy=0; + else + { sk->llc.remote_busy=1; + if(!llc_t1_running(sk)) + llc_start_t1(sk); + } + } + else if(type==cmd && pf) + { + if(cmd==RR) + llc_queue_rr_resp(sk,PF); + else + { + send_response(sk, RR|PF); + if(!llc_t1_running(sk)) + llc_start_t1(sk); + } + if(sk->llc.nr!=nr) + { + llc_ack_frames(sk,nr); + llc_reset_t1(sk); + } + if(cmd==RR) + sk->llc.remote_busy=0; + else + sk->llc.remote_busy=1; + } + } + else if(cmd==REJ) + { + + } +} + diff --git a/net/802/p8022.c b/net/802/p8022.c new file mode 100644 index 000000000..dd1510774 --- /dev/null +++ b/net/802/p8022.c @@ -0,0 +1,98 @@ +#include +#include +#include +#include +#include + +static struct datalink_proto *p8022_list = NULL; + +static struct datalink_proto * +find_8022_client(unsigned char type) +{ + struct datalink_proto *proto; + + for (proto = p8022_list; + ((proto != NULL) && (*(proto->type) != type)); + proto = proto->next) + ; + + return proto; +} + +int +p8022_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) +{ + struct datalink_proto *proto; + + proto = find_8022_client(*(skb->h.raw)); + if (proto != NULL) { + skb->h.raw += 3; + skb->len -= 3; + return proto->rcvfunc(skb, dev, pt); + } + + skb->sk = NULL; + kfree_skb(skb, FREE_READ); + return 0; +} + +static void +p8022_datalink_header(struct datalink_proto *dl, + struct sk_buff *skb, unsigned char *dest_node) +{ + struct device *dev = skb->dev; + unsigned long len = skb->len; + unsigned long hard_len = dev->hard_header_len; + unsigned char *rawp; + + dev->hard_header(skb->data, dev, len - hard_len, + dest_node, NULL, len - hard_len, skb); + rawp = skb->data + hard_len; + *rawp = dl->type[0]; + rawp++; + *rawp = dl->type[0]; + rawp++; + *rawp = 0x03; /* UI */ + rawp++; + skb->h.raw = rawp; +} + +static struct packet_type p8022_packet_type = +{ + 0, /* MUTTER ntohs(ETH_P_IPX),*/ + NULL, /* All devices */ + p8022_rcv, + NULL, + NULL, +}; + + +void p8022_proto_init(struct net_proto *pro) +{ + p8022_packet_type.type=htons(ETH_P_802_2); + dev_add_pack(&p8022_packet_type); +} + +struct datalink_proto * +register_8022_client(unsigned char type, int (*rcvfunc)(struct sk_buff *, struct device *, struct packet_type *)) +{ + struct datalink_proto *proto; + + if (find_8022_client(type) != NULL) + return NULL; + + proto = (struct datalink_proto *) kmalloc(sizeof(*proto), GFP_ATOMIC); + if (proto != NULL) { + proto->type[0] = type; + proto->type_len = 1; + proto->rcvfunc = rcvfunc; + proto->header_length = 3; + proto->datalink_header = p8022_datalink_header; + proto->string_name = "802.2"; + proto->next = p8022_list; + p8022_list = proto; + } + + return proto; +} + diff --git a/net/802/p8023.c b/net/802/p8023.c new file mode 100644 index 000000000..4b1f5e0bf --- /dev/null +++ b/net/802/p8023.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include +#include + +static void +p8023_datalink_header(struct datalink_proto *dl, + struct sk_buff *skb, unsigned char *dest_node) +{ + struct device *dev = skb->dev; + unsigned long len = skb->len; + unsigned long hard_len = dev->hard_header_len; + + dev->hard_header(skb->data, dev, len - hard_len, + dest_node, NULL, len - hard_len, skb); + skb->h.raw = skb->data + hard_len; +} + +struct datalink_proto * +make_8023_client(void) +{ + struct datalink_proto *proto; + + proto = (struct datalink_proto *) kmalloc(sizeof(*proto), GFP_ATOMIC); + if (proto != NULL) { + proto->type_len = 0; + proto->header_length = 0; + proto->datalink_header = p8023_datalink_header; + proto->string_name = "802.3"; + } + + return proto; +} + diff --git a/net/802/psnap.c b/net/802/psnap.c new file mode 100644 index 000000000..d0186c54e --- /dev/null +++ b/net/802/psnap.c @@ -0,0 +1,123 @@ +/* + * SNAP data link layer. Derived from 802.2 + * + * Alan Cox , from the 802.2 layer by Greg Page. + * Merged in additions from Greg Page's psnap.c. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +static struct datalink_proto *snap_list = NULL; +static struct datalink_proto *snap_dl = NULL; /* 802.2 DL for SNAP */ + +/* + * Find a snap client by matching the 5 bytes. + */ + +static struct datalink_proto *find_snap_client(unsigned char *desc) +{ + struct datalink_proto *proto; + + for (proto = snap_list; proto != NULL && memcmp(proto->type, desc, 5) ; proto = proto->next); + return proto; +} + +/* + * A SNAP packet has arrived + */ + +int snap_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) +{ + static struct packet_type psnap_packet_type = + { + 0, + NULL, /* All Devices */ + snap_rcv, + NULL, + NULL, + }; + + struct datalink_proto *proto; + + proto = find_snap_client(skb->h.raw); + if (proto != NULL) + { + /* + * Pass the frame on. + */ + + skb->h.raw += 5; + skb->len -= 5; + if (psnap_packet_type.type == 0) + psnap_packet_type.type=htons(ETH_P_SNAP); + return proto->rcvfunc(skb, dev, &psnap_packet_type); + } + skb->sk = NULL; + kfree_skb(skb, FREE_READ); + return 0; +} + +/* + * Put a SNAP header on a frame and pass to 802.2 + */ + +static void snap_datalink_header(struct datalink_proto *dl, struct sk_buff *skb, unsigned char *dest_node) +{ + struct device *dev = skb->dev; + unsigned char *rawp; + + rawp = skb->data + snap_dl->header_length+dev->hard_header_len; + memcpy(rawp,dl->type,5); + skb->h.raw = rawp+5; + snap_dl->datalink_header(snap_dl, skb, dest_node); +} + +/* + * Set up the SNAP layer + */ + +void snap_proto_init(struct net_proto *pro) +{ + snap_dl=register_8022_client(0xAA, snap_rcv); + if(snap_dl==NULL) + printk("SNAP - unable to register with 802.2\n"); +} + +/* + * Register SNAP clients. We don't yet use this for IP or IPX. + */ + +struct datalink_proto *register_snap_client(unsigned char *desc, int (*rcvfunc)(struct sk_buff *, struct device *, struct packet_type *)) +{ + struct datalink_proto *proto; + + if (find_snap_client(desc) != NULL) + return NULL; + + proto = (struct datalink_proto *) kmalloc(sizeof(*proto), GFP_ATOMIC); + if (proto != NULL) + { + memcpy(proto->type, desc,5); + proto->type_len = 5; + proto->rcvfunc = rcvfunc; + proto->header_length = 5+snap_dl->header_length; + proto->datalink_header = snap_datalink_header; + proto->string_name = "SNAP"; + proto->next = snap_list; + snap_list = proto; + } + + return proto; +} + diff --git a/net/802/tr.c b/net/802/tr.c new file mode 100644 index 000000000..643cf64c5 --- /dev/null +++ b/net/802/tr.c @@ -0,0 +1,285 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void tr_source_route(struct trh_hdr *trh,struct device *dev); +static void tr_add_rif_info(struct trh_hdr *trh); +static void rif_check_expire(unsigned long dummy); + +typedef struct rif_cache_s *rif_cache; + +struct rif_cache_s { + unsigned char addr[TR_ALEN]; + unsigned short rcf; + unsigned short rseg[8]; + rif_cache next; + unsigned long last_used; +}; + +#define RIF_TABLE_SIZE 16 +rif_cache rif_table[RIF_TABLE_SIZE]={ NULL, }; + +#define RIF_TIMEOUT 60*10*HZ +#define RIF_CHECK_INTERVAL 60*HZ +static struct timer_list rif_timer={ NULL,NULL,RIF_CHECK_INTERVAL,0L,rif_check_expire }; + +int tr_header(unsigned char *buff, struct device *dev, unsigned short type, + void *daddr, void *saddr, unsigned len, struct sk_buff *skb) { + + struct trh_hdr *trh=(struct trh_hdr *)buff; + struct trllc *trllc=(struct trllc *)(buff+sizeof(struct trh_hdr)); + + trh->ac=AC; + trh->fc=LLC_FRAME; + + if(saddr) + memcpy(trh->saddr,saddr,dev->addr_len); + else + memset(trh->saddr,0,dev->addr_len); /* Adapter fills in address */ + + trllc->dsap=trllc->ssap=EXTENDED_SAP; + trllc->llc=UI_CMD; + + trllc->protid[0]=trllc->protid[1]=trllc->protid[2]=0x00; + trllc->ethertype=htons(type); + + if(daddr) { + memcpy(trh->daddr,daddr,dev->addr_len); + tr_source_route(trh,dev); + return(dev->hard_header_len); + } + return -dev->hard_header_len; + +} + +int tr_rebuild_header(void *buff, struct device *dev, unsigned long dest, + struct sk_buff *skb) { + + struct trh_hdr *trh=(struct trh_hdr *)buff; + struct trllc *trllc=(struct trllc *)(buff+sizeof(struct trh_hdr)); + + if(trllc->ethertype != htons(ETH_P_IP)) { + printk("tr_rebuild_header: Don't know how to resolve type %04X addresses ?\n",(unsigned int)htons( trllc->ethertype)); + return 0; + } + + if(arp_find(trh->daddr, dest, dev, dev->pa_addr, skb)) { + return 1; + } + else { + tr_source_route(trh,dev); + return 0; + } +} + +unsigned short tr_type_trans(struct sk_buff *skb, struct device *dev) { + + struct trh_hdr *trh=(struct trh_hdr *)skb->data; + struct trllc *trllc=(struct trllc *)(skb->data+sizeof(struct trh_hdr)); + + if(trh->saddr[0] & TR_RII) + tr_add_rif_info(trh); + + if(*trh->daddr & 1) + { + if(!memcmp(trh->daddr,dev->broadcast,TR_ALEN)) + skb->pkt_type=PACKET_BROADCAST; + else + skb->pkt_type=PACKET_MULTICAST; + } + + else if(dev->flags & IFF_PROMISC) + { + if(memcmp(trh->daddr, dev->dev_addr, TR_ALEN)) + skb->pkt_type=PACKET_OTHERHOST; + } + + return trllc->ethertype; +} + +/* We try to do source routing... */ + +static void tr_source_route(struct trh_hdr *trh,struct device *dev) { + + int i; + unsigned int hash; + rif_cache entry; + + /* Broadcasts are single route as stated in RFC 1042 */ + if(!memcmp(&(trh->daddr[0]),&(dev->broadcast[0]),TR_ALEN)) { + trh->rcf=htons((((sizeof(trh->rcf)) << 8) & TR_RCF_LEN_MASK) + | TR_RCF_FRAME2K | TR_RCF_LIMITED_BROADCAST); + trh->saddr[0]|=TR_RII; + } + else { + for(i=0,hash=0;idaddr[i++]); + hash&=RIF_TABLE_SIZE-1; + for(entry=rif_table[hash];entry && memcmp(&(entry->addr[0]),&(trh->daddr[0]),TR_ALEN);entry=entry->next); + + if(entry) { +#if 0 +printk("source routing for %02X %02X %02X %02X %02X %02X\n",trh->daddr[0], + trh->daddr[1],trh->daddr[2],trh->daddr[3],trh->daddr[4],trh->daddr[5]); +#endif + if((ntohs(entry->rcf) & TR_RCF_LEN_MASK) >> 8) { + trh->rcf=entry->rcf; + memcpy(&trh->rseg[0],&entry->rseg[0],8*sizeof(unsigned short)); + trh->rcf^=htons(TR_RCF_DIR_BIT); + trh->rcf&=htons(0x1fff); /* Issam Chehab */ + + trh->saddr[0]|=TR_RII; + entry->last_used=jiffies; + } + } + else { + trh->rcf=htons((((sizeof(trh->rcf)) << 8) & TR_RCF_LEN_MASK) + | TR_RCF_FRAME2K | TR_RCF_LIMITED_BROADCAST); + trh->saddr[0]|=TR_RII; + } + } + +} + +static void tr_add_rif_info(struct trh_hdr *trh) { + + int i; + unsigned int hash; + rif_cache entry; + + + trh->saddr[0]&=0x7f; + for(i=0,hash=0;isaddr[i++]); + hash&=RIF_TABLE_SIZE-1; +#if 0 + printk("hash: %d\n",hash); +#endif + for(entry=rif_table[hash];entry && memcmp(&(entry->addr[0]),&(trh->saddr[0]),TR_ALEN);entry=entry->next); + + if(entry==NULL) { +#if 0 +printk("adding rif_entry: addr:%02X:%02X:%02X:%02X:%02X:%02X rcf:%04X\n", + trh->saddr[0],trh->saddr[1],trh->saddr[2], + trh->saddr[3],trh->saddr[4],trh->saddr[5], + trh->rcf); +#endif + entry=kmalloc(sizeof(struct rif_cache_s),GFP_ATOMIC); + if(!entry) { + printk("tr.c: Couldn't malloc rif cache entry !\n"); + return; + } + entry->rcf=trh->rcf; + memcpy(&(entry->rseg[0]),&(trh->rseg[0]),8*sizeof(unsigned short)); + memcpy(&(entry->addr[0]),&(trh->saddr[0]),TR_ALEN); + entry->next=rif_table[hash]; + entry->last_used=jiffies; + rif_table[hash]=entry; + } +/* Y. Tahara added */ + else { + if ( entry->rcf != trh->rcf ) { + if (!(trh->rcf & htons(TR_RCF_BROADCAST_MASK))) { +#if 0 +printk("updating rif_entry: addr:%02X:%02X:%02X:%02X:%02X:%02X rcf:%04X\n", + trh->saddr[0],trh->saddr[1],trh->saddr[2], + trh->saddr[3],trh->saddr[4],trh->saddr[5], + trh->rcf); +#endif + entry->rcf = trh->rcf; + memcpy(&(entry->rseg[0]),&(trh->rseg[0]),8*sizeof(unsigned short)); + entry->last_used=jiffies; + } + } + } + +} + +static void rif_check_expire(unsigned long dummy) { + + int i; + unsigned long now=jiffies,flags; + + save_flags(flags); + cli(); + + for(i=0; i < RIF_TABLE_SIZE;i++) { + + rif_cache entry, *pentry=rif_table+i; + + while((entry=*pentry)) + if((now-entry->last_used) > RIF_TIMEOUT) { + *pentry=entry->next; + kfree_s(entry,sizeof(struct rif_cache_s)); + } + else + pentry=&entry->next; + } + restore_flags(flags); + + del_timer(&rif_timer); + rif_timer.expires=RIF_CHECK_INTERVAL; + add_timer(&rif_timer); + +} + +int rif_get_info(char *buffer,char **start, off_t offset, int length) { + + int len=0; + off_t begin=0; + off_t pos=0; + int size,i; + + rif_cache entry; + + size=sprintf(buffer, +" TR address rcf routing segments TTL\n\n"); + pos+=size; + len+=size; + + for(i=0;i < RIF_TABLE_SIZE;i++) { + for(entry=rif_table[i];entry;entry=entry->next) { + size=sprintf(buffer+len,"%02X:%02X:%02X:%02X:%02X:%02X %04X %04X %04X %04X %04X %04X %04X %04X %04X %lu\n", + entry->addr[0],entry->addr[1],entry->addr[2],entry->addr[3],entry->addr[4],entry->addr[5], + entry->rcf,entry->rseg[0],entry->rseg[1],entry->rseg[2],entry->rseg[3], + entry->rseg[4],entry->rseg[5],entry->rseg[6],entry->rseg[7],jiffies-entry->last_used); + len+=size; + pos=begin+len; + + if(posoffset+length) + break; + } + if(pos>offset+length) + break; + } + + *start=buffer+(offset-begin); /* Start of wanted data */ + len-=(offset-begin); /* Start slop */ + if(len>length) + len=length; /* Ending slop */ + return len; +} + +void rif_init(struct net_proto *unused) { + + add_timer(&rif_timer); + +} + -- cgit v1.2.3