diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-04-29 21:13:14 +0000 |
---|---|---|
committer | <ralf@linux-mips.org> | 1997-04-29 21:13:14 +0000 |
commit | 19c9bba94152148523ba0f7ef7cffe3d45656b11 (patch) | |
tree | 40b1cb534496a7f1ca0f5c314a523c69f1fee464 /net/appletalk | |
parent | 7206675c40394c78a90e74812bbdbf8cf3cca1be (diff) |
Import of Linux/MIPS 2.1.36
Diffstat (limited to 'net/appletalk')
-rw-r--r-- | net/appletalk/Makefile | 6 | ||||
-rw-r--r-- | net/appletalk/aarp.c | 51 | ||||
-rw-r--r-- | net/appletalk/ddp.c | 1014 |
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(<alk_packet_type); - + ppptalk_packet_type.type=htons(ETH_P_PPPTALK); dev_add_pack(&ppptalk_packet_type); - + register_netdevice_notifier(&ddp_notifier); aarp_proto_init(); @@ -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(<alk_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(); |