/* * @(#) $Id: rsvp_maps.c,v 4.9 1998/08/17 20:52:33 mtalwar Exp $ */ /************************ rsvp_maps.c ******************************* * * * Packet map and routines * * * *********************************************************************/ /**************************************************************************** RSVPD -- ReSerVation Protocol Daemon USC Information Sciences Institute Marina del Rey, California Original Version: Shai Herzog, Nov. 1993. Current Version: Steven Berson & Bob Braden, May 1996. Copyright (c) 1996 by the University of Southern California All rights reserved. Permission to use, copy, modify, and distribute this software and its documentation in source and binary forms for any purpose and without fee is hereby granted, provided that both the above copyright notice and this permission notice appear in all copies, and that any documentation, advertising materials, and other materials related to such distribution and use acknowledge that the software was developed in part by the University of Southern California, Information Sciences Institute. The name of the University may not be used to endorse or promote products derived from this software without specific prior written permission. THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about the suitability of this software for any purpose. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Other copyrights might apply to parts of this software and are so noted when applicable. ********************************************************************/ #include "rsvp_daemon.h" extern Fobject * copy_obj2Fobj(Object_header *); extern void FQins(Fobject *, Fobject **); extern void FQkill(Fobject **); static int send_msgto(int, net_addr *, net_addr *,struct packet *); static void build_base(struct packet *); static void build_obj2pkt(Object_header *, struct packet *); static int rsvp_map_packet(struct packet *); static int check_version_sum(struct packet *pkt); static u_int16_t in_cksum(u_char *, int); #ifdef SECURITY extern int check_integrity(struct packet *); extern void set_integrity(struct packet *, int); extern void fin_integrity(struct packet *); #else /* SECURITY */ static int check_integrity(struct packet *); static void set_integrity(struct packet *, int); static void fin_integrity(struct packet *); #endif /* SECURITY */ char *Type_name[] = {"", "PATH ", "RESV ", "PATH-ERR", "RESV-ERR", "PATH-TEAR", "RESV-TEAR", "RCONFIRM", "", "DREQ", "DREP"}; /* * build_send_pkt(): Build RSVP message from a given packet map, and send it. */ int build_send_pkt( int vif, net_addr *to, net_addr *src, struct packet *opkt) { struct packet lpkt, *pkt = &lpkt; char buff[MAX_PKT+IPUDP_HDR_AREA_SIZE]; packet_map *mapp = opkt->pkt_map; FlowDesc *flwdp; SenderDesc *sdscp; #ifdef RSVP_DIAGS DIAG_RESPONSE *resp; #endif int i; assert(opkt->pkt_order == BO_HOST); *pkt = *opkt; /* Local copy of packet struct */ pkt->pkt_data = (common_header *) (buff+IPUDP_HDR_AREA_SIZE); /* If we need an INTEGRITY object, add it to the map and * initialize it. Then build fixed part of packet from map. * Then, if there is INTEGRITY object, point map to object * in packet (whihc must come immediately after common hdr). */ set_integrity(pkt, vif); build_base(pkt); if (mapp->rsvp_integrity) pkt->pkt_map->rsvp_integrity = (INTEGRITY *) (1 + pkt->pkt_data); pkt->pkt_flags &= ~PKTFLG_Send_RA; switch (mapp->rsvp_msgtype) { case RSVP_CONFIRM: /* Confirm: send Router Alert Option */ pkt->pkt_flags |= PKTFLG_Send_RA; case RSVP_RESV: case RSVP_RESV_ERR: case RSVP_RESV_TEAR: switch (Style(pkt)) { case STYLE_WF: flwdp = FlowDesc_of(pkt, 0); build_obj2pkt(Object_of(flwdp->rsvp_specp), pkt); break; case STYLE_FF: for (i= 0; i < mapp->rsvp_nlist; i++) { int size; flwdp = FlowDesc_of(pkt, i); size = FlowDesc_size(flwdp); if (size + pkt->pkt_len > Max_rsvp_msg) { /* This rudimentary semantic fragmentation * code is an obsolete remnant, which is * left here as a place-holder. */ if (send_msgto(vif, to, src, pkt)<0) return(-1); build_base(pkt); } build_obj2pkt(Object_of(flwdp->rsvp_specp), pkt); build_obj2pkt(Object_of(flwdp->rsvp_filtp), pkt); #ifdef LABEL if(flwdp->rsvp_label) build_obj2pkt(Object_of(flwdp->rsvp_label), pkt); #endif } break; case STYLE_SE: flwdp = FlowDesc_of(pkt, 0); build_obj2pkt(Object_of(flwdp->rsvp_specp), pkt); for (i= 0; i < mapp->rsvp_nlist; i++) { flwdp = FlowDesc_of(pkt, i); build_obj2pkt(Object_of(flwdp->rsvp_filtp), pkt); } break; } break; case RSVP_PATH: case RSVP_PATH_TEAR: /* Path or Path_Tear: send Router Alert Option */ pkt->pkt_flags |= PKTFLG_Send_RA; case RSVP_PATH_ERR: sdscp = SenderDesc_of(pkt); build_obj2pkt(Object_of(sdscp->rsvp_stempl), pkt); #ifdef LABEL build_obj2pkt(Object_of(sdscp->rsvp_label), pkt); #endif build_obj2pkt(Object_of(sdscp->rsvp_stspec), pkt); build_obj2pkt(Object_of(sdscp->rsvp_adspec), pkt); break; #ifdef RSVP_DIAGS case RSVP_DREQ: case RSVP_DREP: if (DIAG_HBIT(mapp->rsvp_diag) == 1) build_obj2pkt(Object_of(pkt->pkt_map->rsvp_route),pkt); resp = mapp->rsvp_diag_response; for (i= 0; i < mapp->rsvp_resplist; i++) { build_obj2pkt(Object_of(resp), pkt); (char *)resp += Obj_Length(resp); } break; #endif default: assert(0); break; } return (send_msgto(vif, to, src, pkt)); } /* * send_msgto(): Given an RSVP message, complete its common header, * convert it to network byte order, compute a checksum, and send it. */ static int send_msgto( int vif, net_addr *to, net_addr *src, struct packet *pkt) { common_header *hdrp = pkt->pkt_data; assert(pkt->pkt_order == BO_HOST); /* * Complete common header and convert to network byte order */ memset((char *)hdrp, 0, sizeof(common_header)); hdrp->rsvp_verflags = RSVP_MAKE_VERFLAGS(RSVP_VERSION, 0); hdrp->rsvp_type = pkt->pkt_map->rsvp_msgtype; hdrp->rsvp_length = pkt->pkt_len; hton_packet(pkt); assert(pkt->pkt_order == BO_NET); /* * Set ttl in common header and, either checksum packet * or, if there is INTEGRITY object, compute digest. */ hdrp->rsvp_snd_TTL = pkt->pkt_ttl; hdrp->rsvp_cksum = 0; if (pkt->pkt_map->rsvp_integrity) fin_integrity(pkt); else hdrp->rsvp_cksum = in_cksum((u_int8_t *)pkt->pkt_data, pkt->pkt_len); return do_sendmsg(vif, to, src, pkt->pkt_flags, pkt->pkt_ttl, (u_char *) pkt->pkt_data, pkt->pkt_len); } /* build_base(): Start building new packet from given map. * * o Initialize pkt len to size of common header; this field * will be used for bookkeeping as the variable part of the * packet is built. * o Copy objects into packet from fixed part of map. * o Copy unknown objects into packet * (Note that we have lost any order information...) * o Set byte order to HOST. */ static void build_base(struct packet *pkt) { Object_header **mappp, *pktp; Fobject *fobjp; pkt->pkt_len = sizeof(common_header); pktp = (Object_header *) ((common_header *) pkt->pkt_data + 1); mappp = (Object_header **) &pkt->pkt_map->rsvp_diag; #ifdef EX_ROUTE /* * The argument of the while function was changed for making * explicit routing work. The pkt_map structure has more objects than before. */ if (pkt->pkt_map->rsvp_label){ while (mappp <= (Object_header **) &pkt->pkt_map->rsvp_label) { if (*mappp) build_obj2pkt(*mappp, pkt); mappp++; } } else { if(pkt->pkt_map->rsvp_exroute){ while (mappp <= (Object_header **) &pkt->pkt_map->rsvp_exroute) { if (*mappp) build_obj2pkt(*mappp, pkt); mappp++; } } else { while (mappp <= (Object_header **) &pkt->pkt_map->rsvp_style) { if (*mappp) build_obj2pkt(*mappp, pkt); mappp++; } } } #else while (mappp <= (Object_header **) &pkt->pkt_map->rsvp_style) { if (*mappp) build_obj2pkt(*mappp, pkt); mappp++; } #endif for (fobjp = pkt->pkt_map->rsvp_UnkObjList; fobjp; fobjp = fobjp->Fobj_next) { if (fobjp) build_obj2pkt(&fobjp->Fobj_objhdr, pkt); } pkt->pkt_order = BO_HOST; } /* built_obj2pkt(): Move object *objp into packet buffer at offset * determined from pkt_len field in packet structure, and * advance pkt_len field. */ static void build_obj2pkt(Object_header *objp, struct packet *pkt) { Object_header *pktp; if (objp && (Object_Size(objp) > 0) ) { pktp = (Object_header *) ((char *) pkt->pkt_data + pkt->pkt_len); move_object(objp, pktp); pkt->pkt_len += Obj_Length(pktp); } } /* Check version and checksum in incoming packet, converting * common header to host byte order in the process. Ignore * zero checksum. */ static int check_version_sum(struct packet *pkt) { int pkt_version = RSVP_VERSION_OF(pkt->pkt_data); int rerrno; assert(pkt->pkt_order == BO_NET); /* * Check version, checksum (if non-zero), and length. */ if (pkt_version != RSVP_VERSION) { log(LOG_WARNING, 0, "Bad pkt version #%d\n", pkt_version); return PKT_ERR_VERSION; } if ((pkt->pkt_data->rsvp_cksum) && in_cksum((u_char *) pkt->pkt_data, pkt->pkt_len)) { log(LOG_WARNING, 0, "Checksum error\n"); return PKT_ERR_CKSUM; } /* Make one pass over the raw packet (in network format) stopping * if/when the integrity object is found. Since the integrity * object is one of the first in the packet, this would make an * extra pass over the entire packet only if no integrity object * is included. */ rerrno = check_integrity(pkt); if (rerrno < 0) /* Integrity Error */ return rerrno; NTOH16(pkt->pkt_data->rsvp_length); if (pkt->pkt_data->rsvp_length != pkt->pkt_len) { log(LOG_WARNING, 0, "Pkt length wrong (%u)\n", pkt->pkt_len); return PKT_ERR_LENGTH; } return PKT_OK; } /* * rsvp_pkt_map(): Build packet map from RSVP message. */ int rsvp_pkt_map(struct packet *pkt) { int rerrno = PKT_OK; packet_map *mapp = pkt->pkt_map; /* If this packet was received from the network (ie if it is * in NET byte order), do basic input processing. Otherwise, * it came from API and the map is already built. * * Verify version number and RSVP checksum, and discard * message if any mismatch is found. * * Parse packet and construct map, converting objects to host * byte order. Note that rsvp_map_packet() call may do mallocs * for policy or unknown class objects. */ if (pkt->pkt_order == BO_NET) { memset((char *) mapp, 0, sizeof(packet_map)); rerrno = check_version_sum(pkt); if (rerrno != PKT_OK) return(rerrno); rerrno = rsvp_map_packet(pkt); } return(rerrno); } /* * rsvp_map_packet(): Given input packet and map vector pointed to * by packet structure, parse the packet and build a map of * it, converting the packet to host byte order as we go. * Returns PKT_OK (0) or negative PKT_ERR_.... or positive * errno (if unknown object class). */ static int rsvp_map_packet(struct packet *pkt) { common_header *hdrp = pkt->pkt_data; packet_map *mapp = pkt->pkt_map; char *end_of_data = (char *) pkt->pkt_data + pkt->pkt_len; Object_header *objp; style_t optvec = 0; FlowDesc *flwdp = NULL; SenderDesc *sdscp = SenderDesc_of(pkt); FLOWSPEC *Last_specp = NULL; Fobject *Fobjp; mapp->rsvp_msgtype = RSVP_TYPE_OF(pkt->pkt_data); if ((mapp->rsvp_msgtype < 1) || (mapp->rsvp_msgtype > RSVP_MAX_MSGTYPE)) return(PKT_ERR_MSGTYPE); objp = (Object_header *) (hdrp + 1); while (objp < (Object_header *)end_of_data) { #if BYTE_ORDER == LITTLE_ENDIAN ntoh_object(objp); #endif if ((Obj_Length(objp)&3) || Obj_Length(objp)<4 || (char *)Next_Object(objp) > end_of_data){ return PKT_ERR_OBJLEN; } switch (Obj_Class(objp)) { case class_NULL: /* Ignore it */ break; #ifdef RSVP_DIAGS case class_DIAGNOSTIC: mapp->rsvp_diag = (DIAGNOSTIC *) objp; break; case class_ROUTE: mapp->rsvp_route = (ROUTE *) objp; break; case class_DIAG_RESPONSE: if(!mapp->rsvp_diag_response) mapp->rsvp_diag_response = (DIAG_RESPONSE *)objp; mapp->rsvp_resplist++; break; #endif case class_SESSION: mapp->rsvp_session = (SESSION *) objp; break; /*********** OBSOLETE case class_SESSION_GROUP: mapp->rsvp_sess_grp = (SESSION_GROUP *) objp; break; ***********/ case class_RSVP_HOP: mapp->rsvp_hop = (RSVP_HOP *) objp; break; case class_INTEGRITY: mapp->rsvp_integrity = (INTEGRITY *) objp; break; case class_TIME_VALUES: mapp->rsvp_timev = (TIME_VALUES *) objp; break; case class_ERROR_SPEC: mapp->rsvp_errspec = (ERROR_SPEC *) objp; break; case class_SCOPE: mapp->rsvp_scope_list = (SCOPE *) objp; break; case class_STYLE: if (!IsResv(mapp)) return PKT_ERR_BADOBJ; mapp->rsvp_style = (STYLE *) objp; optvec = Style(pkt); break; case class_FLOWSPEC: /* Each flowspec begins new flow descriptor */ if (!IsResv(mapp)) return PKT_ERR_BADOBJ; flwdp = &mapp->rsvp_list[mapp->rsvp_nlist].Resv_list; Last_specp = flwdp->rsvp_specp = (FLOWSPEC *)objp; flwdp->rsvp_filtp = NULL; #ifdef LABEL flwdp->rsvp_label = NULL; #endif break; case class_FILTER_SPEC: if (!IsResv(mapp)) return PKT_ERR_BADOBJ; flwdp = &mapp->rsvp_list[mapp->rsvp_nlist++].Resv_list; flwdp->rsvp_filtp = (FILTER_SPEC *)objp; if (flwdp->rsvp_specp == NULL && mapp->rsvp_msgtype != RSVP_RESV_TEAR) { if (mapp->rsvp_nlist == 0) return PKT_ERR_ORDER; /* First must be flowspec */ if (optvec == STYLE_FF) flwdp->rsvp_specp = Last_specp; /* FF: Flowspec ellided -- use last */ } flwdp = &mapp->rsvp_list[mapp->rsvp_nlist].Resv_list; flwdp->rsvp_specp = NULL; #ifdef LABEL flwdp->rsvp_label = NULL; #endif break; #ifdef LABEL case class_Label: if (IsResv(mapp)){ flwdp = &mapp->rsvp_list[(mapp->rsvp_nlist)-1].Resv_list; flwdp->rsvp_label = (Label *)objp; } if(IsPath(mapp)) { if(Obj_CType((Label *)objp) == ctype_Labelreq) mapp->rsvp_label = (Labelreq *) objp; else sdscp->rsvp_label = (Label *) objp; } break; case class_Label_Request: if(IsPath(mapp)) mapp->rsvp_label = (Labelreq *) objp; break; #endif case class_SENDER_TEMPLATE: if (!IsPath(mapp)) return PKT_ERR_BADOBJ; if (mapp->rsvp_nlist > 0) return PKT_ERR_BADOBJ; mapp->rsvp_nlist = 1; sdscp->rsvp_stempl = (SENDER_TEMPLATE *) objp; break; case class_SENDER_TSPEC: if (!IsPath(mapp)) return PKT_ERR_BADOBJ; /* Could test for duplicate Sender_Tspec or Adspec... * instead, just take the last one that is found. */ sdscp->rsvp_stspec = (SENDER_TSPEC *) objp; break; case class_ADSPEC: if (!IsPath(mapp)) return PKT_ERR_BADOBJ; sdscp->rsvp_adspec = (ADSPEC *) objp; break; case class_POLICY_DATA: /* Save policy objects in list of framed objects */ Fobjp = copy_obj2Fobj(objp); if (!Fobjp) { Log_Mem_Full("PD obj"); break; } FQins(Fobjp, &mapp->rsvp_dpolicy); break; #ifdef EX_ROUTE /* * This function determines the EXROUTE object out of the * packet structure. */ case class_EXROUTE_DATA: mapp->rsvp_exroute = (EXROUTE *) objp; break; #endif case class_RECORD_ROUTE: break; case class_CONFIRM: mapp->rsvp_confirm = (CONFIRM *) objp; break; default: /* Unknown object class. Look at high-order * bits to decide what to do. */ switch (Obj_Class(objp) & UNKN_CLASS_MASK) { case 0x00: case 0x40: /* Reject message. Return * code, val=(class,ctype) */ return (Set_Errno(RSVP_Err_UNKN_OBJ_CLASS, ((Obj_Class(objp)<<8)|Obj_CType(objp)))); case 0x80: /* Ignore object */ break; case 0xc0: /* Save and forward object. Copy it into * a framed object and add to end of list. */ Fobjp = copy_obj2Fobj(objp); if (!Fobjp) { Log_Mem_Full("Unk Class obj"); break; } FQins(Fobjp, &mapp->rsvp_UnkObjList); break; } log(LOG_WARNING, 0, "Unknown class %d ctype %d\n", Obj_Class(objp), Obj_CType(objp)); break; } objp = Next_Object(objp); } if (objp != (Object_header *)end_of_data) { log(LOG_WARNING, 0, "Hdr len err: %d\n", (char *)objp - (char *) end_of_data); return PKT_ERR_LENGTH; } pkt->pkt_order = BO_HOST; if (!(mapp->rsvp_session)) return PKT_ERR_NOSESS; /* * Do style-dependent processing of Resv-type msg */ if (IsResv(mapp)) { switch (optvec) { case 0: /* Error: missing style */ return PKT_ERR_NOSTYLE; case STYLE_WF: if (flwdp) { /* Found a flowspec => msg not empty */ mapp->rsvp_nlist = 1; flwdp->rsvp_filtp = NULL; } break; case STYLE_SE: case STYLE_FF: break; default: /* Error message sent at higher level */ break; } } return PKT_OK; } /* * Compute TCP/UDP/IP checksum. * See p. 7 of RFC-1071. */ static u_int16_t in_cksum(u_int8_t *bp, int n) { u_int16_t *sp = (u_int16_t *) bp; u_int32_t sum = 0; /* Sum half-words */ while (n>1) { sum += *sp++; n -= 2; } /* Add left-over byte, if any */ if (n>0) sum += * (char *) sp; /* Fold 32-bit sum to 16 bits */ sum = (sum & 0xFFFF) + (sum >> 16); sum = ~(sum + (sum >> 16)) & 0xFFFF; if (sum == 0xffff) sum = 0; return (u_int16_t)sum; } #ifndef SECURITY static int check_integrity(struct packet *pkt) { return(1); } /* * set_integrity() * Initialize INTEGRITY object, if one is required, for * sending packet through specified vif. */ static void set_integrity(struct packet *pkt, int vif, net_addr *scrp) { } /* * fin_integrity() * Compute crypto digest over given packet and complete * the INTEGRITY object. */ static void fin_integrity(struct packet *pkt) { } #endif /* SECURITY */ void net_error(net_error_type type,char *s) { switch (type) { case NET_ERROR_SYSTEM: log(LOG_ERR,errno,s); return; case NET_ERROR_USER: default: log(LOG_INFO,0,s); return; } }