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