summaryrefslogtreecommitdiffstats
path: root/net/appletalk
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-04-29 21:13:14 +0000
committer <ralf@linux-mips.org>1997-04-29 21:13:14 +0000
commit19c9bba94152148523ba0f7ef7cffe3d45656b11 (patch)
tree40b1cb534496a7f1ca0f5c314a523c69f1fee464 /net/appletalk
parent7206675c40394c78a90e74812bbdbf8cf3cca1be (diff)
Import of Linux/MIPS 2.1.36
Diffstat (limited to 'net/appletalk')
-rw-r--r--net/appletalk/Makefile6
-rw-r--r--net/appletalk/aarp.c51
-rw-r--r--net/appletalk/ddp.c1014
3 files changed, 541 insertions, 530 deletions
diff --git a/net/appletalk/Makefile b/net/appletalk/Makefile
index bfe567264..19379a44a 100644
--- a/net/appletalk/Makefile
+++ b/net/appletalk/Makefile
@@ -8,9 +8,13 @@
# Note 2! The CFLAGS definition is now in the main makefile...
O_TARGET := appletalk.o
-O_OBJS := aarp.o ddp.o sysctl_net_atalk.o
+O_OBJS := aarp.o ddp.o
M_OBJS := $(O_TARGET)
+ifeq ($(CONFIG_SYSCTL),y)
+O_OBJS += sysctl_net_atalk.o
+endif
+
include $(TOPDIR)/Rules.make
tar:
diff --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c
index 4b8d4fb7e..e3e87f9e4 100644
--- a/net/appletalk/aarp.c
+++ b/net/appletalk/aarp.c
@@ -3,15 +3,15 @@
* ethernet 'ELAP'.
*
* Alan Cox <Alan.Cox@linux.org>
- * <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.
- * [see the pre-1.3 test code for details 8)]
+ * This doesn't fit cleanly with the IP arp. Potentially we can use
+ * the generic neighbour discovery code to clean this up.
*
* FIXME:
* We ought to handle the retransmits with a single list and a
* separate fast timer for when it is needed.
+ * Use neighbour discovery code.
+ * Token Ring Support.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -115,8 +115,7 @@ static void aarp_send_query(struct aarp_entry *a)
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->dev = a->dev;
+ skb->dev = dev;
/*
* Set up the ARP.
@@ -149,8 +148,9 @@ static void aarp_send_query(struct aarp_entry *a)
/*
* Send it.
*/
-
- dev_queue_xmit(skb, dev, SOPRI_NORMAL);
+
+ skb->priority = SOPRI_NORMAL;
+ dev_queue_xmit(skb);
/*
* Update the sending count
@@ -175,7 +175,6 @@ static void aarp_send_reply(struct device *dev, struct at_addr *us, struct at_ad
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->dev = dev;
/*
@@ -212,8 +211,8 @@ static void aarp_send_reply(struct device *dev, struct at_addr *us, struct at_ad
/*
* Send it.
*/
-
- dev_queue_xmit(skb, dev, SOPRI_NORMAL);
+ skb->priority = SOPRI_NORMAL;
+ dev_queue_xmit(skb);
}
@@ -239,7 +238,6 @@ void aarp_send_probe(struct device *dev, struct at_addr *us)
eah = (struct elapaarp *)skb_put(skb,sizeof(struct elapaarp));
skb->arp = 1;
- skb->free = 1;
skb->dev = dev;
/*
@@ -273,8 +271,8 @@ void aarp_send_probe(struct device *dev, struct at_addr *us)
/*
* Send it.
*/
-
- dev_queue_xmit(skb, dev, SOPRI_NORMAL);
+ skb->priority = SOPRI_NORMAL;
+ dev_queue_xmit(skb);
}
@@ -443,9 +441,11 @@ int aarp_send_ddp(struct device *dev,struct sk_buff *skb, struct at_addr *sa, vo
* Compressible ?
*
* IFF: src_net==dest_net==device_net
+ * (zero matches anything)
*/
- if(at->s_net==sa->s_net && sa->s_net==ddp->deh_snet)
+ if( ( ddp->deh_snet==0 || at->s_net==ddp->deh_snet)
+ &&( ddp->deh_dnet==0 || at->s_net==ddp->deh_dnet) )
{
skb_pull(skb,sizeof(struct ddpehdr)-4);
/*
@@ -467,9 +467,11 @@ int aarp_send_ddp(struct device *dev,struct sk_buff *skb, struct at_addr *sa, vo
skb->data[2]=ft;
if(skb->sk==NULL)
- dev_queue_xmit(skb, skb->dev, SOPRI_NORMAL);
+ skb->priority = SOPRI_NORMAL;
else
- dev_queue_xmit(skb, skb->dev, skb->sk->priority);
+ skb->priority = skb->sk->priority;
+ skb->dev = dev;
+ dev_queue_xmit(skb);
return 1;
}
@@ -497,9 +499,10 @@ int aarp_send_ddp(struct device *dev,struct sk_buff *skb, struct at_addr *sa, vo
{
ddp_dl->datalink_header(ddp_dl, skb, ddp_eth_multicast);
if(skb->sk==NULL)
- dev_queue_xmit(skb, skb->dev, SOPRI_NORMAL);
+ skb->priority = SOPRI_NORMAL;
else
- dev_queue_xmit(skb, skb->dev, skb->sk->priority);
+ skb->priority = skb->sk->priority;
+ dev_queue_xmit(skb);
restore_flags(flags);
return 1;
}
@@ -513,9 +516,10 @@ int aarp_send_ddp(struct device *dev,struct sk_buff *skb, struct at_addr *sa, vo
a->expires_at=jiffies+AARP_EXPIRY_TIME*10;
ddp_dl->datalink_header(ddp_dl, skb, a->hwaddr);
if(skb->sk==NULL)
- dev_queue_xmit(skb, skb->dev, SOPRI_NORMAL);
+ skb->priority = SOPRI_NORMAL;
else
- dev_queue_xmit(skb, skb->dev, skb->sk->priority);
+ skb->priority = skb->sk->priority;
+ dev_queue_xmit(skb);
restore_flags(flags);
return 1;
}
@@ -621,9 +625,10 @@ static void aarp_resolved(struct aarp_entry **list, struct aarp_entry *a, int ha
a->expires_at=jiffies+AARP_EXPIRY_TIME*10;
ddp_dl->datalink_header(ddp_dl,skb,a->hwaddr);
if(skb->sk==NULL)
- dev_queue_xmit(skb, skb->dev, SOPRI_NORMAL);
+ skb->priority = SOPRI_NORMAL;
else
- dev_queue_xmit(skb, skb->dev, skb->sk->priority);
+ skb->priority = skb->sk->priority;
+ dev_queue_xmit(skb);
}
}
else
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index 211842144..eba533a23 100644
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -3,10 +3,9 @@
* ethernet 'ELAP'.
*
* Alan Cox <Alan.Cox@linux.org>
- * <iialan@www.linux.org.uk>
*
- * With more than a little assistance from
- *
+ * With more than a little assistance from
+ *
* Wesley Craig <netatalk@umich.edu>
*
* Fixes:
@@ -24,16 +23,16 @@
* Alan Cox : Hooks for PPP (based on the
* localtalk hook).
* Alan Cox : Posix bits
+ * Alan Cox/Mike Freeman : Possible fix to NBP problems
+ * Bradford Johnson : IP-over-DDP (experimental)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * TODO
- * ASYNC I/O
*/
-
+
#include <linux/config.h>
#include <linux/module.h>
#include <asm/uaccess.h>
@@ -62,6 +61,8 @@
#include <net/p8022.h>
#include <net/psnap.h>
#include <net/sock.h>
+#include <linux/ip.h>
+#include <net/route.h>
#include <linux/atalk.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
@@ -78,6 +79,7 @@
#endif
struct datalink_proto *ddp_dl, *aarp_dl;
+static struct proto_ops atalk_dgram_ops;
#define min(a,b) (((a)<(b))?(a):(b))
@@ -87,73 +89,46 @@ struct datalink_proto *ddp_dl, *aarp_dl;
* *
\***********************************************************************************************************************/
-static atalk_socket *volatile atalk_socket_list=NULL;
+static struct sock *atalk_socket_list=NULL;
/*
* Note: Sockets may not be removed _during_ an interrupt or inet_bh
* handler using this technique. They can be added although we do not
* use this facility.
*/
-
-static void atalk_remove_socket(atalk_socket *sk)
+
+extern inline void atalk_remove_socket(struct sock *sk)
{
- unsigned long flags;
- atalk_socket *s;
-
- save_flags(flags);
- cli();
-
- s=atalk_socket_list;
- if(s==sk)
- {
- atalk_socket_list=s->next;
- restore_flags(flags);
- return;
- }
- while(s && s->next)
- {
- if(s->next==sk)
- {
- s->next=sk->next;
- restore_flags(flags);
- return;
- }
- s=s->next;
- }
- restore_flags(flags);
+ sklist_remove_socket(&atalk_socket_list,sk);
}
-static void atalk_insert_socket(atalk_socket *sk)
+extern inline void atalk_insert_socket(struct sock *sk)
{
- unsigned long flags;
- save_flags(flags);
- cli();
- sk->next=atalk_socket_list;
- atalk_socket_list=sk;
- restore_flags(flags);
+ sklist_insert_socket(&atalk_socket_list,sk);
}
-static atalk_socket *atalk_search_socket(struct sockaddr_at *to, struct atalk_iface *atif)
+static struct sock *atalk_search_socket(struct sockaddr_at *to, struct atalk_iface *atif)
{
- atalk_socket *s;
+ struct sock *s;
- for( s = atalk_socket_list; s != NULL; s = s->next )
+ for( s = atalk_socket_list; s != NULL; s = s->next )
{
- if ( to->sat_port != s->protinfo.af_at.src_port )
+ if ( to->sat_port != s->protinfo.af_at.src_port )
{
continue;
}
if ( to->sat_addr.s_net == 0 &&
to->sat_addr.s_node == ATADDR_BCAST &&
- s->protinfo.af_at.src_net == atif->address.s_net )
+ s->protinfo.af_at.src_net == atif->address.s_net )
{
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 ))
+ (to->sat_addr.s_node == s->protinfo.af_at.src_node
+ ||to->sat_addr.s_node == ATADDR_BCAST
+ ||to->sat_addr.s_node == ATADDR_ANYNODE ))
{
break;
}
@@ -166,22 +141,22 @@ static atalk_socket *atalk_search_socket(struct sockaddr_at *to, struct atalk_if
/*
* Find a socket in the list.
*/
-
-static atalk_socket *atalk_find_socket(struct sockaddr_at *sat)
+
+static struct sock *atalk_find_socket(struct sockaddr_at *sat)
{
- atalk_socket *s;
+ struct sock *s;
- for ( s = atalk_socket_list; s != NULL; s = s->next )
+ for ( s = atalk_socket_list; s != NULL; s = s->next )
{
- if ( s->protinfo.af_at.src_net != sat->sat_addr.s_net )
+ 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 )
+ if ( s->protinfo.af_at.src_node != sat->sat_addr.s_node )
{
continue;
}
- if ( s->protinfo.af_at.src_port != sat->sat_port )
+ if ( s->protinfo.af_at.src_port != sat->sat_port )
{
continue;
}
@@ -190,60 +165,19 @@ static atalk_socket *atalk_find_socket(struct sockaddr_at *sat)
return( s );
}
-/*
- * This is only called from user mode. Thus it protects itself against
- * interrupt users but doesn't worry about being called during work.
- * Once it is removed from the queue no interrupt or bottom half will
- * touch it and we are (fairly 8-) ) safe.
- */
-
-static void atalk_destroy_socket(atalk_socket *sk);
-
-/*
- * Handler for deferred kills.
- */
-
-static void atalk_destroy_timer(unsigned long data)
-{
- atalk_destroy_socket((atalk_socket *)data);
-}
-
-static void atalk_destroy_socket(atalk_socket *sk)
+extern inline void atalk_destroy_socket(struct sock *sk)
{
- struct sk_buff *skb;
- atalk_remove_socket(sk);
-
- while((skb=skb_dequeue(&sk->receive_queue))!=NULL)
- {
- kfree_skb(skb,FREE_READ);
- }
-
- if(sk->wmem_alloc == 0 && sk->rmem_alloc == 0 && sk->dead)
- {
- sk_free(sk);
- MOD_DEC_USE_COUNT;
- }
- else
- {
- /*
- * Someone is using our buffers still.. defer
- */
- init_timer(&sk->timer);
- sk->timer.expires=jiffies+10*HZ;
- sk->timer.function=atalk_destroy_timer;
- sk->timer.data = (unsigned long)sk;
- add_timer(&sk->timer);
- }
+ sklist_destroy_socket(&atalk_socket_list,sk);
+ MOD_DEC_USE_COUNT;
}
-
/*
- * Called from proc fs
+ * Called from proc fs
*/
-
+
int atalk_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
{
- atalk_socket *s;
+ struct sock *s;
int len=0;
off_t pos=0;
off_t begin=0;
@@ -264,12 +198,14 @@ int atalk_get_info(char *buffer, char **start, off_t offset, int length, int dum
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,"%08X:%08X ",
+ atomic_read(&s->wmem_alloc),
+ atomic_read(&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 */
pos=begin+len;
-
+
if(pos<offset)
{
len=0; /* Keep dumping into the buffer start */
@@ -278,13 +214,13 @@ int atalk_get_info(char *buffer, char **start, off_t offset, int length, int dum
if(pos>offset+length) /* We have dumped enough */
break;
}
-
+
/* The data in question runs from begin to begin+len */
*start=buffer+(offset-begin); /* Start of wanted data */
len-=(offset-begin); /* Remove unwanted header data from length */
if(len>length)
len=length; /* Remove unwanted tail data from length */
-
+
return len;
}
@@ -302,38 +238,41 @@ static struct atalk_iface *atalk_iface_list=NULL;
/*
* Appletalk interface control
*/
-
+
/*
- * Drop a device. Doesn't drop any of its routes - that is the
- * the callers problem. Called when we down the interface or
+ * Drop a device. Doesn't drop any of its routes - that is the
+ * the callers problem. Called when we down the interface or
* delete the address.
*/
-
+
static void atif_drop_device(struct device *dev)
{
struct atalk_iface **iface = &atalk_iface_list;
struct atalk_iface *tmp;
- while ((tmp = *iface) != NULL)
+ while ((tmp = *iface) != NULL)
{
- if (tmp->dev == dev)
+ if (tmp->dev == dev)
{
*iface = tmp->next;
kfree_s(tmp, sizeof(struct atalk_iface));
+ dev->atalk_ptr=NULL;
}
else
iface = &tmp->next;
}
+ MOD_DEC_USE_COUNT;
}
static struct atalk_iface *atif_add_device(struct device *dev, struct at_addr *sa)
{
struct atalk_iface *iface=(struct atalk_iface *)
kmalloc(sizeof(*iface), GFP_KERNEL);
- unsigned long flags;
+ unsigned long flags;
if(iface==NULL)
return NULL;
iface->dev=dev;
+ dev->atalk_ptr=iface;
iface->address= *sa;
iface->status=0;
save_flags(flags);
@@ -341,13 +280,14 @@ static struct atalk_iface *atif_add_device(struct device *dev, struct at_addr *s
iface->next=atalk_iface_list;
atalk_iface_list=iface;
restore_flags(flags);
+ MOD_INC_USE_COUNT;
return iface;
}
/*
* Perform phase 2 AARP probing on our tentative address.
*/
-
+
static int atif_probe_device(struct atalk_iface *atif)
{
int ct;
@@ -356,19 +296,18 @@ static int atif_probe_device(struct atalk_iface *atif)
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.
- *
+ * addresses. This needs tidying up when someone does localtalk
+ * drivers
*/
if((atif->dev->type == ARPHRD_LOCALTLK || atif->dev->type == ARPHRD_PPP)
- && atif->dev->do_ioctl)
+ && atif->dev->do_ioctl)
{
/* fake up the request and pass it down */
sa = (struct sockaddr_at*)&atreq.ifr_addr;
@@ -388,11 +327,11 @@ static int atif_probe_device(struct atalk_iface *atif)
* properly. We can then also dump the localtalk test.
*/
return err;
- }
+ }
/*
* Offset the network we start probing with.
*/
-
+
if(probe_net==ATADDR_ANYNET)
{
if(!netrange)
@@ -400,15 +339,15 @@ static int atif_probe_device(struct atalk_iface *atif)
else
probe_net=ntohs(atif->nets.nr_firstnet) + (jiffies%netrange);
}
-
+
if(probe_node == ATADDR_ANYNODE)
probe_node = jiffies&0xFF;
-
-
+
+
/*
* Scan the networks.
*/
-
+
for(netct=0;netct<=netrange;netct++)
{
/*
@@ -450,10 +389,9 @@ static int atif_probe_device(struct atalk_iface *atif)
struct at_addr *atalk_find_dev_addr(struct device *dev)
{
- struct atalk_iface *iface;
- for(iface=atalk_iface_list;iface!=NULL;iface=iface->next)
- if(iface->dev==dev)
- return &iface->address;
+ struct atalk_iface *iface=dev->atalk_ptr;
+ if(iface)
+ return &iface->address;
return NULL;
}
@@ -463,55 +401,40 @@ static struct at_addr *atalk_find_primary(void)
for(iface=atalk_iface_list;iface!=NULL;iface=iface->next)
if(!(iface->dev->flags&IFF_LOOPBACK))
return &iface->address;
- if ( atalk_iface_list != NULL ) {
- return &atalk_iface_list->address;
- } else {
- return NULL;
- }
-}
-
-/*
- * Give a device find its atif control structure
- */
-
-struct atalk_iface *atalk_find_dev(struct device *dev)
-{
- struct atalk_iface *iface;
- for(iface=atalk_iface_list;iface!=NULL;iface=iface->next)
- if(iface->dev==dev)
- return iface;
- return NULL;
+ if ( atalk_iface_list != NULL )
+ return &atalk_iface_list->address;
+ else
+ return NULL;
}
/*
* Find a match for 'any network' - ie any of our interfaces with that
* node number will do just nicely.
*/
-
+
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 ))
- continue;
- if ( node == ATADDR_BCAST || iface->address.s_node == node )
- return iface;
- }
+ struct atalk_iface *iface=dev->atalk_ptr;
+ if (iface==NULL || ( iface->status & ATIF_PROBE ))
+ return NULL;
+ if ( node == ATADDR_BCAST || iface->address.s_node == node || node == ATADDR_ANYNODE)
+ return iface;
return NULL;
}
/*
* Find a match for a specific network:node pair
*/
-
+
static struct atalk_iface *atalk_find_interface(int net, int node)
{
struct atalk_iface *iface;
for(iface=atalk_iface_list;iface!=NULL;iface=iface->next)
{
- if((node==ATADDR_BCAST || iface->address.s_node==node)
- && iface->address.s_net==net && !(iface->status&ATIF_PROBE))
+ if((node==ATADDR_BCAST || node==ATADDR_ANYNODE
+ || iface->address.s_node==node)
+ && iface->address.s_net==net
+ && !(iface->status&ATIF_PROBE))
return iface;
}
return NULL;
@@ -523,7 +446,7 @@ static struct atalk_iface *atalk_find_interface(int net, int node)
* the socket (later on...). We know about host routes and the fact
* that a route must be direct to broadcast.
*/
-
+
static struct atalk_route *atrtr_find(struct at_addr *target)
{
struct atalk_route *r;
@@ -542,12 +465,12 @@ static struct atalk_route *atrtr_find(struct at_addr *target)
return NULL;
}
-
+
/*
* Given an appletalk network find the device to use. This can be
- * a simple lookup. Funny stuff like routers can wait 8)
+ * a simple lookup.
*/
-
+
static struct device *atrtr_get_dev(struct at_addr *sa)
{
struct atalk_route *atr=atrtr_find(sa);
@@ -560,7 +483,7 @@ static struct device *atrtr_get_dev(struct at_addr *sa)
/*
* Set up a default router.
*/
-
+
static void atrtr_set_default(struct device *dev)
{
atrtr_default.dev=dev;
@@ -574,7 +497,7 @@ static void atrtr_set_default(struct device *dev)
* entry in the list. While it uses netranges we always set them to one
* entry to work like netatalk.
*/
-
+
static int atrtr_create(struct rtentry *r, struct device *devhint)
{
struct sockaddr_at *ta=(struct sockaddr_at *)&r->rt_dst;
@@ -582,22 +505,22 @@ static int atrtr_create(struct rtentry *r, struct device *devhint)
struct atalk_route *rt;
struct atalk_iface *iface, *riface;
unsigned long flags;
-
+
save_flags(flags);
-
+
/*
* Fixme: Raise/Lower a routing change semaphore for these
* operations.
*/
-
+
/*
* Validate the request
- */
+ */
if(ta->sat_family!=AF_APPLETALK)
return -EINVAL;
if(devhint == NULL && ga->sat_family != AF_APPLETALK)
return -EINVAL;
-
+
/*
* Now walk the routing table and make our decisions
*/
@@ -607,7 +530,7 @@ 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(ta->sat_addr.s_net == rt->target.s_net)
{
if(!(rt->flags&RTF_HOST))
break;
@@ -616,9 +539,9 @@ static int atrtr_create(struct rtentry *r, struct device *devhint)
}
}
- if ( devhint == NULL )
+ if ( devhint == NULL )
{
- for ( riface = NULL, iface = atalk_iface_list; iface; iface = iface->next )
+ 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 ))
@@ -646,11 +569,11 @@ static int atrtr_create(struct rtentry *r, struct device *devhint)
/*
* Fill in the entry.
*/
- rt->target=ta->sat_addr;
+ rt->target=ta->sat_addr;
rt->dev=devhint;
rt->flags=r->rt_flags;
rt->gateway=ga->sat_addr;
-
+
restore_flags(flags);
return 0;
}
@@ -659,17 +582,17 @@ static int atrtr_create(struct rtentry *r, struct device *devhint)
/*
* Delete a route. Find it and discard it.
*/
-
+
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));
@@ -684,15 +607,15 @@ static int atrtr_delete( struct at_addr *addr )
* Called when a device is downed. Just throw away any routes
* via it.
*/
-
+
void atrtr_device_down(struct device *dev)
{
struct atalk_route **r = &atalk_router_list;
struct atalk_route *tmp;
- while ((tmp = *r) != NULL)
+ while ((tmp = *r) != NULL)
{
- if (tmp->dev == dev)
+ if (tmp->dev == dev)
{
*r = tmp->next;
kfree_s(tmp, sizeof(struct atalk_route));
@@ -727,7 +650,7 @@ static int ddp_device_event(struct notifier_block *this, unsigned long event, vo
/*
* Device configuration ioctl calls.
*/
-
+
int atif_ioctl(int cmd, void *arg)
{
struct ifreq atreq;
@@ -740,17 +663,17 @@ int atif_ioctl(int cmd, void *arg)
int ct;
int limit;
struct rtentry rtdef;
-
+
err = copy_from_user(&atreq,arg,sizeof(atreq));
if (err)
- return -EFAULT;
+ return -EFAULT;
if((dev=dev_get(atreq.ifr_name))==NULL)
return -ENODEV;
-
+
sa=(struct sockaddr_at*)&atreq.ifr_addr;
atif=atalk_find_dev(dev);
-
+
switch(cmd)
{
case SIOCSIFADDR:
@@ -778,7 +701,7 @@ int atif_ioctl(int cmd, void *arg)
*/
if(atif->status&ATIF_PROBE)
return -EBUSY;
-
+
atif->address.s_net=sa->sat_addr.s_net;
atif->address.s_node=sa->sat_addr.s_node;
atrtr_device_down(dev); /* Flush old routes */
@@ -786,14 +709,16 @@ int atif_ioctl(int cmd, void *arg)
else
{
atif=atif_add_device(dev, &sa->sat_addr);
+ if (atif == NULL)
+ return -ENOMEM;
}
atif->nets= *nr;
/*
- * Check if the chosen address is used. If so we
- * error and atalkd will try another.
+ * Check if the chosen address is used. If so we
+ * error and atalkd will try another.
*/
-
+
if(!(dev->flags&IFF_LOOPBACK) && atif_probe_device(atif)<0)
{
atif_drop_device(dev);
@@ -804,7 +729,7 @@ int atif_ioctl(int cmd, void *arg)
* Hey it worked - add the direct
* routes.
*/
-
+
sa=(struct sockaddr_at *)&rtdef.rt_gateway;
sa->sat_family=AF_APPLETALK;
sa->sat_addr.s_net=atif->address.s_net;
@@ -818,13 +743,13 @@ 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)
@@ -866,15 +791,15 @@ int atif_ioctl(int cmd, void *arg)
/*
* Routing ioctl() calls
*/
-
+
static int atrtr_ioctl(unsigned int cmd, void *arg)
{
int err;
struct rtentry rt;
-
+
err = copy_from_user(&rt,arg,sizeof(rt));
if (err)
- return -EFAULT;
+ return -EFAULT;
switch(cmd)
{
@@ -971,15 +896,15 @@ int atalk_rt_get_info(char *buffer, char **start, off_t offset, int length, int
* Checksum: This is 'optional'. It's quite likely also a good
* candidate for assembler hackery 8)
*/
-
+
unsigned short atalk_checksum(struct ddpehdr *ddp, int len)
{
unsigned long sum=0; /* Assume unsigned long is >16 bits */
unsigned char *data=(unsigned char *)ddp;
-
+
len-=4; /* skip header 4 bytes */
- data+=4;
-
+ data+=4;
+
/* This ought to be unwrapped neatly. I'll trust gcc for now */
while(len--)
{
@@ -996,133 +921,16 @@ unsigned short atalk_checksum(struct ddpehdr *ddp, int len)
return htons((unsigned short)sum);
return 0xFFFF; /* Use 0xFFFF for 0. 0 itself means none */
}
-
-/*
- * 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 separate.
- */
-
-static int atalk_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
-/* atalk_socket *sk=(atalk_socket *)sock->data;*/
- switch(cmd)
- {
- default:
- return(-EINVAL);
- }
-}
-
-/*
- * Set 'magic' options for appletalk. If we don't have any this is fine
- * as it is.
- */
-
-static int atalk_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
-{
- atalk_socket *sk;
- int err,opt;
-
- sk=(atalk_socket *)sock->data;
-
- if(optval==NULL)
- return(-EINVAL);
-
- err = get_user(opt, (int *)optval);
- if (err)
- return err;
-
- switch(level)
- {
- case SOL_ATALK:
- switch(optname)
- {
- default:
- return -EOPNOTSUPP;
- }
- break;
-
- case SOL_SOCKET:
- return sock_setsockopt(sk,level,optname,optval,optlen);
-
- default:
- return -EOPNOTSUPP;
- }
-}
-
-
-/*
- * Get any magic options. Comment above applies.
- */
-
-static int atalk_getsockopt(struct socket *sock, int level, int optname,
- char *optval, int *optlen)
-{
- atalk_socket *sk;
- int val=0;
- int err;
-
- sk=(atalk_socket *)sock->data;
-
- switch(level)
- {
-
- case SOL_ATALK:
- switch(optname)
- {
- default:
- return -ENOPROTOOPT;
- }
- break;
-
- case SOL_SOCKET:
- return sock_getsockopt(sk,level,optname,optval,optlen);
-
- default:
- return -EOPNOTSUPP;
- }
- err = put_user(sizeof(int),optlen);
- if (!err)
- err = put_user(val, (int *) optval);
- return err;
-}
-
-/*
- * Only for connection oriented sockets - ignore
- */
-
-static int atalk_listen(struct socket *sock, int backlog)
-{
- return -EOPNOTSUPP;
-}
-
-/*
- * These are standard.
- */
-
-static void def_callback1(struct sock *sk)
-{
- if(!sk->dead)
- wake_up_interruptible(sk->sleep);
-}
-
-static void def_callback2(struct sock *sk, int len)
-{
- if(!sk->dead)
- {
- wake_up_interruptible(sk->sleep);
- sock_wake_async(sk->socket,0);
- }
-}
/*
* Create a socket. Initialise the socket, blank the addresses
* set the state.
*/
-
+
static int atalk_create(struct socket *sock, int protocol)
{
- atalk_socket *sk;
- sk=(atalk_socket *)sk_alloc(GFP_KERNEL);
+ struct sock *sk;
+ sk=sk_alloc(GFP_KERNEL);
if(sk==NULL)
return(-ENOMEM);
switch(sock->type)
@@ -1132,6 +940,7 @@ static int atalk_create(struct socket *sock, int protocol)
case SOCK_RAW:
/* We permit DDP datagram sockets */
case SOCK_DGRAM:
+ sock->ops = &atalk_dgram_ops;
break;
default:
sk_free((void *)sk);
@@ -1140,32 +949,10 @@ static int atalk_create(struct socket *sock, int protocol)
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->priority=1;
- skb_queue_head_init(&sk->receive_queue);
- skb_queue_head_init(&sk->write_queue);
- skb_queue_head_init(&sk->back_log);
- sk->state=TCP_CLOSE;
- sk->socket=sock;
- sk->type=sock->type;
+ sock_init_data(sock,sk);
+ /* Checksums on by default */
sk->mtu=DDP_MAXSZ;
-
- if(sock!=NULL)
- {
- sock->data=(void *)sk;
- sk->sleep=sock->wait;
- }
-
- sk->state_change=def_callback1;
- sk->data_ready=def_callback2;
- sk->write_space=def_callback1;
- sk->error_report=def_callback1;
-
sk->zapped=1;
return(0);
}
@@ -1173,7 +960,7 @@ static int atalk_create(struct socket *sock, int protocol)
/*
* Copy a socket. No work needed.
*/
-
+
static int atalk_dup(struct socket *newsock,struct socket *oldsock)
{
return(atalk_create(newsock,SOCK_DGRAM));
@@ -1182,25 +969,25 @@ static int atalk_dup(struct socket *newsock,struct socket *oldsock)
/*
* Free a socket. No work needed
*/
-
+
static int atalk_release(struct socket *sock, struct socket *peer)
{
- atalk_socket *sk=(atalk_socket *)sock->data;
+ struct sock *sk=sock->sk;
if(sk==NULL)
return(0);
if(!sk->dead)
sk->state_change(sk);
sk->dead=1;
- sock->data=NULL;
+ sock->sk=NULL;
atalk_destroy_socket(sk);
return(0);
}
-
+
/*
* Pick a source address if one is not given. Just return
* an error if not supportable.
*/
-
+
static int atalk_pick_port(struct sockaddr_at *sat)
{
for ( sat->sat_port = ATPORT_RESERVED; sat->sat_port < ATPORT_LAST; sat->sat_port++ )
@@ -1210,8 +997,8 @@ static int atalk_pick_port(struct sockaddr_at *sat)
}
return -EBUSY;
}
-
-static int atalk_autobind(atalk_socket *sk)
+
+static int atalk_autobind(struct sock *sk)
{
struct at_addr *ap = atalk_find_primary();
struct sockaddr_at sat;
@@ -1233,17 +1020,17 @@ 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)
{
- atalk_socket *sk;
+ struct sock *sk;
struct sockaddr_at *addr=(struct sockaddr_at *)uaddr;
-
- sk=(atalk_socket *)sock->data;
-
+
+ sk=sock->sk;
+
if(sk->zapped==0)
return(-EINVAL);
-
+
if(addr_len!=sizeof(struct sockaddr_at))
return -EINVAL;
@@ -1259,7 +1046,7 @@ static int atalk_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
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->protinfo.af_at.src_net=addr->sat_addr.s_net;
@@ -1277,7 +1064,7 @@ static int atalk_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
sk->protinfo.af_at.src_port=addr->sat_port;
if(atalk_find_socket(addr)!=NULL)
- return -EADDRINUSE;
+ return -EADDRINUSE;
atalk_insert_socket(sk);
sk->zapped=0;
@@ -1287,35 +1074,40 @@ static int atalk_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
/*
* Set the address we talk to.
*/
-
+
static int atalk_connect(struct socket *sock, struct sockaddr *uaddr,
int addr_len, int flags)
{
- atalk_socket *sk=(atalk_socket *)sock->data;
+ struct sock *sk=sock->sk;
struct sockaddr_at *addr;
-
- sk->state = TCP_CLOSE;
+
+ sk->state = TCP_CLOSE;
sock->state = SS_UNCONNECTED;
if(addr_len!=sizeof(*addr))
return(-EINVAL);
addr=(struct sockaddr_at *)uaddr;
-
+
if(addr->sat_family!=AF_APPLETALK)
return -EAFNOSUPPORT;
-#if 0 /* Netatalk doesn't check this - fix netatalk first!*/
if(addr->sat_addr.s_node==ATADDR_BCAST && !sk->broadcast)
+ {
+#if 1
+ printk(KERN_WARNING "%s is broken and did not set SO_BROADCAST. It will break when 2.2 is released.\n",
+ current->comm);
+#else
return -EACCES;
-#endif
+#endif
+ }
if(sk->zapped)
{
if(atalk_autobind(sk)<0)
return -EBUSY;
- }
-
+ }
+
if(atrtr_get_dev(&addr->sat_addr)==NULL)
return -ENETUNREACH;
-
+
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;
@@ -1327,7 +1119,7 @@ static int atalk_connect(struct socket *sock, struct sockaddr *uaddr,
/*
* Not relevant
*/
-
+
static int atalk_socketpair(struct socket *sock1, struct socket *sock2)
{
return(-EOPNOTSUPP);
@@ -1336,11 +1128,13 @@ static int atalk_socketpair(struct socket *sock1, struct socket *sock2)
/*
* Not relevant
*/
-
+
static int atalk_accept(struct socket *sock, struct socket *newsock, int flags)
{
- if(newsock->data)
- sk_free(newsock->data);
+ if(newsock->sk) {
+ sk_free(newsock->sk);
+ MOD_DEC_USE_COUNT;
+ }
return -EOPNOTSUPP;
}
@@ -1348,22 +1142,22 @@ static int atalk_accept(struct socket *sock, struct socket *newsock, int flags)
* Find the name of an appletalk socket. Just copy the right
* fields into the sockaddr.
*/
-
+
static int atalk_getname(struct socket *sock, struct sockaddr *uaddr,
int *uaddr_len, int peer)
{
struct sockaddr_at sat;
- atalk_socket *sk;
-
- sk=(atalk_socket *)sock->data;
+ struct sock *sk;
+
+ sk=sock->sk;
if(sk->zapped)
{
if(atalk_autobind(sk)<0)
return -ENOBUFS;
- }
-
+ }
+
*uaddr_len = sizeof(struct sockaddr_at);
-
+
if(peer)
{
if(sk->state!=TCP_ESTABLISHED)
@@ -1383,29 +1177,233 @@ static int atalk_getname(struct socket *sock, struct sockaddr *uaddr,
return(0);
}
+/*
+ * IP-over-DDP support. Under construction.
+ */
+
+#ifdef CONFIG_IPDDP
+
+#define SIOCADDIPDDPRT SIOCDEVPRIVATE
+#define SIOCDELIPDDPRT SIOCDEVPRIVATE+1
+#define SIOCFINDIPDDPRT SIOCDEVPRIVATE+2
+
+struct ipddp_route
+{
+ struct device *dev; /* Carrier device */
+ __u32 ip; /* IP address */
+ struct at_addr at; /* Gateway appletalk address */
+ int flags;
+ struct ipddp_route *next;
+};
+
+static struct ipddp_route *ipddp_route_head;
+
+static struct ipddp_route ipddp_route_test;
+
+int ipddp_open(struct device *dev)
+{
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+int ipddp_close(struct device *dev)
+{
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+int ipddp_xmit(struct sk_buff *skb, struct device *dev)
+{
+ /* Retrieve the saved address hint */
+ struct at_addr *a=(struct at_addr *)skb->data;
+ skb_pull(skb,4);
+
+ ((struct net_device_stats *) dev->priv)->tx_packets++;
+ ((struct net_device_stats *) dev->priv)->tx_bytes+=skb->len;
+
+ /* printk("ipddp_xmit called with headroom %d\n",skb_headroom(skb)); */
+
+ if( aarp_send_ddp(skb->dev,skb,a,NULL) < 0 )
+ dev_kfree_skb(skb,FREE_WRITE);
+
+ return 0;
+}
+
+struct net_device_stats *ipddp_get_stats(struct device *dev)
+{
+ return (struct net_device_stats *) dev->priv;
+}
+
+int ipddp_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
+{
+ struct ipddp_route *urt = (struct ipddp_route *)ifr->ifr_data;
+
+ if(!suser())
+ return -EPERM;
+
+ /* for now we only have one route at a time */
+
+ switch(cmd)
+ {
+ case SIOCADDIPDDPRT:
+ if(copy_from_user(&ipddp_route_test,urt,sizeof(struct ipddp_route)))
+ return -EFAULT;
+ ipddp_route_test.dev = atrtr_get_dev(&ipddp_route_test.at);
+ if (dev==NULL)
+ return -ENETUNREACH;
+ ipddp_route_test.next = NULL;
+ printk("added ipddp route through %s\n",ipddp_route_test.dev->name);
+ ipddp_route_head = &ipddp_route_test;
+ return 0;
+ case SIOCFINDIPDDPRT:
+ if(copy_to_user(urt,&ipddp_route_test,sizeof(struct ipddp_route)))
+ return -EFAULT;
+ return 0;
+ case SIOCDELIPDDPRT:
+ ipddp_route_test.dev = NULL;
+ ipddp_route_head = NULL;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+int ipddp_header (struct sk_buff *skb, struct device *dev, unsigned short type,
+ void *daddr, void *saddr, unsigned len)
+{
+ /* printk("ipddp_header\n"); */
+ /* Push down the header space and the type byte */
+ skb_push(skb, sizeof(struct ddpehdr)+1+4);
+ return 0;
+}
+
+/*
+ * Now the packet really wants to go out.
+ */
+
+int ipddp_rebuild_header (struct sk_buff *skb)
+{
+ struct ddpehdr *ddp;
+ struct at_addr at;
+ struct ipddp_route *rt;
+ struct at_addr *our_addr;
+ u32 paddr = ((struct rtable *)skb->dst)->rt_gateway;
+
+ /*
+ * On entry skb->data points to the ddpehdr we reserved earlier.
+ * skb->h.raw will be the higher level header.
+ */
+
+ /*
+ * We created this earlier
+ */
+
+ ddp = (struct ddpehdr *) (skb->data+4);
+
+ /* find appropriate route */
+
+ for(rt=ipddp_route_head;rt;rt=rt->next)
+ {
+ if(rt->ip == paddr)
+ break;
+ }
+
+ if(!rt) {
+ printk("ipddp unreachable dst %08lx\n",ntohl(paddr));
+ return -ENETUNREACH;
+ }
+
+ our_addr = atalk_find_dev_addr(rt->dev);
+
+ /* fill in ddpehdr */
+ ddp->deh_len = skb->len;
+ ddp->deh_hops = 1;
+ ddp->deh_pad = 0;
+ ddp->deh_sum = 0;
+ ddp->deh_dnet = rt->at.s_net; /* FIXME more hops?? */
+ ddp->deh_snet = our_addr->s_net;
+ ddp->deh_dnode = rt->at.s_node;
+ ddp->deh_snode = our_addr->s_node;
+ ddp->deh_dport = 72;
+ ddp->deh_sport = 72;
+
+ *((__u8 *)(ddp+1)) = 22; /* ddp type = IP */
+
+ /* fix up length field */
+ *((__u16 *)ddp)=ntohs(*((__u16 *)ddp));
+
+ /* set skb->dev to appropriate device */
+ skb->dev = rt->dev;
+
+ /* skb->raddr = (unsigned long) at */
+ at = rt->at;
+ /* Hide it at the start of the buffer */
+ memcpy(skb->data,(void *)&at,sizeof(at));
+ skb->arp = 1; /* so the actual device doesn't try to arp it... */
+ skb->protocol = htons(ETH_P_ATALK); /* Protocol has changed */
+
+ return 0;
+}
+
+int ipddp_init (struct device *dev)
+{
+ ether_setup(dev);
+ dev->hard_start_xmit = ipddp_xmit;
+ dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL);
+ if(!dev->priv)
+ return -ENOMEM;
+ memset(dev->priv,0,sizeof(struct enet_statistics));
+ dev->get_stats = ipddp_get_stats;
+ dev->do_ioctl = ipddp_ioctl;
+ dev->type = ARPHRD_IPDDP; /* IP over DDP tunnel */
+ dev->family = AF_INET;
+ dev->mtu = 585;
+ dev->flags |= IFF_NOARP;
+ dev->hard_header = ipddp_header; /* see ip_output.c */
+ dev->rebuild_header = ipddp_rebuild_header;
+ /*
+ * The worst case header we will need is currently a
+ * ethernet header (14 bytes) and a ddp header (sizeof ddpehdr+1)
+ * We send over SNAP so that takes another 8 bytes.
+ */
+ dev->hard_header_len = 14+8+sizeof(struct ddpehdr)+1;
+ dev->open = ipddp_open;
+ dev->stop = ipddp_close;
+
+ return 0;
+}
+
+static struct device dev_ipddp = {
+ "ipddp0\0 ",
+ 0, 0, 0, 0,
+ 0x0, 0,
+ 0, 0, 0, NULL, ipddp_init };
+
+#endif /* CONFIG_IPDDP */
+
/*
* 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
+ * skb->h.raw is the DDP header, skb->len is the DDP length. The physical headers have been
* extracted. PPP should probably pass frames marked as for this layer
* [ie ARPHRD_ETHERTALK]
*/
-
+
static int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
{
- atalk_socket *sock;
+ struct sock *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))
{
kfree_skb(skb,FREE_READ);
return(0);
}
-
-
+
+
/*
* Fix up the length field [Ok this is horrible but otherwise
* I end up with unions of bit fields and messy bit field order
@@ -1421,9 +1419,9 @@ static int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type
/*
* Trim buffer in case of stray trailing data
*/
-
+
origlen = skb->len;
-
+
skb_trim(skb,min(skb->len,ddp->deh_len));
/*
@@ -1431,7 +1429,7 @@ static int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type
* (Otherwise we'll detonate most spectacularly
* in the middle of recvmsg()).
*/
-
+
if(skb->len<sizeof(*ddp))
{
kfree_skb(skb,FREE_READ);
@@ -1440,7 +1438,7 @@ static int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type
/*
* Any checksums. Note we don't do htons() on this == is assumed to be
- * valid for net byte orders all over the networking code...
+ * valid for net byte orders all over the networking code...
*/
if(ddp->deh_sum && atalk_checksum(ddp, ddp->deh_len)!= ddp->deh_sum)
@@ -1450,16 +1448,12 @@ static int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type
return(0);
}
-#ifdef CONFIG_FIREWALL
-
- if(call_in_firewall(AF_APPLETALK, skb->dev, ddp, NULL)!=FW_ACCEPT)
+ if(call_in_firewall(AF_APPLETALK, skb->dev, ddp, NULL,&skb)!=FW_ACCEPT)
{
kfree_skb(skb, FREE_READ);
return 0;
}
-
-#endif
-
+
/* Check the packet is aimed at us */
if(ddp->deh_dnet == 0) /* Net 0 is 'this network' */
@@ -1468,30 +1462,29 @@ static int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type
atif=atalk_find_interface(ddp->deh_dnet,ddp->deh_dnode);
/* Not ours */
- if(atif==NULL)
+ if(atif==NULL)
{
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)
+ 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)
+
+ if(call_fw_firewall(AF_APPLETALK, skb->dev, ddp, NULL, &skb)!=FW_ACCEPT)
{
kfree_skb(skb, FREE_READ);
return(0);
}
-#endif
+
ta.s_net=ddp->deh_dnet;
ta.s_node=ddp->deh_dnode;
@@ -1508,7 +1501,7 @@ static int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type
* 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;
@@ -1516,14 +1509,14 @@ static int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type
}
/* Fix up skb->len field */
- skb_trim(skb,min(origlen, rt->dev->hard_header_len +
+ 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
*/
-
+
skb=skb_unshare(skb, GFP_ATOMIC, FREE_READ);
if(skb)
{
@@ -1548,7 +1541,29 @@ static int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type
return(0);
}
-
+#ifdef CONFIG_IPDDP
+ /*
+ * Check if IP-over-DDP
+ */
+
+ if(skb->data[12]==22)
+ {
+ struct net_device_stats *estats =
+ (struct net_device_stats *) dev_ipddp.priv;
+ skb->protocol=htons(ETH_P_IP);
+ skb_pull(skb,13);
+ skb->dev=&dev_ipddp;
+ skb->h.raw = skb->data;
+ /* printk("passing up ipddp, 0x%02x better be 45\n",skb->data[0]);
+ * printk("tot_len %d, skb->len %d\n",
+ * ntohs(skb->h.iph->tot_len),skb->len);
+ */
+ estats->rx_packets++;
+ estats->rx_bytes+=skb->len+13;
+ netif_rx(skb);
+ return 0;
+ }
+#endif /* CONFIG_IPDDP */
/*
* Queue packet (standard)
*/
@@ -1569,7 +1584,7 @@ static int atalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type
* header and append a long one.
*/
-
+
static int ltalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
{
struct ddpehdr *ddp;
@@ -1577,49 +1592,49 @@ static int ltalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type
/*
* 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_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
+ ddp->deh_hops=15; /* Non routable, so force a drop
if we slip up later */
*((__u16 *)ddp)=htons(*((__u16 *)ddp)); /* Mend the byte order */
}
@@ -1627,9 +1642,10 @@ static int ltalk_rcv(struct sk_buff *skb, struct device *dev, struct packet_type
return atalk_rcv(skb,dev,pt);
}
-static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, int len, int nonblock, int flags)
+static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, int len,
+ struct scm_cookie *scm)
{
- atalk_socket *sk=(atalk_socket *)sock->data;
+ struct sock *sk=sock->sk;
struct sockaddr_at *usat=(struct sockaddr_at *)msg->msg_name;
struct sockaddr_at local_satalk, gsat;
struct sk_buff *skb;
@@ -1639,13 +1655,14 @@ static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, int len, int n
struct atalk_route *rt;
int loopback=0;
int err;
-
- if(flags)
+ int flags = msg->msg_flags;
+
+ if(flags&~MSG_DONTWAIT)
return -EINVAL;
-
+
if(len>587)
return -EMSGSIZE;
-
+
if(usat)
{
if(sk->zapped)
@@ -1658,10 +1675,10 @@ static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, int len, int n
return(-EINVAL);
if(usat->sat_family != AF_APPLETALK)
return -EINVAL;
-#if 0 /* netatalk doesn't implement this check */
+#if 0 /* netatalk doesn't implement this check */
if(usat->sat_addr.s_node==ATADDR_BCAST && !sk->broadcast)
return -EPERM;
-#endif
+#endif
}
else
{
@@ -1673,19 +1690,18 @@ static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, int len, int n
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 */
-
- if(sk->debug)
- printk("SK %p: Got address.\n",sk);
-
+
+ SOCK_DEBUG(sk, "SK %p: Got address.\n",sk);
+
size=sizeof(struct ddpehdr)+len+ddp_dl->header_length; /* For headers */
if(usat->sat_addr.s_net!=0 || usat->sat_addr.s_node == ATADDR_ANYNODE)
{
rt=atrtr_find(&usat->sat_addr);
if(rt==NULL)
- return -ENETUNREACH;
+ return -ENETUNREACH;
dev=rt->dev;
}
else
@@ -1699,26 +1715,23 @@ static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, int len, int n
dev=rt->dev;
}
- if(sk->debug)
- printk("SK %p: Size needed %d, device %s\n", sk, size, dev->name);
-
+ SOCK_DEBUG(sk, "SK %p: Size needed %d, device %s\n", sk, size, dev->name);
+
size += dev->hard_header_len;
- skb = sock_alloc_send_skb(sk, size, 0, 0 , &err);
+ skb = sock_alloc_send_skb(sk, size, 0, flags&MSG_DONTWAIT, &err);
if(skb==NULL)
return err;
skb->sk=sk;
- skb->free=1;
skb->arp=1;
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);
-
+
+ SOCK_DEBUG(sk, "SK %p: Begin build.\n", sk);
+
ddp=(struct ddpehdr *)skb_put(skb,sizeof(struct ddpehdr));
ddp->deh_pad=0;
ddp->deh_hops=0;
@@ -1737,36 +1750,31 @@ static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, int len, int n
ddp->deh_dport=usat->sat_port;
ddp->deh_sport=sk->protinfo.af_at.src_port;
- if(sk->debug)
- printk("SK %p: Copy user data (%d bytes).\n", sk, len);
-
+ SOCK_DEBUG(sk, "SK %p: Copy user data (%d bytes).\n", sk, 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)
+ if(call_out_firewall(AF_APPLETALK, skb->dev, ddp, NULL, &skb)!=FW_ACCEPT)
{
kfree_skb(skb, FREE_WRITE);
return -EPERM;
- }
-
-#endif
-
+ }
+
/*
* Loopback broadcast packets to non gateway targets (ie routes
* to group we are in)
*/
-
+
if(ddp->deh_dnode==ATADDR_BCAST)
{
if((!(rt->flags&RTF_GATEWAY))&&(!(dev->flags&IFF_LOOPBACK)))
@@ -1775,8 +1783,7 @@ static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, int len, int n
if(skb2)
{
loopback=1;
- if(sk->debug)
- printk("SK %p: send out(copy).\n", sk);
+ SOCK_DEBUG(sk, "SK %p: send out(copy).\n", sk);
if(aarp_send_ddp(dev,skb2,&usat->sat_addr, NULL)==-1)
kfree_skb(skb2, FREE_WRITE);
/* else queued/sent above in the aarp queue */
@@ -1784,53 +1791,46 @@ static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, int len, int n
}
}
- if((dev->flags&IFF_LOOPBACK) || loopback)
+ if((dev->flags&IFF_LOOPBACK) || loopback)
{
- if(sk->debug)
- printk("SK %p: Loop back.\n", sk);
+ SOCK_DEBUG(sk, "SK %p: Loop back.\n", sk);
/* loop back */
- atomic_sub(skb->truesize, &sk->wmem_alloc);
+ skb_orphan(skb);
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_pull(skb,dev->hard_header_len);
skb_pull(skb,ddp_dl->header_length);
atalk_rcv(skb,dev,NULL);
}
- else
+ else
{
- if(sk->debug)
- printk("SK %p: send out.\n", sk);
-
+ SOCK_DEBUG(sk, "SK %p: send out.\n", sk);
if ( rt->flags & RTF_GATEWAY ) {
gsat.sat_addr = rt->gateway;
usat = &gsat;
}
-
+
if(aarp_send_ddp(dev,skb,&usat->sat_addr, NULL)==-1)
kfree_skb(skb, FREE_WRITE);
/* else queued/sent above in the aarp queue */
}
- if(sk->debug)
- printk("SK %p: Done write (%d).\n", sk, len);
+ SOCK_DEBUG(sk, "SK %p: Done write (%d).\n", sk, len);
return len;
}
-static int atalk_recvmsg(struct socket *sock, struct msghdr *msg, int size, int noblock, int flags, int *addr_len)
+static int atalk_recvmsg(struct socket *sock, struct msghdr *msg, int size,
+ int flags, struct scm_cookie *scm)
{
- atalk_socket *sk=(atalk_socket *)sock->data;
+ struct sock *sk=sock->sk;
struct sockaddr_at *sat=(struct sockaddr_at *)msg->msg_name;
struct ddpehdr *ddp = NULL;
int copied = 0;
struct sk_buff *skb;
int er = 0;
-
- if(addr_len)
- *addr_len=sizeof(*sat);
- skb=skb_recv_datagram(sk,flags,noblock,&er);
+ skb=skb_recv_datagram(sk,flags&~MSG_DONTWAIT,flags&MSG_DONTWAIT,&er);
if(skb==NULL)
return er;
@@ -1856,8 +1856,8 @@ static int atalk_recvmsg(struct socket *sock, struct msghdr *msg, int size, int
msg->msg_flags|=MSG_TRUNC;
}
er = skb_copy_datagram_iovec(skb,sizeof(*ddp),msg->msg_iov,copied);
- if (er)
- goto out;
+ if (er)
+ goto out;
}
if(sat)
{
@@ -1866,10 +1866,11 @@ static int atalk_recvmsg(struct socket *sock, struct msghdr *msg, int size, int
sat->sat_addr.s_node=ddp->deh_snode;
sat->sat_addr.s_net=ddp->deh_snet;
}
+ msg->msg_namelen=sizeof(*sat);
out:
skb_free_datagram(sk, skb);
return er ? er : (copied);
-}
+}
static int atalk_shutdown(struct socket *sk,int how)
@@ -1877,13 +1878,6 @@ static int atalk_shutdown(struct socket *sk,int how)
return -EOPNOTSUPP;
}
-static int atalk_select(struct socket *sock , int sel_type, select_table *wait)
-{
- atalk_socket *sk=(atalk_socket *)sock->data;
-
- return datagram_select(sk,sel_type,wait);
-}
-
/*
* Appletalk ioctl calls.
*/
@@ -1891,15 +1885,15 @@ 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)
{
long amount=0;
- atalk_socket *sk=(atalk_socket *)sock->data;
-
+ struct sock *sk=sock->sk;
+
switch(cmd)
{
/*
* Protocol layer
*/
case TIOCOUTQ:
- amount=sk->sndbuf-sk->wmem_alloc;
+ amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
if(amount<0)
amount=0;
break;
@@ -1929,7 +1923,7 @@ static int atalk_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg)
return(atrtr_ioctl(cmd,(void *)arg));
/*
* Interface
- */
+ */
case SIOCGIFADDR:
case SIOCSIFADDR:
case SIOCGIFBRDADDR:
@@ -1965,10 +1959,14 @@ static int atalk_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg)
return put_user(amount, (int *)arg);
}
-static struct proto_ops atalk_proto_ops = {
+static struct net_proto_family atalk_family_ops = {
AF_APPLETALK,
-
- atalk_create,
+ atalk_create
+};
+
+static struct proto_ops atalk_dgram_ops = {
+ AF_APPLETALK,
+
atalk_dup,
atalk_release,
atalk_bind,
@@ -1976,13 +1974,13 @@ static struct proto_ops atalk_proto_ops = {
atalk_socketpair,
atalk_accept,
atalk_getname,
- atalk_select,
+ datagram_poll,
atalk_ioctl,
- atalk_listen,
+ sock_no_listen,
atalk_shutdown,
- atalk_setsockopt,
- atalk_getsockopt,
- atalk_fcntl,
+ sock_no_setsockopt,
+ sock_no_getsockopt,
+ sock_no_fcntl,
atalk_sendmsg,
atalk_recvmsg
};
@@ -2038,16 +2036,16 @@ static struct proc_dir_entry proc_atalk_iface = {
void atalk_proto_init(struct net_proto *pro)
{
- (void) sock_register(atalk_proto_ops.family, &atalk_proto_ops);
+ (void) sock_register(&atalk_family_ops);
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);
+
+ 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();
@@ -2057,15 +2055,19 @@ void atalk_proto_init(struct net_proto *pro)
proc_net_register(&proc_atalk_iface);
#endif
+#ifdef CONFIG_IPDDP
+ register_netdev(&dev_ipddp);
+#endif /* CONFIG_IPDDP */
+
printk(KERN_INFO "Appletalk 0.18 for Linux NET3.037\n");
}
#ifdef MODULE
+EXPORT_NO_SYMBOLS;
int init_module(void)
{
atalk_proto_init(NULL);
- register_symtab(0);
return 0;
}
@@ -2073,7 +2075,7 @@ int init_module(void)
* 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)
{
@@ -2113,12 +2115,12 @@ void cleanup_module(void)
proc_net_unregister(PROC_NET_ATALK);
proc_net_unregister(PROC_NET_AT_ROUTE);
proc_net_unregister(PROC_NET_ATIF);
-#endif
+#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);
+ sock_unregister(atalk_family_ops.family);
free_route_list();
free_interface_list();