diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-01-07 02:33:00 +0000 |
---|---|---|
committer | <ralf@linux-mips.org> | 1997-01-07 02:33:00 +0000 |
commit | beb116954b9b7f3bb56412b2494b562f02b864b1 (patch) | |
tree | 120e997879884e1b9d93b265221b939d2ef1ade1 /net/appletalk | |
parent | 908d4681a1dc3792ecafbe64265783a86c4cccb6 (diff) |
Import of Linux/MIPS 2.1.14
Diffstat (limited to 'net/appletalk')
-rw-r--r-- | net/appletalk/Makefile | 26 | ||||
-rw-r--r-- | net/appletalk/aarp.c | 179 | ||||
-rw-r--r-- | net/appletalk/ddp.c | 820 | ||||
-rw-r--r-- | net/appletalk/sysctl_net_atalk.c | 13 |
4 files changed, 721 insertions, 317 deletions
diff --git a/net/appletalk/Makefile b/net/appletalk/Makefile index a14da6dd9..bfe567264 100644 --- a/net/appletalk/Makefile +++ b/net/appletalk/Makefile @@ -7,29 +7,11 @@ # # 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 $< +O_TARGET := appletalk.o +O_OBJS := aarp.o ddp.o sysctl_net_atalk.o +M_OBJS := $(O_TARGET) - -OBJS := aarp.o ddp.o - - -appletalk.o: $(OBJS) - $(LD) -r -o appletalk.o $(OBJS) - -dep: - $(CPP) -M *.c > .depend +include $(TOPDIR)/Rules.make tar: tar -cvf /dev/f1 . - -# -# include a dependency file if one exists -# -ifeq (.depend,$(wildcard .depend)) -include .depend -endif diff --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c index 52a46347a..4b8d4fb7e 100644 --- a/net/appletalk/aarp.c +++ b/net/appletalk/aarp.c @@ -3,7 +3,7 @@ * ethernet 'ELAP'. * * Alan Cox <Alan.Cox@linux.org> - * <iialan@www.linux.org.uk> + * <alan@cymru.net> * * This doesn't fit cleanly with the IP arp. This isn't a problem as * the IP arp wants extracting from the device layer in 1.3.x anyway. @@ -11,7 +11,7 @@ * * FIXME: * We ought to handle the retransmits with a single list and a - * seperate fast timer for when it is needed. + * separate fast timer for when it is needed. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -23,10 +23,9 @@ * Inside Appletalk (2nd Ed). */ -#include <asm/segment.h> +#include <asm/uaccess.h> #include <asm/system.h> #include <asm/bitops.h> -#include <linux/config.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/sched.h> @@ -42,13 +41,13 @@ #include <linux/notifier.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> +#include <linux/if_arp.h> #include <linux/skbuff.h> #include <net/sock.h> #include <net/datalink.h> #include <net/psnap.h> -#include <net/atalk.h> +#include <linux/atalk.h> -#ifdef CONFIG_ATALK /* * Lists of aarp entries */ @@ -103,7 +102,7 @@ static void aarp_send_query(struct aarp_entry *a) struct device *dev=a->dev; int len=dev->hard_header_len+sizeof(struct elapaarp)+aarp_dl->header_length; struct sk_buff *skb=alloc_skb(len, GFP_ATOMIC); - struct elapaarp *eah=(struct elapaarp *)(skb->data+dev->hard_header_len+aarp_dl->header_length); + struct elapaarp *eah; struct at_addr *sat=atalk_find_dev_addr(dev); if(skb==NULL || sat==NULL) @@ -112,10 +111,11 @@ static void aarp_send_query(struct aarp_entry *a) /* * Set up the buffer. */ - + + skb_reserve(skb,dev->hard_header_len+aarp_dl->header_length); + eah = (struct elapaarp *)skb_put(skb,sizeof(struct elapaarp)); skb->arp = 1; skb->free = 1; - skb->len = len; skb->dev = a->dev; /* @@ -150,7 +150,6 @@ static void aarp_send_query(struct aarp_entry *a) * Send it. */ - dev_queue_xmit(skb, dev, SOPRI_NORMAL); /* @@ -164,7 +163,7 @@ static void aarp_send_reply(struct device *dev, struct at_addr *us, struct at_ad { int len=dev->hard_header_len+sizeof(struct elapaarp)+aarp_dl->header_length; struct sk_buff *skb=alloc_skb(len, GFP_ATOMIC); - struct elapaarp *eah=(struct elapaarp *)(skb->data+dev->hard_header_len+aarp_dl->header_length); + struct elapaarp *eah; if(skb==NULL) return; @@ -172,10 +171,11 @@ static void aarp_send_reply(struct device *dev, struct at_addr *us, struct at_ad /* * Set up the buffer. */ - + + skb_reserve(skb,dev->hard_header_len+aarp_dl->header_length); + eah = (struct elapaarp *)skb_put(skb,sizeof(struct elapaarp)); skb->arp = 1; skb->free = 1; - skb->len = len; skb->dev = dev; /* @@ -225,7 +225,7 @@ void aarp_send_probe(struct device *dev, struct at_addr *us) { int len=dev->hard_header_len+sizeof(struct elapaarp)+aarp_dl->header_length; struct sk_buff *skb=alloc_skb(len, GFP_ATOMIC); - struct elapaarp *eah=(struct elapaarp *)(skb->data+dev->hard_header_len+aarp_dl->header_length); + struct elapaarp *eah; static char aarp_eth_multicast[ETH_ALEN]={ 0x09, 0x00, 0x07, 0xFF, 0xFF, 0xFF }; if(skb==NULL) @@ -234,10 +234,12 @@ void aarp_send_probe(struct device *dev, struct at_addr *us) /* * Set up the buffer. */ - + + skb_reserve(skb,dev->hard_header_len+aarp_dl->header_length); + eah = (struct elapaarp *)skb_put(skb,sizeof(struct elapaarp)); + skb->arp = 1; skb->free = 1; - skb->len = len; skb->dev = dev; /* @@ -358,9 +360,9 @@ static void aarp_expire_timeout(unsigned long unused) } del_timer(&aarp_timer); if(unresolved_count==0) - aarp_timer.expires=AARP_EXPIRY_TIME; + aarp_timer.expires=jiffies+AARP_EXPIRY_TIME; else - aarp_timer.expires=AARP_TICK_TIME; + aarp_timer.expires=jiffies+AARP_TICK_TIME; add_timer(&aarp_timer); } @@ -368,7 +370,7 @@ static void aarp_expire_timeout(unsigned long unused) * Network device notifier chain handler. */ -static int aarp_device_event(unsigned long event, void *ptr) +static int aarp_device_event(struct notifier_block *this, unsigned long event, void *ptr) { int ct=0; if(event==NETDEV_DOWN) @@ -428,14 +430,60 @@ int aarp_send_ddp(struct device *dev,struct sk_buff *skb, struct at_addr *sa, vo unsigned long flags; /* + * Check for localtalk first + */ + + if(dev->type==ARPHRD_LOCALTLK) + { + struct at_addr *at=atalk_find_dev_addr(dev); + struct ddpehdr *ddp=(struct ddpehdr *)skb->data; + int ft=2; + + /* + * Compressible ? + * + * IFF: src_net==dest_net==device_net + */ + + if(at->s_net==sa->s_net && sa->s_net==ddp->deh_snet) + { + skb_pull(skb,sizeof(struct ddpehdr)-4); + /* + * The upper two remaining bytes are the port + * numbers we just happen to need. Now put the + * length in the lower two. + */ + *((__u16 *)skb->data)=htons(skb->len); + ft=1; + } + /* + * Nice and easy. No AARP type protocols occur here + * so we can just shovel it out with a 3 byte LLAP header + */ + + skb_push(skb,3); + skb->data[0]=sa->s_node; + skb->data[1]=at->s_node; + skb->data[2]=ft; + + if(skb->sk==NULL) + dev_queue_xmit(skb, skb->dev, SOPRI_NORMAL); + else + dev_queue_xmit(skb, skb->dev, skb->sk->priority); + return 1; + } + + /* * Non ELAP we cannot do. */ + if(dev->type!=ARPHRD_ETHER) { return -1; } skb->dev = dev; + skb->protocol = htons(ETH_P_ATALK); hash=sa->s_node%(AARP_HASH_SIZE-1); save_flags(flags); @@ -461,6 +509,7 @@ int aarp_send_ddp(struct device *dev,struct sk_buff *skb, struct at_addr *sa, vo /* * Return 1 and fill in the address */ + a->expires_at=jiffies+AARP_EXPIRY_TIME*10; ddp_dl->datalink_header(ddp_dl, skb, a->hwaddr); if(skb->sk==NULL) @@ -470,22 +519,27 @@ int aarp_send_ddp(struct device *dev,struct sk_buff *skb, struct at_addr *sa, vo restore_flags(flags); return 1; } + /* * Do we have an unresolved entry: This is the less common path */ + a=aarp_find_entry(unresolved[hash],dev,sa); if(a!=NULL) { /* * Queue onto the unresolved queue */ + skb_queue_tail(&a->packet_queue, skb); restore_flags(flags); return 0; } + /* * Allocate a new entry */ + a=aarp_alloc(); if(a==NULL) { @@ -496,9 +550,11 @@ int aarp_send_ddp(struct device *dev,struct sk_buff *skb, struct at_addr *sa, vo restore_flags(flags); return -1; } + /* * Set up the queue */ + skb_queue_tail(&a->packet_queue, skb); a->expires_at=jiffies+AARP_RESOLVE_TIME; a->dev=dev; @@ -508,26 +564,37 @@ int aarp_send_ddp(struct device *dev,struct sk_buff *skb, struct at_addr *sa, vo unresolved[hash]=a; unresolved_count++; restore_flags(flags); + /* * Send an initial request for the address */ + aarp_send_query(a); + /* * Switch to fast timer if needed (That is if this is the * first unresolved entry to get added) */ + if(unresolved_count==1) { del_timer(&aarp_timer); - aarp_timer.expires=AARP_TICK_TIME; + aarp_timer.expires=jiffies+AARP_TICK_TIME; add_timer(&aarp_timer); } + /* * Tell the ddp layer we have taken over for this frame. */ + return 0; } +/* + * An entry in the aarp unresolved queue has become resolved. Send + * all the frames queued under it. + */ + static void aarp_resolved(struct aarp_entry **list, struct aarp_entry *a, int hash) { struct sk_buff *skb; @@ -537,10 +604,18 @@ static void aarp_resolved(struct aarp_entry **list, struct aarp_entry *a, int ha { unresolved_count--; *list=a->next; - /* Move into the resolved list */ + + /* + * Move into the resolved list + */ + a->next=resolved[hash]; resolved[hash]=a; - /* Kick frames off */ + + /* + * Kick frames off + */ + while((skb=skb_dequeue(&a->packet_queue))!=NULL) { a->expires_at=jiffies+AARP_EXPIRY_TIME*10; @@ -556,6 +631,11 @@ static void aarp_resolved(struct aarp_entry **list, struct aarp_entry *a, int ha } } +/* + * This is called by the SNAP driver whenever we see an AARP SNAP + * frame. We currently only support ethernet. + */ + static int aarp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) { struct elapaarp *ea=(struct elapaarp *)skb->h.raw; @@ -580,7 +660,7 @@ static int aarp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type * Frame size ok ? */ - if(skb->len<sizeof(*ea)) + if(!skb_pull(skb,sizeof(*ea))) { kfree_skb(skb, FREE_READ); return 0; @@ -636,6 +716,7 @@ static int aarp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type /* * Fail the probe (in use) */ + ifa->status|=ATIF_PROBE_FAIL; restore_flags(flags); kfree_skb(skb, FREE_READ); @@ -658,12 +739,13 @@ static int aarp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type /* * We can fill one in - this is good */ + memcpy(a->hwaddr,ea->hw_src,ETH_ALEN); aarp_resolved(&unresolved[hash],a,hash); if(unresolved_count==0) { del_timer(&aarp_timer); - aarp_timer.expires=AARP_EXPIRY_TIME; + aarp_timer.expires=jiffies+AARP_EXPIRY_TIME; add_timer(&aarp_timer); } break; @@ -691,6 +773,7 @@ static int aarp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type /* * aarp_my_address has found the address to use for us. */ + aarp_send_reply(dev,ma,&sa,ea->hw_src); break; } @@ -705,17 +788,57 @@ static struct notifier_block aarp_notifier={ 0 }; +static char aarp_snap_id[]={0x00,0x00,0x00,0x80,0xF3}; + void aarp_proto_init(void) { - static char aarp_snap_id[]={0x00,0x00,0x00,0x80,0xF3}; if((aarp_dl=register_snap_client(aarp_snap_id, aarp_rcv))==NULL) - printk("Unable to register AARP with SNAP.\n"); + printk(KERN_CRIT "Unable to register AARP with SNAP.\n"); init_timer(&aarp_timer); aarp_timer.function=aarp_expire_timeout; aarp_timer.data=0; - aarp_timer.expires=AARP_EXPIRY_TIME; + aarp_timer.expires=jiffies+AARP_EXPIRY_TIME; add_timer(&aarp_timer); register_netdevice_notifier(&aarp_notifier); } -#endif + + +#ifdef MODULE + +/* Free all the entries in an aarp list. Caller should turn off interrupts. */ +static void free_entry_list(struct aarp_entry *list) +{ + struct aarp_entry *tmp; + + while (list != NULL) + { + tmp = list->next; + aarp_expire(list); + list = tmp; + } +} + +/* General module cleanup. Called from cleanup_module() in ddp.c. */ +void aarp_cleanup_module(void) +{ + unsigned long flags; + int i; + + save_flags(flags); + cli(); + + del_timer(&aarp_timer); + unregister_netdevice_notifier(&aarp_notifier); + unregister_snap_client(aarp_snap_id); + + for (i = 0; i < AARP_HASH_SIZE; i++) + { + free_entry_list(resolved[i]); + free_entry_list(unresolved[i]); + } + + restore_flags(flags); +} + +#endif /* MODULE */ diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 67ad1bf22..211842144 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -9,6 +9,22 @@ * * Wesley Craig <netatalk@umich.edu> * + * Fixes: + * Michael Callahan : Made routing work + * Wesley Craig : Fix probing to listen to a + * passed node id. + * Alan Cox : Added send/recvmsg support + * Alan Cox : Moved at. to protinfo in + * socket. + * Alan Cox : Added firewall hooks. + * Alan Cox : Supports new ARPHRD_LOOPBACK + * Christer Weinigel : Routing and /proc fixes. + * Bradford Johnson : Localtalk. + * Tom Dyas : Module support. + * Alan Cox : Hooks for PPP (based on the + * localtalk hook). + * Alan Cox : Posix bits + * * 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 @@ -16,13 +32,13 @@ * * TODO * ASYNC I/O - * Testing. */ -#include <asm/segment.h> +#include <linux/config.h> +#include <linux/module.h> +#include <asm/uaccess.h> #include <asm/system.h> #include <asm/bitops.h> -#include <linux/config.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/sched.h> @@ -34,21 +50,25 @@ #include <linux/errno.h> #include <linux/interrupt.h> #include <linux/if_ether.h> +#include <linux/route.h> #include <linux/inet.h> #include <linux/notifier.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> +#include <linux/if_arp.h> #include <linux/skbuff.h> #include <linux/termios.h> /* For TIOCOUTQ/INQ */ #include <net/datalink.h> #include <net/p8022.h> #include <net/psnap.h> #include <net/sock.h> -#include <net/atalk.h> +#include <linux/atalk.h> +#include <linux/proc_fs.h> +#include <linux/stat.h> +#include <linux/firewall.h> -#ifdef CONFIG_ATALK -#define APPLETALK_DEBUG +#undef APPLETALK_DEBUG #ifdef APPLETALK_DEBUG @@ -117,23 +137,28 @@ static atalk_socket *atalk_search_socket(struct sockaddr_at *to, struct atalk_if { atalk_socket *s; - for( s = atalk_socket_list; s != NULL; s = s->next ) { - if ( to->sat_port != s->at.src_port ) { - continue; - } + for( s = atalk_socket_list; s != NULL; s = s->next ) + { + if ( to->sat_port != s->protinfo.af_at.src_port ) + { + continue; + } - if ( to->sat_addr.s_net == 0 && + if ( to->sat_addr.s_net == 0 && to->sat_addr.s_node == ATADDR_BCAST && - s->at.src_net == atif->address.s_net ) { - break; - } + s->protinfo.af_at.src_net == atif->address.s_net ) + { + break; + } - if ( to->sat_addr.s_net == s->at.src_net && - to->sat_addr.s_node == s->at.src_node ) { - break; - } + if ( to->sat_addr.s_net == s->protinfo.af_at.src_net && + (to->sat_addr.s_node == s->protinfo.af_at.src_node + ||to->sat_addr.s_node == ATADDR_BCAST )) + { + break; + } - /* XXXX.0 */ + /* XXXX.0 */ } return( s ); } @@ -146,17 +171,21 @@ static atalk_socket *atalk_find_socket(struct sockaddr_at *sat) { atalk_socket *s; - for ( s = atalk_socket_list; s != NULL; s = s->next ) { - if ( s->at.src_net != sat->sat_addr.s_net ) { - continue; - } - if ( s->at.src_node != sat->sat_addr.s_node ) { - continue; - } - if ( s->at.src_port != sat->sat_port ) { - continue; - } - break; + for ( s = atalk_socket_list; s != NULL; s = s->next ) + { + if ( s->protinfo.af_at.src_net != sat->sat_addr.s_net ) + { + continue; + } + if ( s->protinfo.af_at.src_node != sat->sat_addr.s_node ) + { + continue; + } + if ( s->protinfo.af_at.src_port != sat->sat_port ) + { + continue; + } + break; } return( s ); } @@ -190,14 +219,17 @@ static void atalk_destroy_socket(atalk_socket *sk) } if(sk->wmem_alloc == 0 && sk->rmem_alloc == 0 && sk->dead) - kfree_s(sk,sizeof(*sk)); + { + sk_free(sk); + MOD_DEC_USE_COUNT; + } else { /* * Someone is using our buffers still.. defer */ init_timer(&sk->timer); - sk->timer.expires=10*HZ; + sk->timer.expires=jiffies+10*HZ; sk->timer.function=atalk_destroy_timer; sk->timer.data = (unsigned long)sk; add_timer(&sk->timer); @@ -205,8 +237,11 @@ static void atalk_destroy_socket(atalk_socket *sk) } -/* Called from proc fs */ -int atalk_get_info(char *buffer, char **start, off_t offset, int length) +/* + * Called from proc fs + */ + +int atalk_get_info(char *buffer, char **start, off_t offset, int length, int dummy) { atalk_socket *s; int len=0; @@ -214,20 +249,22 @@ int atalk_get_info(char *buffer, char **start, off_t offset, int length) off_t begin=0; /* - * Fill this in to print out the appletalk info you want + * Output the appletalk data for the /proc virtual fs. */ - /* Theory.. Keep printing in the same place until we pass offset */ - len += sprintf (buffer,"Type local_addr remote_addr tx_queue rx_queue st uid\n"); for (s = atalk_socket_list; s != NULL; s = s->next) { len += sprintf (buffer+len,"%02X ", s->type); len += sprintf (buffer+len,"%04X:%02X:%02X ", - s->at.src_net,s->at.src_node,s->at.src_port); + ntohs(s->protinfo.af_at.src_net), + s->protinfo.af_at.src_node, + s->protinfo.af_at.src_port); len += sprintf (buffer+len,"%04X:%02X:%02X ", - s->at.dest_net,s->at.dest_node,s->at.dest_port); - len += sprintf (buffer+len,"%08lX:%08lX ", s->wmem_alloc, s->rmem_alloc); + ntohs(s->protinfo.af_at.dest_net), + s->protinfo.af_at.dest_node, + s->protinfo.af_at.dest_port); + len += sprintf (buffer+len,"%08X:%08X ", s->wmem_alloc, s->rmem_alloc); len += sprintf (buffer+len,"%02X %d\n", s->state, SOCK_INODE(s->socket)->i_uid); /* Are we still dumping unwanted data then discard the record */ @@ -316,10 +353,42 @@ static int atif_probe_device(struct atalk_iface *atif) int ct; int netrange=ntohs(atif->nets.nr_lastnet)-ntohs(atif->nets.nr_firstnet)+1; int probe_net=ntohs(atif->address.s_net); + int probe_node=atif->address.s_node; int netct; int nodect; - + struct ifreq atreq; + struct sockaddr_at *sa; + int err; + +/* + * THIS IS A HACK: Farallon cards want to do their own picking of + * addresses. This needs tidying up post 1.4, but we need it in + * now for the 1.4 release as is. + * + */ + if((atif->dev->type == ARPHRD_LOCALTLK || atif->dev->type == ARPHRD_PPP) + && atif->dev->do_ioctl) + { + /* fake up the request and pass it down */ + sa = (struct sockaddr_at*)&atreq.ifr_addr; + sa->sat_addr.s_node = probe_node; + sa->sat_addr.s_net = probe_net; + if (!(err=atif->dev->do_ioctl(atif->dev,&atreq,SIOCSIFADDR))) + { + (void)atif->dev->do_ioctl(atif->dev,&atreq,SIOCGIFADDR); + atif->address.s_net=htons(sa->sat_addr.s_net); + atif->address.s_node=sa->sat_addr.s_node; + return 0; + } + /* + * If it didn't like our faked request then fail: + * This should check against -ENOIOCTLCMD and fall + * through. That needs us to fix all the devices up + * properly. We can then also dump the localtalk test. + */ + return err; + } /* * Offset the network we start probing with. */ @@ -332,6 +401,9 @@ static int atif_probe_device(struct atalk_iface *atif) probe_net=ntohs(atif->nets.nr_firstnet) + (jiffies%netrange); } + if(probe_node == ATADDR_ANYNODE) + probe_node = jiffies&0xFF; + /* * Scan the networks. @@ -340,14 +412,13 @@ static int atif_probe_device(struct atalk_iface *atif) for(netct=0;netct<=netrange;netct++) { /* - * Sweep the available nodes from a random start. + * Sweep the available nodes from a given start. */ - int nodeoff=jiffies&255; - + atif->address.s_net=htons(probe_net); for(nodect=0;nodect<256;nodect++) { - atif->address.s_node=((nodect+nodeoff)&0xFF); + atif->address.s_node=((nodect+probe_node)&0xFF); if(atif->address.s_node>0&&atif->address.s_node<254) { /* @@ -420,13 +491,12 @@ struct atalk_iface *atalk_find_dev(struct device *dev) static struct atalk_iface *atalk_find_anynet(int node, struct device *dev) { struct atalk_iface *iface; - for(iface=atalk_iface_list;iface!=NULL;iface=iface->next) { - if ( iface->dev != dev || ( iface->status & ATIF_PROBE )) { + for(iface=atalk_iface_list;iface!=NULL;iface=iface->next) + { + if ( iface->dev != dev || ( iface->status & ATIF_PROBE )) continue; - } - if ( node == ATADDR_BCAST || iface->address.s_node == node ) { + if ( node == ATADDR_BCAST || iface->address.s_node == node ) return iface; - } } return NULL; } @@ -537,29 +607,30 @@ static int atrtr_create(struct rtentry *r, struct device *devhint) if(r->rt_flags != rt->flags) continue; - if(ta->sat_addr.s_net == rt->target.s_net) { - if(!(rt->flags&RTF_HOST)) - break; - if(ta->sat_addr.s_node == rt->target.s_node) - break; + if(ta->sat_addr.s_net == rt->target.s_net) + { + if(!(rt->flags&RTF_HOST)) + break; + if(ta->sat_addr.s_node == rt->target.s_node) + break; } } - if ( devhint == NULL ) { - for ( riface = NULL, iface = atalk_iface_list; iface; - iface = iface->next ) { - if ( riface == NULL && ntohs( ga->sat_addr.s_net ) >= - ntohs( iface->nets.nr_firstnet ) && - ntohs( ga->sat_addr.s_net ) <= - ntohs( iface->nets.nr_lastnet )) - riface = iface; - if ( ga->sat_addr.s_net == iface->address.s_net && - ga->sat_addr.s_node == iface->address.s_node ) - riface = iface; - } - if ( riface == NULL ) - return -ENETUNREACH; - devhint = riface->dev; + if ( devhint == NULL ) + { + for ( riface = NULL, iface = atalk_iface_list; iface; iface = iface->next ) + { + if ( riface == NULL && ntohs( ga->sat_addr.s_net ) >= ntohs( iface->nets.nr_firstnet ) && + ntohs( ga->sat_addr.s_net ) <= ntohs( iface->nets.nr_lastnet )) + { + riface = iface; + } + if ( ga->sat_addr.s_net == iface->address.s_net && ga->sat_addr.s_node == iface->address.s_node ) + riface = iface; + } + if ( riface == NULL ) + return -ENETUNREACH; + devhint = riface->dev; } if(rt==NULL) @@ -594,10 +665,12 @@ static int atrtr_delete( struct at_addr *addr ) struct atalk_route **r = &atalk_router_list; struct atalk_route *tmp; - while ((tmp = *r) != NULL) { + while ((tmp = *r) != NULL) + { if (tmp->target.s_net == addr->s_net && (!(tmp->flags&RTF_GATEWAY) || - tmp->target.s_node == addr->s_node )) { + tmp->target.s_node == addr->s_node )) + { *r = tmp->next; kfree_s(tmp, sizeof(struct atalk_route)); return 0; @@ -617,8 +690,10 @@ void atrtr_device_down(struct device *dev) struct atalk_route **r = &atalk_router_list; struct atalk_route *tmp; - while ((tmp = *r) != NULL) { - if (tmp->dev == dev) { + while ((tmp = *r) != NULL) + { + if (tmp->dev == dev) + { *r = tmp->next; kfree_s(tmp, sizeof(struct atalk_route)); } @@ -630,11 +705,11 @@ void atrtr_device_down(struct device *dev) } /* - * A device event has occured. Watch for devices going down and + * A device event has occurred. Watch for devices going down and * delete our use of them (iface and route). */ -static int ddp_device_event(unsigned long event, void *ptr) +static int ddp_device_event(struct notifier_block *this, unsigned long event, void *ptr) { if(event==NETDEV_DOWN) { @@ -661,17 +736,15 @@ int atif_ioctl(int cmd, void *arg) struct sockaddr_at *sa; struct device *dev; struct atalk_iface *atif; - int ro=(cmd==SIOCSIFADDR); - int err=verify_area(ro?VERIFY_READ:VERIFY_WRITE, arg,sizeof(atreq)); + int err; int ct; int limit; struct rtentry rtdef; - if(err) - return err; - - memcpy_fromfs(&atreq,arg,sizeof(atreq)); - + err = copy_from_user(&atreq,arg,sizeof(atreq)); + if (err) + return -EFAULT; + if((dev=dev_get(atreq.ifr_name))==NULL) return -ENODEV; @@ -685,10 +758,16 @@ int atif_ioctl(int cmd, void *arg) return -EPERM; if(sa->sat_family!=AF_APPLETALK) return -EINVAL; - if(dev->type!=ARPHRD_ETHER) + if(dev->type!=ARPHRD_ETHER&&dev->type!=ARPHRD_LOOPBACK + &&dev->type!=ARPHRD_LOCALTLK && dev->type!=ARPHRD_PPP) return -EPROTONOSUPPORT; nr=(struct netrange *)&sa->sat_zero[0]; - if(nr->nr_phase!=2) + /* + * Phase 1 is fine on localtalk but we don't + * do Ethertalk phase 1. Anyone wanting to add + * it go ahead. + */ + if(dev->type==ARPHRD_ETHER && nr->nr_phase!=2) return -EPROTONOSUPPORT; if(sa->sat_addr.s_node==ATADDR_BCAST || sa->sat_addr.s_node == 254) return -EINVAL; @@ -739,15 +818,18 @@ int atif_ioctl(int cmd, void *arg) /* * Routerless initial state. */ - if(nr->nr_firstnet==htons(0) && nr->nr_lastnet==htons(0xFFFE)) { + if(nr->nr_firstnet==htons(0) && nr->nr_lastnet==htons(0xFFFE)) + { sa->sat_addr.s_net=atif->address.s_net; atrtr_create(&rtdef, dev); atrtr_set_default(dev); - } else { + } + else + { limit=ntohs(nr->nr_lastnet); if(limit-ntohs(nr->nr_firstnet) > 256) { - printk("Too many routes/iface.\n"); + printk(KERN_WARNING "Too many routes/iface.\n"); return -EINVAL; } for(ct=ntohs(nr->nr_firstnet);ct<=limit;ct++) @@ -772,8 +854,13 @@ int atif_ioctl(int cmd, void *arg) ((struct sockaddr_at *)(&atreq.ifr_addr))->sat_addr.s_node=ATADDR_BCAST; break; } - memcpy_tofs(arg,&atreq,sizeof(atreq)); - return 0; + err = copy_to_user(arg,&atreq,sizeof(atreq)); + + if (err) + { + err = -EFAULT; + } + return err; } /* @@ -785,11 +872,10 @@ static int atrtr_ioctl(unsigned int cmd, void *arg) int err; struct rtentry rt; - err=verify_area(VERIFY_READ, arg, sizeof(rt)); - if(err) - return err; - memcpy_fromfs(&rt,arg,sizeof(rt)); - + err = copy_from_user(&rt,arg,sizeof(rt)); + if (err) + return -EFAULT; + switch(cmd) { case SIOCDELRT: @@ -805,7 +891,7 @@ static int atrtr_ioctl(unsigned int cmd, void *arg) /* Called from proc fs - just make it print the ifaces neatly */ -int atalk_if_get_info(char *buffer, char **start, off_t offset, int length) +int atalk_if_get_info(char *buffer, char **start, off_t offset, int length, int dummy) { struct atalk_iface *iface; int len=0; @@ -838,7 +924,7 @@ int atalk_if_get_info(char *buffer, char **start, off_t offset, int length) /* Called from proc fs - just make it print the routes neatly */ -int atalk_rt_get_info(char *buffer, char **start, off_t offset, int length) +int atalk_rt_get_info(char *buffer, char **start, off_t offset, int length, int dummy) { struct atalk_route *rt; int len=0; @@ -849,13 +935,13 @@ int atalk_rt_get_info(char *buffer, char **start, off_t offset, int length) if(atrtr_default.dev) { rt=&atrtr_default; - len += sprintf (buffer+len,"Default %5d:%-3d %-4d %s\n", + len += sprintf (buffer+len,"Default %04X:%02X %-4d %s\n", ntohs(rt->gateway.s_net), rt->gateway.s_node, rt->flags, rt->dev->name); } for (rt = atalk_router_list; rt != NULL; rt = rt->next) { - len += sprintf (buffer+len,"%04X:%02X %5d:%-3d %-4d %s\n", + len += sprintf (buffer+len,"%04X:%02X %04X:%02X %-4d %s\n", ntohs(rt->target.s_net),rt->target.s_node, ntohs(rt->gateway.s_net), rt->gateway.s_node, rt->flags, rt->dev->name); @@ -913,7 +999,7 @@ unsigned short atalk_checksum(struct ddpehdr *ddp, int len) /* * Generic fcntl calls are already dealt with. If we don't need funny ones - * this is the all you need. Async I/O is also seperate. + * this is the all you need. Async I/O is also separate. */ static int atalk_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg) @@ -941,10 +1027,9 @@ static int atalk_setsockopt(struct socket *sock, int level, int optname, char *o if(optval==NULL) return(-EINVAL); - err=verify_area(VERIFY_READ,optval,sizeof(int)); - if(err) + err = get_user(opt, (int *)optval); + if (err) return err; - opt=get_fs_long((unsigned long *)optval); switch(level) { @@ -956,7 +1041,7 @@ static int atalk_setsockopt(struct socket *sock, int level, int optname, char *o } break; - case SOL_SOCKET: + case SOL_SOCKET: return sock_setsockopt(sk,level,optname,optval,optlen); default: @@ -995,13 +1080,10 @@ static int atalk_getsockopt(struct socket *sock, int level, int optname, default: return -EOPNOTSUPP; } - err=verify_area(VERIFY_WRITE,optlen,sizeof(int)); - if(err) - return err; - put_fs_long(sizeof(int),(unsigned long *)optlen); - err=verify_area(VERIFY_WRITE,optval,sizeof(int)); - put_fs_long(val,(unsigned long *)optval); - return(0); + err = put_user(sizeof(int),optlen); + if (!err) + err = put_user(val, (int *) optval); + return err; } /* @@ -1040,7 +1122,7 @@ static void def_callback2(struct sock *sk, int len) static int atalk_create(struct socket *sock, int protocol) { atalk_socket *sk; - sk=(atalk_socket *)kmalloc(sizeof(*sk),GFP_KERNEL); + sk=(atalk_socket *)sk_alloc(GFP_KERNEL); if(sk==NULL) return(-ENOMEM); switch(sock->type) @@ -1052,42 +1134,25 @@ static int atalk_create(struct socket *sock, int protocol) case SOCK_DGRAM: break; default: - kfree_s((void *)sk,sizeof(*sk)); + sk_free((void *)sk); return(-ESOCKTNOSUPPORT); } - sk->dead=0; - sk->next=NULL; - sk->broadcast=0; + + MOD_INC_USE_COUNT; + sk->no_check=0; /* Checksums on by default */ + sk->allocation=GFP_KERNEL; sk->rcvbuf=SK_RMEM_MAX; sk->sndbuf=SK_WMEM_MAX; sk->pair=NULL; - sk->wmem_alloc=0; - sk->rmem_alloc=0; - sk->inuse=0; - sk->proc=0; sk->priority=1; - sk->shutdown=0; - sk->prot=NULL; /* So we use default free mechanisms */ - sk->broadcast=0; - sk->err=0; skb_queue_head_init(&sk->receive_queue); skb_queue_head_init(&sk->write_queue); - sk->send_head=NULL; skb_queue_head_init(&sk->back_log); sk->state=TCP_CLOSE; sk->socket=sock; sk->type=sock->type; - sk->debug=0; - - sk->at.src_net=0; - sk->at.src_node=0; - sk->at.src_port=0; - sk->at.dest_net=0; - sk->at.dest_node=0; - sk->at.dest_port=0; - sk->mtu=DDP_MAXSZ; if(sock!=NULL) @@ -1138,10 +1203,11 @@ static int atalk_release(struct socket *sock, struct socket *peer) static int atalk_pick_port(struct sockaddr_at *sat) { - for ( sat->sat_port = ATPORT_RESERVED; sat->sat_port < ATPORT_LAST; - sat->sat_port++ ) - if ( atalk_find_socket( sat ) == NULL ) - return sat->sat_port; + for ( sat->sat_port = ATPORT_RESERVED; sat->sat_port < ATPORT_LAST; sat->sat_port++ ) + { + if ( atalk_find_socket( sat ) == NULL ) + return sat->sat_port; + } return -EBUSY; } @@ -1152,13 +1218,13 @@ static int atalk_autobind(atalk_socket *sk) int n; if ( ap == NULL || ap->s_net == htons( ATADDR_ANYNET )) - return -EADDRNOTAVAIL; - sk->at.src_net = sat.sat_addr.s_net = ap->s_net; - sk->at.src_node = sat.sat_addr.s_node = ap->s_node; + return -EADDRNOTAVAIL; + sk->protinfo.af_at.src_net = sat.sat_addr.s_net = ap->s_net; + sk->protinfo.af_at.src_node = sat.sat_addr.s_node = ap->s_node; if (( n = atalk_pick_port( &sat )) < 0 ) - return( n ); - sk->at.src_port=n; + return( n ); + sk->protinfo.af_at.src_port=n; atalk_insert_socket(sk); sk->zapped=0; return 0; @@ -1168,7 +1234,7 @@ static int atalk_autobind(atalk_socket *sk) * Set the address 'our end' of the connection. */ -static int atalk_bind(struct socket *sock, struct sockaddr *uaddr,int addr_len) +static int atalk_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) { atalk_socket *sk; struct sockaddr_at *addr=(struct sockaddr_at *)uaddr; @@ -1176,7 +1242,7 @@ static int atalk_bind(struct socket *sock, struct sockaddr *uaddr,int addr_len) sk=(atalk_socket *)sock->data; if(sk->zapped==0) - return(-EIO); + return(-EINVAL); if(addr_len!=sizeof(struct sockaddr_at)) return -EINVAL; @@ -1189,16 +1255,15 @@ static int atalk_bind(struct socket *sock, struct sockaddr *uaddr,int addr_len) struct at_addr *ap=atalk_find_primary(); if(ap==NULL) return -EADDRNOTAVAIL; - sk->at.src_net=addr->sat_addr.s_net=ap->s_net; - sk->at.src_node=addr->sat_addr.s_node=ap->s_node; + sk->protinfo.af_at.src_net=addr->sat_addr.s_net=ap->s_net; + sk->protinfo.af_at.src_node=addr->sat_addr.s_node=ap->s_node; } else { - if ( atalk_find_interface( addr->sat_addr.s_net, - addr->sat_addr.s_node ) == NULL ) - return -EADDRNOTAVAIL; - sk->at.src_net=addr->sat_addr.s_net; - sk->at.src_node=addr->sat_addr.s_node; + if ( atalk_find_interface( addr->sat_addr.s_net, addr->sat_addr.s_node ) == NULL ) + return -EADDRNOTAVAIL; + sk->protinfo.af_at.src_net=addr->sat_addr.s_net; + sk->protinfo.af_at.src_node=addr->sat_addr.s_node; } if(addr->sat_port == ATADDR_ANYPORT) @@ -1206,10 +1271,10 @@ static int atalk_bind(struct socket *sock, struct sockaddr *uaddr,int addr_len) int n = atalk_pick_port(addr); if(n < 0) return n; - sk->at.src_port=addr->sat_port=n; + sk->protinfo.af_at.src_port=addr->sat_port=n; } else - sk->at.src_port=addr->sat_port; + sk->protinfo.af_at.src_port=addr->sat_port; if(atalk_find_socket(addr)!=NULL) return -EADDRINUSE; @@ -1238,9 +1303,9 @@ static int atalk_connect(struct socket *sock, struct sockaddr *uaddr, if(addr->sat_family!=AF_APPLETALK) return -EAFNOSUPPORT; -#if 0 /* Netatalk doesnt check this */ +#if 0 /* Netatalk doesn't check this - fix netatalk first!*/ if(addr->sat_addr.s_node==ATADDR_BCAST && !sk->broadcast) - return -EPERM; + return -EACCES; #endif if(sk->zapped) { @@ -1251,9 +1316,9 @@ static int atalk_connect(struct socket *sock, struct sockaddr *uaddr, if(atrtr_get_dev(&addr->sat_addr)==NULL) return -ENETUNREACH; - sk->at.dest_port=addr->sat_port; - sk->at.dest_net=addr->sat_addr.s_net; - sk->at.dest_node=addr->sat_addr.s_node; + sk->protinfo.af_at.dest_port=addr->sat_port; + sk->protinfo.af_at.dest_net=addr->sat_addr.s_net; + sk->protinfo.af_at.dest_node=addr->sat_addr.s_node; sock->state = SS_CONNECTED; sk->state=TCP_ESTABLISHED; return(0); @@ -1275,7 +1340,7 @@ static int atalk_socketpair(struct socket *sock1, struct socket *sock2) static int atalk_accept(struct socket *sock, struct socket *newsock, int flags) { if(newsock->data) - kfree_s(newsock->data,sizeof(atalk_socket)); + sk_free(newsock->data); return -EOPNOTSUPP; } @@ -1294,7 +1359,7 @@ static int atalk_getname(struct socket *sock, struct sockaddr *uaddr, if(sk->zapped) { if(atalk_autobind(sk)<0) - return -EBUSY; + return -ENOBUFS; } *uaddr_len = sizeof(struct sockaddr_at); @@ -1303,15 +1368,15 @@ static int atalk_getname(struct socket *sock, struct sockaddr *uaddr, { if(sk->state!=TCP_ESTABLISHED) return -ENOTCONN; - sat.sat_addr.s_net=sk->at.dest_net; - sat.sat_addr.s_node=sk->at.dest_node; - sat.sat_port=sk->at.dest_port; + sat.sat_addr.s_net=sk->protinfo.af_at.dest_net; + sat.sat_addr.s_node=sk->protinfo.af_at.dest_node; + sat.sat_port=sk->protinfo.af_at.dest_port; } else { - sat.sat_addr.s_net=sk->at.src_net; - sat.sat_addr.s_node=sk->at.src_node; - sat.sat_port=sk->at.src_port; + sat.sat_addr.s_net=sk->protinfo.af_at.src_net; + sat.sat_addr.s_node=sk->protinfo.af_at.src_node; + sat.sat_port=sk->protinfo.af_at.src_port; } sat.sat_family = AF_APPLETALK; memcpy(uaddr,&sat,sizeof(sat)); @@ -1321,15 +1386,17 @@ static int atalk_getname(struct socket *sock, struct sockaddr *uaddr, /* * Receive a packet (in skb) from device dev. This has come from the SNAP decoder, and on entry * skb->h.raw is the DDP header, skb->len is the DDP length. The physical headers have been - * extracted. + * extracted. PPP should probably pass frames marked as for this layer + * [ie ARPHRD_ETHERTALK] */ -int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) +static int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) { atalk_socket *sock; struct ddpehdr *ddp=(void *)skb->h.raw; struct atalk_iface *atif; struct sockaddr_at tosat; + int origlen; /* Size check */ if(skb->len<sizeof(*ddp)) @@ -1342,7 +1409,11 @@ int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) /* * Fix up the length field [Ok this is horrible but otherwise * I end up with unions of bit fields and messy bit field order - * compiler/endian dependancies..] + * compiler/endian dependencies..] + * + * FIXME: This is a write to a shared object. Granted it + * happens to be safe BUT.. (Its safe as user space will not + * run until we put it back) */ *((__u16 *)ddp)=ntohs(*((__u16 *)ddp)); @@ -1351,12 +1422,14 @@ int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) * Trim buffer in case of stray trailing data */ - skb->len=min(skb->len,ddp->deh_len); + origlen = skb->len; + + skb_trim(skb,min(skb->len,ddp->deh_len)); /* * Size check to see if ddp->deh_len was crap * (Otherwise we'll detonate most spectacularly - * in the middle of recvfrom()). + * in the middle of recvmsg()). */ if(skb->len<sizeof(*ddp)) @@ -1376,6 +1449,16 @@ int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) kfree_skb(skb,FREE_READ); return(0); } + +#ifdef CONFIG_FIREWALL + + if(call_in_firewall(AF_APPLETALK, skb->dev, ddp, NULL)!=FW_ACCEPT) + { + kfree_skb(skb, FREE_READ); + return 0; + } + +#endif /* Check the packet is aimed at us */ @@ -1389,8 +1472,29 @@ int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) { struct atalk_route *rt; struct at_addr ta; + + /* Don't route multicast, etc., packets, or packets + sent to "this network" */ + if (skb->pkt_type != PACKET_HOST || ddp->deh_dnet == 0) + { + kfree_skb(skb, FREE_READ); + return(0); + } + +#ifdef CONFIG_FIREWALL + /* + * Check firewall allows this routing + */ + + if(call_fw_firewall(AF_APPLETALK, skb->dev, ddp, NULL)!=FW_ACCEPT) + { + kfree_skb(skb, FREE_READ); + return(0); + } +#endif ta.s_net=ddp->deh_dnet; ta.s_node=ddp->deh_dnode; + /* Route the packet */ rt=atrtr_find(&ta); if(rt==NULL || ddp->deh_hops==15) @@ -1399,12 +1503,34 @@ int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) return(0); } ddp->deh_hops++; + + /* + * Route goes through another gateway, so + * set the target to the gateway instead. + */ + + if(rt->flags&RTF_GATEWAY) + { + ta.s_net = rt->gateway.s_net; + ta.s_node = rt->gateway.s_node; + } + + /* Fix up skb->len field */ + skb_trim(skb,min(origlen, rt->dev->hard_header_len + + ddp_dl->header_length + ddp->deh_len)); + *((__u16 *)ddp)=ntohs(*((__u16 *)ddp)); /* Mend the byte order */ /* * Send the buffer onwards */ - if(aarp_send_ddp(dev,skb, &ta, NULL)==-1) - kfree_skb(skb, FREE_READ); + + skb=skb_unshare(skb, GFP_ATOMIC, FREE_READ); + if(skb) + { + skb->arp = 1; /* Resolved */ + if(aarp_send_ddp(rt->dev, skb, &ta, NULL)==-1) + kfree_skb(skb, FREE_READ); + } return 0; } @@ -1437,11 +1563,74 @@ int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) return(0); } -static int atalk_sendto(struct socket *sock, void *ubuf, int len, int noblock, - unsigned flags, struct sockaddr *sat, int addr_len) +/* + * Receive a localtalk frame. We make some demands on the caller here. + * Caller must provide enough headroom on the packet to pull the short + * header and append a long one. + */ + + +static int ltalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) +{ + struct ddpehdr *ddp; + struct at_addr *ap; + /* + * Expand any short form frames. + */ + + if(skb->mac.raw[2]==1) + { + /* + * Find our address. + */ + + ap=atalk_find_dev_addr(dev); + if(ap==NULL || skb->len<sizeof(struct ddpshdr)) + { + kfree_skb(skb, FREE_READ); + return 0; + } + + /* + * The push leaves us with a ddephdr not an shdr, and + * handily the port bytes in the right place preset. + */ + + skb_push(skb, sizeof(*ddp)-4); + ddp=(struct ddpehdr *)skb->data; + + /* + * Now fill in the long header. + */ + + /* + * These two first. The mac overlays the new source/dest + * network information so we MUST copy these before + * we write the network numbers ! + */ + + ddp->deh_dnode=skb->mac.raw[0]; /* From physical header */ + ddp->deh_snode=skb->mac.raw[1]; /* From physical header */ + + ddp->deh_dnet=ap->s_net; /* Network number */ + ddp->deh_snet=ap->s_net; + ddp->deh_sum=0; /* No checksum */ + /* + * Not sure about this bit... + */ + ddp->deh_len=skb->len; + ddp->deh_hops=15; /* Non routable, so force a drop + if we slip up later */ + *((__u16 *)ddp)=htons(*((__u16 *)ddp)); /* Mend the byte order */ + } + skb->h.raw = skb->data; + return atalk_rcv(skb,dev,pt); +} + +static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, int len, int nonblock, int flags) { atalk_socket *sk=(atalk_socket *)sock->data; - struct sockaddr_at *usat=(struct sockaddr_at *)sat; + struct sockaddr_at *usat=(struct sockaddr_at *)msg->msg_name; struct sockaddr_at local_satalk, gsat; struct sk_buff *skb; struct device *dev; @@ -1460,17 +1649,16 @@ static int atalk_sendto(struct socket *sock, void *ubuf, int len, int noblock, if(usat) { if(sk->zapped) - /* put the autobinding in */ { if(atalk_autobind(sk)<0) return -EBUSY; } - if(addr_len <sizeof(*usat)) + if(msg->msg_namelen <sizeof(*usat)) return(-EINVAL); if(usat->sat_family != AF_APPLETALK) return -EINVAL; -#if 0 /* netatalk doesnt implement this check */ +#if 0 /* netatalk doesn't implement this check */ if(usat->sat_addr.s_node==ATADDR_BCAST && !sk->broadcast) return -EPERM; #endif @@ -1481,9 +1669,9 @@ static int atalk_sendto(struct socket *sock, void *ubuf, int len, int noblock, return -ENOTCONN; usat=&local_satalk; usat->sat_family=AF_APPLETALK; - usat->sat_port=sk->at.dest_port; - usat->sat_addr.s_node=sk->at.dest_node; - usat->sat_addr.s_net=sk->at.dest_net; + usat->sat_port=sk->protinfo.af_at.dest_port; + usat->sat_addr.s_node=sk->protinfo.af_at.dest_node; + usat->sat_addr.s_net=sk->protinfo.af_at.dest_net; } /* Build a packet */ @@ -1504,7 +1692,7 @@ static int atalk_sendto(struct socket *sock, void *ubuf, int len, int noblock, { struct at_addr at_hint; at_hint.s_node=0; - at_hint.s_net=sk->at.src_net; + at_hint.s_net=sk->protinfo.af_at.src_net; rt=atrtr_find(&at_hint); if(rt==NULL) return -ENETUNREACH; @@ -1516,49 +1704,63 @@ static int atalk_sendto(struct socket *sock, void *ubuf, int len, int noblock, size += dev->hard_header_len; - skb = sock_alloc_send_skb(sk, size, 0 , &err); + skb = sock_alloc_send_skb(sk, size, 0, 0 , &err); if(skb==NULL) return err; skb->sk=sk; skb->free=1; skb->arp=1; - skb->len=size; + skb_reserve(skb,ddp_dl->header_length); + skb_reserve(skb,dev->hard_header_len); skb->dev=dev; if(sk->debug) printk("SK %p: Begin build.\n", sk); - skb->h.raw=skb->data+ddp_dl->header_length+dev->hard_header_len; - - ddp=(struct ddpehdr *)skb->h.raw; + ddp=(struct ddpehdr *)skb_put(skb,sizeof(struct ddpehdr)); ddp->deh_pad=0; ddp->deh_hops=0; ddp->deh_len=len+sizeof(*ddp); /* * Fix up the length field [Ok this is horrible but otherwise * I end up with unions of bit fields and messy bit field order - * compiler/endian dependancies.. + * compiler/endian dependencies.. */ *((__u16 *)ddp)=ntohs(*((__u16 *)ddp)); ddp->deh_dnet=usat->sat_addr.s_net; - ddp->deh_snet=sk->at.src_net; + ddp->deh_snet=sk->protinfo.af_at.src_net; ddp->deh_dnode=usat->sat_addr.s_node; - ddp->deh_snode=sk->at.src_node; + ddp->deh_snode=sk->protinfo.af_at.src_node; ddp->deh_dport=usat->sat_port; - ddp->deh_sport=sk->at.src_port; + ddp->deh_sport=sk->protinfo.af_at.src_port; if(sk->debug) printk("SK %p: Copy user data (%d bytes).\n", sk, len); - memcpy_fromfs((char *)(ddp+1),ubuf,len); - + err = memcpy_fromiovec(skb_put(skb,len),msg->msg_iov,len); + if (err) + { + kfree_skb(skb, FREE_WRITE); + return -EFAULT; + } + if(sk->no_check==1) ddp->deh_sum=0; else ddp->deh_sum=atalk_checksum(ddp, len+sizeof(*ddp)); + +#ifdef CONFIG_FIREWALL + + if(call_out_firewall(AF_APPLETALK, skb->dev, ddp, NULL)!=FW_ACCEPT) + { + kfree_skb(skb, FREE_WRITE); + return -EPERM; + } + +#endif /* * Loopback broadcast packets to non gateway targets (ie routes @@ -1587,12 +1789,13 @@ static int atalk_sendto(struct socket *sock, void *ubuf, int len, int noblock, if(sk->debug) printk("SK %p: Loop back.\n", sk); /* loop back */ - sk->wmem_alloc-=skb->mem_len; + atomic_sub(skb->truesize, &sk->wmem_alloc); ddp_dl->datalink_header(ddp_dl, skb, dev->dev_addr); skb->sk = NULL; + skb->mac.raw=skb->data; skb->h.raw = skb->data + ddp_dl->header_length + dev->hard_header_len; - skb->len -= ddp_dl->header_length ; - skb->len -= dev->hard_header_len ; + skb_pull(skb,dev->hard_header_len); + skb_pull(skb,ddp_dl->header_length); atalk_rcv(skb,dev,NULL); } else @@ -1614,27 +1817,15 @@ static int atalk_sendto(struct socket *sock, void *ubuf, int len, int noblock, return len; } -static int atalk_send(struct socket *sock, void *ubuf, int size, int noblock, unsigned flags) -{ - return atalk_sendto(sock,ubuf,size,noblock,flags,NULL,0); -} -static int atalk_recvfrom(struct socket *sock, void *ubuf, int size, int noblock, - unsigned flags, struct sockaddr *sip, int *addr_len) +static int atalk_recvmsg(struct socket *sock, struct msghdr *msg, int size, int noblock, int flags, int *addr_len) { atalk_socket *sk=(atalk_socket *)sock->data; - struct sockaddr_at *sat=(struct sockaddr_at *)sip; + struct sockaddr_at *sat=(struct sockaddr_at *)msg->msg_name; struct ddpehdr *ddp = NULL; int copied = 0; struct sk_buff *skb; - int er; - - if(sk->err) - { - er= -sk->err; - sk->err=0; - return er; - } + int er = 0; if(addr_len) *addr_len=sizeof(*sat); @@ -1648,15 +1839,25 @@ static int atalk_recvfrom(struct socket *sock, void *ubuf, int size, int noblock { copied=ddp->deh_len; if(copied > size) + { copied=size; - skb_copy_datagram(skb,0,ubuf,copied); + msg->msg_flags|=MSG_TRUNC; + } + er = skb_copy_datagram_iovec(skb,0,msg->msg_iov,copied); + if (er) + goto out; } else { copied=ddp->deh_len - sizeof(*ddp); if (copied > size) + { copied = size; - skb_copy_datagram(skb,sizeof(*ddp),ubuf,copied); + msg->msg_flags|=MSG_TRUNC; + } + er = skb_copy_datagram_iovec(skb,sizeof(*ddp),msg->msg_iov,copied); + if (er) + goto out; } if(sat) { @@ -1665,32 +1866,12 @@ static int atalk_recvfrom(struct socket *sock, void *ubuf, int size, int noblock sat->sat_addr.s_node=ddp->deh_snode; sat->sat_addr.s_net=ddp->deh_snet; } - skb_free_datagram(skb); - return(copied); +out: + skb_free_datagram(sk, skb); + return er ? er : (copied); } -static int atalk_write(struct socket *sock, char *ubuf, int size, int noblock) -{ - return atalk_send(sock,ubuf,size,noblock,0); -} - - -static int atalk_recv(struct socket *sock, void *ubuf, int size , int noblock, - unsigned flags) -{ - atalk_socket *sk=(atalk_socket *)sock->data; - if(sk->zapped) - return -ENOTCONN; - return atalk_recvfrom(sock,ubuf,size,noblock,flags,NULL, NULL); -} - -static int atalk_read(struct socket *sock, char *ubuf, int size, int noblock) -{ - return atalk_recv(sock,ubuf,size,noblock,0); -} - - static int atalk_shutdown(struct socket *sk,int how) { return -EOPNOTSUPP; @@ -1709,10 +1890,8 @@ static int atalk_select(struct socket *sock , int sel_type, select_table *wait) static int atalk_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg) { - int err; long amount=0; atalk_socket *sk=(atalk_socket *)sock->data; - int v; switch(cmd) { @@ -1720,16 +1899,16 @@ static int atalk_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg) * Protocol layer */ case TIOCOUTQ: - v=sk->sndbuf-sk->wmem_alloc; - if(v<0) - v=0; + amount=sk->sndbuf-sk->wmem_alloc; + if(amount<0) + amount=0; break; case TIOCINQ: { struct sk_buff *skb; /* These two are safe on a single CPU system as only user tasks fiddle here */ if((skb=skb_peek(&sk->receive_queue))!=NULL) - v=skb->len-sizeof(struct ddpehdr); + amount=skb->len-sizeof(struct ddpehdr); break; } case SIOCGSTAMP: @@ -1737,11 +1916,7 @@ static int atalk_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg) { if(sk->stamp.tv_sec==0) return -ENOENT; - err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(struct timeval)); - if(err) - return err; - memcpy_tofs((void *)arg,&sk->stamp,sizeof(struct timeval)); - return 0; + return copy_to_user((void *)arg,&sk->stamp,sizeof(struct timeval)) ? -EFAULT : 0; } return -EINVAL; /* @@ -1765,7 +1940,6 @@ static int atalk_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg) case SIOCSIFLINK: case SIOCGIFHWADDR: case SIOCSIFHWADDR: - case OLD_SIOCGIFHWADDR: case SIOCGIFFLAGS: case SIOCSIFFLAGS: case SIOCGIFMTU: @@ -1788,11 +1962,7 @@ static int atalk_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg) default: return -EINVAL; } - err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(unsigned long)); - if(err) - return err; - put_fs_long(amount,(unsigned long *)arg); - return(0); + return put_user(amount, (int *)arg); } static struct proto_ops atalk_proto_ops = { @@ -1806,19 +1976,15 @@ static struct proto_ops atalk_proto_ops = { atalk_socketpair, atalk_accept, atalk_getname, - atalk_read, - atalk_write, atalk_select, atalk_ioctl, atalk_listen, - atalk_send, - atalk_recv, - atalk_sendto, - atalk_recvfrom, atalk_shutdown, atalk_setsockopt, atalk_getsockopt, atalk_fcntl, + atalk_sendmsg, + atalk_recvmsg }; static struct notifier_block ddp_notifier={ @@ -1827,17 +1993,137 @@ static struct notifier_block ddp_notifier={ 0 }; +struct packet_type ltalk_packet_type= +{ + 0, + NULL, + ltalk_rcv, + NULL, + NULL +}; + +struct packet_type ppptalk_packet_type= +{ + 0, + NULL, + atalk_rcv, + NULL, + NULL +}; + +static char ddp_snap_id[]={0x08,0x00,0x07,0x80,0x9B}; + +#ifdef CONFIG_PROC_FS +static struct proc_dir_entry proc_appletalk = { + PROC_NET_ATALK, 9, "appletalk", + S_IFREG | S_IRUGO, 1, 0, 0, + 0, &proc_net_inode_operations, + atalk_get_info +}; +static struct proc_dir_entry proc_atalk_route = { + PROC_NET_AT_ROUTE, 11,"atalk_route", + S_IFREG | S_IRUGO, 1, 0, 0, + 0, &proc_net_inode_operations, + atalk_rt_get_info +}; +static struct proc_dir_entry proc_atalk_iface = { + PROC_NET_ATIF, 11,"atalk_iface", + S_IFREG | S_IRUGO, 1, 0, 0, + 0, &proc_net_inode_operations, + atalk_if_get_info +}; +#endif + /* Called by proto.c on kernel start up */ void atalk_proto_init(struct net_proto *pro) { - static char ddp_snap_id[]={0x08,0x00,0x07,0x80,0x9B}; (void) sock_register(atalk_proto_ops.family, &atalk_proto_ops); - if((ddp_dl=register_snap_client(ddp_snap_id, atalk_rcv))==NULL) - printk("Unable to register DDP with SNAP.\n"); + if ((ddp_dl = register_snap_client(ddp_snap_id, atalk_rcv)) == NULL) + printk(KERN_CRIT "Unable to register DDP with SNAP.\n"); + + ltalk_packet_type.type=htons(ETH_P_LOCALTALK); + dev_add_pack(<alk_packet_type); + + ppptalk_packet_type.type=htons(ETH_P_PPPTALK); + dev_add_pack(&ppptalk_packet_type); + register_netdevice_notifier(&ddp_notifier); aarp_proto_init(); - printk("Appletalk ALPHA 0.08 for Linux NET3.029\n"); - + +#ifdef CONFIG_PROC_FS + proc_net_register(&proc_appletalk); + proc_net_register(&proc_atalk_route); + proc_net_register(&proc_atalk_iface); +#endif + + printk(KERN_INFO "Appletalk 0.18 for Linux NET3.037\n"); } -#endif + +#ifdef MODULE + +int init_module(void) +{ + atalk_proto_init(NULL); + register_symtab(0); + return 0; +} + +/* + * FIX THIS: If there are any routes/devices configured + * for appletalk we must not be unloaded. + */ + +/* Remove all route entries. Interrupts must be off. */ +extern inline void free_route_list(void) +{ + struct atalk_route *list = atalk_router_list, *tmp; + + while (list != NULL) + { + tmp = list->next; + kfree_s(list, sizeof(struct atalk_route)); + list = tmp; + } +} + +/* Remove all interface entries. Interrupts must be off. */ +extern inline void free_interface_list(void) +{ + struct atalk_iface *list = atalk_iface_list, *tmp; + + while (list != NULL) + { + tmp = list->next; + kfree_s(list, sizeof(struct atalk_iface)); + list = tmp; + } +} + +void cleanup_module(void) +{ + unsigned long flags; + + save_flags(flags); + cli(); + + aarp_cleanup_module(); + +#ifdef CONFIG_PROC_FS + proc_net_unregister(PROC_NET_ATALK); + proc_net_unregister(PROC_NET_AT_ROUTE); + proc_net_unregister(PROC_NET_ATIF); +#endif + unregister_netdevice_notifier(&ddp_notifier); + dev_remove_pack(<alk_packet_type); + dev_remove_pack(&ppptalk_packet_type); + unregister_snap_client(ddp_snap_id); + sock_unregister(atalk_proto_ops.family); + + free_route_list(); + free_interface_list(); + + restore_flags(flags); +} + +#endif /* MODULE */ diff --git a/net/appletalk/sysctl_net_atalk.c b/net/appletalk/sysctl_net_atalk.c new file mode 100644 index 000000000..307278992 --- /dev/null +++ b/net/appletalk/sysctl_net_atalk.c @@ -0,0 +1,13 @@ +/* -*- linux-c -*- + * sysctl_net_atalk.c: sysctl interface to net Appletalk subsystem. + * + * Begun April 1, 1996, Mike Shaver. + * Added /proc/sys/net/atalk directory entry (empty =) ). [MS] + */ + +#include <linux/mm.h> +#include <linux/sysctl.h> + +ctl_table atalk_table[] = { + {0} +}; |