📄 ddp.c
字号:
int len = 0; off_t pos = 0; off_t begin = 0; len += sprintf(buffer,"Interface Address Networks Status\n"); spin_lock_bh(&atalk_iface_lock); for (iface = atalk_iface_list; iface != NULL; iface = iface->next) { len += sprintf(buffer+len,"%-16s %04X:%02X %04X-%04X %d\n", iface->dev->name, ntohs(iface->address.s_net), iface->address.s_node, ntohs(iface->nets.nr_firstnet), ntohs(iface->nets.nr_lastnet), iface->status); pos = begin + len; if (pos < offset) { len = 0; begin = pos; } if (pos > offset + length) break; } spin_unlock_bh(&atalk_iface_lock); *start = buffer + (offset - begin); len -= (offset - begin); if (len > length) len = length; return (len);}/* Called from proc fs - just make it print the routes neatly */static int atalk_rt_get_info(char *buffer, char **start, off_t offset, int length){ struct atalk_route *rt; int len = 0; off_t pos = 0; off_t begin = 0; len += sprintf(buffer,"Target Router Flags Dev\n"); if (atrtr_default.dev) { rt = &atrtr_default; len += sprintf(buffer+len,"Default %04X:%02X %-4d %s\n", ntohs(rt->gateway.s_net), rt->gateway.s_node, rt->flags, rt->dev->name); } read_lock_bh(&atalk_router_lock); for (rt = atalk_router_list; rt != NULL; rt = rt->next) { len += sprintf(buffer+len,"%04X:%02X %04X:%02X %-4d %s\n", ntohs(rt->target.s_net), rt->target.s_node, ntohs(rt->gateway.s_net), rt->gateway.s_node, rt->flags, rt->dev->name); pos = begin + len; if (pos < offset) { len = 0; begin = pos; } if (pos > offset + length) break; } read_unlock_bh(&atalk_router_lock); *start = buffer + (offset - begin); len -= (offset - begin); if (len > length) len = length; return len;}/**************************************************************************\* ** Handling for system calls applied via the various interfaces to an ** AppleTalk socket object. ** *\**************************************************************************//* * 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; /* This ought to be unwrapped neatly. I'll trust gcc for now */ while (len--) { sum += *data; sum <<= 1; if (sum & 0x10000) { sum++; sum &= 0xFFFF; } data++; } if (sum) return htons((unsigned short) sum); return 0xFFFF; /* Use 0xFFFF for 0. 0 itself means none */}/* * Create a socket. Initialise the socket, blank the addresses * set the state. */static int atalk_create(struct socket *sock, int protocol){ struct sock *sk; sk = sk_alloc(PF_APPLETALK, GFP_KERNEL, 1); if (sk == NULL) return -ENOMEM; switch (sock->type) { /* * We permit SOCK_DGRAM and RAW is an extension. It is * trivial to do and gives you the full ELAP frame. * Should be handy for CAP 8) */ case SOCK_RAW: case SOCK_DGRAM: sock->ops = &atalk_dgram_ops; break; case SOCK_STREAM: /* * TO DO: if you want to implement ADSP, here's the place to start */ /* sock->ops = &atalk_stream_ops; break; */ default: sk_free((void *) sk); return -ESOCKTNOSUPPORT; }; MOD_INC_USE_COUNT; sock_init_data(sock, sk); sk->destruct = NULL; /* Checksums on by default */ sk->zapped = 1; return 0;}/* * Free a socket. No work needed */static int atalk_release(struct socket *sock){ struct sock *sk=sock->sk; if (sk == NULL) return 0; if (!sk->dead) sk->state_change(sk); sk->dead = 1; sock->sk = NULL; atalk_destroy_socket(sk); return 0;}/* * Pick a source port when one is not given. If we can * find a suitable free one, we insert the socket into * the tables using it. * * This whole operation must be atomic. */static int atalk_pick_and_bind_port(struct sock *sk, struct sockaddr_at *sat){ struct sock *s; int retval; spin_lock_bh(&atalk_sockets_lock); for (sat->sat_port = ATPORT_RESERVED; sat->sat_port < ATPORT_LAST; sat->sat_port++) { for (s = atalk_sockets; s != NULL; s = s->next) { if (s->protinfo.af_at.src_net == sat->sat_addr.s_net && s->protinfo.af_at.src_node == sat->sat_addr.s_node && s->protinfo.af_at.src_port == sat->sat_port) goto try_next_port; } /* Wheee, it's free, assign and insert. */ if ((sk->next = atalk_sockets) != NULL) atalk_sockets->pprev = &sk->next; atalk_sockets = sk; sk->pprev = &atalk_sockets; sk->protinfo.af_at.src_port = sat->sat_port; retval = 0; goto out; try_next_port: ; } retval = -EBUSY;out: spin_unlock_bh(&atalk_sockets_lock); return retval;}static int atalk_autobind(struct sock *sk){ struct at_addr *ap = atalk_find_primary(); struct sockaddr_at sat; int n; if (ap == NULL || ap->s_net == htons(ATADDR_ANYNET)) return -EADDRNOTAVAIL; sk->protinfo.af_at.src_net = sat.sat_addr.s_net = ap->s_net; sk->protinfo.af_at.src_node = sat.sat_addr.s_node = ap->s_node; if ((n = atalk_pick_and_bind_port(sk, &sat)) < 0) return n; sk->zapped = 0; return 0;}/* * Set the address 'our end' of the connection. */static int atalk_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len){ struct sock *sk; struct sockaddr_at *addr = (struct sockaddr_at *)uaddr; sk = sock->sk; if(sk->zapped == 0) return -EINVAL; if(addr_len != sizeof(struct sockaddr_at)) return -EINVAL; if(addr->sat_family != AF_APPLETALK) return -EAFNOSUPPORT; if(addr->sat_addr.s_net == htons(ATADDR_ANYNET)) { struct at_addr *ap = atalk_find_primary(); if(ap == NULL) return -EADDRNOTAVAIL; sk->protinfo.af_at.src_net = addr->sat_addr.s_net = ap->s_net; sk->protinfo.af_at.src_node = addr->sat_addr.s_node= ap->s_node; } else { if (atalk_find_interface(addr->sat_addr.s_net, addr->sat_addr.s_node) == NULL) return -EADDRNOTAVAIL; sk->protinfo.af_at.src_net = addr->sat_addr.s_net; sk->protinfo.af_at.src_node = addr->sat_addr.s_node; } if (addr->sat_port == ATADDR_ANYPORT) { int n = atalk_pick_and_bind_port(sk, addr); if (n < 0) return n; } else { sk->protinfo.af_at.src_port = addr->sat_port; if (atalk_find_or_insert_socket(sk, addr) != NULL) return -EADDRINUSE; } sk->zapped = 0; return 0;}/* * Set the address we talk to. */static int atalk_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags){ struct sock *sk = sock->sk; struct sockaddr_at *addr; 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 (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 } 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; sock->state = SS_CONNECTED; sk->state = TCP_ESTABLISHED; return 0;}/* * 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; 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) return -ENOTCONN; sat.sat_addr.s_net = sk->protinfo.af_at.dest_net; sat.sat_addr.s_node = sk->protinfo.af_at.dest_node; sat.sat_port = sk->protinfo.af_at.dest_port; } else { sat.sat_addr.s_net = sk->protinfo.af_at.src_net; sat.sat_addr.s_node = sk->protinfo.af_at.src_node; sat.sat_port = sk->protinfo.af_at.src_port; } sat.sat_family = AF_APPLETALK; memcpy(uaddr, &sat, sizeof(sat)); return 0;}/* * 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 * 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 net_device *dev, struct packet_type *pt){ struct sock *sock; struct ddpehdr *ddp = (void *) skb->h.raw; struct atalk_iface *atif; struct sockaddr_at tosat; int origlen; struct ddpebits ddphv; /* Size check */ if (skb->len < sizeof(*ddp)) { kfree_skb(skb); 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 * compiler/endian dependencies..] * * FIXME: This is a write to a shared object. Granted it * happens to be safe BUT.. (Its safe as user space will not * run until we put it back) */ *((__u16 *)&ddphv) = ntohs(*((__u16 *)ddp)); /* * Trim buffer in case of stray trailing data */ origlen = skb->len; skb_trim(skb, min(skb->len, ddphv.deh_len)); /* * Size check to see if ddp->deh_len was crap * (Otherwise we'll detonate most spectacularly * in the middle of recvmsg()). */ if (skb->len < sizeof(*ddp)) { kfree_skb(skb); return 0; } /* * Any checksums. Note we don't do htons() on this == is assumed to be * valid for net byte orders all over the networking code... */ if (ddp->deh_sum && atalk_checksum(ddp, ddphv.deh_len) != ddp->deh_sum) { /* Not a valid AppleTalk frame - dustbin time */ kfree_skb(skb); return 0; } /* Check the packet is aimed at us */ if (ddp->deh_dnet == 0) /* Net 0 is 'this network' */ atif = atalk_find_anynet(ddp->deh_dnode, dev); else atif = atalk_find_interface(ddp->deh_dnet, ddp->deh_dnode); /* * Not ours, so we route the packet via the correct AppleTalk interface. */ 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) { /* * FIX ME: * Can it ever happen that a packet is from a PPP iface and needs to be broadcast onto the default network? */ if (dev->type == ARPHRD_PPP) printk(KERN_DEBUG "AppleTalk: didn't forward broadcast packet received from PPP iface\n"); kfree_skb(skb); return 0; } ta.s_net = ddp->deh_dnet; ta.s_node = ddp->deh_dnode; /* Route the packet */ rt = atrtr_find(&ta); if (rt == NULL || ddphv.deh_hops == DDP_MAXHOPS) { kfree_skb(skb); return 0; } ddphv.deh_hops++; /* * Route goes through another gateway, so * set the target to the gateway instead. */ if (rt->flags & RTF_GATEWAY) { ta.s_net = rt->gateway.s_net; ta.s_node = rt->gateway.s_node; } /* Fix up skb->len field */ skb_trim(skb, min(origlen, rt->dev->hard_header_len + ddp_dl->header_length + ddphv.deh_len)); /* Mend the byte order */ *((__u16 *)ddp) = ntohs(*((__u16 *)&ddphv)); /* * Send the buffer onwards * * Now we must always be careful. If it's come from * LocalTalk to EtherTalk it might not fit * * Order matters here: If a packet has to be copied * to make a new headroom (rare hopefully) then it * won't need unsharing. * * Note. ddp-> becomes invalid at the realloc. */ if (skb_headroom(skb) < 22) { struct sk_buff *newskb; /* 22 bytes - 12 ether, 2 len, 3 802.2 5 snap */ newskb = skb_realloc_headroom(skb, 32); kfree_skb(skb); if (!newskb) return 0; skb = newskb; } else skb = skb_unshare(skb, GFP_ATOMIC); /* * If the buffer didn't vanish into the lack of * space bitbucket we can send it. */ if (skb) { if (aarp_send_ddp(rt->dev, skb, &ta, NULL) == -1) kfree_skb(skb); } return 0; }#if defined(CONFIG_IPDDP) || defined(CONFIG_IPDDP_MODULE) /* * Check if IP-over-DDP */ if (skb->data[12] == 22) { struct net_device *dev; /* This needs to be able to handle ipddp"N" devices */ if ((dev = __dev_get_by_name("ipddp0")) == NULL) return -ENODEV; skb->protocol = htons(ETH_P_IP); skb_pull(skb, 13); skb->dev = dev; skb->h.raw = skb->data; ((struct net_device_stats *)dev->priv)->rx_packets++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -