summaryrefslogtreecommitdiffstats
path: root/net/appletalk
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-01-07 02:33:00 +0000
committer <ralf@linux-mips.org>1997-01-07 02:33:00 +0000
commitbeb116954b9b7f3bb56412b2494b562f02b864b1 (patch)
tree120e997879884e1b9d93b265221b939d2ef1ade1 /net/appletalk
parent908d4681a1dc3792ecafbe64265783a86c4cccb6 (diff)
Import of Linux/MIPS 2.1.14
Diffstat (limited to 'net/appletalk')
-rw-r--r--net/appletalk/Makefile26
-rw-r--r--net/appletalk/aarp.c179
-rw-r--r--net/appletalk/ddp.c820
-rw-r--r--net/appletalk/sysctl_net_atalk.c13
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(&ltalk_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(&ltalk_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}
+};