1 /* $NetBSD: ddp_input.c,v 1.17 2007/12/21 02:46:37 dyoung 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.17 2007/12/21 02:46:37 dyoung 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/at_extern.h> 50 51 int ddp_forward = 1; 52 int ddp_firewall = 0; 53 extern int ddp_cksum; 54 void ddp_input __P((struct mbuf *, struct ifnet *, 55 struct elaphdr *, int)); 56 57 /* 58 * Could probably merge these two code segments a little better... 59 */ 60 void 61 atintr() 62 { 63 struct elaphdr *elhp, elh; 64 struct ifnet *ifp; 65 struct mbuf *m; 66 struct at_ifaddr *aa; 67 int s; 68 69 for (;;) { 70 s = splnet(); 71 72 IF_DEQUEUE(&atintrq2, m); 73 74 splx(s); 75 76 if (m == 0) /* no more queued packets */ 77 break; 78 79 m_claimm(m, &atalk_rx_mowner); 80 ifp = m->m_pkthdr.rcvif; 81 for (aa = at_ifaddr.tqh_first; aa; aa = aa->aa_list.tqe_next) { 82 if (aa->aa_ifp == ifp && (aa->aa_flags & AFA_PHASE2)) 83 break; 84 } 85 if (aa == NULL) { /* ifp not an appletalk interface */ 86 m_freem(m); 87 continue; 88 } 89 ddp_input(m, ifp, (struct elaphdr *) NULL, 2); 90 } 91 92 for (;;) { 93 s = splnet(); 94 95 IF_DEQUEUE(&atintrq1, m); 96 97 splx(s); 98 99 if (m == 0) /* no more queued packets */ 100 101 break; 102 103 m_claimm(m, &atalk_rx_mowner); 104 ifp = m->m_pkthdr.rcvif; 105 for (aa = at_ifaddr.tqh_first; aa; aa = aa->aa_list.tqe_next) { 106 if (aa->aa_ifp == ifp && 107 (aa->aa_flags & AFA_PHASE2) == 0) 108 break; 109 } 110 if (aa == NULL) { /* ifp not an appletalk interface */ 111 m_freem(m); 112 continue; 113 } 114 if (m->m_len < SZ_ELAPHDR && 115 ((m = m_pullup(m, SZ_ELAPHDR)) == 0)) { 116 ddpstat.ddps_tooshort++; 117 continue; 118 } 119 elhp = mtod(m, struct elaphdr *); 120 m_adj(m, SZ_ELAPHDR); 121 122 if (elhp->el_type == ELAP_DDPEXTEND) { 123 ddp_input(m, ifp, (struct elaphdr *) NULL, 1); 124 } else { 125 bcopy((void *) elhp, (void *) & elh, SZ_ELAPHDR); 126 ddp_input(m, ifp, &elh, 1); 127 } 128 } 129 } 130 131 struct route forwro; 132 133 void 134 ddp_input(m, ifp, elh, phase) 135 struct mbuf *m; 136 struct ifnet *ifp; 137 struct elaphdr *elh; 138 int phase; 139 { 140 struct rtentry *rt; 141 struct sockaddr_at from, to; 142 struct ddpshdr *dsh, ddps; 143 struct at_ifaddr *aa; 144 struct ddpehdr *deh = NULL, ddpe; 145 struct ddpcb *ddp; 146 int dlen, mlen; 147 u_short cksum = 0; 148 union { 149 struct sockaddr dst; 150 struct sockaddr_at dsta; 151 } u; 152 153 bzero((void *) & from, sizeof(struct sockaddr_at)); 154 if (elh) { 155 ddpstat.ddps_short++; 156 157 if (m->m_len < sizeof(struct ddpshdr) && 158 ((m = m_pullup(m, sizeof(struct ddpshdr))) == 0)) { 159 ddpstat.ddps_tooshort++; 160 return; 161 } 162 dsh = mtod(m, struct ddpshdr *); 163 bcopy((void *) dsh, (void *) & ddps, sizeof(struct ddpshdr)); 164 ddps.dsh_bytes = ntohl(ddps.dsh_bytes); 165 dlen = ddps.dsh_len; 166 167 to.sat_addr.s_net = ATADDR_ANYNET; 168 to.sat_addr.s_node = elh->el_dnode; 169 to.sat_port = ddps.dsh_dport; 170 from.sat_addr.s_net = ATADDR_ANYNET; 171 from.sat_addr.s_node = elh->el_snode; 172 from.sat_port = ddps.dsh_sport; 173 174 for (aa = at_ifaddr.tqh_first; aa; aa = aa->aa_list.tqe_next) { 175 if (aa->aa_ifp == ifp && 176 (aa->aa_flags & AFA_PHASE2) == 0 && 177 (AA_SAT(aa)->sat_addr.s_node == 178 to.sat_addr.s_node || 179 to.sat_addr.s_node == ATADDR_BCAST)) 180 break; 181 } 182 if (aa == NULL) { 183 m_freem(m); 184 return; 185 } 186 } else { 187 ddpstat.ddps_long++; 188 189 if (m->m_len < sizeof(struct ddpehdr) && 190 ((m = m_pullup(m, sizeof(struct ddpehdr))) == 0)) { 191 ddpstat.ddps_tooshort++; 192 return; 193 } 194 deh = mtod(m, struct ddpehdr *); 195 bcopy((void *) deh, (void *) & ddpe, sizeof(struct ddpehdr)); 196 ddpe.deh_bytes = ntohl(ddpe.deh_bytes); 197 dlen = ddpe.deh_len; 198 199 if ((cksum = ddpe.deh_sum) == 0) { 200 ddpstat.ddps_nosum++; 201 } 202 from.sat_addr.s_net = ddpe.deh_snet; 203 from.sat_addr.s_node = ddpe.deh_snode; 204 from.sat_port = ddpe.deh_sport; 205 to.sat_addr.s_net = ddpe.deh_dnet; 206 to.sat_addr.s_node = ddpe.deh_dnode; 207 to.sat_port = ddpe.deh_dport; 208 209 if (to.sat_addr.s_net == ATADDR_ANYNET) { 210 for (aa = at_ifaddr.tqh_first; aa; 211 aa = aa->aa_list.tqe_next) { 212 if (phase == 1 && (aa->aa_flags & AFA_PHASE2)) 213 continue; 214 215 if (phase == 2 && 216 (aa->aa_flags & AFA_PHASE2) == 0) 217 continue; 218 219 if (aa->aa_ifp == ifp && 220 (AA_SAT(aa)->sat_addr.s_node == 221 to.sat_addr.s_node || 222 to.sat_addr.s_node == ATADDR_BCAST || 223 (ifp->if_flags & IFF_LOOPBACK))) 224 break; 225 } 226 } else { 227 for (aa = at_ifaddr.tqh_first; aa; 228 aa = aa->aa_list.tqe_next) { 229 if (to.sat_addr.s_net == aa->aa_firstnet && 230 to.sat_addr.s_node == 0) 231 break; 232 233 if ((ntohs(to.sat_addr.s_net) < 234 ntohs(aa->aa_firstnet) || 235 ntohs(to.sat_addr.s_net) > 236 ntohs(aa->aa_lastnet)) && 237 (ntohs(to.sat_addr.s_net) < 0xff00 || 238 ntohs(to.sat_addr.s_net) > 0xfffe)) 239 continue; 240 241 if (to.sat_addr.s_node != 242 AA_SAT(aa)->sat_addr.s_node && 243 to.sat_addr.s_node != ATADDR_BCAST) 244 continue; 245 246 break; 247 } 248 } 249 } 250 251 /* 252 * Adjust the length, removing any padding that may have been added 253 * at a link layer. We do this before we attempt to forward a packet, 254 * possibly on a different media. 255 */ 256 mlen = m->m_pkthdr.len; 257 if (mlen < dlen) { 258 ddpstat.ddps_toosmall++; 259 m_freem(m); 260 return; 261 } 262 if (mlen > dlen) { 263 m_adj(m, dlen - mlen); 264 } 265 /* 266 * XXX Should we deliver broadcasts locally, also, or rely on the 267 * link layer to give us a copy? For the moment, the latter. 268 */ 269 if (aa == NULL || (to.sat_addr.s_node == ATADDR_BCAST && 270 aa->aa_ifp != ifp && (ifp->if_flags & IFF_LOOPBACK) == 0)) { 271 if (ddp_forward == 0) { 272 m_freem(m); 273 return; 274 } 275 sockaddr_at_init(&u.dsta, &to.sat_addr, 0); 276 rt = rtcache_lookup(&forwro, &u.dst); 277 #if 0 /* XXX The if-condition is always false. What was this 278 * actually trying to test? 279 */ 280 if (to.sat_addr.s_net != 281 satocsat(rtcache_getdst(&forwro))->sat_addr.s_net && 282 ddpe.deh_hops == DDP_MAXHOPS) { 283 m_freem(m); 284 return; 285 } 286 #endif 287 if (ddp_firewall && (rt == NULL || rt->rt_ifp != ifp)) { 288 m_freem(m); 289 return; 290 } 291 ddpe.deh_hops++; 292 ddpe.deh_bytes = htonl(ddpe.deh_bytes); 293 bcopy((void *) & ddpe, (void *) deh, sizeof(u_short));/*XXX*/ 294 if (ddp_route(m, &forwro)) { 295 ddpstat.ddps_cantforward++; 296 } else { 297 ddpstat.ddps_forward++; 298 } 299 return; 300 } 301 from.sat_len = sizeof(struct sockaddr_at); 302 from.sat_family = AF_APPLETALK; 303 304 if (elh) { 305 m_adj(m, sizeof(struct ddpshdr)); 306 } else { 307 if (ddp_cksum && cksum && cksum != at_cksum(m, sizeof(int))) { 308 ddpstat.ddps_badsum++; 309 m_freem(m); 310 return; 311 } 312 m_adj(m, sizeof(struct ddpehdr)); 313 } 314 315 if ((ddp = ddp_search(&from, &to, aa)) == NULL) { 316 m_freem(m); 317 return; 318 } 319 if (sbappendaddr(&ddp->ddp_socket->so_rcv, (struct sockaddr *) & from, 320 m, (struct mbuf *) 0) == 0) { 321 ddpstat.ddps_nosockspace++; 322 m_freem(m); 323 return; 324 } 325 #if IFA_STATS 326 if (aa) 327 aa->aa_ifa.ifa_data.ifad_inbytes += dlen; 328 #endif 329 sorwakeup(ddp->ddp_socket); 330 } 331 332 #if 0 333 334 #define BPXLEN 48 335 #define BPALEN 16 336 #include <ctype.h> 337 338 static void 339 bprint(data, len) 340 char *data; 341 int len; 342 { 343 char xout[BPXLEN], aout[BPALEN]; 344 int i = 0; 345 346 bzero(xout, BPXLEN); 347 bzero(aout, BPALEN); 348 349 for (;;) { 350 if (len < 1) { 351 if (i != 0) { 352 printf("%s\t%s\n", xout, aout); 353 } 354 printf("%s\n", "(end)"); 355 break; 356 } 357 xout[(i * 3)] = hexdigits[(*data & 0xf0) >> 4]; 358 xout[(i * 3) + 1] = hexdigits[*data & 0x0f]; 359 360 if ((u_char) * data < 0x7f && (u_char) * data > 0x20) { 361 aout[i] = *data; 362 } else { 363 aout[i] = '.'; 364 } 365 366 xout[(i * 3) + 2] = ' '; 367 368 i++; 369 len--; 370 data++; 371 372 if (i > BPALEN - 2) { 373 printf("%s\t%s\n", xout, aout); 374 bzero(xout, BPXLEN); 375 bzero(aout, BPALEN); 376 i = 0; 377 continue; 378 } 379 } 380 } 381 382 static void 383 m_printm(m) 384 struct mbuf *m; 385 { 386 for (; m; m = m->m_next) 387 bprint(mtod(m, char *), m->m_len); 388 } 389 #endif 390