1 /* $NetBSD: ddp_input.c,v 1.25 2009/04/18 14:58:05 tsutsui Exp $ */ 2 3 /* 4 * Copyright (c) 1990,1994 Regents of The University of Michigan. 5 * All Rights Reserved. 6 * 7 * Permission to use, copy, modify, and distribute this software and 8 * its documentation for any purpose and without fee is hereby granted, 9 * provided that the above copyright notice appears in all copies and 10 * that both that copyright notice and this permission notice appear 11 * in supporting documentation, and that the name of The University 12 * of Michigan not be used in advertising or publicity pertaining to 13 * distribution of the software without specific, written prior 14 * permission. This software is supplied as is without expressed or 15 * implied warranties of any kind. 16 * 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 20 * Research Systems Unix Group 21 * The University of Michigan 22 * c/o Wesley Craig 23 * 535 W. William Street 24 * Ann Arbor, Michigan 25 * +1-313-764-2278 26 * netatalk@umich.edu 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: ddp_input.c,v 1.25 2009/04/18 14:58:05 tsutsui Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/kernel.h> 35 #include <net/netisr.h> 36 #include <sys/mbuf.h> 37 #include <sys/socket.h> 38 #include <sys/socketvar.h> 39 #include <sys/syslog.h> 40 #include <net/if.h> 41 #include <net/route.h> 42 #include <net/if_ether.h> 43 #include <netinet/in.h> 44 45 #include <netatalk/at.h> 46 #include <netatalk/at_var.h> 47 #include <netatalk/ddp.h> 48 #include <netatalk/ddp_var.h> 49 #include <netatalk/ddp_private.h> 50 #include <netatalk/at_extern.h> 51 52 int ddp_forward = 1; 53 int ddp_firewall = 0; 54 extern int ddp_cksum; 55 void ddp_input(struct mbuf *, struct ifnet *, 56 struct elaphdr *, int); 57 58 /* 59 * Could probably merge these two code segments a little better... 60 */ 61 void 62 atintr(void) 63 { 64 struct elaphdr *elhp, elh; 65 struct ifnet *ifp; 66 struct mbuf *m; 67 struct at_ifaddr *aa; 68 int s; 69 70 mutex_enter(softnet_lock); 71 for (;;) { 72 s = splnet(); 73 74 IF_DEQUEUE(&atintrq2, m); 75 76 splx(s); 77 78 if (m == 0) /* no more queued packets */ 79 break; 80 81 m_claimm(m, &atalk_rx_mowner); 82 ifp = m->m_pkthdr.rcvif; 83 for (aa = at_ifaddr.tqh_first; aa; aa = aa->aa_list.tqe_next) { 84 if (aa->aa_ifp == ifp && (aa->aa_flags & AFA_PHASE2)) 85 break; 86 } 87 if (aa == NULL) { /* ifp not an appletalk interface */ 88 m_freem(m); 89 continue; 90 } 91 ddp_input(m, ifp, (struct elaphdr *) NULL, 2); 92 } 93 94 for (;;) { 95 s = splnet(); 96 97 IF_DEQUEUE(&atintrq1, m); 98 99 splx(s); 100 101 if (m == 0) /* no more queued packets */ 102 103 break; 104 105 m_claimm(m, &atalk_rx_mowner); 106 ifp = m->m_pkthdr.rcvif; 107 for (aa = at_ifaddr.tqh_first; aa; aa = aa->aa_list.tqe_next) { 108 if (aa->aa_ifp == ifp && 109 (aa->aa_flags & AFA_PHASE2) == 0) 110 break; 111 } 112 if (aa == NULL) { /* ifp not an appletalk interface */ 113 m_freem(m); 114 continue; 115 } 116 if (m->m_len < SZ_ELAPHDR && 117 ((m = m_pullup(m, SZ_ELAPHDR)) == 0)) { 118 DDP_STATINC(DDP_STAT_TOOSHORT); 119 continue; 120 } 121 elhp = mtod(m, struct elaphdr *); 122 m_adj(m, SZ_ELAPHDR); 123 124 if (elhp->el_type == ELAP_DDPEXTEND) { 125 ddp_input(m, ifp, (struct elaphdr *) NULL, 1); 126 } else { 127 memcpy((void *) & elh, (void *) elhp, SZ_ELAPHDR); 128 ddp_input(m, ifp, &elh, 1); 129 } 130 } 131 mutex_exit(softnet_lock); 132 } 133 134 struct route forwro; 135 136 void 137 ddp_input(struct mbuf *m, struct ifnet *ifp, struct elaphdr *elh, int phase) 138 { 139 struct rtentry *rt; 140 struct sockaddr_at from, to; 141 struct ddpshdr *dsh, ddps; 142 struct at_ifaddr *aa; 143 struct ddpehdr *deh = NULL, ddpe; 144 struct ddpcb *ddp; 145 int dlen, mlen; 146 u_short cksum = 0; 147 union { 148 struct sockaddr dst; 149 struct sockaddr_at dsta; 150 } u; 151 152 memset((void *) & from, 0, sizeof(struct sockaddr_at)); 153 if (elh) { 154 DDP_STATINC(DDP_STAT_SHORT); 155 156 if (m->m_len < sizeof(struct ddpshdr) && 157 ((m = m_pullup(m, sizeof(struct ddpshdr))) == 0)) { 158 DDP_STATINC(DDP_STAT_TOOSHORT); 159 return; 160 } 161 dsh = mtod(m, struct ddpshdr *); 162 memcpy((void *) & ddps, (void *) dsh, sizeof(struct ddpshdr)); 163 ddps.dsh_bytes = ntohl(ddps.dsh_bytes); 164 dlen = ddps.dsh_len; 165 166 to.sat_addr.s_net = ATADDR_ANYNET; 167 to.sat_addr.s_node = elh->el_dnode; 168 to.sat_port = ddps.dsh_dport; 169 from.sat_addr.s_net = ATADDR_ANYNET; 170 from.sat_addr.s_node = elh->el_snode; 171 from.sat_port = ddps.dsh_sport; 172 173 for (aa = at_ifaddr.tqh_first; aa; aa = aa->aa_list.tqe_next) { 174 if (aa->aa_ifp == ifp && 175 (aa->aa_flags & AFA_PHASE2) == 0 && 176 (AA_SAT(aa)->sat_addr.s_node == 177 to.sat_addr.s_node || 178 to.sat_addr.s_node == ATADDR_BCAST)) 179 break; 180 } 181 if (aa == NULL) { 182 m_freem(m); 183 return; 184 } 185 } else { 186 DDP_STATINC(DDP_STAT_LONG); 187 188 if (m->m_len < sizeof(struct ddpehdr) && 189 ((m = m_pullup(m, sizeof(struct ddpehdr))) == 0)) { 190 DDP_STATINC(DDP_STAT_TOOSHORT); 191 return; 192 } 193 deh = mtod(m, struct ddpehdr *); 194 memcpy((void *) & ddpe, (void *) deh, sizeof(struct ddpehdr)); 195 ddpe.deh_bytes = ntohl(ddpe.deh_bytes); 196 dlen = ddpe.deh_len; 197 198 if ((cksum = ddpe.deh_sum) == 0) { 199 DDP_STATINC(DDP_STAT_NOSUM); 200 } 201 from.sat_addr.s_net = ddpe.deh_snet; 202 from.sat_addr.s_node = ddpe.deh_snode; 203 from.sat_port = ddpe.deh_sport; 204 to.sat_addr.s_net = ddpe.deh_dnet; 205 to.sat_addr.s_node = ddpe.deh_dnode; 206 to.sat_port = ddpe.deh_dport; 207 208 if (to.sat_addr.s_net == ATADDR_ANYNET) { 209 for (aa = at_ifaddr.tqh_first; aa; 210 aa = aa->aa_list.tqe_next) { 211 if (phase == 1 && (aa->aa_flags & AFA_PHASE2)) 212 continue; 213 214 if (phase == 2 && 215 (aa->aa_flags & AFA_PHASE2) == 0) 216 continue; 217 218 if (aa->aa_ifp == ifp && 219 (AA_SAT(aa)->sat_addr.s_node == 220 to.sat_addr.s_node || 221 to.sat_addr.s_node == ATADDR_BCAST || 222 (ifp->if_flags & IFF_LOOPBACK))) 223 break; 224 } 225 } else { 226 for (aa = at_ifaddr.tqh_first; aa; 227 aa = aa->aa_list.tqe_next) { 228 if (to.sat_addr.s_net == aa->aa_firstnet && 229 to.sat_addr.s_node == 0) 230 break; 231 232 if ((ntohs(to.sat_addr.s_net) < 233 ntohs(aa->aa_firstnet) || 234 ntohs(to.sat_addr.s_net) > 235 ntohs(aa->aa_lastnet)) && 236 (ntohs(to.sat_addr.s_net) < 0xff00 || 237 ntohs(to.sat_addr.s_net) > 0xfffe)) 238 continue; 239 240 if (to.sat_addr.s_node != 241 AA_SAT(aa)->sat_addr.s_node && 242 to.sat_addr.s_node != ATADDR_BCAST) 243 continue; 244 245 break; 246 } 247 } 248 } 249 250 /* 251 * Adjust the length, removing any padding that may have been added 252 * at a link layer. We do this before we attempt to forward a packet, 253 * possibly on a different media. 254 */ 255 mlen = m->m_pkthdr.len; 256 if (mlen < dlen) { 257 DDP_STATINC(DDP_STAT_TOOSMALL); 258 m_freem(m); 259 return; 260 } 261 if (mlen > dlen) { 262 m_adj(m, dlen - mlen); 263 } 264 /* 265 * XXX Should we deliver broadcasts locally, also, or rely on the 266 * link layer to give us a copy? For the moment, the latter. 267 */ 268 if (aa == NULL || (to.sat_addr.s_node == ATADDR_BCAST && 269 aa->aa_ifp != ifp && (ifp->if_flags & IFF_LOOPBACK) == 0)) { 270 if (ddp_forward == 0) { 271 m_freem(m); 272 return; 273 } 274 sockaddr_at_init(&u.dsta, &to.sat_addr, 0); 275 rt = rtcache_lookup(&forwro, &u.dst); 276 #if 0 /* XXX The if-condition is always false. What was this 277 * actually trying to test? 278 */ 279 if (to.sat_addr.s_net != 280 satocsat(rtcache_getdst(&forwro))->sat_addr.s_net && 281 ddpe.deh_hops == DDP_MAXHOPS) { 282 m_freem(m); 283 return; 284 } 285 #endif 286 if (ddp_firewall && (rt == NULL || rt->rt_ifp != ifp)) { 287 m_freem(m); 288 return; 289 } 290 ddpe.deh_hops++; 291 ddpe.deh_bytes = htonl(ddpe.deh_bytes); 292 memcpy((void *) deh, (void *) & ddpe, sizeof(u_short));/*XXX*/ 293 if (ddp_route(m, &forwro)) { 294 DDP_STATINC(DDP_STAT_CANTFORWARD); 295 } else { 296 DDP_STATINC(DDP_STAT_FORWARD); 297 } 298 return; 299 } 300 from.sat_len = sizeof(struct sockaddr_at); 301 from.sat_family = AF_APPLETALK; 302 303 if (elh) { 304 m_adj(m, sizeof(struct ddpshdr)); 305 } else { 306 if (ddp_cksum && cksum && cksum != at_cksum(m, sizeof(int))) { 307 DDP_STATINC(DDP_STAT_BADSUM); 308 m_freem(m); 309 return; 310 } 311 m_adj(m, sizeof(struct ddpehdr)); 312 } 313 314 if ((ddp = ddp_search(&from, &to, aa)) == NULL) { 315 m_freem(m); 316 return; 317 } 318 if (sbappendaddr(&ddp->ddp_socket->so_rcv, (struct sockaddr *) & from, 319 m, (struct mbuf *) 0) == 0) { 320 DDP_STATINC(DDP_STAT_NOSOCKSPACE); 321 m_freem(m); 322 return; 323 } 324 #if IFA_STATS 325 if (aa) 326 aa->aa_ifa.ifa_data.ifad_inbytes += dlen; 327 #endif 328 sorwakeup(ddp->ddp_socket); 329 } 330 331 #if 0 332 333 #define BPXLEN 48 334 #define BPALEN 16 335 #include <ctype.h> 336 337 static void 338 bprint(char *data, int len) 339 { 340 char xout[BPXLEN], aout[BPALEN]; 341 int i = 0; 342 343 memset(xout, 0, BPXLEN); 344 memset(aout, 0, BPALEN); 345 346 for (;;) { 347 if (len < 1) { 348 if (i != 0) { 349 printf("%s\t%s\n", xout, aout); 350 } 351 printf("%s\n", "(end)"); 352 break; 353 } 354 xout[(i * 3)] = hexdigits[(*data & 0xf0) >> 4]; 355 xout[(i * 3) + 1] = hexdigits[*data & 0x0f]; 356 357 if ((u_char) * data < 0x7f && (u_char) * data > 0x20) { 358 aout[i] = *data; 359 } else { 360 aout[i] = '.'; 361 } 362 363 xout[(i * 3) + 2] = ' '; 364 365 i++; 366 len--; 367 data++; 368 369 if (i > BPALEN - 2) { 370 printf("%s\t%s\n", xout, aout); 371 memset(xout, 0, BPXLEN); 372 memset(aout, 0, BPALEN); 373 i = 0; 374 continue; 375 } 376 } 377 } 378 379 static void 380 m_printm(struct mbuf *m) 381 { 382 for (; m; m = m->m_next) 383 bprint(mtod(m, char *), m->m_len); 384 } 385 #endif 386