diff options
| author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
| commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
| tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /net/appletalk | |
Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'net/appletalk')
| -rw-r--r-- | net/appletalk/Makefile | 9 | ||||
| -rw-r--r-- | net/appletalk/aarp.c | 1069 | ||||
| -rw-r--r-- | net/appletalk/atalk_proc.c | 321 | ||||
| -rw-r--r-- | net/appletalk/ddp.c | 1931 | ||||
| -rw-r--r-- | net/appletalk/dev.c | 43 | ||||
| -rw-r--r-- | net/appletalk/sysctl_net_atalk.c | 83 |
6 files changed, 3456 insertions, 0 deletions
diff --git a/net/appletalk/Makefile b/net/appletalk/Makefile new file mode 100644 index 00000000000..5cda56edef5 --- /dev/null +++ b/net/appletalk/Makefile | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | # | ||
| 2 | # Makefile for the Linux AppleTalk layer. | ||
| 3 | # | ||
| 4 | |||
| 5 | obj-$(CONFIG_ATALK) += appletalk.o | ||
| 6 | |||
| 7 | appletalk-y := aarp.o ddp.o dev.o | ||
| 8 | appletalk-$(CONFIG_PROC_FS) += atalk_proc.o | ||
| 9 | appletalk-$(CONFIG_SYSCTL) += sysctl_net_atalk.o | ||
diff --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c new file mode 100644 index 00000000000..54640c01b50 --- /dev/null +++ b/net/appletalk/aarp.c | |||
| @@ -0,0 +1,1069 @@ | |||
| 1 | /* | ||
| 2 | * AARP: An implementation of the AppleTalk AARP protocol for | ||
| 3 | * Ethernet 'ELAP'. | ||
| 4 | * | ||
| 5 | * Alan Cox <Alan.Cox@linux.org> | ||
| 6 | * | ||
| 7 | * This doesn't fit cleanly with the IP arp. Potentially we can use | ||
| 8 | * the generic neighbour discovery code to clean this up. | ||
| 9 | * | ||
| 10 | * FIXME: | ||
| 11 | * We ought to handle the retransmits with a single list and a | ||
| 12 | * separate fast timer for when it is needed. | ||
| 13 | * Use neighbour discovery code. | ||
| 14 | * Token Ring Support. | ||
| 15 | * | ||
| 16 | * This program is free software; you can redistribute it and/or | ||
| 17 | * modify it under the terms of the GNU General Public License | ||
| 18 | * as published by the Free Software Foundation; either version | ||
| 19 | * 2 of the License, or (at your option) any later version. | ||
| 20 | * | ||
| 21 | * | ||
| 22 | * References: | ||
| 23 | * Inside AppleTalk (2nd Ed). | ||
| 24 | * Fixes: | ||
| 25 | * Jaume Grau - flush caches on AARP_PROBE | ||
| 26 | * Rob Newberry - Added proxy AARP and AARP proc fs, | ||
| 27 | * moved probing from DDP module. | ||
| 28 | * Arnaldo C. Melo - don't mangle rx packets | ||
| 29 | * | ||
| 30 | */ | ||
| 31 | |||
| 32 | #include <linux/config.h> | ||
| 33 | #include <linux/if_arp.h> | ||
| 34 | #include <net/sock.h> | ||
| 35 | #include <net/datalink.h> | ||
| 36 | #include <net/psnap.h> | ||
| 37 | #include <linux/atalk.h> | ||
| 38 | #include <linux/init.h> | ||
| 39 | #include <linux/proc_fs.h> | ||
| 40 | #include <linux/seq_file.h> | ||
| 41 | |||
| 42 | int sysctl_aarp_expiry_time = AARP_EXPIRY_TIME; | ||
| 43 | int sysctl_aarp_tick_time = AARP_TICK_TIME; | ||
| 44 | int sysctl_aarp_retransmit_limit = AARP_RETRANSMIT_LIMIT; | ||
| 45 | int sysctl_aarp_resolve_time = AARP_RESOLVE_TIME; | ||
| 46 | |||
| 47 | /* Lists of aarp entries */ | ||
| 48 | /** | ||
| 49 | * struct aarp_entry - AARP entry | ||
| 50 | * @last_sent - Last time we xmitted the aarp request | ||
| 51 | * @packet_queue - Queue of frames wait for resolution | ||
| 52 | * @status - Used for proxy AARP | ||
| 53 | * expires_at - Entry expiry time | ||
| 54 | * target_addr - DDP Address | ||
| 55 | * dev - Device to use | ||
| 56 | * hwaddr - Physical i/f address of target/router | ||
| 57 | * xmit_count - When this hits 10 we give up | ||
| 58 | * next - Next entry in chain | ||
| 59 | */ | ||
| 60 | struct aarp_entry { | ||
| 61 | /* These first two are only used for unresolved entries */ | ||
| 62 | unsigned long last_sent; | ||
| 63 | struct sk_buff_head packet_queue; | ||
| 64 | int status; | ||
| 65 | unsigned long expires_at; | ||
| 66 | struct atalk_addr target_addr; | ||
| 67 | struct net_device *dev; | ||
| 68 | char hwaddr[6]; | ||
| 69 | unsigned short xmit_count; | ||
| 70 | struct aarp_entry *next; | ||
| 71 | }; | ||
| 72 | |||
| 73 | /* Hashed list of resolved, unresolved and proxy entries */ | ||
| 74 | static struct aarp_entry *resolved[AARP_HASH_SIZE]; | ||
| 75 | static struct aarp_entry *unresolved[AARP_HASH_SIZE]; | ||
| 76 | static struct aarp_entry *proxies[AARP_HASH_SIZE]; | ||
| 77 | static int unresolved_count; | ||
| 78 | |||
| 79 | /* One lock protects it all. */ | ||
| 80 | static DEFINE_RWLOCK(aarp_lock); | ||
| 81 | |||
| 82 | /* Used to walk the list and purge/kick entries. */ | ||
| 83 | static struct timer_list aarp_timer; | ||
| 84 | |||
| 85 | /* | ||
| 86 | * Delete an aarp queue | ||
| 87 | * | ||
| 88 | * Must run under aarp_lock. | ||
| 89 | */ | ||
| 90 | static void __aarp_expire(struct aarp_entry *a) | ||
| 91 | { | ||
| 92 | skb_queue_purge(&a->packet_queue); | ||
| 93 | kfree(a); | ||
| 94 | } | ||
| 95 | |||
| 96 | /* | ||
| 97 | * Send an aarp queue entry request | ||
| 98 | * | ||
| 99 | * Must run under aarp_lock. | ||
| 100 | */ | ||
| 101 | static void __aarp_send_query(struct aarp_entry *a) | ||
| 102 | { | ||
| 103 | static unsigned char aarp_eth_multicast[ETH_ALEN] = | ||
| 104 | { 0x09, 0x00, 0x07, 0xFF, 0xFF, 0xFF }; | ||
| 105 | struct net_device *dev = a->dev; | ||
| 106 | struct elapaarp *eah; | ||
| 107 | int len = dev->hard_header_len + sizeof(*eah) + aarp_dl->header_length; | ||
| 108 | struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC); | ||
| 109 | struct atalk_addr *sat = atalk_find_dev_addr(dev); | ||
| 110 | |||
| 111 | if (!skb) | ||
| 112 | return; | ||
| 113 | |||
| 114 | if (!sat) { | ||
| 115 | kfree_skb(skb); | ||
| 116 | return; | ||
| 117 | } | ||
| 118 | |||
| 119 | /* Set up the buffer */ | ||
| 120 | skb_reserve(skb, dev->hard_header_len + aarp_dl->header_length); | ||
| 121 | skb->nh.raw = skb->h.raw = skb_put(skb, sizeof(*eah)); | ||
| 122 | skb->protocol = htons(ETH_P_ATALK); | ||
| 123 | skb->dev = dev; | ||
| 124 | eah = aarp_hdr(skb); | ||
| 125 | |||
| 126 | /* Set up the ARP */ | ||
| 127 | eah->hw_type = htons(AARP_HW_TYPE_ETHERNET); | ||
| 128 | eah->pa_type = htons(ETH_P_ATALK); | ||
| 129 | eah->hw_len = ETH_ALEN; | ||
| 130 | eah->pa_len = AARP_PA_ALEN; | ||
| 131 | eah->function = htons(AARP_REQUEST); | ||
| 132 | |||
| 133 | memcpy(eah->hw_src, dev->dev_addr, ETH_ALEN); | ||
| 134 | |||
| 135 | eah->pa_src_zero = 0; | ||
| 136 | eah->pa_src_net = sat->s_net; | ||
| 137 | eah->pa_src_node = sat->s_node; | ||
| 138 | |||
| 139 | memset(eah->hw_dst, '\0', ETH_ALEN); | ||
| 140 | |||
| 141 | eah->pa_dst_zero = 0; | ||
| 142 | eah->pa_dst_net = a->target_addr.s_net; | ||
| 143 | eah->pa_dst_node = a->target_addr.s_node; | ||
| 144 | |||
| 145 | /* Send it */ | ||
| 146 | aarp_dl->request(aarp_dl, skb, aarp_eth_multicast); | ||
| 147 | /* Update the sending count */ | ||
| 148 | a->xmit_count++; | ||
| 149 | a->last_sent = jiffies; | ||
| 150 | } | ||
| 151 | |||
| 152 | /* This runs under aarp_lock and in softint context, so only atomic memory | ||
| 153 | * allocations can be used. */ | ||
| 154 | static void aarp_send_reply(struct net_device *dev, struct atalk_addr *us, | ||
| 155 | struct atalk_addr *them, unsigned char *sha) | ||
| 156 | { | ||
| 157 | struct elapaarp *eah; | ||
| 158 | int len = dev->hard_header_len + sizeof(*eah) + aarp_dl->header_length; | ||
| 159 | struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC); | ||
| 160 | |||
| 161 | if (!skb) | ||
| 162 | return; | ||
| 163 | |||
| 164 | /* Set up the buffer */ | ||
| 165 | skb_reserve(skb, dev->hard_header_len + aarp_dl->header_length); | ||
| 166 | skb->nh.raw = skb->h.raw = skb_put(skb, sizeof(*eah)); | ||
| 167 | skb->protocol = htons(ETH_P_ATALK); | ||
| 168 | skb->dev = dev; | ||
| 169 | eah = aarp_hdr(skb); | ||
| 170 | |||
| 171 | /* Set up the ARP */ | ||
| 172 | eah->hw_type = htons(AARP_HW_TYPE_ETHERNET); | ||
| 173 | eah->pa_type = htons(ETH_P_ATALK); | ||
| 174 | eah->hw_len = ETH_ALEN; | ||
| 175 | eah->pa_len = AARP_PA_ALEN; | ||
| 176 | eah->function = htons(AARP_REPLY); | ||
| 177 | |||
| 178 | memcpy(eah->hw_src, dev->dev_addr, ETH_ALEN); | ||
| 179 | |||
| 180 | eah->pa_src_zero = 0; | ||
| 181 | eah->pa_src_net = us->s_net; | ||
| 182 | eah->pa_src_node = us->s_node; | ||
| 183 | |||
| 184 | if (!sha) | ||
| 185 | memset(eah->hw_dst, '\0', ETH_ALEN); | ||
| 186 | else | ||
| 187 | memcpy(eah->hw_dst, sha, ETH_ALEN); | ||
| 188 | |||
| 189 | eah->pa_dst_zero = 0; | ||
| 190 | eah->pa_dst_net = them->s_net; | ||
| 191 | eah->pa_dst_node = them->s_node; | ||
| 192 | |||
| 193 | /* Send it */ | ||
| 194 | aarp_dl->request(aarp_dl, skb, sha); | ||
| 195 | } | ||
| 196 | |||
| 197 | /* | ||
| 198 | * Send probe frames. Called from aarp_probe_network and | ||
| 199 | * aarp_proxy_probe_network. | ||
| 200 | */ | ||
| 201 | |||
| 202 | static void aarp_send_probe(struct net_device *dev, struct atalk_addr *us) | ||
| 203 | { | ||
| 204 | struct elapaarp *eah; | ||
| 205 | int len = dev->hard_header_len + sizeof(*eah) + aarp_dl->header_length; | ||
| 206 | struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC); | ||
| 207 | static unsigned char aarp_eth_multicast[ETH_ALEN] = | ||
| 208 | { 0x09, 0x00, 0x07, 0xFF, 0xFF, 0xFF }; | ||
| 209 | |||
| 210 | if (!skb) | ||
| 211 | return; | ||
| 212 | |||
| 213 | /* Set up the buffer */ | ||
| 214 | skb_reserve(skb, dev->hard_header_len + aarp_dl->header_length); | ||
| 215 | skb->nh.raw = skb->h.raw = skb_put(skb, sizeof(*eah)); | ||
| 216 | skb->protocol = htons(ETH_P_ATALK); | ||
| 217 | skb->dev = dev; | ||
| 218 | eah = aarp_hdr(skb); | ||
| 219 | |||
| 220 | /* Set up the ARP */ | ||
| 221 | eah->hw_type = htons(AARP_HW_TYPE_ETHERNET); | ||
| 222 | eah->pa_type = htons(ETH_P_ATALK); | ||
| 223 | eah->hw_len = ETH_ALEN; | ||
| 224 | eah->pa_len = AARP_PA_ALEN; | ||
| 225 | eah->function = htons(AARP_PROBE); | ||
| 226 | |||
| 227 | memcpy(eah->hw_src, dev->dev_addr, ETH_ALEN); | ||
| 228 | |||
| 229 | eah->pa_src_zero = 0; | ||
| 230 | eah->pa_src_net = us->s_net; | ||
| 231 | eah->pa_src_node = us->s_node; | ||
| 232 | |||
| 233 | memset(eah->hw_dst, '\0', ETH_ALEN); | ||
| 234 | |||
| 235 | eah->pa_dst_zero = 0; | ||
| 236 | eah->pa_dst_net = us->s_net; | ||
| 237 | eah->pa_dst_node = us->s_node; | ||
| 238 | |||
| 239 | /* Send it */ | ||
| 240 | aarp_dl->request(aarp_dl, skb, aarp_eth_multicast); | ||
| 241 | } | ||
| 242 | |||
| 243 | /* | ||
| 244 | * Handle an aarp timer expire | ||
| 245 | * | ||
| 246 | * Must run under the aarp_lock. | ||
| 247 | */ | ||
| 248 | |||
| 249 | static void __aarp_expire_timer(struct aarp_entry **n) | ||
| 250 | { | ||
| 251 | struct aarp_entry *t; | ||
| 252 | |||
| 253 | while (*n) | ||
| 254 | /* Expired ? */ | ||
| 255 | if (time_after(jiffies, (*n)->expires_at)) { | ||
| 256 | t = *n; | ||
| 257 | *n = (*n)->next; | ||
| 258 | __aarp_expire(t); | ||
| 259 | } else | ||
| 260 | n = &((*n)->next); | ||
| 261 | } | ||
| 262 | |||
| 263 | /* | ||
| 264 | * Kick all pending requests 5 times a second. | ||
| 265 | * | ||
| 266 | * Must run under the aarp_lock. | ||
| 267 | */ | ||
| 268 | static void __aarp_kick(struct aarp_entry **n) | ||
| 269 | { | ||
| 270 | struct aarp_entry *t; | ||
| 271 | |||
| 272 | while (*n) | ||
| 273 | /* Expired: if this will be the 11th tx, we delete instead. */ | ||
| 274 | if ((*n)->xmit_count >= sysctl_aarp_retransmit_limit) { | ||
| 275 | t = *n; | ||
| 276 | *n = (*n)->next; | ||
| 277 | __aarp_expire(t); | ||
| 278 | } else { | ||
| 279 | __aarp_send_query(*n); | ||
| 280 | n = &((*n)->next); | ||
| 281 | } | ||
| 282 | } | ||
| 283 | |||
| 284 | /* | ||
| 285 | * A device has gone down. Take all entries referring to the device | ||
| 286 | * and remove them. | ||
| 287 | * | ||
| 288 | * Must run under the aarp_lock. | ||
| 289 | */ | ||
| 290 | static void __aarp_expire_device(struct aarp_entry **n, struct net_device *dev) | ||
| 291 | { | ||
| 292 | struct aarp_entry *t; | ||
| 293 | |||
| 294 | while (*n) | ||
| 295 | if ((*n)->dev == dev) { | ||
| 296 | t = *n; | ||
| 297 | *n = (*n)->next; | ||
| 298 | __aarp_expire(t); | ||
| 299 | } else | ||
| 300 | n = &((*n)->next); | ||
| 301 | } | ||
| 302 | |||
| 303 | /* Handle the timer event */ | ||
| 304 | static void aarp_expire_timeout(unsigned long unused) | ||
| 305 | { | ||
| 306 | int ct; | ||
| 307 | |||
| 308 | write_lock_bh(&aarp_lock); | ||
| 309 | |||
| 310 | for (ct = 0; ct < AARP_HASH_SIZE; ct++) { | ||
| 311 | __aarp_expire_timer(&resolved[ct]); | ||
| 312 | __aarp_kick(&unresolved[ct]); | ||
| 313 | __aarp_expire_timer(&unresolved[ct]); | ||
| 314 | __aarp_expire_timer(&proxies[ct]); | ||
| 315 | } | ||
| 316 | |||
| 317 | write_unlock_bh(&aarp_lock); | ||
| 318 | mod_timer(&aarp_timer, jiffies + | ||
| 319 | (unresolved_count ? sysctl_aarp_tick_time : | ||
| 320 | sysctl_aarp_expiry_time)); | ||
| 321 | } | ||
| 322 | |||
| 323 | /* Network device notifier chain handler. */ | ||
| 324 | static int aarp_device_event(struct notifier_block *this, unsigned long event, | ||
| 325 | void *ptr) | ||
| 326 | { | ||
| 327 | int ct; | ||
| 328 | |||
| 329 | if (event == NETDEV_DOWN) { | ||
| 330 | write_lock_bh(&aarp_lock); | ||
| 331 | |||
| 332 | for (ct = 0; ct < AARP_HASH_SIZE; ct++) { | ||
| 333 | __aarp_expire_device(&resolved[ct], ptr); | ||
| 334 | __aarp_expire_device(&unresolved[ct], ptr); | ||
| 335 | __aarp_expire_device(&proxies[ct], ptr); | ||
| 336 | } | ||
| 337 | |||
| 338 | write_unlock_bh(&aarp_lock); | ||
| 339 | } | ||
| 340 | return NOTIFY_DONE; | ||
| 341 | } | ||
| 342 | |||
| 343 | /* Expire all entries in a hash chain */ | ||
| 344 | static void __aarp_expire_all(struct aarp_entry **n) | ||
| 345 | { | ||
| 346 | struct aarp_entry *t; | ||
| 347 | |||
| 348 | while (*n) { | ||
| 349 | t = *n; | ||
| 350 | *n = (*n)->next; | ||
| 351 | __aarp_expire(t); | ||
| 352 | } | ||
| 353 | } | ||
| 354 | |||
| 355 | /* Cleanup all hash chains -- module unloading */ | ||
| 356 | static void aarp_purge(void) | ||
| 357 | { | ||
| 358 | int ct; | ||
| 359 | |||
| 360 | write_lock_bh(&aarp_lock); | ||
| 361 | for (ct = 0; ct < AARP_HASH_SIZE; ct++) { | ||
| 362 | __aarp_expire_all(&resolved[ct]); | ||
| 363 | __aarp_expire_all(&unresolved[ct]); | ||
| 364 | __aarp_expire_all(&proxies[ct]); | ||
| 365 | } | ||
| 366 | write_unlock_bh(&aarp_lock); | ||
| 367 | } | ||
| 368 | |||
| 369 | /* | ||
| 370 | * Create a new aarp entry. This must use GFP_ATOMIC because it | ||
| 371 | * runs while holding spinlocks. | ||
| 372 | */ | ||
| 373 | static struct aarp_entry *aarp_alloc(void) | ||
| 374 | { | ||
| 375 | struct aarp_entry *a = kmalloc(sizeof(*a), GFP_ATOMIC); | ||
| 376 | |||
| 377 | if (a) | ||
| 378 | skb_queue_head_init(&a->packet_queue); | ||
| 379 | return a; | ||
| 380 | } | ||
| 381 | |||
| 382 | /* | ||
| 383 | * Find an entry. We might return an expired but not yet purged entry. We | ||
| 384 | * don't care as it will do no harm. | ||
| 385 | * | ||
| 386 | * This must run under the aarp_lock. | ||
| 387 | */ | ||
| 388 | static struct aarp_entry *__aarp_find_entry(struct aarp_entry *list, | ||
| 389 | struct net_device *dev, | ||
| 390 | struct atalk_addr *sat) | ||
| 391 | { | ||
| 392 | while (list) { | ||
| 393 | if (list->target_addr.s_net == sat->s_net && | ||
| 394 | list->target_addr.s_node == sat->s_node && | ||
| 395 | list->dev == dev) | ||
| 396 | break; | ||
| 397 | list = list->next; | ||
| 398 | } | ||
| 399 | |||
| 400 | return list; | ||
| 401 | } | ||
| 402 | |||
| 403 | /* Called from the DDP code, and thus must be exported. */ | ||
| 404 | void aarp_proxy_remove(struct net_device *dev, struct atalk_addr *sa) | ||
| 405 | { | ||
| 406 | int hash = sa->s_node % (AARP_HASH_SIZE - 1); | ||
| 407 | struct aarp_entry *a; | ||
| 408 | |||
| 409 | write_lock_bh(&aarp_lock); | ||
| 410 | |||
| 411 | a = __aarp_find_entry(proxies[hash], dev, sa); | ||
| 412 | if (a) | ||
| 413 | a->expires_at = jiffies - 1; | ||
| 414 | |||
| 415 | write_unlock_bh(&aarp_lock); | ||
| 416 | } | ||
| 417 | |||
| 418 | /* This must run under aarp_lock. */ | ||
| 419 | static struct atalk_addr *__aarp_proxy_find(struct net_device *dev, | ||
| 420 | struct atalk_addr *sa) | ||
| 421 | { | ||
| 422 | int hash = sa->s_node % (AARP_HASH_SIZE - 1); | ||
| 423 | struct aarp_entry *a = __aarp_find_entry(proxies[hash], dev, sa); | ||
| 424 | |||
| 425 | return a ? sa : NULL; | ||
| 426 | } | ||
| 427 | |||
| 428 | /* | ||
| 429 | * Probe a Phase 1 device or a device that requires its Net:Node to | ||
| 430 | * be set via an ioctl. | ||
| 431 | */ | ||
| 432 | static void aarp_send_probe_phase1(struct atalk_iface *iface) | ||
| 433 | { | ||
| 434 | struct ifreq atreq; | ||
| 435 | struct sockaddr_at *sa = (struct sockaddr_at *)&atreq.ifr_addr; | ||
| 436 | |||
| 437 | sa->sat_addr.s_node = iface->address.s_node; | ||
| 438 | sa->sat_addr.s_net = ntohs(iface->address.s_net); | ||
| 439 | |||
| 440 | /* We pass the Net:Node to the drivers/cards by a Device ioctl. */ | ||
| 441 | if (!(iface->dev->do_ioctl(iface->dev, &atreq, SIOCSIFADDR))) { | ||
| 442 | (void)iface->dev->do_ioctl(iface->dev, &atreq, SIOCGIFADDR); | ||
| 443 | if (iface->address.s_net != htons(sa->sat_addr.s_net) || | ||
| 444 | iface->address.s_node != sa->sat_addr.s_node) | ||
| 445 | iface->status |= ATIF_PROBE_FAIL; | ||
| 446 | |||
| 447 | iface->address.s_net = htons(sa->sat_addr.s_net); | ||
| 448 | iface->address.s_node = sa->sat_addr.s_node; | ||
| 449 | } | ||
| 450 | } | ||
| 451 | |||
| 452 | |||
| 453 | void aarp_probe_network(struct atalk_iface *atif) | ||
| 454 | { | ||
| 455 | if (atif->dev->type == ARPHRD_LOCALTLK || | ||
| 456 | atif->dev->type == ARPHRD_PPP) | ||
| 457 | aarp_send_probe_phase1(atif); | ||
| 458 | else { | ||
| 459 | unsigned int count; | ||
| 460 | |||
| 461 | for (count = 0; count < AARP_RETRANSMIT_LIMIT; count++) { | ||
| 462 | aarp_send_probe(atif->dev, &atif->address); | ||
| 463 | |||
| 464 | /* Defer 1/10th */ | ||
| 465 | current->state = TASK_INTERRUPTIBLE; | ||
| 466 | schedule_timeout(HZ / 10); | ||
| 467 | |||
| 468 | if (atif->status & ATIF_PROBE_FAIL) | ||
| 469 | break; | ||
| 470 | } | ||
| 471 | } | ||
| 472 | } | ||
| 473 | |||
| 474 | int aarp_proxy_probe_network(struct atalk_iface *atif, struct atalk_addr *sa) | ||
| 475 | { | ||
| 476 | int hash, retval = -EPROTONOSUPPORT; | ||
| 477 | struct aarp_entry *entry; | ||
| 478 | unsigned int count; | ||
| 479 | |||
| 480 | /* | ||
| 481 | * we don't currently support LocalTalk or PPP for proxy AARP; | ||
| 482 | * if someone wants to try and add it, have fun | ||
| 483 | */ | ||
| 484 | if (atif->dev->type == ARPHRD_LOCALTLK || | ||
| 485 | atif->dev->type == ARPHRD_PPP) | ||
| 486 | goto out; | ||
| 487 | |||
| 488 | /* | ||
| 489 | * create a new AARP entry with the flags set to be published -- | ||
| 490 | * we need this one to hang around even if it's in use | ||
| 491 | */ | ||
| 492 | entry = aarp_alloc(); | ||
| 493 | retval = -ENOMEM; | ||
| 494 | if (!entry) | ||
| 495 | goto out; | ||
| 496 | |||
| 497 | entry->expires_at = -1; | ||
| 498 | entry->status = ATIF_PROBE; | ||
| 499 | entry->target_addr.s_node = sa->s_node; | ||
| 500 | entry->target_addr.s_net = sa->s_net; | ||
| 501 | entry->dev = atif->dev; | ||
| 502 | |||
| 503 | write_lock_bh(&aarp_lock); | ||
| 504 | |||
| 505 | hash = sa->s_node % (AARP_HASH_SIZE - 1); | ||
| 506 | entry->next = proxies[hash]; | ||
| 507 | proxies[hash] = entry; | ||
| 508 | |||
| 509 | for (count = 0; count < AARP_RETRANSMIT_LIMIT; count++) { | ||
| 510 | aarp_send_probe(atif->dev, sa); | ||
| 511 | |||
| 512 | /* Defer 1/10th */ | ||
| 513 | current->state = TASK_INTERRUPTIBLE; | ||
| 514 | write_unlock_bh(&aarp_lock); | ||
| 515 | schedule_timeout(HZ / 10); | ||
| 516 | write_lock_bh(&aarp_lock); | ||
| 517 | |||
| 518 | if (entry->status & ATIF_PROBE_FAIL) | ||
| 519 | break; | ||
| 520 | } | ||
| 521 | |||
| 522 | if (entry->status & ATIF_PROBE_FAIL) { | ||
| 523 | entry->expires_at = jiffies - 1; /* free the entry */ | ||
| 524 | retval = -EADDRINUSE; /* return network full */ | ||
| 525 | } else { /* clear the probing flag */ | ||
| 526 | entry->status &= ~ATIF_PROBE; | ||
| 527 | retval = 1; | ||
| 528 | } | ||
| 529 | |||
| 530 | write_unlock_bh(&aarp_lock); | ||
| 531 | out: | ||
| 532 | return retval; | ||
| 533 | } | ||
| 534 | |||
| 535 | /* Send a DDP frame */ | ||
| 536 | int aarp_send_ddp(struct net_device *dev, struct sk_buff *skb, | ||
| 537 | struct atalk_addr *sa, void *hwaddr) | ||
| 538 | { | ||
| 539 | static char ddp_eth_multicast[ETH_ALEN] = | ||
| 540 | { 0x09, 0x00, 0x07, 0xFF, 0xFF, 0xFF }; | ||
| 541 | int hash; | ||
| 542 | struct aarp_entry *a; | ||
| 543 | |||
| 544 | skb->nh.raw = skb->data; | ||
| 545 | |||
| 546 | /* Check for LocalTalk first */ | ||
| 547 | if (dev->type == ARPHRD_LOCALTLK) { | ||
| 548 | struct atalk_addr *at = atalk_find_dev_addr(dev); | ||
| 549 | struct ddpehdr *ddp = (struct ddpehdr *)skb->data; | ||
| 550 | int ft = 2; | ||
| 551 | |||
| 552 | /* | ||
| 553 | * Compressible ? | ||
| 554 | * | ||
| 555 | * IFF: src_net == dest_net == device_net | ||
| 556 | * (zero matches anything) | ||
| 557 | */ | ||
| 558 | |||
| 559 | if ((!ddp->deh_snet || at->s_net == ddp->deh_snet) && | ||
| 560 | (!ddp->deh_dnet || at->s_net == ddp->deh_dnet)) { | ||
| 561 | skb_pull(skb, sizeof(*ddp) - 4); | ||
| 562 | |||
| 563 | /* | ||
| 564 | * The upper two remaining bytes are the port | ||
| 565 | * numbers we just happen to need. Now put the | ||
| 566 | * length in the lower two. | ||
| 567 | */ | ||
| 568 | *((__u16 *)skb->data) = htons(skb->len); | ||
| 569 | ft = 1; | ||
| 570 | } | ||
| 571 | /* | ||
| 572 | * Nice and easy. No AARP type protocols occur here so we can | ||
| 573 | * just shovel it out with a 3 byte LLAP header | ||
| 574 | */ | ||
| 575 | |||
| 576 | skb_push(skb, 3); | ||
| 577 | skb->data[0] = sa->s_node; | ||
| 578 | skb->data[1] = at->s_node; | ||
| 579 | skb->data[2] = ft; | ||
| 580 | skb->dev = dev; | ||
| 581 | goto sendit; | ||
| 582 | } | ||
| 583 | |||
| 584 | /* On a PPP link we neither compress nor aarp. */ | ||
| 585 | if (dev->type == ARPHRD_PPP) { | ||
| 586 | skb->protocol = htons(ETH_P_PPPTALK); | ||
| 587 | skb->dev = dev; | ||
| 588 | goto sendit; | ||
| 589 | } | ||
| 590 | |||
| 591 | /* Non ELAP we cannot do. */ | ||
| 592 | if (dev->type != ARPHRD_ETHER) | ||
| 593 | return -1; | ||
| 594 | |||
| 595 | skb->dev = dev; | ||
| 596 | skb->protocol = htons(ETH_P_ATALK); | ||
| 597 | hash = sa->s_node % (AARP_HASH_SIZE - 1); | ||
| 598 | |||
| 599 | /* Do we have a resolved entry? */ | ||
| 600 | if (sa->s_node == ATADDR_BCAST) { | ||
| 601 | /* Send it */ | ||
| 602 | ddp_dl->request(ddp_dl, skb, ddp_eth_multicast); | ||
| 603 | goto sent; | ||
| 604 | } | ||
| 605 | |||
| 606 | write_lock_bh(&aarp_lock); | ||
| 607 | a = __aarp_find_entry(resolved[hash], dev, sa); | ||
| 608 | |||
| 609 | if (a) { /* Return 1 and fill in the address */ | ||
| 610 | a->expires_at = jiffies + (sysctl_aarp_expiry_time * 10); | ||
| 611 | ddp_dl->request(ddp_dl, skb, a->hwaddr); | ||
| 612 | write_unlock_bh(&aarp_lock); | ||
| 613 | goto sent; | ||
| 614 | } | ||
| 615 | |||
| 616 | /* Do we have an unresolved entry: This is the less common path */ | ||
| 617 | a = __aarp_find_entry(unresolved[hash], dev, sa); | ||
| 618 | if (a) { /* Queue onto the unresolved queue */ | ||
| 619 | skb_queue_tail(&a->packet_queue, skb); | ||
| 620 | goto out_unlock; | ||
| 621 | } | ||
| 622 | |||
| 623 | /* Allocate a new entry */ | ||
| 624 | a = aarp_alloc(); | ||
| 625 | if (!a) { | ||
| 626 | /* Whoops slipped... good job it's an unreliable protocol 8) */ | ||
| 627 | write_unlock_bh(&aarp_lock); | ||
| 628 | return -1; | ||
| 629 | } | ||
| 630 | |||
| 631 | /* Set up the queue */ | ||
| 632 | skb_queue_tail(&a->packet_queue, skb); | ||
| 633 | a->expires_at = jiffies + sysctl_aarp_resolve_time; | ||
| 634 | a->dev = dev; | ||
| 635 | a->next = unresolved[hash]; | ||
| 636 | a->target_addr = *sa; | ||
| 637 | a->xmit_count = 0; | ||
| 638 | unresolved[hash] = a; | ||
| 639 | unresolved_count++; | ||
| 640 | |||
| 641 | /* Send an initial request for the address */ | ||
| 642 | __aarp_send_query(a); | ||
| 643 | |||
| 644 | /* | ||
| 645 | * Switch to fast timer if needed (That is if this is the first | ||
| 646 | * unresolved entry to get added) | ||
| 647 | */ | ||
| 648 | |||
| 649 | if (unresolved_count == 1) | ||
| 650 | mod_timer(&aarp_timer, jiffies + sysctl_aarp_tick_time); | ||
| 651 | |||
| 652 | /* Now finally, it is safe to drop the lock. */ | ||
| 653 | out_unlock: | ||
| 654 | write_unlock_bh(&aarp_lock); | ||
| 655 | |||
| 656 | /* Tell the ddp layer we have taken over for this frame. */ | ||
| 657 | return 0; | ||
| 658 | |||
| 659 | sendit: | ||
| 660 | if (skb->sk) | ||
| 661 | skb->priority = skb->sk->sk_priority; | ||
| 662 | dev_queue_xmit(skb); | ||
| 663 | sent: | ||
| 664 | return 1; | ||
| 665 | } | ||
| 666 | |||
| 667 | /* | ||
| 668 | * An entry in the aarp unresolved queue has become resolved. Send | ||
| 669 | * all the frames queued under it. | ||
| 670 | * | ||
| 671 | * Must run under aarp_lock. | ||
| 672 | */ | ||
| 673 | static void __aarp_resolved(struct aarp_entry **list, struct aarp_entry *a, | ||
| 674 | int hash) | ||
| 675 | { | ||
| 676 | struct sk_buff *skb; | ||
| 677 | |||
| 678 | while (*list) | ||
| 679 | if (*list == a) { | ||
| 680 | unresolved_count--; | ||
| 681 | *list = a->next; | ||
| 682 | |||
| 683 | /* Move into the resolved list */ | ||
| 684 | a->next = resolved[hash]; | ||
| 685 | resolved[hash] = a; | ||
| 686 | |||
| 687 | /* Kick frames off */ | ||
| 688 | while ((skb = skb_dequeue(&a->packet_queue)) != NULL) { | ||
| 689 | a->expires_at = jiffies + | ||
| 690 | sysctl_aarp_expiry_time * 10; | ||
| 691 | ddp_dl->request(ddp_dl, skb, a->hwaddr); | ||
| 692 | } | ||
| 693 | } else | ||
| 694 | list = &((*list)->next); | ||
| 695 | } | ||
| 696 | |||
| 697 | /* | ||
| 698 | * This is called by the SNAP driver whenever we see an AARP SNAP | ||
| 699 | * frame. We currently only support Ethernet. | ||
| 700 | */ | ||
| 701 | static int aarp_rcv(struct sk_buff *skb, struct net_device *dev, | ||
| 702 | struct packet_type *pt) | ||
| 703 | { | ||
| 704 | struct elapaarp *ea = aarp_hdr(skb); | ||
| 705 | int hash, ret = 0; | ||
| 706 | __u16 function; | ||
| 707 | struct aarp_entry *a; | ||
| 708 | struct atalk_addr sa, *ma, da; | ||
| 709 | struct atalk_iface *ifa; | ||
| 710 | |||
| 711 | /* We only do Ethernet SNAP AARP. */ | ||
| 712 | if (dev->type != ARPHRD_ETHER) | ||
| 713 | goto out0; | ||
| 714 | |||
| 715 | /* Frame size ok? */ | ||
| 716 | if (!skb_pull(skb, sizeof(*ea))) | ||
| 717 | goto out0; | ||
| 718 | |||
| 719 | function = ntohs(ea->function); | ||
| 720 | |||
| 721 | /* Sanity check fields. */ | ||
| 722 | if (function < AARP_REQUEST || function > AARP_PROBE || | ||
| 723 | ea->hw_len != ETH_ALEN || ea->pa_len != AARP_PA_ALEN || | ||
| 724 | ea->pa_src_zero || ea->pa_dst_zero) | ||
| 725 | goto out0; | ||
| 726 | |||
| 727 | /* Looks good. */ | ||
| 728 | hash = ea->pa_src_node % (AARP_HASH_SIZE - 1); | ||
| 729 | |||
| 730 | /* Build an address. */ | ||
| 731 | sa.s_node = ea->pa_src_node; | ||
| 732 | sa.s_net = ea->pa_src_net; | ||
| 733 | |||
| 734 | /* Process the packet. Check for replies of me. */ | ||
| 735 | ifa = atalk_find_dev(dev); | ||
| 736 | if (!ifa) | ||
| 737 | goto out1; | ||
| 738 | |||
| 739 | if (ifa->status & ATIF_PROBE && | ||
| 740 | ifa->address.s_node == ea->pa_dst_node && | ||
| 741 | ifa->address.s_net == ea->pa_dst_net) { | ||
| 742 | ifa->status |= ATIF_PROBE_FAIL; /* Fail the probe (in use) */ | ||
| 743 | goto out1; | ||
| 744 | } | ||
| 745 | |||
| 746 | /* Check for replies of proxy AARP entries */ | ||
| 747 | da.s_node = ea->pa_dst_node; | ||
| 748 | da.s_net = ea->pa_dst_net; | ||
| 749 | |||
| 750 | write_lock_bh(&aarp_lock); | ||
| 751 | a = __aarp_find_entry(proxies[hash], dev, &da); | ||
| 752 | |||
| 753 | if (a && a->status & ATIF_PROBE) { | ||
| 754 | a->status |= ATIF_PROBE_FAIL; | ||
| 755 | /* | ||
| 756 | * we do not respond to probe or request packets for | ||
| 757 | * this address while we are probing this address | ||
| 758 | */ | ||
| 759 | goto unlock; | ||
| 760 | } | ||
| 761 | |||
| 762 | switch (function) { | ||
| 763 | case AARP_REPLY: | ||
| 764 | if (!unresolved_count) /* Speed up */ | ||
| 765 | break; | ||
| 766 | |||
| 767 | /* Find the entry. */ | ||
| 768 | a = __aarp_find_entry(unresolved[hash], dev, &sa); | ||
| 769 | if (!a || dev != a->dev) | ||
| 770 | break; | ||
| 771 | |||
| 772 | /* We can fill one in - this is good. */ | ||
| 773 | memcpy(a->hwaddr, ea->hw_src, ETH_ALEN); | ||
| 774 | __aarp_resolved(&unresolved[hash], a, hash); | ||
| 775 | if (!unresolved_count) | ||
| 776 | mod_timer(&aarp_timer, | ||
| 777 | jiffies + sysctl_aarp_expiry_time); | ||
| 778 | break; | ||
| 779 | |||
| 780 | case AARP_REQUEST: | ||
| 781 | case AARP_PROBE: | ||
| 782 | |||
| 783 | /* | ||
| 784 | * If it is my address set ma to my address and reply. | ||
| 785 | * We can treat probe and request the same. Probe | ||
| 786 | * simply means we shouldn't cache the querying host, | ||
| 787 | * as in a probe they are proposing an address not | ||
| 788 | * using one. | ||
| 789 | * | ||
| 790 | * Support for proxy-AARP added. We check if the | ||
| 791 | * address is one of our proxies before we toss the | ||
| 792 | * packet out. | ||
| 793 | */ | ||
| 794 | |||
| 795 | sa.s_node = ea->pa_dst_node; | ||
| 796 | sa.s_net = ea->pa_dst_net; | ||
| 797 | |||
| 798 | /* See if we have a matching proxy. */ | ||
| 799 | ma = __aarp_proxy_find(dev, &sa); | ||
| 800 | if (!ma) | ||
| 801 | ma = &ifa->address; | ||
| 802 | else { /* We need to make a copy of the entry. */ | ||
| 803 | da.s_node = sa.s_node; | ||
| 804 | da.s_net = da.s_net; | ||
| 805 | ma = &da; | ||
| 806 | } | ||
| 807 | |||
| 808 | if (function == AARP_PROBE) { | ||
| 809 | /* | ||
| 810 | * A probe implies someone trying to get an | ||
| 811 | * address. So as a precaution flush any | ||
| 812 | * entries we have for this address. | ||
| 813 | */ | ||
| 814 | struct aarp_entry *a; | ||
| 815 | |||
| 816 | a = __aarp_find_entry(resolved[sa.s_node % | ||
| 817 | (AARP_HASH_SIZE - 1)], | ||
| 818 | skb->dev, &sa); | ||
| 819 | |||
| 820 | /* | ||
| 821 | * Make it expire next tick - that avoids us | ||
| 822 | * getting into a probe/flush/learn/probe/ | ||
| 823 | * flush/learn cycle during probing of a slow | ||
| 824 | * to respond host addr. | ||
| 825 | */ | ||
| 826 | if (a) { | ||
| 827 | a->expires_at = jiffies - 1; | ||
| 828 | mod_timer(&aarp_timer, jiffies + | ||
| 829 | sysctl_aarp_tick_time); | ||
| 830 | } | ||
| 831 | } | ||
| 832 | |||
| 833 | if (sa.s_node != ma->s_node) | ||
| 834 | break; | ||
| 835 | |||
| 836 | if (sa.s_net && ma->s_net && sa.s_net != ma->s_net) | ||
| 837 | break; | ||
| 838 | |||
| 839 | sa.s_node = ea->pa_src_node; | ||
| 840 | sa.s_net = ea->pa_src_net; | ||
| 841 | |||
| 842 | /* aarp_my_address has found the address to use for us. | ||
| 843 | */ | ||
| 844 | aarp_send_reply(dev, ma, &sa, ea->hw_src); | ||
| 845 | break; | ||
| 846 | } | ||
| 847 | |||
| 848 | unlock: | ||
| 849 | write_unlock_bh(&aarp_lock); | ||
| 850 | out1: | ||
| 851 | ret = 1; | ||
| 852 | out0: | ||
| 853 | kfree_skb(skb); | ||
| 854 | return ret; | ||
| 855 | } | ||
| 856 | |||
| 857 | static struct notifier_block aarp_notifier = { | ||
| 858 | .notifier_call = aarp_device_event, | ||
| 859 | }; | ||
| 860 | |||
| 861 | static unsigned char aarp_snap_id[] = { 0x00, 0x00, 0x00, 0x80, 0xF3 }; | ||
| 862 | |||
| 863 | void __init aarp_proto_init(void) | ||
| 864 | { | ||
| 865 | aarp_dl = register_snap_client(aarp_snap_id, aarp_rcv); | ||
| 866 | if (!aarp_dl) | ||
| 867 | printk(KERN_CRIT "Unable to register AARP with SNAP.\n"); | ||
| 868 | init_timer(&aarp_timer); | ||
| 869 | aarp_timer.function = aarp_expire_timeout; | ||
| 870 | aarp_timer.data = 0; | ||
| 871 | aarp_timer.expires = jiffies + sysctl_aarp_expiry_time; | ||
| 872 | add_timer(&aarp_timer); | ||
| 873 | register_netdevice_notifier(&aarp_notifier); | ||
| 874 | } | ||
| 875 | |||
| 876 | /* Remove the AARP entries associated with a device. */ | ||
| 877 | void aarp_device_down(struct net_device *dev) | ||
| 878 | { | ||
| 879 | int ct; | ||
| 880 | |||
| 881 | write_lock_bh(&aarp_lock); | ||
| 882 | |||
| 883 | for (ct = 0; ct < AARP_HASH_SIZE; ct++) { | ||
| 884 | __aarp_expire_device(&resolved[ct], dev); | ||
| 885 | __aarp_expire_device(&unresolved[ct], dev); | ||
| 886 | __aarp_expire_device(&proxies[ct], dev); | ||
| 887 | } | ||
| 888 | |||
| 889 | write_unlock_bh(&aarp_lock); | ||
| 890 | } | ||
| 891 | |||
| 892 | #ifdef CONFIG_PROC_FS | ||
| 893 | struct aarp_iter_state { | ||
| 894 | int bucket; | ||
| 895 | struct aarp_entry **table; | ||
| 896 | }; | ||
| 897 | |||
| 898 | /* | ||
| 899 | * Get the aarp entry that is in the chain described | ||
| 900 | * by the iterator. | ||
| 901 | * If pos is set then skip till that index. | ||
| 902 | * pos = 1 is the first entry | ||
| 903 | */ | ||
| 904 | static struct aarp_entry *iter_next(struct aarp_iter_state *iter, loff_t *pos) | ||
| 905 | { | ||
| 906 | int ct = iter->bucket; | ||
| 907 | struct aarp_entry **table = iter->table; | ||
| 908 | loff_t off = 0; | ||
| 909 | struct aarp_entry *entry; | ||
| 910 | |||
| 911 | rescan: | ||
| 912 | while(ct < AARP_HASH_SIZE) { | ||
| 913 | for (entry = table[ct]; entry; entry = entry->next) { | ||
| 914 | if (!pos || ++off == *pos) { | ||
| 915 | iter->table = table; | ||
| 916 | iter->bucket = ct; | ||
| 917 | return entry; | ||
| 918 | } | ||
| 919 | } | ||
| 920 | ++ct; | ||
| 921 | } | ||
| 922 | |||
| 923 | if (table == resolved) { | ||
| 924 | ct = 0; | ||
| 925 | table = unresolved; | ||
| 926 | goto rescan; | ||
| 927 | } | ||
| 928 | if (table == unresolved) { | ||
| 929 | ct = 0; | ||
| 930 | table = proxies; | ||
| 931 | goto rescan; | ||
| 932 | } | ||
| 933 | return NULL; | ||
| 934 | } | ||
| 935 | |||
| 936 | static void *aarp_seq_start(struct seq_file *seq, loff_t *pos) | ||
| 937 | { | ||
| 938 | struct aarp_iter_state *iter = seq->private; | ||
| 939 | |||
| 940 | read_lock_bh(&aarp_lock); | ||
| 941 | iter->table = resolved; | ||
| 942 | iter->bucket = 0; | ||
| 943 | |||
| 944 | return *pos ? iter_next(iter, pos) : SEQ_START_TOKEN; | ||
| 945 | } | ||
| 946 | |||
| 947 | static void *aarp_seq_next(struct seq_file *seq, void *v, loff_t *pos) | ||
| 948 | { | ||
| 949 | struct aarp_entry *entry = v; | ||
| 950 | struct aarp_iter_state *iter = seq->private; | ||
| 951 | |||
| 952 | ++*pos; | ||
| 953 | |||
| 954 | /* first line after header */ | ||
| 955 | if (v == SEQ_START_TOKEN) | ||
| 956 | entry = iter_next(iter, NULL); | ||
| 957 | |||
| 958 | /* next entry in current bucket */ | ||
| 959 | else if (entry->next) | ||
| 960 | entry = entry->next; | ||
| 961 | |||
| 962 | /* next bucket or table */ | ||
| 963 | else { | ||
| 964 | ++iter->bucket; | ||
| 965 | entry = iter_next(iter, NULL); | ||
| 966 | } | ||
| 967 | return entry; | ||
| 968 | } | ||
| 969 | |||
| 970 | static void aarp_seq_stop(struct seq_file *seq, void *v) | ||
| 971 | { | ||
| 972 | read_unlock_bh(&aarp_lock); | ||
| 973 | } | ||
| 974 | |||
| 975 | static const char *dt2str(unsigned long ticks) | ||
| 976 | { | ||
| 977 | static char buf[32]; | ||
| 978 | |||
| 979 | sprintf(buf, "%ld.%02ld", ticks / HZ, ((ticks % HZ) * 100 ) / HZ); | ||
| 980 | |||
| 981 | return buf; | ||
| 982 | } | ||
| 983 | |||
| 984 | static int aarp_seq_show(struct seq_file *seq, void *v) | ||
| 985 | { | ||
| 986 | struct aarp_iter_state *iter = seq->private; | ||
| 987 | struct aarp_entry *entry = v; | ||
| 988 | unsigned long now = jiffies; | ||
| 989 | |||
| 990 | if (v == SEQ_START_TOKEN) | ||
| 991 | seq_puts(seq, | ||
| 992 | "Address Interface Hardware Address" | ||
| 993 | " Expires LastSend Retry Status\n"); | ||
| 994 | else { | ||
| 995 | seq_printf(seq, "%04X:%02X %-12s", | ||
| 996 | ntohs(entry->target_addr.s_net), | ||
| 997 | (unsigned int) entry->target_addr.s_node, | ||
| 998 | entry->dev ? entry->dev->name : "????"); | ||
| 999 | seq_printf(seq, "%02X:%02X:%02X:%02X:%02X:%02X", | ||
| 1000 | entry->hwaddr[0] & 0xFF, | ||
| 1001 | entry->hwaddr[1] & 0xFF, | ||
| 1002 | entry->hwaddr[2] & 0xFF, | ||
| 1003 | entry->hwaddr[3] & 0xFF, | ||
| 1004 | entry->hwaddr[4] & 0xFF, | ||
| 1005 | entry->hwaddr[5] & 0xFF); | ||
| 1006 | seq_printf(seq, " %8s", | ||
| 1007 | dt2str((long)entry->expires_at - (long)now)); | ||
| 1008 | if (iter->table == unresolved) | ||
| 1009 | seq_printf(seq, " %8s %6hu", | ||
| 1010 | dt2str(now - entry->last_sent), | ||
| 1011 | entry->xmit_count); | ||
| 1012 | else | ||
| 1013 | seq_puts(seq, " "); | ||
| 1014 | seq_printf(seq, " %s\n", | ||
| 1015 | (iter->table == resolved) ? "resolved" | ||
| 1016 | : (iter->table == unresolved) ? "unresolved" | ||
| 1017 | : (iter->table == proxies) ? "proxies" | ||
| 1018 | : "unknown"); | ||
| 1019 | } | ||
| 1020 | return 0; | ||
| 1021 | } | ||
| 1022 | |||
| 1023 | static struct seq_operations aarp_seq_ops = { | ||
| 1024 | .start = aarp_seq_start, | ||
| 1025 | .next = aarp_seq_next, | ||
| 1026 | .stop = aarp_seq_stop, | ||
| 1027 | .show = aarp_seq_show, | ||
| 1028 | }; | ||
| 1029 | |||
| 1030 | static int aarp_seq_open(struct inode *inode, struct file *file) | ||
| 1031 | { | ||
| 1032 | struct seq_file *seq; | ||
| 1033 | int rc = -ENOMEM; | ||
| 1034 | struct aarp_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); | ||
| 1035 | |||
| 1036 | if (!s) | ||
| 1037 | goto out; | ||
| 1038 | |||
| 1039 | rc = seq_open(file, &aarp_seq_ops); | ||
| 1040 | if (rc) | ||
| 1041 | goto out_kfree; | ||
| 1042 | |||
| 1043 | seq = file->private_data; | ||
| 1044 | seq->private = s; | ||
| 1045 | memset(s, 0, sizeof(*s)); | ||
| 1046 | out: | ||
| 1047 | return rc; | ||
| 1048 | out_kfree: | ||
| 1049 | kfree(s); | ||
| 1050 | goto out; | ||
| 1051 | } | ||
| 1052 | |||
| 1053 | struct file_operations atalk_seq_arp_fops = { | ||
| 1054 | .owner = THIS_MODULE, | ||
| 1055 | .open = aarp_seq_open, | ||
| 1056 | .read = seq_read, | ||
| 1057 | .llseek = seq_lseek, | ||
| 1058 | .release = seq_release_private, | ||
| 1059 | }; | ||
| 1060 | #endif | ||
| 1061 | |||
| 1062 | /* General module cleanup. Called from cleanup_module() in ddp.c. */ | ||
| 1063 | void aarp_cleanup_module(void) | ||
| 1064 | { | ||
| 1065 | del_timer_sync(&aarp_timer); | ||
| 1066 | unregister_netdevice_notifier(&aarp_notifier); | ||
| 1067 | unregister_snap_client(aarp_dl); | ||
| 1068 | aarp_purge(); | ||
| 1069 | } | ||
diff --git a/net/appletalk/atalk_proc.c b/net/appletalk/atalk_proc.c new file mode 100644 index 00000000000..dc4048dd98c --- /dev/null +++ b/net/appletalk/atalk_proc.c | |||
| @@ -0,0 +1,321 @@ | |||
| 1 | /* | ||
| 2 | * atalk_proc.c - proc support for Appletalk | ||
| 3 | * | ||
| 4 | * Copyright(c) Arnaldo Carvalho de Melo <acme@conectiva.com.br> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify it | ||
| 7 | * under the terms of the GNU General Public License as published by the | ||
| 8 | * Free Software Foundation, version 2. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/config.h> | ||
| 12 | #include <linux/init.h> | ||
| 13 | #include <linux/proc_fs.h> | ||
| 14 | #include <linux/seq_file.h> | ||
| 15 | #include <net/sock.h> | ||
| 16 | #include <linux/atalk.h> | ||
| 17 | |||
| 18 | |||
| 19 | static __inline__ struct atalk_iface *atalk_get_interface_idx(loff_t pos) | ||
| 20 | { | ||
| 21 | struct atalk_iface *i; | ||
| 22 | |||
| 23 | for (i = atalk_interfaces; pos && i; i = i->next) | ||
| 24 | --pos; | ||
| 25 | |||
| 26 | return i; | ||
| 27 | } | ||
| 28 | |||
| 29 | static void *atalk_seq_interface_start(struct seq_file *seq, loff_t *pos) | ||
| 30 | { | ||
| 31 | loff_t l = *pos; | ||
| 32 | |||
| 33 | read_lock_bh(&atalk_interfaces_lock); | ||
| 34 | return l ? atalk_get_interface_idx(--l) : SEQ_START_TOKEN; | ||
| 35 | } | ||
| 36 | |||
| 37 | static void *atalk_seq_interface_next(struct seq_file *seq, void *v, loff_t *pos) | ||
| 38 | { | ||
| 39 | struct atalk_iface *i; | ||
| 40 | |||
| 41 | ++*pos; | ||
| 42 | if (v == SEQ_START_TOKEN) { | ||
| 43 | i = NULL; | ||
| 44 | if (atalk_interfaces) | ||
| 45 | i = atalk_interfaces; | ||
| 46 | goto out; | ||
| 47 | } | ||
| 48 | i = v; | ||
| 49 | i = i->next; | ||
| 50 | out: | ||
| 51 | return i; | ||
| 52 | } | ||
| 53 | |||
| 54 | static void atalk_seq_interface_stop(struct seq_file *seq, void *v) | ||
| 55 | { | ||
| 56 | read_unlock_bh(&atalk_interfaces_lock); | ||
| 57 | } | ||
| 58 | |||
| 59 | static int atalk_seq_interface_show(struct seq_file *seq, void *v) | ||
| 60 | { | ||
| 61 | struct atalk_iface *iface; | ||
| 62 | |||
| 63 | if (v == SEQ_START_TOKEN) { | ||
| 64 | seq_puts(seq, "Interface Address Networks " | ||
| 65 | "Status\n"); | ||
| 66 | goto out; | ||
| 67 | } | ||
| 68 | |||
| 69 | iface = v; | ||
| 70 | seq_printf(seq, "%-16s %04X:%02X %04X-%04X %d\n", | ||
| 71 | iface->dev->name, ntohs(iface->address.s_net), | ||
| 72 | iface->address.s_node, ntohs(iface->nets.nr_firstnet), | ||
| 73 | ntohs(iface->nets.nr_lastnet), iface->status); | ||
| 74 | out: | ||
| 75 | return 0; | ||
| 76 | } | ||
| 77 | |||
| 78 | static __inline__ struct atalk_route *atalk_get_route_idx(loff_t pos) | ||
| 79 | { | ||
| 80 | struct atalk_route *r; | ||
| 81 | |||
| 82 | for (r = atalk_routes; pos && r; r = r->next) | ||
| 83 | --pos; | ||
| 84 | |||
| 85 | return r; | ||
| 86 | } | ||
| 87 | |||
| 88 | static void *atalk_seq_route_start(struct seq_file *seq, loff_t *pos) | ||
| 89 | { | ||
| 90 | loff_t l = *pos; | ||
| 91 | |||
| 92 | read_lock_bh(&atalk_routes_lock); | ||
| 93 | return l ? atalk_get_route_idx(--l) : SEQ_START_TOKEN; | ||
| 94 | } | ||
| 95 | |||
| 96 | static void *atalk_seq_route_next(struct seq_file *seq, void *v, loff_t *pos) | ||
| 97 | { | ||
| 98 | struct atalk_route *r; | ||
| 99 | |||
| 100 | ++*pos; | ||
| 101 | if (v == SEQ_START_TOKEN) { | ||
| 102 | r = NULL; | ||
| 103 | if (atalk_routes) | ||
| 104 | r = atalk_routes; | ||
| 105 | goto out; | ||
| 106 | } | ||
| 107 | r = v; | ||
| 108 | r = r->next; | ||
| 109 | out: | ||
| 110 | return r; | ||
| 111 | } | ||
| 112 | |||
| 113 | static void atalk_seq_route_stop(struct seq_file *seq, void *v) | ||
| 114 | { | ||
| 115 | read_unlock_bh(&atalk_routes_lock); | ||
| 116 | } | ||
| 117 | |||
| 118 | static int atalk_seq_route_show(struct seq_file *seq, void *v) | ||
| 119 | { | ||
| 120 | struct atalk_route *rt; | ||
| 121 | |||
| 122 | if (v == SEQ_START_TOKEN) { | ||
| 123 | seq_puts(seq, "Target Router Flags Dev\n"); | ||
| 124 | goto out; | ||
| 125 | } | ||
| 126 | |||
| 127 | if (atrtr_default.dev) { | ||
| 128 | rt = &atrtr_default; | ||
| 129 | seq_printf(seq, "Default %04X:%02X %-4d %s\n", | ||
| 130 | ntohs(rt->gateway.s_net), rt->gateway.s_node, | ||
| 131 | rt->flags, rt->dev->name); | ||
| 132 | } | ||
| 133 | |||
| 134 | rt = v; | ||
| 135 | seq_printf(seq, "%04X:%02X %04X:%02X %-4d %s\n", | ||
| 136 | ntohs(rt->target.s_net), rt->target.s_node, | ||
| 137 | ntohs(rt->gateway.s_net), rt->gateway.s_node, | ||
| 138 | rt->flags, rt->dev->name); | ||
| 139 | out: | ||
| 140 | return 0; | ||
| 141 | } | ||
| 142 | |||
| 143 | static __inline__ struct sock *atalk_get_socket_idx(loff_t pos) | ||
| 144 | { | ||
| 145 | struct sock *s; | ||
| 146 | struct hlist_node *node; | ||
| 147 | |||
| 148 | sk_for_each(s, node, &atalk_sockets) | ||
| 149 | if (!pos--) | ||
| 150 | goto found; | ||
| 151 | s = NULL; | ||
| 152 | found: | ||
| 153 | return s; | ||
| 154 | } | ||
| 155 | |||
| 156 | static void *atalk_seq_socket_start(struct seq_file *seq, loff_t *pos) | ||
| 157 | { | ||
| 158 | loff_t l = *pos; | ||
| 159 | |||
| 160 | read_lock_bh(&atalk_sockets_lock); | ||
| 161 | return l ? atalk_get_socket_idx(--l) : SEQ_START_TOKEN; | ||
| 162 | } | ||
| 163 | |||
| 164 | static void *atalk_seq_socket_next(struct seq_file *seq, void *v, loff_t *pos) | ||
| 165 | { | ||
| 166 | struct sock *i; | ||
| 167 | |||
| 168 | ++*pos; | ||
| 169 | if (v == SEQ_START_TOKEN) { | ||
| 170 | i = sk_head(&atalk_sockets); | ||
| 171 | goto out; | ||
| 172 | } | ||
| 173 | i = sk_next(v); | ||
| 174 | out: | ||
| 175 | return i; | ||
| 176 | } | ||
| 177 | |||
| 178 | static void atalk_seq_socket_stop(struct seq_file *seq, void *v) | ||
| 179 | { | ||
| 180 | read_unlock_bh(&atalk_sockets_lock); | ||
| 181 | } | ||
| 182 | |||
| 183 | static int atalk_seq_socket_show(struct seq_file *seq, void *v) | ||
| 184 | { | ||
| 185 | struct sock *s; | ||
| 186 | struct atalk_sock *at; | ||
| 187 | |||
| 188 | if (v == SEQ_START_TOKEN) { | ||
| 189 | seq_printf(seq, "Type Local_addr Remote_addr Tx_queue " | ||
| 190 | "Rx_queue St UID\n"); | ||
| 191 | goto out; | ||
| 192 | } | ||
| 193 | |||
| 194 | s = v; | ||
| 195 | at = at_sk(s); | ||
| 196 | |||
| 197 | seq_printf(seq, "%02X %04X:%02X:%02X %04X:%02X:%02X %08X:%08X " | ||
| 198 | "%02X %d\n", | ||
| 199 | s->sk_type, ntohs(at->src_net), at->src_node, at->src_port, | ||
| 200 | ntohs(at->dest_net), at->dest_node, at->dest_port, | ||
| 201 | atomic_read(&s->sk_wmem_alloc), | ||
| 202 | atomic_read(&s->sk_rmem_alloc), | ||
| 203 | s->sk_state, SOCK_INODE(s->sk_socket)->i_uid); | ||
| 204 | out: | ||
| 205 | return 0; | ||
| 206 | } | ||
| 207 | |||
| 208 | static struct seq_operations atalk_seq_interface_ops = { | ||
| 209 | .start = atalk_seq_interface_start, | ||
| 210 | .next = atalk_seq_interface_next, | ||
| 211 | .stop = atalk_seq_interface_stop, | ||
| 212 | .show = atalk_seq_interface_show, | ||
| 213 | }; | ||
| 214 | |||
| 215 | static struct seq_operations atalk_seq_route_ops = { | ||
| 216 | .start = atalk_seq_route_start, | ||
| 217 | .next = atalk_seq_route_next, | ||
| 218 | .stop = atalk_seq_route_stop, | ||
| 219 | .show = atalk_seq_route_show, | ||
| 220 | }; | ||
| 221 | |||
| 222 | static struct seq_operations atalk_seq_socket_ops = { | ||
| 223 | .start = atalk_seq_socket_start, | ||
| 224 | .next = atalk_seq_socket_next, | ||
| 225 | .stop = atalk_seq_socket_stop, | ||
| 226 | .show = atalk_seq_socket_show, | ||
| 227 | }; | ||
| 228 | |||
| 229 | static int atalk_seq_interface_open(struct inode *inode, struct file *file) | ||
| 230 | { | ||
| 231 | return seq_open(file, &atalk_seq_interface_ops); | ||
| 232 | } | ||
| 233 | |||
| 234 | static int atalk_seq_route_open(struct inode *inode, struct file *file) | ||
| 235 | { | ||
| 236 | return seq_open(file, &atalk_seq_route_ops); | ||
| 237 | } | ||
| 238 | |||
| 239 | static int atalk_seq_socket_open(struct inode *inode, struct file *file) | ||
| 240 | { | ||
| 241 | return seq_open(file, &atalk_seq_socket_ops); | ||
| 242 | } | ||
| 243 | |||
| 244 | static struct file_operations atalk_seq_interface_fops = { | ||
| 245 | .owner = THIS_MODULE, | ||
| 246 | .open = atalk_seq_interface_open, | ||
| 247 | .read = seq_read, | ||
| 248 | .llseek = seq_lseek, | ||
| 249 | .release = seq_release, | ||
| 250 | }; | ||
| 251 | |||
| 252 | static struct file_operations atalk_seq_route_fops = { | ||
| 253 | .owner = THIS_MODULE, | ||
| 254 | .open = atalk_seq_route_open, | ||
| 255 | .read = seq_read, | ||
| 256 | .llseek = seq_lseek, | ||
| 257 | .release = seq_release, | ||
| 258 | }; | ||
| 259 | |||
| 260 | static struct file_operations atalk_seq_socket_fops = { | ||
| 261 | .owner = THIS_MODULE, | ||
| 262 | .open = atalk_seq_socket_open, | ||
| 263 | .read = seq_read, | ||
| 264 | .llseek = seq_lseek, | ||
| 265 | .release = seq_release, | ||
| 266 | }; | ||
| 267 | |||
| 268 | static struct proc_dir_entry *atalk_proc_dir; | ||
| 269 | |||
| 270 | int __init atalk_proc_init(void) | ||
| 271 | { | ||
| 272 | struct proc_dir_entry *p; | ||
| 273 | int rc = -ENOMEM; | ||
| 274 | |||
| 275 | atalk_proc_dir = proc_mkdir("atalk", proc_net); | ||
| 276 | if (!atalk_proc_dir) | ||
| 277 | goto out; | ||
| 278 | atalk_proc_dir->owner = THIS_MODULE; | ||
| 279 | |||
| 280 | p = create_proc_entry("interface", S_IRUGO, atalk_proc_dir); | ||
| 281 | if (!p) | ||
| 282 | goto out_interface; | ||
| 283 | p->proc_fops = &atalk_seq_interface_fops; | ||
| 284 | |||
| 285 | p = create_proc_entry("route", S_IRUGO, atalk_proc_dir); | ||
| 286 | if (!p) | ||
| 287 | goto out_route; | ||
| 288 | p->proc_fops = &atalk_seq_route_fops; | ||
| 289 | |||
| 290 | p = create_proc_entry("socket", S_IRUGO, atalk_proc_dir); | ||
| 291 | if (!p) | ||
| 292 | goto out_socket; | ||
| 293 | p->proc_fops = &atalk_seq_socket_fops; | ||
| 294 | |||
| 295 | p = create_proc_entry("arp", S_IRUGO, atalk_proc_dir); | ||
| 296 | if (!p) | ||
| 297 | goto out_arp; | ||
| 298 | p->proc_fops = &atalk_seq_arp_fops; | ||
| 299 | |||
| 300 | rc = 0; | ||
| 301 | out: | ||
| 302 | return rc; | ||
| 303 | out_arp: | ||
| 304 | remove_proc_entry("socket", atalk_proc_dir); | ||
| 305 | out_socket: | ||
| 306 | remove_proc_entry("route", atalk_proc_dir); | ||
| 307 | out_route: | ||
| 308 | remove_proc_entry("interface", atalk_proc_dir); | ||
| 309 | out_interface: | ||
| 310 | remove_proc_entry("atalk", proc_net); | ||
| 311 | goto out; | ||
| 312 | } | ||
| 313 | |||
| 314 | void __exit atalk_proc_exit(void) | ||
| 315 | { | ||
| 316 | remove_proc_entry("interface", atalk_proc_dir); | ||
| 317 | remove_proc_entry("route", atalk_proc_dir); | ||
| 318 | remove_proc_entry("socket", atalk_proc_dir); | ||
| 319 | remove_proc_entry("arp", atalk_proc_dir); | ||
| 320 | remove_proc_entry("atalk", proc_net); | ||
| 321 | } | ||
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c new file mode 100644 index 00000000000..d1fea5c3dda --- /dev/null +++ b/net/appletalk/ddp.c | |||
| @@ -0,0 +1,1931 @@ | |||
| 1 | /* | ||
| 2 | * DDP: An implementation of the AppleTalk DDP protocol for | ||
| 3 | * Ethernet 'ELAP'. | ||
| 4 | * | ||
| 5 | * Alan Cox <Alan.Cox@linux.org> | ||
| 6 | * | ||
| 7 | * With more than a little assistance from | ||
| 8 | * | ||
| 9 | * Wesley Craig <netatalk@umich.edu> | ||
| 10 | * | ||
| 11 | * Fixes: | ||
| 12 | * Neil Horman : Added missing device ioctls | ||
| 13 | * Michael Callahan : Made routing work | ||
| 14 | * Wesley Craig : Fix probing to listen to a | ||
| 15 | * passed node id. | ||
| 16 | * Alan Cox : Added send/recvmsg support | ||
| 17 | * Alan Cox : Moved at. to protinfo in | ||
| 18 | * socket. | ||
| 19 | * Alan Cox : Added firewall hooks. | ||
| 20 | * Alan Cox : Supports new ARPHRD_LOOPBACK | ||
| 21 | * Christer Weinigel : Routing and /proc fixes. | ||
| 22 | * Bradford Johnson : LocalTalk. | ||
| 23 | * Tom Dyas : Module support. | ||
| 24 | * Alan Cox : Hooks for PPP (based on the | ||
| 25 | * LocalTalk hook). | ||
| 26 | * Alan Cox : Posix bits | ||
| 27 | * Alan Cox/Mike Freeman : Possible fix to NBP problems | ||
| 28 | * Bradford Johnson : IP-over-DDP (experimental) | ||
| 29 | * Jay Schulist : Moved IP-over-DDP to its own | ||
| 30 | * driver file. (ipddp.c & ipddp.h) | ||
| 31 | * Jay Schulist : Made work as module with | ||
| 32 | * AppleTalk drivers, cleaned it. | ||
| 33 | * Rob Newberry : Added proxy AARP and AARP | ||
| 34 | * procfs, moved probing to AARP | ||
| 35 | * module. | ||
| 36 | * Adrian Sun/ | ||
| 37 | * Michael Zuelsdorff : fix for net.0 packets. don't | ||
| 38 | * allow illegal ether/tokentalk | ||
| 39 | * port assignment. we lose a | ||
| 40 | * valid localtalk port as a | ||
| 41 | * result. | ||
| 42 | * Arnaldo C. de Melo : Cleanup, in preparation for | ||
| 43 | * shared skb support 8) | ||
| 44 | * Arnaldo C. de Melo : Move proc stuff to atalk_proc.c, | ||
| 45 | * use seq_file | ||
| 46 | * | ||
| 47 | * This program is free software; you can redistribute it and/or | ||
| 48 | * modify it under the terms of the GNU General Public License | ||
| 49 | * as published by the Free Software Foundation; either version | ||
| 50 | * 2 of the License, or (at your option) any later version. | ||
| 51 | * | ||
| 52 | */ | ||
| 53 | |||
| 54 | #include <linux/config.h> | ||
| 55 | #include <linux/module.h> | ||
| 56 | #include <linux/tcp.h> | ||
| 57 | #include <linux/if_arp.h> | ||
| 58 | #include <linux/termios.h> /* For TIOCOUTQ/INQ */ | ||
| 59 | #include <net/datalink.h> | ||
| 60 | #include <net/psnap.h> | ||
| 61 | #include <net/sock.h> | ||
| 62 | #include <net/route.h> | ||
| 63 | #include <linux/atalk.h> | ||
| 64 | |||
| 65 | struct datalink_proto *ddp_dl, *aarp_dl; | ||
| 66 | static struct proto_ops atalk_dgram_ops; | ||
| 67 | |||
| 68 | /**************************************************************************\ | ||
| 69 | * * | ||
| 70 | * Handlers for the socket list. * | ||
| 71 | * * | ||
| 72 | \**************************************************************************/ | ||
| 73 | |||
| 74 | HLIST_HEAD(atalk_sockets); | ||
| 75 | DEFINE_RWLOCK(atalk_sockets_lock); | ||
| 76 | |||
| 77 | static inline void __atalk_insert_socket(struct sock *sk) | ||
| 78 | { | ||
| 79 | sk_add_node(sk, &atalk_sockets); | ||
| 80 | } | ||
| 81 | |||
| 82 | static inline void atalk_remove_socket(struct sock *sk) | ||
| 83 | { | ||
| 84 | write_lock_bh(&atalk_sockets_lock); | ||
| 85 | sk_del_node_init(sk); | ||
| 86 | write_unlock_bh(&atalk_sockets_lock); | ||
| 87 | } | ||
| 88 | |||
| 89 | static struct sock *atalk_search_socket(struct sockaddr_at *to, | ||
| 90 | struct atalk_iface *atif) | ||
| 91 | { | ||
| 92 | struct sock *s; | ||
| 93 | struct hlist_node *node; | ||
| 94 | |||
| 95 | read_lock_bh(&atalk_sockets_lock); | ||
| 96 | sk_for_each(s, node, &atalk_sockets) { | ||
| 97 | struct atalk_sock *at = at_sk(s); | ||
| 98 | |||
| 99 | if (to->sat_port != at->src_port) | ||
| 100 | continue; | ||
| 101 | |||
| 102 | if (to->sat_addr.s_net == ATADDR_ANYNET && | ||
| 103 | to->sat_addr.s_node == ATADDR_BCAST && | ||
| 104 | at->src_net == atif->address.s_net) | ||
| 105 | goto found; | ||
| 106 | |||
| 107 | if (to->sat_addr.s_net == at->src_net && | ||
| 108 | (to->sat_addr.s_node == at->src_node || | ||
| 109 | to->sat_addr.s_node == ATADDR_BCAST || | ||
| 110 | to->sat_addr.s_node == ATADDR_ANYNODE)) | ||
| 111 | goto found; | ||
| 112 | |||
| 113 | /* XXXX.0 -- we got a request for this router. make sure | ||
| 114 | * that the node is appropriately set. */ | ||
| 115 | if (to->sat_addr.s_node == ATADDR_ANYNODE && | ||
| 116 | to->sat_addr.s_net != ATADDR_ANYNET && | ||
| 117 | atif->address.s_node == at->src_node) { | ||
| 118 | to->sat_addr.s_node = atif->address.s_node; | ||
| 119 | goto found; | ||
| 120 | } | ||
| 121 | } | ||
| 122 | s = NULL; | ||
| 123 | found: | ||
| 124 | read_unlock_bh(&atalk_sockets_lock); | ||
| 125 | return s; | ||
| 126 | } | ||
| 127 | |||
| 128 | /** | ||
| 129 | * atalk_find_or_insert_socket - Try to find a socket matching ADDR | ||
| 130 | * @sk - socket to insert in the list if it is not there already | ||
| 131 | * @sat - address to search for | ||
| 132 | * | ||
| 133 | * Try to find a socket matching ADDR in the socket list, if found then return | ||
| 134 | * it. If not, insert SK into the socket list. | ||
| 135 | * | ||
| 136 | * This entire operation must execute atomically. | ||
| 137 | */ | ||
| 138 | static struct sock *atalk_find_or_insert_socket(struct sock *sk, | ||
| 139 | struct sockaddr_at *sat) | ||
| 140 | { | ||
| 141 | struct sock *s; | ||
| 142 | struct hlist_node *node; | ||
| 143 | struct atalk_sock *at; | ||
| 144 | |||
| 145 | write_lock_bh(&atalk_sockets_lock); | ||
| 146 | sk_for_each(s, node, &atalk_sockets) { | ||
| 147 | at = at_sk(s); | ||
| 148 | |||
| 149 | if (at->src_net == sat->sat_addr.s_net && | ||
| 150 | at->src_node == sat->sat_addr.s_node && | ||
| 151 | at->src_port == sat->sat_port) | ||
| 152 | goto found; | ||
| 153 | } | ||
| 154 | s = NULL; | ||
| 155 | __atalk_insert_socket(sk); /* Wheee, it's free, assign and insert. */ | ||
| 156 | found: | ||
| 157 | write_unlock_bh(&atalk_sockets_lock); | ||
| 158 | return s; | ||
| 159 | } | ||
| 160 | |||
| 161 | static void atalk_destroy_timer(unsigned long data) | ||
| 162 | { | ||
| 163 | struct sock *sk = (struct sock *)data; | ||
| 164 | |||
| 165 | if (atomic_read(&sk->sk_wmem_alloc) || | ||
| 166 | atomic_read(&sk->sk_rmem_alloc)) { | ||
| 167 | sk->sk_timer.expires = jiffies + SOCK_DESTROY_TIME; | ||
| 168 | add_timer(&sk->sk_timer); | ||
| 169 | } else | ||
| 170 | sock_put(sk); | ||
| 171 | } | ||
| 172 | |||
| 173 | static inline void atalk_destroy_socket(struct sock *sk) | ||
| 174 | { | ||
| 175 | atalk_remove_socket(sk); | ||
| 176 | skb_queue_purge(&sk->sk_receive_queue); | ||
| 177 | |||
| 178 | if (atomic_read(&sk->sk_wmem_alloc) || | ||
| 179 | atomic_read(&sk->sk_rmem_alloc)) { | ||
| 180 | init_timer(&sk->sk_timer); | ||
| 181 | sk->sk_timer.expires = jiffies + SOCK_DESTROY_TIME; | ||
| 182 | sk->sk_timer.function = atalk_destroy_timer; | ||
| 183 | sk->sk_timer.data = (unsigned long)sk; | ||
| 184 | add_timer(&sk->sk_timer); | ||
| 185 | } else | ||
| 186 | sock_put(sk); | ||
| 187 | } | ||
| 188 | |||
| 189 | /**************************************************************************\ | ||
| 190 | * * | ||
| 191 | * Routing tables for the AppleTalk socket layer. * | ||
| 192 | * * | ||
| 193 | \**************************************************************************/ | ||
| 194 | |||
| 195 | /* Anti-deadlock ordering is atalk_routes_lock --> iface_lock -DaveM */ | ||
| 196 | struct atalk_route *atalk_routes; | ||
| 197 | DEFINE_RWLOCK(atalk_routes_lock); | ||
| 198 | |||
| 199 | struct atalk_iface *atalk_interfaces; | ||
| 200 | DEFINE_RWLOCK(atalk_interfaces_lock); | ||
| 201 | |||
| 202 | /* For probing devices or in a routerless network */ | ||
| 203 | struct atalk_route atrtr_default; | ||
| 204 | |||
| 205 | /* AppleTalk interface control */ | ||
| 206 | /* | ||
| 207 | * Drop a device. Doesn't drop any of its routes - that is the caller's | ||
| 208 | * problem. Called when we down the interface or delete the address. | ||
| 209 | */ | ||
| 210 | static void atif_drop_device(struct net_device *dev) | ||
| 211 | { | ||
| 212 | struct atalk_iface **iface = &atalk_interfaces; | ||
| 213 | struct atalk_iface *tmp; | ||
| 214 | |||
| 215 | write_lock_bh(&atalk_interfaces_lock); | ||
| 216 | while ((tmp = *iface) != NULL) { | ||
| 217 | if (tmp->dev == dev) { | ||
| 218 | *iface = tmp->next; | ||
| 219 | dev_put(dev); | ||
| 220 | kfree(tmp); | ||
| 221 | dev->atalk_ptr = NULL; | ||
| 222 | } else | ||
| 223 | iface = &tmp->next; | ||
| 224 | } | ||
| 225 | write_unlock_bh(&atalk_interfaces_lock); | ||
| 226 | } | ||
| 227 | |||
| 228 | static struct atalk_iface *atif_add_device(struct net_device *dev, | ||
| 229 | struct atalk_addr *sa) | ||
| 230 | { | ||
| 231 | struct atalk_iface *iface = kmalloc(sizeof(*iface), GFP_KERNEL); | ||
| 232 | |||
| 233 | if (!iface) | ||
| 234 | goto out; | ||
| 235 | |||
| 236 | memset(iface, 0, sizeof(*iface)); | ||
| 237 | dev_hold(dev); | ||
| 238 | iface->dev = dev; | ||
| 239 | dev->atalk_ptr = iface; | ||
| 240 | iface->address = *sa; | ||
| 241 | iface->status = 0; | ||
| 242 | |||
| 243 | write_lock_bh(&atalk_interfaces_lock); | ||
| 244 | iface->next = atalk_interfaces; | ||
| 245 | atalk_interfaces = iface; | ||
| 246 | write_unlock_bh(&atalk_interfaces_lock); | ||
| 247 | out: | ||
| 248 | return iface; | ||
| 249 | } | ||
| 250 | |||
| 251 | /* Perform phase 2 AARP probing on our tentative address */ | ||
| 252 | static int atif_probe_device(struct atalk_iface *atif) | ||
| 253 | { | ||
| 254 | int netrange = ntohs(atif->nets.nr_lastnet) - | ||
| 255 | ntohs(atif->nets.nr_firstnet) + 1; | ||
| 256 | int probe_net = ntohs(atif->address.s_net); | ||
| 257 | int probe_node = atif->address.s_node; | ||
| 258 | int netct, nodect; | ||
| 259 | |||
| 260 | /* Offset the network we start probing with */ | ||
| 261 | if (probe_net == ATADDR_ANYNET) { | ||
| 262 | probe_net = ntohs(atif->nets.nr_firstnet); | ||
| 263 | if (netrange) | ||
| 264 | probe_net += jiffies % netrange; | ||
| 265 | } | ||
| 266 | if (probe_node == ATADDR_ANYNODE) | ||
| 267 | probe_node = jiffies & 0xFF; | ||
| 268 | |||
| 269 | /* Scan the networks */ | ||
| 270 | atif->status |= ATIF_PROBE; | ||
| 271 | for (netct = 0; netct <= netrange; netct++) { | ||
| 272 | /* Sweep the available nodes from a given start */ | ||
| 273 | atif->address.s_net = htons(probe_net); | ||
| 274 | for (nodect = 0; nodect < 256; nodect++) { | ||
| 275 | atif->address.s_node = (nodect + probe_node) & 0xFF; | ||
| 276 | if (atif->address.s_node > 0 && | ||
| 277 | atif->address.s_node < 254) { | ||
| 278 | /* Probe a proposed address */ | ||
| 279 | aarp_probe_network(atif); | ||
| 280 | |||
| 281 | if (!(atif->status & ATIF_PROBE_FAIL)) { | ||
| 282 | atif->status &= ~ATIF_PROBE; | ||
| 283 | return 0; | ||
| 284 | } | ||
| 285 | } | ||
| 286 | atif->status &= ~ATIF_PROBE_FAIL; | ||
| 287 | } | ||
| 288 | probe_net++; | ||
| 289 | if (probe_net > ntohs(atif->nets.nr_lastnet)) | ||
| 290 | probe_net = ntohs(atif->nets.nr_firstnet); | ||
| 291 | } | ||
| 292 | atif->status &= ~ATIF_PROBE; | ||
| 293 | |||
| 294 | return -EADDRINUSE; /* Network is full... */ | ||
| 295 | } | ||
| 296 | |||
| 297 | |||
| 298 | /* Perform AARP probing for a proxy address */ | ||
| 299 | static int atif_proxy_probe_device(struct atalk_iface *atif, | ||
| 300 | struct atalk_addr* proxy_addr) | ||
| 301 | { | ||
| 302 | int netrange = ntohs(atif->nets.nr_lastnet) - | ||
| 303 | ntohs(atif->nets.nr_firstnet) + 1; | ||
| 304 | /* we probe the interface's network */ | ||
| 305 | int probe_net = ntohs(atif->address.s_net); | ||
| 306 | int probe_node = ATADDR_ANYNODE; /* we'll take anything */ | ||
| 307 | int netct, nodect; | ||
| 308 | |||
| 309 | /* Offset the network we start probing with */ | ||
| 310 | if (probe_net == ATADDR_ANYNET) { | ||
| 311 | probe_net = ntohs(atif->nets.nr_firstnet); | ||
| 312 | if (netrange) | ||
| 313 | probe_net += jiffies % netrange; | ||
| 314 | } | ||
| 315 | |||
| 316 | if (probe_node == ATADDR_ANYNODE) | ||
| 317 | probe_node = jiffies & 0xFF; | ||
| 318 | |||
| 319 | /* Scan the networks */ | ||
| 320 | for (netct = 0; netct <= netrange; netct++) { | ||
| 321 | /* Sweep the available nodes from a given start */ | ||
| 322 | proxy_addr->s_net = htons(probe_net); | ||
| 323 | for (nodect = 0; nodect < 256; nodect++) { | ||
| 324 | proxy_addr->s_node = (nodect + probe_node) & 0xFF; | ||
| 325 | if (proxy_addr->s_node > 0 && | ||
| 326 | proxy_addr->s_node < 254) { | ||
| 327 | /* Tell AARP to probe a proposed address */ | ||
| 328 | int ret = aarp_proxy_probe_network(atif, | ||
| 329 | proxy_addr); | ||
| 330 | |||
| 331 | if (ret != -EADDRINUSE) | ||
| 332 | return ret; | ||
| 333 | } | ||
| 334 | } | ||
| 335 | probe_net++; | ||
| 336 | if (probe_net > ntohs(atif->nets.nr_lastnet)) | ||
| 337 | probe_net = ntohs(atif->nets.nr_firstnet); | ||
| 338 | } | ||
| 339 | |||
| 340 | return -EADDRINUSE; /* Network is full... */ | ||
| 341 | } | ||
| 342 | |||
| 343 | |||
| 344 | struct atalk_addr *atalk_find_dev_addr(struct net_device *dev) | ||
| 345 | { | ||
| 346 | struct atalk_iface *iface = dev->atalk_ptr; | ||
| 347 | return iface ? &iface->address : NULL; | ||
| 348 | } | ||
| 349 | |||
| 350 | static struct atalk_addr *atalk_find_primary(void) | ||
| 351 | { | ||
| 352 | struct atalk_iface *fiface = NULL; | ||
| 353 | struct atalk_addr *retval; | ||
| 354 | struct atalk_iface *iface; | ||
| 355 | |||
| 356 | /* | ||
| 357 | * Return a point-to-point interface only if | ||
| 358 | * there is no non-ptp interface available. | ||
| 359 | */ | ||
| 360 | read_lock_bh(&atalk_interfaces_lock); | ||
| 361 | for (iface = atalk_interfaces; iface; iface = iface->next) { | ||
| 362 | if (!fiface && !(iface->dev->flags & IFF_LOOPBACK)) | ||
| 363 | fiface = iface; | ||
| 364 | if (!(iface->dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT))) { | ||
| 365 | retval = &iface->address; | ||
| 366 | goto out; | ||
| 367 | } | ||
| 368 | } | ||
| 369 | |||
| 370 | if (fiface) | ||
| 371 | retval = &fiface->address; | ||
| 372 | else if (atalk_interfaces) | ||
| 373 | retval = &atalk_interfaces->address; | ||
| 374 | else | ||
| 375 | retval = NULL; | ||
| 376 | out: | ||
| 377 | read_unlock_bh(&atalk_interfaces_lock); | ||
| 378 | return retval; | ||
| 379 | } | ||
| 380 | |||
| 381 | /* | ||
| 382 | * Find a match for 'any network' - ie any of our interfaces with that | ||
| 383 | * node number will do just nicely. | ||
| 384 | */ | ||
| 385 | static struct atalk_iface *atalk_find_anynet(int node, struct net_device *dev) | ||
| 386 | { | ||
| 387 | struct atalk_iface *iface = dev->atalk_ptr; | ||
| 388 | |||
| 389 | if (!iface || iface->status & ATIF_PROBE) | ||
| 390 | goto out_err; | ||
| 391 | |||
| 392 | if (node != ATADDR_BCAST && | ||
| 393 | iface->address.s_node != node && | ||
| 394 | node != ATADDR_ANYNODE) | ||
| 395 | goto out_err; | ||
| 396 | out: | ||
| 397 | return iface; | ||
| 398 | out_err: | ||
| 399 | iface = NULL; | ||
| 400 | goto out; | ||
| 401 | } | ||
| 402 | |||
| 403 | /* Find a match for a specific network:node pair */ | ||
| 404 | static struct atalk_iface *atalk_find_interface(int net, int node) | ||
| 405 | { | ||
| 406 | struct atalk_iface *iface; | ||
| 407 | |||
| 408 | read_lock_bh(&atalk_interfaces_lock); | ||
| 409 | for (iface = atalk_interfaces; iface; iface = iface->next) { | ||
| 410 | if ((node == ATADDR_BCAST || | ||
| 411 | node == ATADDR_ANYNODE || | ||
| 412 | iface->address.s_node == node) && | ||
| 413 | iface->address.s_net == net && | ||
| 414 | !(iface->status & ATIF_PROBE)) | ||
| 415 | break; | ||
| 416 | |||
| 417 | /* XXXX.0 -- net.0 returns the iface associated with net */ | ||
| 418 | if (node == ATADDR_ANYNODE && net != ATADDR_ANYNET && | ||
| 419 | ntohs(iface->nets.nr_firstnet) <= ntohs(net) && | ||
| 420 | ntohs(net) <= ntohs(iface->nets.nr_lastnet)) | ||
| 421 | break; | ||
| 422 | } | ||
| 423 | read_unlock_bh(&atalk_interfaces_lock); | ||
| 424 | return iface; | ||
| 425 | } | ||
| 426 | |||
| 427 | |||
| 428 | /* | ||
| 429 | * Find a route for an AppleTalk packet. This ought to get cached in | ||
| 430 | * the socket (later on...). We know about host routes and the fact | ||
| 431 | * that a route must be direct to broadcast. | ||
| 432 | */ | ||
| 433 | static struct atalk_route *atrtr_find(struct atalk_addr *target) | ||
| 434 | { | ||
| 435 | /* | ||
| 436 | * we must search through all routes unless we find a | ||
| 437 | * host route, because some host routes might overlap | ||
| 438 | * network routes | ||
| 439 | */ | ||
| 440 | struct atalk_route *net_route = NULL; | ||
| 441 | struct atalk_route *r; | ||
| 442 | |||
| 443 | read_lock_bh(&atalk_routes_lock); | ||
| 444 | for (r = atalk_routes; r; r = r->next) { | ||
| 445 | if (!(r->flags & RTF_UP)) | ||
| 446 | continue; | ||
| 447 | |||
| 448 | if (r->target.s_net == target->s_net) { | ||
| 449 | if (r->flags & RTF_HOST) { | ||
| 450 | /* | ||
| 451 | * if this host route is for the target, | ||
| 452 | * the we're done | ||
| 453 | */ | ||
| 454 | if (r->target.s_node == target->s_node) | ||
| 455 | goto out; | ||
| 456 | } else | ||
| 457 | /* | ||
| 458 | * this route will work if there isn't a | ||
| 459 | * direct host route, so cache it | ||
| 460 | */ | ||
| 461 | net_route = r; | ||
| 462 | } | ||
| 463 | } | ||
| 464 | |||
| 465 | /* | ||
| 466 | * if we found a network route but not a direct host | ||
| 467 | * route, then return it | ||
| 468 | */ | ||
| 469 | if (net_route) | ||
| 470 | r = net_route; | ||
| 471 | else if (atrtr_default.dev) | ||
| 472 | r = &atrtr_default; | ||
| 473 | else /* No route can be found */ | ||
| 474 | r = NULL; | ||
| 475 | out: | ||
| 476 | read_unlock_bh(&atalk_routes_lock); | ||
| 477 | return r; | ||
| 478 | } | ||
| 479 | |||
| 480 | |||
| 481 | /* | ||
| 482 | * Given an AppleTalk network, find the device to use. This can be | ||
| 483 | * a simple lookup. | ||
| 484 | */ | ||
| 485 | struct net_device *atrtr_get_dev(struct atalk_addr *sa) | ||
| 486 | { | ||
| 487 | struct atalk_route *atr = atrtr_find(sa); | ||
| 488 | return atr ? atr->dev : NULL; | ||
| 489 | } | ||
| 490 | |||
| 491 | /* Set up a default router */ | ||
| 492 | static void atrtr_set_default(struct net_device *dev) | ||
| 493 | { | ||
| 494 | atrtr_default.dev = dev; | ||
| 495 | atrtr_default.flags = RTF_UP; | ||
| 496 | atrtr_default.gateway.s_net = htons(0); | ||
| 497 | atrtr_default.gateway.s_node = 0; | ||
| 498 | } | ||
| 499 | |||
| 500 | /* | ||
| 501 | * Add a router. Basically make sure it looks valid and stuff the | ||
| 502 | * entry in the list. While it uses netranges we always set them to one | ||
| 503 | * entry to work like netatalk. | ||
| 504 | */ | ||
| 505 | static int atrtr_create(struct rtentry *r, struct net_device *devhint) | ||
| 506 | { | ||
| 507 | struct sockaddr_at *ta = (struct sockaddr_at *)&r->rt_dst; | ||
| 508 | struct sockaddr_at *ga = (struct sockaddr_at *)&r->rt_gateway; | ||
| 509 | struct atalk_route *rt; | ||
| 510 | struct atalk_iface *iface, *riface; | ||
| 511 | int retval = -EINVAL; | ||
| 512 | |||
| 513 | /* | ||
| 514 | * Fixme: Raise/Lower a routing change semaphore for these | ||
| 515 | * operations. | ||
| 516 | */ | ||
| 517 | |||
| 518 | /* Validate the request */ | ||
| 519 | if (ta->sat_family != AF_APPLETALK || | ||
| 520 | (!devhint && ga->sat_family != AF_APPLETALK)) | ||
| 521 | goto out; | ||
| 522 | |||
| 523 | /* Now walk the routing table and make our decisions */ | ||
| 524 | write_lock_bh(&atalk_routes_lock); | ||
| 525 | for (rt = atalk_routes; rt; rt = rt->next) { | ||
| 526 | if (r->rt_flags != rt->flags) | ||
| 527 | continue; | ||
| 528 | |||
| 529 | if (ta->sat_addr.s_net == rt->target.s_net) { | ||
| 530 | if (!(rt->flags & RTF_HOST)) | ||
| 531 | break; | ||
| 532 | if (ta->sat_addr.s_node == rt->target.s_node) | ||
| 533 | break; | ||
| 534 | } | ||
| 535 | } | ||
| 536 | |||
| 537 | if (!devhint) { | ||
| 538 | riface = NULL; | ||
| 539 | |||
| 540 | read_lock_bh(&atalk_interfaces_lock); | ||
| 541 | for (iface = atalk_interfaces; iface; iface = iface->next) { | ||
| 542 | if (!riface && | ||
| 543 | ntohs(ga->sat_addr.s_net) >= | ||
| 544 | ntohs(iface->nets.nr_firstnet) && | ||
| 545 | ntohs(ga->sat_addr.s_net) <= | ||
| 546 | ntohs(iface->nets.nr_lastnet)) | ||
| 547 | riface = iface; | ||
| 548 | |||
| 549 | if (ga->sat_addr.s_net == iface->address.s_net && | ||
| 550 | ga->sat_addr.s_node == iface->address.s_node) | ||
| 551 | riface = iface; | ||
| 552 | } | ||
| 553 | read_unlock_bh(&atalk_interfaces_lock); | ||
| 554 | |||
| 555 | retval = -ENETUNREACH; | ||
| 556 | if (!riface) | ||
| 557 | goto out_unlock; | ||
| 558 | |||
| 559 | devhint = riface->dev; | ||
| 560 | } | ||
| 561 | |||
| 562 | if (!rt) { | ||
| 563 | rt = kmalloc(sizeof(*rt), GFP_ATOMIC); | ||
| 564 | |||
| 565 | retval = -ENOBUFS; | ||
| 566 | if (!rt) | ||
| 567 | goto out_unlock; | ||
| 568 | memset(rt, 0, sizeof(*rt)); | ||
| 569 | |||
| 570 | rt->next = atalk_routes; | ||
| 571 | atalk_routes = rt; | ||
| 572 | } | ||
| 573 | |||
| 574 | /* Fill in the routing entry */ | ||
| 575 | rt->target = ta->sat_addr; | ||
| 576 | rt->dev = devhint; | ||
| 577 | rt->flags = r->rt_flags; | ||
| 578 | rt->gateway = ga->sat_addr; | ||
| 579 | |||
| 580 | retval = 0; | ||
| 581 | out_unlock: | ||
| 582 | write_unlock_bh(&atalk_routes_lock); | ||
| 583 | out: | ||
| 584 | return retval; | ||
| 585 | } | ||
| 586 | |||
| 587 | /* Delete a route. Find it and discard it */ | ||
| 588 | static int atrtr_delete(struct atalk_addr * addr) | ||
| 589 | { | ||
| 590 | struct atalk_route **r = &atalk_routes; | ||
| 591 | int retval = 0; | ||
| 592 | struct atalk_route *tmp; | ||
| 593 | |||
| 594 | write_lock_bh(&atalk_routes_lock); | ||
| 595 | while ((tmp = *r) != NULL) { | ||
| 596 | if (tmp->target.s_net == addr->s_net && | ||
| 597 | (!(tmp->flags&RTF_GATEWAY) || | ||
| 598 | tmp->target.s_node == addr->s_node)) { | ||
| 599 | *r = tmp->next; | ||
| 600 | dev_put(tmp->dev); | ||
| 601 | kfree(tmp); | ||
| 602 | goto out; | ||
| 603 | } | ||
| 604 | r = &tmp->next; | ||
| 605 | } | ||
| 606 | retval = -ENOENT; | ||
| 607 | out: | ||
| 608 | write_unlock_bh(&atalk_routes_lock); | ||
| 609 | return retval; | ||
| 610 | } | ||
| 611 | |||
| 612 | /* | ||
| 613 | * Called when a device is downed. Just throw away any routes | ||
| 614 | * via it. | ||
| 615 | */ | ||
| 616 | static void atrtr_device_down(struct net_device *dev) | ||
| 617 | { | ||
| 618 | struct atalk_route **r = &atalk_routes; | ||
| 619 | struct atalk_route *tmp; | ||
| 620 | |||
| 621 | write_lock_bh(&atalk_routes_lock); | ||
| 622 | while ((tmp = *r) != NULL) { | ||
| 623 | if (tmp->dev == dev) { | ||
| 624 | *r = tmp->next; | ||
| 625 | dev_put(dev); | ||
| 626 | kfree(tmp); | ||
| 627 | } else | ||
| 628 | r = &tmp->next; | ||
| 629 | } | ||
| 630 | write_unlock_bh(&atalk_routes_lock); | ||
| 631 | |||
| 632 | if (atrtr_default.dev == dev) | ||
| 633 | atrtr_set_default(NULL); | ||
| 634 | } | ||
| 635 | |||
| 636 | /* Actually down the interface */ | ||
| 637 | static inline void atalk_dev_down(struct net_device *dev) | ||
| 638 | { | ||
| 639 | atrtr_device_down(dev); /* Remove all routes for the device */ | ||
| 640 | aarp_device_down(dev); /* Remove AARP entries for the device */ | ||
| 641 | atif_drop_device(dev); /* Remove the device */ | ||
| 642 | } | ||
| 643 | |||
| 644 | /* | ||
| 645 | * A device event has occurred. Watch for devices going down and | ||
| 646 | * delete our use of them (iface and route). | ||
| 647 | */ | ||
| 648 | static int ddp_device_event(struct notifier_block *this, unsigned long event, | ||
| 649 | void *ptr) | ||
| 650 | { | ||
| 651 | if (event == NETDEV_DOWN) | ||
| 652 | /* Discard any use of this */ | ||
| 653 | atalk_dev_down(ptr); | ||
| 654 | |||
| 655 | return NOTIFY_DONE; | ||
| 656 | } | ||
| 657 | |||
| 658 | /* ioctl calls. Shouldn't even need touching */ | ||
| 659 | /* Device configuration ioctl calls */ | ||
| 660 | static int atif_ioctl(int cmd, void __user *arg) | ||
| 661 | { | ||
| 662 | static char aarp_mcast[6] = { 0x09, 0x00, 0x00, 0xFF, 0xFF, 0xFF }; | ||
| 663 | struct ifreq atreq; | ||
| 664 | struct atalk_netrange *nr; | ||
| 665 | struct sockaddr_at *sa; | ||
| 666 | struct net_device *dev; | ||
| 667 | struct atalk_iface *atif; | ||
| 668 | int ct; | ||
| 669 | int limit; | ||
| 670 | struct rtentry rtdef; | ||
| 671 | int add_route; | ||
| 672 | |||
| 673 | if (copy_from_user(&atreq, arg, sizeof(atreq))) | ||
| 674 | return -EFAULT; | ||
| 675 | |||
| 676 | dev = __dev_get_by_name(atreq.ifr_name); | ||
| 677 | if (!dev) | ||
| 678 | return -ENODEV; | ||
| 679 | |||
| 680 | sa = (struct sockaddr_at *)&atreq.ifr_addr; | ||
| 681 | atif = atalk_find_dev(dev); | ||
| 682 | |||
| 683 | switch (cmd) { | ||
| 684 | case SIOCSIFADDR: | ||
| 685 | if (!capable(CAP_NET_ADMIN)) | ||
| 686 | return -EPERM; | ||
| 687 | if (sa->sat_family != AF_APPLETALK) | ||
| 688 | return -EINVAL; | ||
| 689 | if (dev->type != ARPHRD_ETHER && | ||
| 690 | dev->type != ARPHRD_LOOPBACK && | ||
| 691 | dev->type != ARPHRD_LOCALTLK && | ||
| 692 | dev->type != ARPHRD_PPP) | ||
| 693 | return -EPROTONOSUPPORT; | ||
| 694 | |||
| 695 | nr = (struct atalk_netrange *)&sa->sat_zero[0]; | ||
| 696 | add_route = 1; | ||
| 697 | |||
| 698 | /* | ||
| 699 | * if this is a point-to-point iface, and we already | ||
| 700 | * have an iface for this AppleTalk address, then we | ||
| 701 | * should not add a route | ||
| 702 | */ | ||
| 703 | if ((dev->flags & IFF_POINTOPOINT) && | ||
| 704 | atalk_find_interface(sa->sat_addr.s_net, | ||
| 705 | sa->sat_addr.s_node)) { | ||
| 706 | printk(KERN_DEBUG "AppleTalk: point-to-point " | ||
| 707 | "interface added with " | ||
| 708 | "existing address\n"); | ||
| 709 | add_route = 0; | ||
| 710 | } | ||
| 711 | |||
| 712 | /* | ||
| 713 | * Phase 1 is fine on LocalTalk but we don't do | ||
| 714 | * EtherTalk phase 1. Anyone wanting to add it go ahead. | ||
| 715 | */ | ||
| 716 | if (dev->type == ARPHRD_ETHER && nr->nr_phase != 2) | ||
| 717 | return -EPROTONOSUPPORT; | ||
| 718 | if (sa->sat_addr.s_node == ATADDR_BCAST || | ||
| 719 | sa->sat_addr.s_node == 254) | ||
| 720 | return -EINVAL; | ||
| 721 | if (atif) { | ||
| 722 | /* Already setting address */ | ||
| 723 | if (atif->status & ATIF_PROBE) | ||
| 724 | return -EBUSY; | ||
| 725 | |||
| 726 | atif->address.s_net = sa->sat_addr.s_net; | ||
| 727 | atif->address.s_node = sa->sat_addr.s_node; | ||
| 728 | atrtr_device_down(dev); /* Flush old routes */ | ||
| 729 | } else { | ||
| 730 | atif = atif_add_device(dev, &sa->sat_addr); | ||
| 731 | if (!atif) | ||
| 732 | return -ENOMEM; | ||
| 733 | } | ||
| 734 | atif->nets = *nr; | ||
| 735 | |||
| 736 | /* | ||
| 737 | * Check if the chosen address is used. If so we | ||
| 738 | * error and atalkd will try another. | ||
| 739 | */ | ||
| 740 | |||
| 741 | if (!(dev->flags & IFF_LOOPBACK) && | ||
| 742 | !(dev->flags & IFF_POINTOPOINT) && | ||
| 743 | atif_probe_device(atif) < 0) { | ||
| 744 | atif_drop_device(dev); | ||
| 745 | return -EADDRINUSE; | ||
| 746 | } | ||
| 747 | |||
| 748 | /* Hey it worked - add the direct routes */ | ||
| 749 | sa = (struct sockaddr_at *)&rtdef.rt_gateway; | ||
| 750 | sa->sat_family = AF_APPLETALK; | ||
| 751 | sa->sat_addr.s_net = atif->address.s_net; | ||
| 752 | sa->sat_addr.s_node = atif->address.s_node; | ||
| 753 | sa = (struct sockaddr_at *)&rtdef.rt_dst; | ||
| 754 | rtdef.rt_flags = RTF_UP; | ||
| 755 | sa->sat_family = AF_APPLETALK; | ||
| 756 | sa->sat_addr.s_node = ATADDR_ANYNODE; | ||
| 757 | if (dev->flags & IFF_LOOPBACK || | ||
| 758 | dev->flags & IFF_POINTOPOINT) | ||
| 759 | rtdef.rt_flags |= RTF_HOST; | ||
| 760 | |||
| 761 | /* Routerless initial state */ | ||
| 762 | if (nr->nr_firstnet == htons(0) && | ||
| 763 | nr->nr_lastnet == htons(0xFFFE)) { | ||
| 764 | sa->sat_addr.s_net = atif->address.s_net; | ||
| 765 | atrtr_create(&rtdef, dev); | ||
| 766 | atrtr_set_default(dev); | ||
| 767 | } else { | ||
| 768 | limit = ntohs(nr->nr_lastnet); | ||
| 769 | if (limit - ntohs(nr->nr_firstnet) > 4096) { | ||
| 770 | printk(KERN_WARNING "Too many routes/" | ||
| 771 | "iface.\n"); | ||
| 772 | return -EINVAL; | ||
| 773 | } | ||
| 774 | if (add_route) | ||
| 775 | for (ct = ntohs(nr->nr_firstnet); | ||
| 776 | ct <= limit; ct++) { | ||
| 777 | sa->sat_addr.s_net = htons(ct); | ||
| 778 | atrtr_create(&rtdef, dev); | ||
| 779 | } | ||
| 780 | } | ||
| 781 | dev_mc_add(dev, aarp_mcast, 6, 1); | ||
| 782 | return 0; | ||
| 783 | |||
| 784 | case SIOCGIFADDR: | ||
| 785 | if (!atif) | ||
| 786 | return -EADDRNOTAVAIL; | ||
| 787 | |||
| 788 | sa->sat_family = AF_APPLETALK; | ||
| 789 | sa->sat_addr = atif->address; | ||
| 790 | break; | ||
| 791 | |||
| 792 | case SIOCGIFBRDADDR: | ||
| 793 | if (!atif) | ||
| 794 | return -EADDRNOTAVAIL; | ||
| 795 | |||
| 796 | sa->sat_family = AF_APPLETALK; | ||
| 797 | sa->sat_addr.s_net = atif->address.s_net; | ||
| 798 | sa->sat_addr.s_node = ATADDR_BCAST; | ||
| 799 | break; | ||
| 800 | |||
| 801 | case SIOCATALKDIFADDR: | ||
| 802 | case SIOCDIFADDR: | ||
| 803 | if (!capable(CAP_NET_ADMIN)) | ||
| 804 | return -EPERM; | ||
| 805 | if (sa->sat_family != AF_APPLETALK) | ||
| 806 | return -EINVAL; | ||
| 807 | atalk_dev_down(dev); | ||
| 808 | break; | ||
| 809 | |||
| 810 | case SIOCSARP: | ||
| 811 | if (!capable(CAP_NET_ADMIN)) | ||
| 812 | return -EPERM; | ||
| 813 | if (sa->sat_family != AF_APPLETALK) | ||
| 814 | return -EINVAL; | ||
| 815 | if (!atif) | ||
| 816 | return -EADDRNOTAVAIL; | ||
| 817 | |||
| 818 | /* | ||
| 819 | * for now, we only support proxy AARP on ELAP; | ||
| 820 | * we should be able to do it for LocalTalk, too. | ||
| 821 | */ | ||
| 822 | if (dev->type != ARPHRD_ETHER) | ||
| 823 | return -EPROTONOSUPPORT; | ||
| 824 | |||
| 825 | /* | ||
| 826 | * atif points to the current interface on this network; | ||
| 827 | * we aren't concerned about its current status (at | ||
| 828 | * least for now), but it has all the settings about | ||
| 829 | * the network we're going to probe. Consequently, it | ||
| 830 | * must exist. | ||
| 831 | */ | ||
| 832 | if (!atif) | ||
| 833 | return -EADDRNOTAVAIL; | ||
| 834 | |||
| 835 | nr = (struct atalk_netrange *)&(atif->nets); | ||
| 836 | /* | ||
| 837 | * Phase 1 is fine on Localtalk but we don't do | ||
| 838 | * Ethertalk phase 1. Anyone wanting to add it go ahead. | ||
| 839 | */ | ||
| 840 | if (dev->type == ARPHRD_ETHER && nr->nr_phase != 2) | ||
| 841 | return -EPROTONOSUPPORT; | ||
| 842 | |||
| 843 | if (sa->sat_addr.s_node == ATADDR_BCAST || | ||
| 844 | sa->sat_addr.s_node == 254) | ||
| 845 | return -EINVAL; | ||
| 846 | |||
| 847 | /* | ||
| 848 | * Check if the chosen address is used. If so we | ||
| 849 | * error and ATCP will try another. | ||
| 850 | */ | ||
| 851 | if (atif_proxy_probe_device(atif, &(sa->sat_addr)) < 0) | ||
| 852 | return -EADDRINUSE; | ||
| 853 | |||
| 854 | /* | ||
| 855 | * We now have an address on the local network, and | ||
| 856 | * the AARP code will defend it for us until we take it | ||
| 857 | * down. We don't set up any routes right now, because | ||
| 858 | * ATCP will install them manually via SIOCADDRT. | ||
| 859 | */ | ||
| 860 | break; | ||
| 861 | |||
| 862 | case SIOCDARP: | ||
| 863 | if (!capable(CAP_NET_ADMIN)) | ||
| 864 | return -EPERM; | ||
| 865 | if (sa->sat_family != AF_APPLETALK) | ||
| 866 | return -EINVAL; | ||
| 867 | if (!atif) | ||
| 868 | return -EADDRNOTAVAIL; | ||
| 869 | |||
| 870 | /* give to aarp module to remove proxy entry */ | ||
| 871 | aarp_proxy_remove(atif->dev, &(sa->sat_addr)); | ||
| 872 | return 0; | ||
| 873 | } | ||
| 874 | |||
| 875 | return copy_to_user(arg, &atreq, sizeof(atreq)) ? -EFAULT : 0; | ||
| 876 | } | ||
| 877 | |||
| 878 | /* Routing ioctl() calls */ | ||
| 879 | static int atrtr_ioctl(unsigned int cmd, void __user *arg) | ||
| 880 | { | ||
| 881 | struct rtentry rt; | ||
| 882 | |||
| 883 | if (copy_from_user(&rt, arg, sizeof(rt))) | ||
| 884 | return -EFAULT; | ||
| 885 | |||
| 886 | switch (cmd) { | ||
| 887 | case SIOCDELRT: | ||
| 888 | if (rt.rt_dst.sa_family != AF_APPLETALK) | ||
| 889 | return -EINVAL; | ||
| 890 | return atrtr_delete(&((struct sockaddr_at *) | ||
| 891 | &rt.rt_dst)->sat_addr); | ||
| 892 | |||
| 893 | case SIOCADDRT: { | ||
| 894 | struct net_device *dev = NULL; | ||
| 895 | if (rt.rt_dev) { | ||
| 896 | char name[IFNAMSIZ]; | ||
| 897 | if (copy_from_user(name, rt.rt_dev, IFNAMSIZ-1)) | ||
| 898 | return -EFAULT; | ||
| 899 | name[IFNAMSIZ-1] = '\0'; | ||
| 900 | dev = __dev_get_by_name(name); | ||
| 901 | if (!dev) | ||
| 902 | return -ENODEV; | ||
| 903 | } | ||
| 904 | return atrtr_create(&rt, dev); | ||
| 905 | } | ||
| 906 | } | ||
| 907 | return -EINVAL; | ||
| 908 | } | ||
| 909 | |||
| 910 | /**************************************************************************\ | ||
| 911 | * * | ||
| 912 | * Handling for system calls applied via the various interfaces to an * | ||
| 913 | * AppleTalk socket object. * | ||
| 914 | * * | ||
| 915 | \**************************************************************************/ | ||
| 916 | |||
| 917 | /* | ||
| 918 | * Checksum: This is 'optional'. It's quite likely also a good | ||
| 919 | * candidate for assembler hackery 8) | ||
| 920 | */ | ||
| 921 | static unsigned long atalk_sum_partial(const unsigned char *data, | ||
| 922 | int len, unsigned long sum) | ||
| 923 | { | ||
| 924 | /* This ought to be unwrapped neatly. I'll trust gcc for now */ | ||
| 925 | while (len--) { | ||
| 926 | sum += *data; | ||
| 927 | sum <<= 1; | ||
| 928 | if (sum & 0x10000) { | ||
| 929 | sum++; | ||
| 930 | sum &= 0xffff; | ||
| 931 | } | ||
| 932 | data++; | ||
| 933 | } | ||
| 934 | return sum; | ||
| 935 | } | ||
| 936 | |||
| 937 | /* Checksum skb data -- similar to skb_checksum */ | ||
| 938 | static unsigned long atalk_sum_skb(const struct sk_buff *skb, int offset, | ||
| 939 | int len, unsigned long sum) | ||
| 940 | { | ||
| 941 | int start = skb_headlen(skb); | ||
| 942 | int i, copy; | ||
| 943 | |||
| 944 | /* checksum stuff in header space */ | ||
| 945 | if ( (copy = start - offset) > 0) { | ||
| 946 | if (copy > len) | ||
| 947 | copy = len; | ||
| 948 | sum = atalk_sum_partial(skb->data + offset, copy, sum); | ||
| 949 | if ( (len -= copy) == 0) | ||
| 950 | return sum; | ||
| 951 | |||
| 952 | offset += copy; | ||
| 953 | } | ||
| 954 | |||
| 955 | /* checksum stuff in frags */ | ||
| 956 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { | ||
| 957 | int end; | ||
| 958 | |||
| 959 | BUG_TRAP(start <= offset + len); | ||
| 960 | |||
| 961 | end = start + skb_shinfo(skb)->frags[i].size; | ||
| 962 | if ((copy = end - offset) > 0) { | ||
| 963 | u8 *vaddr; | ||
| 964 | skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; | ||
| 965 | |||
| 966 | if (copy > len) | ||
| 967 | copy = len; | ||
| 968 | vaddr = kmap_skb_frag(frag); | ||
| 969 | sum = atalk_sum_partial(vaddr + frag->page_offset + | ||
| 970 | offset - start, copy, sum); | ||
| 971 | kunmap_skb_frag(vaddr); | ||
| 972 | |||
| 973 | if (!(len -= copy)) | ||
| 974 | return sum; | ||
| 975 | offset += copy; | ||
| 976 | } | ||
| 977 | start = end; | ||
| 978 | } | ||
| 979 | |||
| 980 | if (skb_shinfo(skb)->frag_list) { | ||
| 981 | struct sk_buff *list = skb_shinfo(skb)->frag_list; | ||
| 982 | |||
| 983 | for (; list; list = list->next) { | ||
| 984 | int end; | ||
| 985 | |||
| 986 | BUG_TRAP(start <= offset + len); | ||
| 987 | |||
| 988 | end = start + list->len; | ||
| 989 | if ((copy = end - offset) > 0) { | ||
| 990 | if (copy > len) | ||
| 991 | copy = len; | ||
| 992 | sum = atalk_sum_skb(list, offset - start, | ||
| 993 | copy, sum); | ||
| 994 | if ((len -= copy) == 0) | ||
| 995 | return sum; | ||
| 996 | offset += copy; | ||
| 997 | } | ||
| 998 | start = end; | ||
| 999 | } | ||
| 1000 | } | ||
| 1001 | |||
| 1002 | BUG_ON(len > 0); | ||
| 1003 | |||
| 1004 | return sum; | ||
| 1005 | } | ||
| 1006 | |||
| 1007 | static unsigned short atalk_checksum(const struct sk_buff *skb, int len) | ||
| 1008 | { | ||
| 1009 | unsigned long sum; | ||
| 1010 | |||
| 1011 | /* skip header 4 bytes */ | ||
| 1012 | sum = atalk_sum_skb(skb, 4, len-4, 0); | ||
| 1013 | |||
| 1014 | /* Use 0xFFFF for 0. 0 itself means none */ | ||
| 1015 | return sum ? htons((unsigned short)sum) : 0xFFFF; | ||
| 1016 | } | ||
| 1017 | |||
| 1018 | static struct proto ddp_proto = { | ||
| 1019 | .name = "DDP", | ||
| 1020 | .owner = THIS_MODULE, | ||
| 1021 | .obj_size = sizeof(struct atalk_sock), | ||
| 1022 | }; | ||
| 1023 | |||
| 1024 | /* | ||
| 1025 | * Create a socket. Initialise the socket, blank the addresses | ||
| 1026 | * set the state. | ||
| 1027 | */ | ||
| 1028 | static int atalk_create(struct socket *sock, int protocol) | ||
| 1029 | { | ||
| 1030 | struct sock *sk; | ||
| 1031 | int rc = -ESOCKTNOSUPPORT; | ||
| 1032 | |||
| 1033 | /* | ||
| 1034 | * We permit SOCK_DGRAM and RAW is an extension. It is trivial to do | ||
| 1035 | * and gives you the full ELAP frame. Should be handy for CAP 8) | ||
| 1036 | */ | ||
| 1037 | if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM) | ||
| 1038 | goto out; | ||
| 1039 | rc = -ENOMEM; | ||
| 1040 | sk = sk_alloc(PF_APPLETALK, GFP_KERNEL, &ddp_proto, 1); | ||
| 1041 | if (!sk) | ||
| 1042 | goto out; | ||
| 1043 | rc = 0; | ||
| 1044 | sock->ops = &atalk_dgram_ops; | ||
| 1045 | sock_init_data(sock, sk); | ||
| 1046 | |||
| 1047 | /* Checksums on by default */ | ||
| 1048 | sock_set_flag(sk, SOCK_ZAPPED); | ||
| 1049 | out: | ||
| 1050 | return rc; | ||
| 1051 | } | ||
| 1052 | |||
| 1053 | /* Free a socket. No work needed */ | ||
| 1054 | static int atalk_release(struct socket *sock) | ||
| 1055 | { | ||
| 1056 | struct sock *sk = sock->sk; | ||
| 1057 | |||
| 1058 | if (sk) { | ||
| 1059 | sock_orphan(sk); | ||
| 1060 | sock->sk = NULL; | ||
| 1061 | atalk_destroy_socket(sk); | ||
| 1062 | } | ||
| 1063 | return 0; | ||
| 1064 | } | ||
| 1065 | |||
| 1066 | /** | ||
| 1067 | * atalk_pick_and_bind_port - Pick a source port when one is not given | ||
| 1068 | * @sk - socket to insert into the tables | ||
| 1069 | * @sat - address to search for | ||
| 1070 | * | ||
| 1071 | * Pick a source port when one is not given. If we can find a suitable free | ||
| 1072 | * one, we insert the socket into the tables using it. | ||
| 1073 | * | ||
| 1074 | * This whole operation must be atomic. | ||
| 1075 | */ | ||
| 1076 | static int atalk_pick_and_bind_port(struct sock *sk, struct sockaddr_at *sat) | ||
| 1077 | { | ||
| 1078 | int retval; | ||
| 1079 | |||
| 1080 | write_lock_bh(&atalk_sockets_lock); | ||
| 1081 | |||
| 1082 | for (sat->sat_port = ATPORT_RESERVED; | ||
| 1083 | sat->sat_port < ATPORT_LAST; | ||
| 1084 | sat->sat_port++) { | ||
| 1085 | struct sock *s; | ||
| 1086 | struct hlist_node *node; | ||
| 1087 | |||
| 1088 | sk_for_each(s, node, &atalk_sockets) { | ||
| 1089 | struct atalk_sock *at = at_sk(s); | ||
| 1090 | |||
| 1091 | if (at->src_net == sat->sat_addr.s_net && | ||
| 1092 | at->src_node == sat->sat_addr.s_node && | ||
| 1093 | at->src_port == sat->sat_port) | ||
| 1094 | goto try_next_port; | ||
| 1095 | } | ||
| 1096 | |||
| 1097 | /* Wheee, it's free, assign and insert. */ | ||
| 1098 | __atalk_insert_socket(sk); | ||
| 1099 | at_sk(sk)->src_port = sat->sat_port; | ||
| 1100 | retval = 0; | ||
| 1101 | goto out; | ||
| 1102 | |||
| 1103 | try_next_port:; | ||
| 1104 | } | ||
| 1105 | |||
| 1106 | retval = -EBUSY; | ||
| 1107 | out: | ||
| 1108 | write_unlock_bh(&atalk_sockets_lock); | ||
| 1109 | return retval; | ||
| 1110 | } | ||
| 1111 | |||
| 1112 | static int atalk_autobind(struct sock *sk) | ||
| 1113 | { | ||
| 1114 | struct atalk_sock *at = at_sk(sk); | ||
| 1115 | struct sockaddr_at sat; | ||
| 1116 | struct atalk_addr *ap = atalk_find_primary(); | ||
| 1117 | int n = -EADDRNOTAVAIL; | ||
| 1118 | |||
| 1119 | if (!ap || ap->s_net == htons(ATADDR_ANYNET)) | ||
| 1120 | goto out; | ||
| 1121 | |||
| 1122 | at->src_net = sat.sat_addr.s_net = ap->s_net; | ||
| 1123 | at->src_node = sat.sat_addr.s_node = ap->s_node; | ||
| 1124 | |||
| 1125 | n = atalk_pick_and_bind_port(sk, &sat); | ||
| 1126 | if (!n) | ||
| 1127 | sock_reset_flag(sk, SOCK_ZAPPED); | ||
| 1128 | out: | ||
| 1129 | return n; | ||
| 1130 | } | ||
| 1131 | |||
| 1132 | /* Set the address 'our end' of the connection */ | ||
| 1133 | static int atalk_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | ||
| 1134 | { | ||
| 1135 | struct sockaddr_at *addr = (struct sockaddr_at *)uaddr; | ||
| 1136 | struct sock *sk = sock->sk; | ||
| 1137 | struct atalk_sock *at = at_sk(sk); | ||
| 1138 | |||
| 1139 | if (!sock_flag(sk, SOCK_ZAPPED) || | ||
| 1140 | addr_len != sizeof(struct sockaddr_at)) | ||
| 1141 | return -EINVAL; | ||
| 1142 | |||
| 1143 | if (addr->sat_family != AF_APPLETALK) | ||
| 1144 | return -EAFNOSUPPORT; | ||
| 1145 | |||
| 1146 | if (addr->sat_addr.s_net == htons(ATADDR_ANYNET)) { | ||
| 1147 | struct atalk_addr *ap = atalk_find_primary(); | ||
| 1148 | |||
| 1149 | if (!ap) | ||
| 1150 | return -EADDRNOTAVAIL; | ||
| 1151 | |||
| 1152 | at->src_net = addr->sat_addr.s_net = ap->s_net; | ||
| 1153 | at->src_node = addr->sat_addr.s_node= ap->s_node; | ||
| 1154 | } else { | ||
| 1155 | if (!atalk_find_interface(addr->sat_addr.s_net, | ||
| 1156 | addr->sat_addr.s_node)) | ||
| 1157 | return -EADDRNOTAVAIL; | ||
| 1158 | |||
| 1159 | at->src_net = addr->sat_addr.s_net; | ||
| 1160 | at->src_node = addr->sat_addr.s_node; | ||
| 1161 | } | ||
| 1162 | |||
| 1163 | if (addr->sat_port == ATADDR_ANYPORT) { | ||
| 1164 | int n = atalk_pick_and_bind_port(sk, addr); | ||
| 1165 | |||
| 1166 | if (n < 0) | ||
| 1167 | return n; | ||
| 1168 | } else { | ||
| 1169 | at->src_port = addr->sat_port; | ||
| 1170 | |||
| 1171 | if (atalk_find_or_insert_socket(sk, addr)) | ||
| 1172 | return -EADDRINUSE; | ||
| 1173 | } | ||
| 1174 | |||
| 1175 | sock_reset_flag(sk, SOCK_ZAPPED); | ||
| 1176 | return 0; | ||
| 1177 | } | ||
| 1178 | |||
| 1179 | /* Set the address we talk to */ | ||
| 1180 | static int atalk_connect(struct socket *sock, struct sockaddr *uaddr, | ||
| 1181 | int addr_len, int flags) | ||
| 1182 | { | ||
| 1183 | struct sock *sk = sock->sk; | ||
| 1184 | struct atalk_sock *at = at_sk(sk); | ||
| 1185 | struct sockaddr_at *addr; | ||
| 1186 | |||
| 1187 | sk->sk_state = TCP_CLOSE; | ||
| 1188 | sock->state = SS_UNCONNECTED; | ||
| 1189 | |||
| 1190 | if (addr_len != sizeof(*addr)) | ||
| 1191 | return -EINVAL; | ||
| 1192 | |||
| 1193 | addr = (struct sockaddr_at *)uaddr; | ||
| 1194 | |||
| 1195 | if (addr->sat_family != AF_APPLETALK) | ||
| 1196 | return -EAFNOSUPPORT; | ||
| 1197 | |||
| 1198 | if (addr->sat_addr.s_node == ATADDR_BCAST && | ||
| 1199 | !sock_flag(sk, SOCK_BROADCAST)) { | ||
| 1200 | #if 1 | ||
| 1201 | printk(KERN_WARNING "%s is broken and did not set " | ||
| 1202 | "SO_BROADCAST. It will break when 2.2 is " | ||
| 1203 | "released.\n", | ||
| 1204 | current->comm); | ||
| 1205 | #else | ||
| 1206 | return -EACCES; | ||
| 1207 | #endif | ||
| 1208 | } | ||
| 1209 | |||
| 1210 | if (sock_flag(sk, SOCK_ZAPPED)) | ||
| 1211 | if (atalk_autobind(sk) < 0) | ||
| 1212 | return -EBUSY; | ||
| 1213 | |||
| 1214 | if (!atrtr_get_dev(&addr->sat_addr)) | ||
| 1215 | return -ENETUNREACH; | ||
| 1216 | |||
| 1217 | at->dest_port = addr->sat_port; | ||
| 1218 | at->dest_net = addr->sat_addr.s_net; | ||
| 1219 | at->dest_node = addr->sat_addr.s_node; | ||
| 1220 | |||
| 1221 | sock->state = SS_CONNECTED; | ||
| 1222 | sk->sk_state = TCP_ESTABLISHED; | ||
| 1223 | return 0; | ||
| 1224 | } | ||
| 1225 | |||
| 1226 | /* | ||
| 1227 | * Find the name of an AppleTalk socket. Just copy the right | ||
| 1228 | * fields into the sockaddr. | ||
| 1229 | */ | ||
| 1230 | static int atalk_getname(struct socket *sock, struct sockaddr *uaddr, | ||
| 1231 | int *uaddr_len, int peer) | ||
| 1232 | { | ||
| 1233 | struct sockaddr_at sat; | ||
| 1234 | struct sock *sk = sock->sk; | ||
| 1235 | struct atalk_sock *at = at_sk(sk); | ||
| 1236 | |||
| 1237 | if (sock_flag(sk, SOCK_ZAPPED)) | ||
| 1238 | if (atalk_autobind(sk) < 0) | ||
| 1239 | return -ENOBUFS; | ||
| 1240 | |||
| 1241 | *uaddr_len = sizeof(struct sockaddr_at); | ||
| 1242 | |||
| 1243 | if (peer) { | ||
| 1244 | if (sk->sk_state != TCP_ESTABLISHED) | ||
| 1245 | return -ENOTCONN; | ||
| 1246 | |||
| 1247 | sat.sat_addr.s_net = at->dest_net; | ||
| 1248 | sat.sat_addr.s_node = at->dest_node; | ||
| 1249 | sat.sat_port = at->dest_port; | ||
| 1250 | } else { | ||
| 1251 | sat.sat_addr.s_net = at->src_net; | ||
| 1252 | sat.sat_addr.s_node = at->src_node; | ||
| 1253 | sat.sat_port = at->src_port; | ||
| 1254 | } | ||
| 1255 | |||
| 1256 | sat.sat_family = AF_APPLETALK; | ||
| 1257 | memcpy(uaddr, &sat, sizeof(sat)); | ||
| 1258 | return 0; | ||
| 1259 | } | ||
| 1260 | |||
| 1261 | #if defined(CONFIG_IPDDP) || defined(CONFIG_IPDDP_MODULE) | ||
| 1262 | static __inline__ int is_ip_over_ddp(struct sk_buff *skb) | ||
| 1263 | { | ||
| 1264 | return skb->data[12] == 22; | ||
| 1265 | } | ||
| 1266 | |||
| 1267 | static int handle_ip_over_ddp(struct sk_buff *skb) | ||
| 1268 | { | ||
| 1269 | struct net_device *dev = __dev_get_by_name("ipddp0"); | ||
| 1270 | struct net_device_stats *stats; | ||
| 1271 | |||
| 1272 | /* This needs to be able to handle ipddp"N" devices */ | ||
| 1273 | if (!dev) | ||
| 1274 | return -ENODEV; | ||
| 1275 | |||
| 1276 | skb->protocol = htons(ETH_P_IP); | ||
| 1277 | skb_pull(skb, 13); | ||
| 1278 | skb->dev = dev; | ||
| 1279 | skb->h.raw = skb->data; | ||
| 1280 | |||
| 1281 | stats = dev->priv; | ||
| 1282 | stats->rx_packets++; | ||
| 1283 | stats->rx_bytes += skb->len + 13; | ||
| 1284 | netif_rx(skb); /* Send the SKB up to a higher place. */ | ||
| 1285 | return 0; | ||
| 1286 | } | ||
| 1287 | #else | ||
| 1288 | /* make it easy for gcc to optimize this test out, i.e. kill the code */ | ||
| 1289 | #define is_ip_over_ddp(skb) 0 | ||
| 1290 | #define handle_ip_over_ddp(skb) 0 | ||
| 1291 | #endif | ||
| 1292 | |||
| 1293 | static void atalk_route_packet(struct sk_buff *skb, struct net_device *dev, | ||
| 1294 | struct ddpehdr *ddp, struct ddpebits *ddphv, | ||
| 1295 | int origlen) | ||
| 1296 | { | ||
| 1297 | struct atalk_route *rt; | ||
| 1298 | struct atalk_addr ta; | ||
| 1299 | |||
| 1300 | /* | ||
| 1301 | * Don't route multicast, etc., packets, or packets sent to "this | ||
| 1302 | * network" | ||
| 1303 | */ | ||
| 1304 | if (skb->pkt_type != PACKET_HOST || !ddp->deh_dnet) { | ||
| 1305 | /* | ||
| 1306 | * FIXME: | ||
| 1307 | * | ||
| 1308 | * Can it ever happen that a packet is from a PPP iface and | ||
| 1309 | * needs to be broadcast onto the default network? | ||
| 1310 | */ | ||
| 1311 | if (dev->type == ARPHRD_PPP) | ||
| 1312 | printk(KERN_DEBUG "AppleTalk: didn't forward broadcast " | ||
| 1313 | "packet received from PPP iface\n"); | ||
| 1314 | goto free_it; | ||
| 1315 | } | ||
| 1316 | |||
| 1317 | ta.s_net = ddp->deh_dnet; | ||
| 1318 | ta.s_node = ddp->deh_dnode; | ||
| 1319 | |||
| 1320 | /* Route the packet */ | ||
| 1321 | rt = atrtr_find(&ta); | ||
| 1322 | if (!rt || ddphv->deh_hops == DDP_MAXHOPS) | ||
| 1323 | goto free_it; | ||
| 1324 | /* FIXME: use skb->cb to be able to use shared skbs */ | ||
| 1325 | ddphv->deh_hops++; | ||
| 1326 | |||
| 1327 | /* | ||
| 1328 | * Route goes through another gateway, so set the target to the | ||
| 1329 | * gateway instead. | ||
| 1330 | */ | ||
| 1331 | |||
| 1332 | if (rt->flags & RTF_GATEWAY) { | ||
| 1333 | ta.s_net = rt->gateway.s_net; | ||
| 1334 | ta.s_node = rt->gateway.s_node; | ||
| 1335 | } | ||
| 1336 | |||
| 1337 | /* Fix up skb->len field */ | ||
| 1338 | skb_trim(skb, min_t(unsigned int, origlen, | ||
| 1339 | (rt->dev->hard_header_len + | ||
| 1340 | ddp_dl->header_length + ddphv->deh_len))); | ||
| 1341 | |||
| 1342 | /* Mend the byte order */ | ||
| 1343 | /* FIXME: use skb->cb to be able to use shared skbs */ | ||
| 1344 | *((__u16 *)ddp) = ntohs(*((__u16 *)ddphv)); | ||
| 1345 | |||
| 1346 | /* | ||
| 1347 | * Send the buffer onwards | ||
| 1348 | * | ||
| 1349 | * Now we must always be careful. If it's come from LocalTalk to | ||
| 1350 | * EtherTalk it might not fit | ||
| 1351 | * | ||
| 1352 | * Order matters here: If a packet has to be copied to make a new | ||
| 1353 | * headroom (rare hopefully) then it won't need unsharing. | ||
| 1354 | * | ||
| 1355 | * Note. ddp-> becomes invalid at the realloc. | ||
| 1356 | */ | ||
| 1357 | if (skb_headroom(skb) < 22) { | ||
| 1358 | /* 22 bytes - 12 ether, 2 len, 3 802.2 5 snap */ | ||
| 1359 | struct sk_buff *nskb = skb_realloc_headroom(skb, 32); | ||
| 1360 | kfree_skb(skb); | ||
| 1361 | if (!nskb) | ||
| 1362 | goto out; | ||
| 1363 | skb = nskb; | ||
| 1364 | } else | ||
| 1365 | skb = skb_unshare(skb, GFP_ATOMIC); | ||
| 1366 | |||
| 1367 | /* | ||
| 1368 | * If the buffer didn't vanish into the lack of space bitbucket we can | ||
| 1369 | * send it. | ||
| 1370 | */ | ||
| 1371 | if (skb && aarp_send_ddp(rt->dev, skb, &ta, NULL) == -1) | ||
| 1372 | goto free_it; | ||
| 1373 | out: | ||
| 1374 | return; | ||
| 1375 | free_it: | ||
| 1376 | kfree_skb(skb); | ||
| 1377 | } | ||
| 1378 | |||
| 1379 | /** | ||
| 1380 | * atalk_rcv - Receive a packet (in skb) from device dev | ||
| 1381 | * @skb - packet received | ||
| 1382 | * @dev - network device where the packet comes from | ||
| 1383 | * @pt - packet type | ||
| 1384 | * | ||
| 1385 | * Receive a packet (in skb) from device dev. This has come from the SNAP | ||
| 1386 | * decoder, and on entry skb->h.raw is the DDP header, skb->len is the DDP | ||
| 1387 | * header, skb->len is the DDP length. The physical headers have been | ||
| 1388 | * extracted. PPP should probably pass frames marked as for this layer. | ||
| 1389 | * [ie ARPHRD_ETHERTALK] | ||
| 1390 | */ | ||
| 1391 | static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, | ||
| 1392 | struct packet_type *pt) | ||
| 1393 | { | ||
| 1394 | struct ddpehdr *ddp; | ||
| 1395 | struct sock *sock; | ||
| 1396 | struct atalk_iface *atif; | ||
| 1397 | struct sockaddr_at tosat; | ||
| 1398 | int origlen; | ||
| 1399 | struct ddpebits ddphv; | ||
| 1400 | |||
| 1401 | /* Don't mangle buffer if shared */ | ||
| 1402 | if (!(skb = skb_share_check(skb, GFP_ATOMIC))) | ||
| 1403 | goto out; | ||
| 1404 | |||
| 1405 | /* Size check and make sure header is contiguous */ | ||
| 1406 | if (!pskb_may_pull(skb, sizeof(*ddp))) | ||
| 1407 | goto freeit; | ||
| 1408 | |||
| 1409 | ddp = ddp_hdr(skb); | ||
| 1410 | |||
| 1411 | /* | ||
| 1412 | * Fix up the length field [Ok this is horrible but otherwise | ||
| 1413 | * I end up with unions of bit fields and messy bit field order | ||
| 1414 | * compiler/endian dependencies..] | ||
| 1415 | */ | ||
| 1416 | *((__u16 *)&ddphv) = ntohs(*((__u16 *)ddp)); | ||
| 1417 | |||
| 1418 | /* Trim buffer in case of stray trailing data */ | ||
| 1419 | origlen = skb->len; | ||
| 1420 | skb_trim(skb, min_t(unsigned int, skb->len, ddphv.deh_len)); | ||
| 1421 | |||
| 1422 | /* | ||
| 1423 | * Size check to see if ddp->deh_len was crap | ||
| 1424 | * (Otherwise we'll detonate most spectacularly | ||
| 1425 | * in the middle of recvmsg()). | ||
| 1426 | */ | ||
| 1427 | if (skb->len < sizeof(*ddp)) | ||
| 1428 | goto freeit; | ||
| 1429 | |||
| 1430 | /* | ||
| 1431 | * Any checksums. Note we don't do htons() on this == is assumed to be | ||
| 1432 | * valid for net byte orders all over the networking code... | ||
| 1433 | */ | ||
| 1434 | if (ddp->deh_sum && | ||
| 1435 | atalk_checksum(skb, ddphv.deh_len) != ddp->deh_sum) | ||
| 1436 | /* Not a valid AppleTalk frame - dustbin time */ | ||
| 1437 | goto freeit; | ||
| 1438 | |||
| 1439 | /* Check the packet is aimed at us */ | ||
| 1440 | if (!ddp->deh_dnet) /* Net 0 is 'this network' */ | ||
| 1441 | atif = atalk_find_anynet(ddp->deh_dnode, dev); | ||
| 1442 | else | ||
| 1443 | atif = atalk_find_interface(ddp->deh_dnet, ddp->deh_dnode); | ||
| 1444 | |||
| 1445 | /* Not ours, so we route the packet via the correct AppleTalk iface */ | ||
| 1446 | if (!atif) { | ||
| 1447 | atalk_route_packet(skb, dev, ddp, &ddphv, origlen); | ||
| 1448 | goto out; | ||
| 1449 | } | ||
| 1450 | |||
| 1451 | /* if IP over DDP is not selected this code will be optimized out */ | ||
| 1452 | if (is_ip_over_ddp(skb)) | ||
| 1453 | return handle_ip_over_ddp(skb); | ||
| 1454 | /* | ||
| 1455 | * Which socket - atalk_search_socket() looks for a *full match* | ||
| 1456 | * of the <net, node, port> tuple. | ||
| 1457 | */ | ||
| 1458 | tosat.sat_addr.s_net = ddp->deh_dnet; | ||
| 1459 | tosat.sat_addr.s_node = ddp->deh_dnode; | ||
| 1460 | tosat.sat_port = ddp->deh_dport; | ||
| 1461 | |||
| 1462 | sock = atalk_search_socket(&tosat, atif); | ||
| 1463 | if (!sock) /* But not one of our sockets */ | ||
| 1464 | goto freeit; | ||
| 1465 | |||
| 1466 | /* Queue packet (standard) */ | ||
| 1467 | skb->sk = sock; | ||
| 1468 | |||
| 1469 | if (sock_queue_rcv_skb(sock, skb) < 0) | ||
| 1470 | goto freeit; | ||
| 1471 | out: | ||
| 1472 | return 0; | ||
| 1473 | freeit: | ||
| 1474 | kfree_skb(skb); | ||
| 1475 | goto out; | ||
| 1476 | } | ||
| 1477 | |||
| 1478 | /* | ||
| 1479 | * Receive a LocalTalk frame. We make some demands on the caller here. | ||
| 1480 | * Caller must provide enough headroom on the packet to pull the short | ||
| 1481 | * header and append a long one. | ||
| 1482 | */ | ||
| 1483 | static int ltalk_rcv(struct sk_buff *skb, struct net_device *dev, | ||
| 1484 | struct packet_type *pt) | ||
| 1485 | { | ||
| 1486 | /* Expand any short form frames */ | ||
| 1487 | if (skb->mac.raw[2] == 1) { | ||
| 1488 | struct ddpehdr *ddp; | ||
| 1489 | /* Find our address */ | ||
| 1490 | struct atalk_addr *ap = atalk_find_dev_addr(dev); | ||
| 1491 | |||
| 1492 | if (!ap || skb->len < sizeof(struct ddpshdr)) | ||
| 1493 | goto freeit; | ||
| 1494 | |||
| 1495 | /* Don't mangle buffer if shared */ | ||
| 1496 | if (!(skb = skb_share_check(skb, GFP_ATOMIC))) | ||
| 1497 | return 0; | ||
| 1498 | |||
| 1499 | /* | ||
| 1500 | * The push leaves us with a ddephdr not an shdr, and | ||
| 1501 | * handily the port bytes in the right place preset. | ||
| 1502 | */ | ||
| 1503 | ddp = (struct ddpehdr *) skb_push(skb, sizeof(*ddp) - 4); | ||
| 1504 | |||
| 1505 | /* Now fill in the long header */ | ||
| 1506 | |||
| 1507 | /* | ||
| 1508 | * These two first. The mac overlays the new source/dest | ||
| 1509 | * network information so we MUST copy these before | ||
| 1510 | * we write the network numbers ! | ||
| 1511 | */ | ||
| 1512 | |||
| 1513 | ddp->deh_dnode = skb->mac.raw[0]; /* From physical header */ | ||
| 1514 | ddp->deh_snode = skb->mac.raw[1]; /* From physical header */ | ||
| 1515 | |||
| 1516 | ddp->deh_dnet = ap->s_net; /* Network number */ | ||
| 1517 | ddp->deh_snet = ap->s_net; | ||
| 1518 | ddp->deh_sum = 0; /* No checksum */ | ||
| 1519 | /* | ||
| 1520 | * Not sure about this bit... | ||
| 1521 | */ | ||
| 1522 | ddp->deh_len = skb->len; | ||
| 1523 | ddp->deh_hops = DDP_MAXHOPS; /* Non routable, so force a drop | ||
| 1524 | if we slip up later */ | ||
| 1525 | /* Mend the byte order */ | ||
| 1526 | *((__u16 *)ddp) = htons(*((__u16 *)ddp)); | ||
| 1527 | } | ||
| 1528 | skb->h.raw = skb->data; | ||
| 1529 | |||
| 1530 | return atalk_rcv(skb, dev, pt); | ||
| 1531 | freeit: | ||
| 1532 | kfree_skb(skb); | ||
| 1533 | return 0; | ||
| 1534 | } | ||
| 1535 | |||
| 1536 | static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, | ||
| 1537 | size_t len) | ||
| 1538 | { | ||
| 1539 | struct sock *sk = sock->sk; | ||
| 1540 | struct atalk_sock *at = at_sk(sk); | ||
| 1541 | struct sockaddr_at *usat = (struct sockaddr_at *)msg->msg_name; | ||
| 1542 | int flags = msg->msg_flags; | ||
| 1543 | int loopback = 0; | ||
| 1544 | struct sockaddr_at local_satalk, gsat; | ||
| 1545 | struct sk_buff *skb; | ||
| 1546 | struct net_device *dev; | ||
| 1547 | struct ddpehdr *ddp; | ||
| 1548 | int size; | ||
| 1549 | struct atalk_route *rt; | ||
| 1550 | int err; | ||
| 1551 | |||
| 1552 | if (flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT)) | ||
| 1553 | return -EINVAL; | ||
| 1554 | |||
| 1555 | if (len > DDP_MAXSZ) | ||
| 1556 | return -EMSGSIZE; | ||
| 1557 | |||
| 1558 | if (usat) { | ||
| 1559 | if (sock_flag(sk, SOCK_ZAPPED)) | ||
| 1560 | if (atalk_autobind(sk) < 0) | ||
| 1561 | return -EBUSY; | ||
| 1562 | |||
| 1563 | if (msg->msg_namelen < sizeof(*usat) || | ||
| 1564 | usat->sat_family != AF_APPLETALK) | ||
| 1565 | return -EINVAL; | ||
| 1566 | |||
| 1567 | /* netatalk doesn't implement this check */ | ||
| 1568 | if (usat->sat_addr.s_node == ATADDR_BCAST && | ||
| 1569 | !sock_flag(sk, SOCK_BROADCAST)) { | ||
| 1570 | printk(KERN_INFO "SO_BROADCAST: Fix your netatalk as " | ||
| 1571 | "it will break before 2.2\n"); | ||
| 1572 | #if 0 | ||
| 1573 | return -EPERM; | ||
| 1574 | #endif | ||
| 1575 | } | ||
| 1576 | } else { | ||
| 1577 | if (sk->sk_state != TCP_ESTABLISHED) | ||
| 1578 | return -ENOTCONN; | ||
| 1579 | usat = &local_satalk; | ||
| 1580 | usat->sat_family = AF_APPLETALK; | ||
| 1581 | usat->sat_port = at->dest_port; | ||
| 1582 | usat->sat_addr.s_node = at->dest_node; | ||
| 1583 | usat->sat_addr.s_net = at->dest_net; | ||
| 1584 | } | ||
| 1585 | |||
| 1586 | /* Build a packet */ | ||
| 1587 | SOCK_DEBUG(sk, "SK %p: Got address.\n", sk); | ||
| 1588 | |||
| 1589 | /* For headers */ | ||
| 1590 | size = sizeof(struct ddpehdr) + len + ddp_dl->header_length; | ||
| 1591 | |||
| 1592 | if (usat->sat_addr.s_net || usat->sat_addr.s_node == ATADDR_ANYNODE) { | ||
| 1593 | rt = atrtr_find(&usat->sat_addr); | ||
| 1594 | if (!rt) | ||
| 1595 | return -ENETUNREACH; | ||
| 1596 | |||
| 1597 | dev = rt->dev; | ||
| 1598 | } else { | ||
| 1599 | struct atalk_addr at_hint; | ||
| 1600 | |||
| 1601 | at_hint.s_node = 0; | ||
| 1602 | at_hint.s_net = at->src_net; | ||
| 1603 | |||
| 1604 | rt = atrtr_find(&at_hint); | ||
| 1605 | if (!rt) | ||
| 1606 | return -ENETUNREACH; | ||
| 1607 | |||
| 1608 | dev = rt->dev; | ||
| 1609 | } | ||
| 1610 | |||
| 1611 | SOCK_DEBUG(sk, "SK %p: Size needed %d, device %s\n", | ||
| 1612 | sk, size, dev->name); | ||
| 1613 | |||
| 1614 | size += dev->hard_header_len; | ||
| 1615 | skb = sock_alloc_send_skb(sk, size, (flags & MSG_DONTWAIT), &err); | ||
| 1616 | if (!skb) | ||
| 1617 | return err; | ||
| 1618 | |||
| 1619 | skb->sk = sk; | ||
| 1620 | skb_reserve(skb, ddp_dl->header_length); | ||
| 1621 | skb_reserve(skb, dev->hard_header_len); | ||
| 1622 | skb->dev = dev; | ||
| 1623 | |||
| 1624 | SOCK_DEBUG(sk, "SK %p: Begin build.\n", sk); | ||
| 1625 | |||
| 1626 | ddp = (struct ddpehdr *)skb_put(skb, sizeof(struct ddpehdr)); | ||
| 1627 | ddp->deh_pad = 0; | ||
| 1628 | ddp->deh_hops = 0; | ||
| 1629 | ddp->deh_len = len + sizeof(*ddp); | ||
| 1630 | /* | ||
| 1631 | * Fix up the length field [Ok this is horrible but otherwise | ||
| 1632 | * I end up with unions of bit fields and messy bit field order | ||
| 1633 | * compiler/endian dependencies.. | ||
| 1634 | */ | ||
| 1635 | *((__u16 *)ddp) = ntohs(*((__u16 *)ddp)); | ||
| 1636 | |||
| 1637 | ddp->deh_dnet = usat->sat_addr.s_net; | ||
| 1638 | ddp->deh_snet = at->src_net; | ||
| 1639 | ddp->deh_dnode = usat->sat_addr.s_node; | ||
| 1640 | ddp->deh_snode = at->src_node; | ||
| 1641 | ddp->deh_dport = usat->sat_port; | ||
| 1642 | ddp->deh_sport = at->src_port; | ||
| 1643 | |||
| 1644 | SOCK_DEBUG(sk, "SK %p: Copy user data (%Zd bytes).\n", sk, len); | ||
| 1645 | |||
| 1646 | err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len); | ||
| 1647 | if (err) { | ||
| 1648 | kfree_skb(skb); | ||
| 1649 | return -EFAULT; | ||
| 1650 | } | ||
| 1651 | |||
| 1652 | if (sk->sk_no_check == 1) | ||
| 1653 | ddp->deh_sum = 0; | ||
| 1654 | else | ||
| 1655 | ddp->deh_sum = atalk_checksum(skb, len + sizeof(*ddp)); | ||
| 1656 | |||
| 1657 | /* | ||
| 1658 | * Loopback broadcast packets to non gateway targets (ie routes | ||
| 1659 | * to group we are in) | ||
| 1660 | */ | ||
| 1661 | if (ddp->deh_dnode == ATADDR_BCAST && | ||
| 1662 | !(rt->flags & RTF_GATEWAY) && !(dev->flags & IFF_LOOPBACK)) { | ||
| 1663 | struct sk_buff *skb2 = skb_copy(skb, GFP_KERNEL); | ||
| 1664 | |||
| 1665 | if (skb2) { | ||
| 1666 | loopback = 1; | ||
| 1667 | SOCK_DEBUG(sk, "SK %p: send out(copy).\n", sk); | ||
| 1668 | if (aarp_send_ddp(dev, skb2, | ||
| 1669 | &usat->sat_addr, NULL) == -1) | ||
| 1670 | kfree_skb(skb2); | ||
| 1671 | /* else queued/sent above in the aarp queue */ | ||
| 1672 | } | ||
| 1673 | } | ||
| 1674 | |||
| 1675 | if (dev->flags & IFF_LOOPBACK || loopback) { | ||
| 1676 | SOCK_DEBUG(sk, "SK %p: Loop back.\n", sk); | ||
| 1677 | /* loop back */ | ||
| 1678 | skb_orphan(skb); | ||
| 1679 | ddp_dl->request(ddp_dl, skb, dev->dev_addr); | ||
| 1680 | } else { | ||
| 1681 | SOCK_DEBUG(sk, "SK %p: send out.\n", sk); | ||
| 1682 | if (rt->flags & RTF_GATEWAY) { | ||
| 1683 | gsat.sat_addr = rt->gateway; | ||
| 1684 | usat = &gsat; | ||
| 1685 | } | ||
| 1686 | |||
| 1687 | if (aarp_send_ddp(dev, skb, &usat->sat_addr, NULL) == -1) | ||
| 1688 | kfree_skb(skb); | ||
| 1689 | /* else queued/sent above in the aarp queue */ | ||
| 1690 | } | ||
| 1691 | SOCK_DEBUG(sk, "SK %p: Done write (%Zd).\n", sk, len); | ||
| 1692 | |||
| 1693 | return len; | ||
| 1694 | } | ||
| 1695 | |||
| 1696 | static int atalk_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, | ||
| 1697 | size_t size, int flags) | ||
| 1698 | { | ||
| 1699 | struct sock *sk = sock->sk; | ||
| 1700 | struct sockaddr_at *sat = (struct sockaddr_at *)msg->msg_name; | ||
| 1701 | struct ddpehdr *ddp; | ||
| 1702 | int copied = 0; | ||
| 1703 | int err = 0; | ||
| 1704 | struct ddpebits ddphv; | ||
| 1705 | struct sk_buff *skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, | ||
| 1706 | flags & MSG_DONTWAIT, &err); | ||
| 1707 | if (!skb) | ||
| 1708 | return err; | ||
| 1709 | |||
| 1710 | /* FIXME: use skb->cb to be able to use shared skbs */ | ||
| 1711 | ddp = ddp_hdr(skb); | ||
| 1712 | *((__u16 *)&ddphv) = ntohs(*((__u16 *)ddp)); | ||
| 1713 | |||
| 1714 | if (sk->sk_type == SOCK_RAW) { | ||
| 1715 | copied = ddphv.deh_len; | ||
| 1716 | if (copied > size) { | ||
| 1717 | copied = size; | ||
| 1718 | msg->msg_flags |= MSG_TRUNC; | ||
| 1719 | } | ||
| 1720 | |||
| 1721 | err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); | ||
| 1722 | } else { | ||
| 1723 | copied = ddphv.deh_len - sizeof(*ddp); | ||
| 1724 | if (copied > size) { | ||
| 1725 | copied = size; | ||
| 1726 | msg->msg_flags |= MSG_TRUNC; | ||
| 1727 | } | ||
| 1728 | err = skb_copy_datagram_iovec(skb, sizeof(*ddp), | ||
| 1729 | msg->msg_iov, copied); | ||
| 1730 | } | ||
| 1731 | |||
| 1732 | if (!err) { | ||
| 1733 | if (sat) { | ||
| 1734 | sat->sat_family = AF_APPLETALK; | ||
| 1735 | sat->sat_port = ddp->deh_sport; | ||
| 1736 | sat->sat_addr.s_node = ddp->deh_snode; | ||
| 1737 | sat->sat_addr.s_net = ddp->deh_snet; | ||
| 1738 | } | ||
| 1739 | msg->msg_namelen = sizeof(*sat); | ||
| 1740 | } | ||
| 1741 | |||
| 1742 | skb_free_datagram(sk, skb); /* Free the datagram. */ | ||
| 1743 | return err ? : copied; | ||
| 1744 | } | ||
| 1745 | |||
| 1746 | |||
| 1747 | /* | ||
| 1748 | * AppleTalk ioctl calls. | ||
| 1749 | */ | ||
| 1750 | static int atalk_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | ||
| 1751 | { | ||
| 1752 | int rc = -EINVAL; | ||
| 1753 | struct sock *sk = sock->sk; | ||
| 1754 | void __user *argp = (void __user *)arg; | ||
| 1755 | |||
| 1756 | switch (cmd) { | ||
| 1757 | /* Protocol layer */ | ||
| 1758 | case TIOCOUTQ: { | ||
| 1759 | long amount = sk->sk_sndbuf - | ||
| 1760 | atomic_read(&sk->sk_wmem_alloc); | ||
| 1761 | |||
| 1762 | if (amount < 0) | ||
| 1763 | amount = 0; | ||
| 1764 | rc = put_user(amount, (int __user *)argp); | ||
| 1765 | break; | ||
| 1766 | } | ||
| 1767 | case TIOCINQ: { | ||
| 1768 | /* | ||
| 1769 | * These two are safe on a single CPU system as only | ||
| 1770 | * user tasks fiddle here | ||
| 1771 | */ | ||
| 1772 | struct sk_buff *skb = skb_peek(&sk->sk_receive_queue); | ||
| 1773 | long amount = 0; | ||
| 1774 | |||
| 1775 | if (skb) | ||
| 1776 | amount = skb->len - sizeof(struct ddpehdr); | ||
| 1777 | rc = put_user(amount, (int __user *)argp); | ||
| 1778 | break; | ||
| 1779 | } | ||
| 1780 | case SIOCGSTAMP: | ||
| 1781 | rc = sock_get_timestamp(sk, argp); | ||
| 1782 | break; | ||
| 1783 | /* Routing */ | ||
| 1784 | case SIOCADDRT: | ||
| 1785 | case SIOCDELRT: | ||
| 1786 | rc = -EPERM; | ||
| 1787 | if (capable(CAP_NET_ADMIN)) | ||
| 1788 | rc = atrtr_ioctl(cmd, argp); | ||
| 1789 | break; | ||
| 1790 | /* Interface */ | ||
| 1791 | case SIOCGIFADDR: | ||
| 1792 | case SIOCSIFADDR: | ||
| 1793 | case SIOCGIFBRDADDR: | ||
| 1794 | case SIOCATALKDIFADDR: | ||
| 1795 | case SIOCDIFADDR: | ||
| 1796 | case SIOCSARP: /* proxy AARP */ | ||
| 1797 | case SIOCDARP: /* proxy AARP */ | ||
| 1798 | rtnl_lock(); | ||
| 1799 | rc = atif_ioctl(cmd, argp); | ||
| 1800 | rtnl_unlock(); | ||
| 1801 | break; | ||
| 1802 | /* Physical layer ioctl calls */ | ||
| 1803 | case SIOCSIFLINK: | ||
| 1804 | case SIOCGIFHWADDR: | ||
| 1805 | case SIOCSIFHWADDR: | ||
| 1806 | case SIOCGIFFLAGS: | ||
| 1807 | case SIOCSIFFLAGS: | ||
| 1808 | case SIOCGIFTXQLEN: | ||
| 1809 | case SIOCSIFTXQLEN: | ||
| 1810 | case SIOCGIFMTU: | ||
| 1811 | case SIOCGIFCONF: | ||
| 1812 | case SIOCADDMULTI: | ||
| 1813 | case SIOCDELMULTI: | ||
| 1814 | case SIOCGIFCOUNT: | ||
| 1815 | case SIOCGIFINDEX: | ||
| 1816 | case SIOCGIFNAME: | ||
| 1817 | rc = dev_ioctl(cmd, argp); | ||
| 1818 | break; | ||
| 1819 | } | ||
| 1820 | |||
| 1821 | return rc; | ||
| 1822 | } | ||
| 1823 | |||
| 1824 | static struct net_proto_family atalk_family_ops = { | ||
| 1825 | .family = PF_APPLETALK, | ||
| 1826 | .create = atalk_create, | ||
| 1827 | .owner = THIS_MODULE, | ||
| 1828 | }; | ||
| 1829 | |||
| 1830 | static struct proto_ops SOCKOPS_WRAPPED(atalk_dgram_ops) = { | ||
| 1831 | .family = PF_APPLETALK, | ||
| 1832 | .owner = THIS_MODULE, | ||
| 1833 | .release = atalk_release, | ||
| 1834 | .bind = atalk_bind, | ||
| 1835 | .connect = atalk_connect, | ||
| 1836 | .socketpair = sock_no_socketpair, | ||
| 1837 | .accept = sock_no_accept, | ||
| 1838 | .getname = atalk_getname, | ||
| 1839 | .poll = datagram_poll, | ||
| 1840 | .ioctl = atalk_ioctl, | ||
| 1841 | .listen = sock_no_listen, | ||
| 1842 | .shutdown = sock_no_shutdown, | ||
| 1843 | .setsockopt = sock_no_setsockopt, | ||
| 1844 | .getsockopt = sock_no_getsockopt, | ||
| 1845 | .sendmsg = atalk_sendmsg, | ||
| 1846 | .recvmsg = atalk_recvmsg, | ||
| 1847 | .mmap = sock_no_mmap, | ||
| 1848 | .sendpage = sock_no_sendpage, | ||
| 1849 | }; | ||
| 1850 | |||
| 1851 | #include <linux/smp_lock.h> | ||
| 1852 | SOCKOPS_WRAP(atalk_dgram, PF_APPLETALK); | ||
| 1853 | |||
| 1854 | static struct notifier_block ddp_notifier = { | ||
| 1855 | .notifier_call = ddp_device_event, | ||
| 1856 | }; | ||
| 1857 | |||
| 1858 | static struct packet_type ltalk_packet_type = { | ||
| 1859 | .type = __constant_htons(ETH_P_LOCALTALK), | ||
| 1860 | .func = ltalk_rcv, | ||
| 1861 | }; | ||
| 1862 | |||
| 1863 | static struct packet_type ppptalk_packet_type = { | ||
| 1864 | .type = __constant_htons(ETH_P_PPPTALK), | ||
| 1865 | .func = atalk_rcv, | ||
| 1866 | }; | ||
| 1867 | |||
| 1868 | static unsigned char ddp_snap_id[] = { 0x08, 0x00, 0x07, 0x80, 0x9B }; | ||
| 1869 | |||
| 1870 | /* Export symbols for use by drivers when AppleTalk is a module */ | ||
| 1871 | EXPORT_SYMBOL(aarp_send_ddp); | ||
| 1872 | EXPORT_SYMBOL(atrtr_get_dev); | ||
| 1873 | EXPORT_SYMBOL(atalk_find_dev_addr); | ||
| 1874 | |||
| 1875 | static char atalk_err_snap[] __initdata = | ||
| 1876 | KERN_CRIT "Unable to register DDP with SNAP.\n"; | ||
| 1877 | |||
| 1878 | /* Called by proto.c on kernel start up */ | ||
| 1879 | static int __init atalk_init(void) | ||
| 1880 | { | ||
| 1881 | int rc = proto_register(&ddp_proto, 0); | ||
| 1882 | |||
| 1883 | if (rc != 0) | ||
| 1884 | goto out; | ||
| 1885 | |||
| 1886 | (void)sock_register(&atalk_family_ops); | ||
| 1887 | ddp_dl = register_snap_client(ddp_snap_id, atalk_rcv); | ||
| 1888 | if (!ddp_dl) | ||
| 1889 | printk(atalk_err_snap); | ||
| 1890 | |||
| 1891 | dev_add_pack(<alk_packet_type); | ||
| 1892 | dev_add_pack(&ppptalk_packet_type); | ||
| 1893 | |||
| 1894 | register_netdevice_notifier(&ddp_notifier); | ||
| 1895 | aarp_proto_init(); | ||
| 1896 | atalk_proc_init(); | ||
| 1897 | atalk_register_sysctl(); | ||
| 1898 | out: | ||
| 1899 | return rc; | ||
| 1900 | } | ||
| 1901 | module_init(atalk_init); | ||
| 1902 | |||
| 1903 | /* | ||
| 1904 | * No explicit module reference count manipulation is needed in the | ||
| 1905 | * protocol. Socket layer sets module reference count for us | ||
| 1906 | * and interfaces reference counting is done | ||
| 1907 | * by the network device layer. | ||
| 1908 | * | ||
| 1909 | * Ergo, before the AppleTalk module can be removed, all AppleTalk | ||
| 1910 | * sockets be closed from user space. | ||
| 1911 | */ | ||
| 1912 | static void __exit atalk_exit(void) | ||
| 1913 | { | ||
| 1914 | #ifdef CONFIG_SYSCTL | ||
| 1915 | atalk_unregister_sysctl(); | ||
| 1916 | #endif /* CONFIG_SYSCTL */ | ||
| 1917 | atalk_proc_exit(); | ||
| 1918 | aarp_cleanup_module(); /* General aarp clean-up. */ | ||
| 1919 | unregister_netdevice_notifier(&ddp_notifier); | ||
| 1920 | dev_remove_pack(<alk_packet_type); | ||
| 1921 | dev_remove_pack(&ppptalk_packet_type); | ||
| 1922 | unregister_snap_client(ddp_dl); | ||
| 1923 | sock_unregister(PF_APPLETALK); | ||
| 1924 | proto_unregister(&ddp_proto); | ||
| 1925 | } | ||
| 1926 | module_exit(atalk_exit); | ||
| 1927 | |||
| 1928 | MODULE_LICENSE("GPL"); | ||
| 1929 | MODULE_AUTHOR("Alan Cox <Alan.Cox@linux.org>"); | ||
| 1930 | MODULE_DESCRIPTION("AppleTalk 0.20\n"); | ||
| 1931 | MODULE_ALIAS_NETPROTO(PF_APPLETALK); | ||
diff --git a/net/appletalk/dev.c b/net/appletalk/dev.c new file mode 100644 index 00000000000..76598445d84 --- /dev/null +++ b/net/appletalk/dev.c | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | /* | ||
| 2 | * Moved here from drivers/net/net_init.c, which is: | ||
| 3 | * Written 1993,1994,1995 by Donald Becker. | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <linux/errno.h> | ||
| 7 | #include <linux/module.h> | ||
| 8 | #include <linux/netdevice.h> | ||
| 9 | #include <linux/if_arp.h> | ||
| 10 | #include <linux/if_ltalk.h> | ||
| 11 | |||
| 12 | static int ltalk_change_mtu(struct net_device *dev, int mtu) | ||
| 13 | { | ||
| 14 | return -EINVAL; | ||
| 15 | } | ||
| 16 | |||
| 17 | static int ltalk_mac_addr(struct net_device *dev, void *addr) | ||
| 18 | { | ||
| 19 | return -EINVAL; | ||
| 20 | } | ||
| 21 | |||
| 22 | void ltalk_setup(struct net_device *dev) | ||
| 23 | { | ||
| 24 | /* Fill in the fields of the device structure with localtalk-generic values. */ | ||
| 25 | |||
| 26 | dev->change_mtu = ltalk_change_mtu; | ||
| 27 | dev->hard_header = NULL; | ||
| 28 | dev->rebuild_header = NULL; | ||
| 29 | dev->set_mac_address = ltalk_mac_addr; | ||
| 30 | dev->hard_header_cache = NULL; | ||
| 31 | dev->header_cache_update= NULL; | ||
| 32 | |||
| 33 | dev->type = ARPHRD_LOCALTLK; | ||
| 34 | dev->hard_header_len = LTALK_HLEN; | ||
| 35 | dev->mtu = LTALK_MTU; | ||
| 36 | dev->addr_len = LTALK_ALEN; | ||
| 37 | dev->tx_queue_len = 10; | ||
| 38 | |||
| 39 | dev->broadcast[0] = 0xFF; | ||
| 40 | |||
| 41 | dev->flags = IFF_BROADCAST|IFF_MULTICAST|IFF_NOARP; | ||
| 42 | } | ||
| 43 | EXPORT_SYMBOL(ltalk_setup); | ||
diff --git a/net/appletalk/sysctl_net_atalk.c b/net/appletalk/sysctl_net_atalk.c new file mode 100644 index 00000000000..af7f0604395 --- /dev/null +++ b/net/appletalk/sysctl_net_atalk.c | |||
| @@ -0,0 +1,83 @@ | |||
| 1 | /* | ||
| 2 | * sysctl_net_atalk.c: sysctl interface to net AppleTalk subsystem. | ||
| 3 | * | ||
| 4 | * Begun April 1, 1996, Mike Shaver. | ||
| 5 | * Added /proc/sys/net/atalk directory entry (empty =) ). [MS] | ||
| 6 | * Dynamic registration, added aarp entries. (5/30/97 Chris Horn) | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/config.h> | ||
| 10 | #include <linux/sysctl.h> | ||
| 11 | #include <net/sock.h> | ||
| 12 | #include <linux/atalk.h> | ||
| 13 | |||
| 14 | static struct ctl_table atalk_table[] = { | ||
| 15 | { | ||
| 16 | .ctl_name = NET_ATALK_AARP_EXPIRY_TIME, | ||
| 17 | .procname = "aarp-expiry-time", | ||
| 18 | .data = &sysctl_aarp_expiry_time, | ||
| 19 | .maxlen = sizeof(int), | ||
| 20 | .mode = 0644, | ||
| 21 | .proc_handler = &proc_dointvec_jiffies, | ||
| 22 | .strategy = &sysctl_jiffies, | ||
| 23 | }, | ||
| 24 | { | ||
| 25 | .ctl_name = NET_ATALK_AARP_TICK_TIME, | ||
| 26 | .procname = "aarp-tick-time", | ||
| 27 | .data = &sysctl_aarp_tick_time, | ||
| 28 | .maxlen = sizeof(int), | ||
| 29 | .mode = 0644, | ||
| 30 | .proc_handler = &proc_dointvec_jiffies, | ||
| 31 | .strategy = &sysctl_jiffies, | ||
| 32 | }, | ||
| 33 | { | ||
| 34 | .ctl_name = NET_ATALK_AARP_RETRANSMIT_LIMIT, | ||
| 35 | .procname = "aarp-retransmit-limit", | ||
| 36 | .data = &sysctl_aarp_retransmit_limit, | ||
| 37 | .maxlen = sizeof(int), | ||
| 38 | .mode = 0644, | ||
| 39 | .proc_handler = &proc_dointvec, | ||
| 40 | }, | ||
| 41 | { | ||
| 42 | .ctl_name = NET_ATALK_AARP_RESOLVE_TIME, | ||
| 43 | .procname = "aarp-resolve-time", | ||
| 44 | .data = &sysctl_aarp_resolve_time, | ||
| 45 | .maxlen = sizeof(int), | ||
| 46 | .mode = 0644, | ||
| 47 | .proc_handler = &proc_dointvec_jiffies, | ||
| 48 | .strategy = &sysctl_jiffies, | ||
| 49 | }, | ||
| 50 | { 0 }, | ||
| 51 | }; | ||
| 52 | |||
| 53 | static struct ctl_table atalk_dir_table[] = { | ||
| 54 | { | ||
| 55 | .ctl_name = NET_ATALK, | ||
| 56 | .procname = "appletalk", | ||
| 57 | .mode = 0555, | ||
| 58 | .child = atalk_table, | ||
| 59 | }, | ||
| 60 | { 0 }, | ||
| 61 | }; | ||
| 62 | |||
| 63 | static struct ctl_table atalk_root_table[] = { | ||
| 64 | { | ||
| 65 | .ctl_name = CTL_NET, | ||
| 66 | .procname = "net", | ||
| 67 | .mode = 0555, | ||
| 68 | .child = atalk_dir_table, | ||
| 69 | }, | ||
| 70 | { 0 }, | ||
| 71 | }; | ||
| 72 | |||
| 73 | static struct ctl_table_header *atalk_table_header; | ||
| 74 | |||
| 75 | void atalk_register_sysctl(void) | ||
| 76 | { | ||
| 77 | atalk_table_header = register_sysctl_table(atalk_root_table, 1); | ||
| 78 | } | ||
| 79 | |||
| 80 | void atalk_unregister_sysctl(void) | ||
| 81 | { | ||
| 82 | unregister_sysctl_table(atalk_table_header); | ||
| 83 | } | ||
