/* * @(#) $Id: rsvp_api.c,v 4.43 1998/08/19 19:45:34 lindell Exp $ */ /************************ rsvp_api.c ******************************** * * * Routines to handle application program interface of rsvpd * * messages. * * * * * *********************************************************************/ /**************************************************************************** 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" #include "rsvp_api.h" #include "rapi_lib.h" #include /* external declarations */ int refresh_api(); void rsvp_resv_err(int, int, int, FiltSpecStar *, struct packet *); void rsvp_path_err(int, int, int, struct packet *); u_long Styleid_to_Optvec[]; int writev(); extern char *style_names[]; void rapi_fmt_flowspec(rapi_flowspec_t *, char *, int); void rapi_fmt_tspec(rapi_tspec_t *, char *, int); void rapi_fmt_adspec(rapi_adspec_t *, char *, int); void rapi_fmt_filtspec(rapi_filter_t *, char *, int); int New_Adspec(ADSPEC *); Session * locate_session(SESSION *); char * cnv_flags(char *, u_char); int api_refresh_t; /* forward declarations */ static void send_to_api(int, rsvp_resp *, int); static void print_api_request(rsvp_req *, int, int); void api_PATH_EVENT_upcall(Session *); void api_PATH_EVENT_init(Session *, int); void api_PATH_EVENT_upcall1(Session *, int, int); void api_RESV_EVENT_upcall(Session *, RSB *); void api_RESV_EVENT_upcall_stat(Session *, RSB *); void api_RESV_EVENT_upcall1(Session *, RSB *, int); void api_PATH_ERR_upcall(struct packet *); void api_RESV_ERR_upcall(struct packet *); static void upcall_to_appl(rsvp_resp *, int, FILTER_SPEC *, int); static void upcall_to_sid(rsvp_resp *, int, int); int api_prepare_path(rsvp_req *, int, api_rec *, struct packet *); int api_prepare_resv(rsvp_req *, api_rec *, struct packet *); int api_new_packet(struct packet *, int, int); int api_tear_oldresv(struct packet *, struct packet *); int api_status(rsvp_req *); int api_dest_status(Session *, rsvp_req *); int api_get_flows(Object_header *, rsvp_req *, struct packet *); int Move_spec_api2d(rapi_flowspec_t *, FLOWSPEC *); char * Move_spec_d2api(FLOWSPEC *, rapi_flowspec_t *); int Move_tspec_api2d(rapi_tspec_t *, SENDER_TSPEC *); char * Move_tspec_d2api(SENDER_TSPEC *, rapi_tspec_t *); int Move_adspec_api2d(rapi_adspec_t *, ADSPEC *); char * Move_adspec_d2api(ADSPEC *, rapi_adspec_t *); int Move_filter_api2d(rapi_filter_t *, FILTER_SPEC *, int); char * Move_filter_d2api(FILTER_SPEC *, rapi_filter_t *); Session * locate_api_session(rsvp_req *, int); void log_api_event(int, char *, net_addr *, int, const char *, int, int); void api_tear_path(api_rec *); void api_tear_resv(api_rec *); void api_free_packet(struct packet *); void api_ERR_upcall_common(rsvp_resp *, struct packet *); int path_set_laddr(rapi_filter_t *); void hton_api_resp(rsvp_resp *, int); int ntoh_rapi_flowspec(IS_specbody_t *); int hton_rapi_flowspec(IS_specbody_t *); int ntoh_rapi_adspec(IS_adsbody_t *); int hton_rapi_adspec(IS_adsbody_t *); static int resp_session_assign(rsvp_resp *resp, SESSION *session); int net_addr_assign_api_addr(net_addr *addr,const api_addr *x, int udp); /* Macro used in api_prepare_xxxx to add an object to API packet and * to the map of the packet. The map address is 'var'; the object * has class (typedef) 'cls' and ctype (value) 'ctype'. */ #define New_Object(var, cls, ctype) \ Init_Object(objp, cls, ctype); \ var = (cls *) objp; \ objp = Next_Object(objp); #define New_VObject(var, cls, ctype, len) \ Init_Var_Obj(objp, cls, ctype,len); \ var = (cls *) objp; \ objp = Next_Object(objp); /* * Array to translate style ID into option vector */ u_long Styleid_to_Optvec [] = {/* 0 unused */ 0, /* 1 WF */ STYLE_WF, /* 2 FF */ STYLE_FF, /* 3 SE */ STYLE_SE }; /* Define all-api-session value for session id parameter */ #define ALL_SID -1 /* * process_api_req(): Process request from API client, received over Unix * socket. Return -1 if API session should be closed. * sid = my local handle. */ int process_api_req(int sid, rsvp_req *req, int len) { api_rec *recp = &api_table[sid]; common_header *hdrp; struct packet new_pkt; int rc; Session *destp; if (IsDebug(DEBUG_ALL)) { print_api_request(req, len, sid); if (l_debug >= LOG_HEXD && len > 0) hexf(stderr, (char *) req, len); } if (len != 0 && (req->rq_version > VERSION_API || req->rq_version < VERSION_APImin)) { log(LOG_ERR, 0, "API: bad version %d\n", req->rq_version); return (-1); /* Close it */ } if (len == 0 || req->rq_type == API_CLOSE) { /* * Close: Session close requested, or client terminated. * If there is stored Path (Resv) message, turn it into a * PathTear (ResvTear) message and procsss it as input. */ api_tear_path(recp); api_tear_resv(recp); return(-1); /* Caller will delete session & timer */ } switch (req->rq_type) { case API2_REGISTER: /* REGISTER command handles 3 different functions: * (1) Session registration (nflwd=0 & no Path state) * (2) New Sender defn (nflwd=1) * (3) Teardown sender (nflwd=0, path state exists) */ net_addr_assign_api_addr(&recp->api_dest,&req->rq_dest,1); recp->api_protid = (req->rq_protid)?req->rq_protid: RSVP_DFLT_PROTID; if (req->rq_nflwd == 0) { /* * No sender descriptor => New registration * or teardown request */ hdrp = recp->api_p_packet.pkt_data; if (hdrp == NULL||hdrp->rsvp_type != RSVP_PATH) { /* * No path state exists => New session * registration. If there is already path * state, trigger path event upcall. */ recp->api_flags = req->rq_flags & ~(API_DIR_SEND|API_DIR_RECV|API_NET_BO); if (NetByteOrderReq(req)) recp->api_flags |= API_NET_BO; #if defined LABEL destp = locate_api_session(req, (recp->api_flags)); #else destp = locate_api_session(req, (recp->api_flags&RAPI_GPI_SESSION)); #endif if (destp) api_PATH_EVENT_init(destp, sid); return(0); /* None in place, just ignore */ } /* * Turn path state into PathTear message, send it, * and then free API packet buffer & map. If there * is no resv state either, stop refresh timer. */ recp->api_flags &= ~API_DIR_SEND; api_tear_path(recp); if (recp->api_r_packet.pkt_data == NULL) del_from_timer((char *) (unsigned long) sid, TIMEV_API); return(0); } /* else, we are registering a sender. Set up virtual Path * message. */ recp->api_flags |= API_DIR_SEND; hdrp = recp->api_p_packet.pkt_data; if (hdrp == NULL) { /* Allocate space for a packet buffer. (Use max * message size; could compute actual size) XXX */ if (api_new_packet(&recp->api_p_packet, 1, MAX_PKT) < 0) return(-1); } rc = api_prepare_path(req, len, recp, &recp->api_p_packet); if (rc == 0) { /* There was a client error. Delete packet. */ api_free_packet(&recp->api_p_packet); return(0); } else if (rc < 0) { /* There was internal error. Return -1 => caller * will close the API socket. */ return(-1); } recp->api_p_packet.pkt_ttl = recp->api_p_packet.pkt_data->rsvp_snd_TTL; /* * We finished updating API state, now handle the request * itself */ refresh_api(sid); break; case API2_RESV: /* Reservation request. */ hdrp = recp->api_r_packet.pkt_data; if (req->rq_nflwd == 0) { recp->api_flags &= ~API_DIR_RECV; /* * No flow descriptors => teardown request */ if (hdrp == NULL||hdrp->rsvp_type != RSVP_RESV) return(0); /* None in place, just ignore */ /* Send ResvTear and free Resv pkt buff and * map. If there is no path state either, stop * refresh timer. */ api_tear_resv(recp); if (recp->api_p_packet.pkt_data == NULL) del_from_timer((char *) (unsigned long) sid, TIMEV_API); return(0); } /* Initialize local packet struct with new data * buffer and map, then call api_prepare_resv() to * move request data into it. */ recp->api_flags |= API_DIR_RECV; if (api_new_packet(&new_pkt, req->rq_nflwd, Max_rsvp_msg) < 0) return(-1); rc = api_prepare_resv(req, recp, &new_pkt); if (rc == 0) { /* There was a client error. Delete packet. */ api_free_packet(&recp->api_r_packet); return(0); } else if (rc < 0) { /* There was internal error. Return -1 => caller * will close the API socket. */ return(-1); } /* If already have Resv, this is a modification; * tear down state that is being removed, and then * free old data buffer and map. */ if (hdrp) { if (api_tear_oldresv(&recp->api_r_packet, &new_pkt)<0) return(-1); } /* Move pointers to data and map into API record */ recp->api_r_packet.pkt_data = new_pkt.pkt_data; recp->api_r_packet.pkt_map = new_pkt.pkt_map; recp->api_r_packet.pkt_len = new_pkt.pkt_len; recp->api_r_packet.pkt_order = BO_HOST; recp->api_r_packet.pkt_flags = 0; recp->api_r_packet.pkt_ttl = 0; /* * We finished updating API state; now handle the request * itself */ refresh_api(sid); /* * Delete any CONFIRM object, which is single-shot. */ recp->api_r_packet.pkt_map->rsvp_confirm = NULL; break; default: log(LOG_ERR, 0, "API: Bad rq_type=%d\n", req->rq_type); return (-1); } add_to_timer((char *) sid, TIMEV_API, api_refresh_t); dump_ds(0); return (0); } /* Allocate new packet buffer and new map for API. * (Use max message size; could compute actual size) XXX */ int api_new_packet(struct packet *pkt, int nflwd, int data_len) { common_header *hdrp; packet_map *mapp; int map_len = Map_Length(nflwd); if ((hdrp = (common_header *) malloc(data_len))==NULL || (mapp = (packet_map *) malloc(map_len))==NULL) { Log_Mem_Full("API send/resv req"); return (-1); } pkt->pkt_offset = 0; pkt->pkt_map = mapp; pkt->pkt_data = hdrp; pkt->pkt_len = 0; pkt->pkt_flags = pkt->pkt_ttl = 0; pkt->pkt_order = BO_HOST; memset((char *)mapp, 0, sizeof(packet_map)); return(0); } void api_tear_path(api_rec *recp) { common_header *hdrp = recp->api_p_packet.pkt_data; if (!hdrp) return; hdrp->rsvp_type = RSVP_PATH_TEAR; recp->api_p_packet.pkt_map->rsvp_msgtype = RSVP_PATH_TEAR; rsvp_pkt_process(&recp->api_p_packet, NULL, api_num); api_free_packet(&recp->api_p_packet); } void api_tear_resv(api_rec *recp) { common_header *hdrp = recp->api_r_packet.pkt_data; if (!hdrp) return; hdrp->rsvp_type = RSVP_RESV_TEAR; recp->api_r_packet.pkt_map->rsvp_msgtype = RSVP_RESV_TEAR; /* * Note that the RSVP spec is designed to allow us to make a valid * ResvTear msg from a Resv msg, by just changing the message type. * We could explicitly delete the flowspec from the ResvTear, but * it's better to exercise the logic that ignores the flowspec. */ rsvp_pkt_process(&recp->api_r_packet, NULL, api_num); api_free_packet(&recp->api_r_packet); } void api_free_packet(struct packet *pkt) { if (pkt->pkt_data) free(pkt->pkt_data); if (pkt->pkt_map) free(pkt->pkt_map); pkt->pkt_data = NULL; pkt->pkt_map = NULL; pkt->pkt_len = 0; } /* Tear down API state in o_pkt that does not appear in n_pkt. */ int api_tear_oldresv(struct packet *o_pkt, struct packet *n_pkt) { int oi, oj, nk; style_t style = Style(o_pkt); o_pkt->pkt_map->rsvp_msgtype = RSVP_RESV_TEAR; if (style != Style(n_pkt)) { /* Styles differ. Just tear down old Resv. */ rsvp_pkt_process(o_pkt, NULL, api_num); api_free_packet(o_pkt); return(0); } /* Rebuild old packet map to include only those filter * specs that don't match new packet map. If any filter * specs remain, send old packet as ResvTear. */ oj = 0; for (oi = 0; oi < o_pkt->rsvp_nflwd; oi++) { FILTER_SPEC *o_filtp = filter_of(FlowDesc_of(o_pkt, oi)); for (nk = 0; nk < n_pkt->rsvp_nflwd; nk++) { if (match_filter(o_filtp, filter_of(FlowDesc_of(n_pkt, nk)))) break; } if (nk == n_pkt->rsvp_nflwd) { /* No match, filter should be torn down. */ if (!Style_is_Shared(style)) spec_of(FlowDesc_of(o_pkt, oj)) = spec_of(FlowDesc_of(o_pkt, oi)); filter_of(FlowDesc_of(o_pkt, oj++)) = filter_of(FlowDesc_of(o_pkt, oi)); } } if (oj) { o_pkt->rsvp_nflwd = oj; rsvp_pkt_process(o_pkt, NULL, api_num); } api_free_packet(o_pkt); return(0); } /* * api_prepare_resv(): Accepts an API request for a resv. and turns it * into a standard RSVP Resv packet... as if it arrived * from another router (except in host byte order). * Returns -1 if error, else 0. */ int api_prepare_resv(rsvp_req *req, api_rec *recp, struct packet *pkt) { Object_header *objp; packet_map *mapp = pkt->pkt_map; int styleID,LIH; net_addr host; memset((char *)pkt->pkt_data, 0, sizeof(common_header)); mapp->rsvp_msgtype = pkt->pkt_data->rsvp_type = RSVP_RESV; objp = (Object_header *)(pkt->pkt_data + 1); mapp->rsvp_session = (SESSION *) objp; #if defined LABEL session_create(mapp->rsvp_session, &recp->api_dest, recp->api_protid, 0, (recp->api_flags) ); #else session_create(mapp->rsvp_session, &recp->api_dest, recp->api_protid, 0, (recp->api_flags&RAPI_GPI_SESSION) ); #endif objp = Next_Object(objp); /* XXX Should check dstport != 0 if protid = 6 or 17. */ /* Reservation local address: apply default and then * map into interface number, which is passed in LIH. */ net_addr_assign_api_addr(&host,&req->rq_host,0); if (IsAddrAPI(&host)) host = Get_local_addr; /* This assumes if's are subset of vif's XXX */ LIH = map_if_addr(&host); /* (signals: from API) */ mapp->rsvp_hop = (RSVP_HOP *) objp; hop_if_create(pkt->rsvp_nhop,&GET_IF(api_num),LIH); objp = Next_Object(objp); New_Object(mapp->rsvp_timev, TIME_VALUES, TIME_VALUES_CTYPE); pkt->rsvp_R = api_refresh_t; /* If requested by application, send CONFIRM object. */ if (req->rq_flags & RAPI_REQ_CONFIRM) { mapp->rsvp_confirm = (CONFIRM *) objp; confirm_if_create(mapp->rsvp_confirm,&Get_local_interface); objp = Next_Object(objp); } /* Style: Map RAPI style into option vector */ styleID = req->rq_style; New_Object(mapp->rsvp_style, STYLE, STYLE_CTYPE); if (styleID > RAPI_RSTYLE_MAX) { log(LOG_ERR, 0, "API: bad styleid\n"); return(-1); } mapp->rsvp_style->style_word = Styleid_to_Optvec[styleID]; pkt->rsvp_nflwd = req->rq_nflwd; api_get_flows(objp, req, pkt); /* XXX test for error */ /* Finish up common header. * Note: no checksum for API packet (per byte-order field) */ pkt->pkt_data->rsvp_cksum = 0; pkt->pkt_data->rsvp_verflags = RSVP_MAKE_VERFLAGS(RSVP_VERSION, 0); pkt->pkt_data->rsvp_length = pkt->pkt_len = (char *)objp - (char *) pkt->pkt_data; /* * If client sent bad local addr, send error upcall and return 0. */ if (LIH < 0) { rsvp_resv_err(RSVP_Err_API_ERROR, RAPI_ERR_BADRECV, 0, (FiltSpecStar *) -1, pkt); return(0); } /* * If client sent DstPort in the SESSION object of zero * but SrcPort in a FILTER_SPEC is non-zero, send * "Conflicting Src Port" error upcall and return 0. */ if (session_get_port(pkt->rsvp_sess) == 0 && filter_of(FlowDesc_of(pkt,0))) { int i; for (i =0; i < pkt->rsvp_nflwd ; i++) if (filterspec_port(filter_of(FlowDesc_of(pkt,i))) != 0) { rsvp_resv_err(RSVP_Err_API_ERROR, RAPI_ERR_BADSPORT, 0, (FiltSpecStar *) -1, pkt); return(0); } } return(1); /* OK */ } /* Parse flow descriptor list of reservation request from API, and * build map entries. */ int api_get_flows(Object_header *objp, rsvp_req *req, struct packet *pkt) { int i; API_Flowspec *api_specp; API_FilterSpec *api_filtp; FlowDesc *flwdp; api_filtp = (API_FilterSpec *) After_APIObj(req->rq_policy); for (i = 0; i < pkt->rsvp_nflwd; i++) { flwdp = FlowDesc_of(pkt, i); api_specp = (API_Flowspec *) After_APIObj(api_filtp); switch (api_specp->form) { case RAPI_FLOWSTYPE_Intserv: /* Check Intserv version */ if ((api_specp->specbody_IS.spec_mh.ismh_version& INTSERV_VERS_MASK) != INTSERV_VERSION0) return -1; /* XXX */ New_VObject(flwdp->rsvp_specp, FLOWSPEC, FLOWSPEC_Intserv0, size_api2d(api_specp->len)); Move_spec_api2d(api_specp, flwdp->rsvp_specp); break; case RAPI_EMPTY_OTYPE: flwdp->rsvp_specp = NULL; break; default: return -1; /* XXX Reason code */ } if (api_filtp->form != RAPI_EMPTY_OTYPE) { flwdp->rsvp_filtp = (FILTER_SPEC *) objp; #ifdef LABEL flwdp->rsvp_label = NULL; #endif Move_filter_api2d(api_filtp, flwdp->rsvp_filtp, TRUE); objp = Next_Object(objp); } else flwdp->rsvp_filtp = NULL; api_filtp = (API_FilterSpec *) After_APIObj(api_specp); } return(0); } /* * api_prepare_path(): Accepts an API request for a path and turns * it into a standard RSVP Path packet... as if it arrived * from another router (except in host byte order). */ int api_prepare_path( rsvp_req *req, int len, api_rec *recp, struct packet *pkt) { SenderDesc *sdscp; Object_header *objp; packet_map *mapp = pkt->pkt_map; API_FilterSpec *api_filtp; API_TSpec *api_tspecp; API_Adspec *api_adspecp; int LIH; memset((char *)pkt->pkt_data, 0, sizeof(common_header)); mapp->rsvp_msgtype = pkt->pkt_data->rsvp_type = RSVP_PATH; objp = (Object_header *)(pkt->pkt_data + 1); mapp->rsvp_session = (SESSION *) objp; session_create(mapp->rsvp_session, &recp->api_dest, recp->api_protid, SESSFLG_E_Police, recp->api_flags ); objp = Next_Object(objp); #ifdef EX_ROUTE /* * The EXROUTE object is insertet in the pkt_map structure */ if ((mapp->rsvp_exroute == NULL) && (req->rq_rlist->route_header.obj_length != 0)) { mapp->rsvp_exroute = (EXROUTE *) objp; Init_Object(mapp->rsvp_exroute, POLICY_DATA, EX_ROUTE_IPv4); memcpy(mapp->rsvp_exroute, req->rq_rlist, Obj_Length(req->rq_rlist)); objp = Next_Object(objp); api_filtp = (API_FilterSpec *)req->rq_rlist; api_filtp = (API_FilterSpec *)((char *)api_filtp + Obj_Length(req->rq_rlist)); } /* This function adds the new ex_route object into the path msg MZ*/ #endif #ifdef LABEL /* * The LABEL object is insertet in the pkt_map structure */ if(req->rq_rlist->route_header.obj_length != 0){ if(((Object_header*)((char *)req->rq_rlist + Obj_Length(req->rq_rlist)))->obj_class == class_Label_Request){ mapp->rsvp_label = (Labelreq *)objp; memset((char *)mapp->rsvp_label, 0 , sizeof(Label)); memcpy(mapp->rsvp_label,(char *)req->rq_rlist + Obj_Length(req->rq_rlist), 8); objp = Next_Object(objp); api_filtp = (API_FilterSpec *)((char *)api_filtp + 8); } } else { if(((Object_header*)((char *)req->rq_rlist + 4))->obj_class == class_Label_Request){ mapp->rsvp_label = (Labelreq *)objp; memset((char *)mapp->rsvp_label, 0 , sizeof(Label)); memcpy(mapp->rsvp_label,(char *)req->rq_rlist + 4, 8); objp = Next_Object(objp); api_filtp = (API_FilterSpec *)req->rq_rlist; api_filtp = (API_FilterSpec *)((char *)api_filtp + 8); } } #endif /* * Push flags from map into packet itself, and set version */ pkt->pkt_data->rsvp_verflags = RSVP_MAKE_VERFLAGS(RSVP_VERSION, mapp->rsvp_flags); /* * Only one flowspec (Tspec) per request. * (Should be enforced by the client library routine). */ if (req->rq_nflwd != 1) { log(LOG_ERR, 0, "API: sender nflwd > 1\n"); return(-1); } pkt->rsvp_nflwd = 1; sdscp = SenderDesc_of(pkt); #ifdef EX_ROUTE /* * Since there are two new objects api_filtp has to be detrmined in a new way */ if (Obj_Length(req->rq_rlist) == 0) { if(mapp->rsvp_label) api_filtp = (API_FilterSpec *) (After_APIObj(req->rq_policy)+sizeof(EXROUTE)+8); else api_filtp = (API_FilterSpec *) (After_APIObj(req->rq_policy)+sizeof(EXROUTE)); } #else api_filtp = (API_FilterSpec *) After_APIObj(req->rq_policy); #endif api_tspecp = (API_TSpec *) After_APIObj(api_filtp); api_adspecp = (API_Adspec *) After_APIObj(api_tspecp); if ((char *)api_adspecp == (char *)req + len) { /* No Adspec included in request */ api_adspecp = NULL; } else if (After_APIObj(api_adspecp) != (char *)req + len) { log(LOG_ERR, 0, "API: Req len err\n"); return(-1); } /* If local address is INADDR_ANY, set default interface. * Map sender local address into interface number and pass * it in LIH. But if *not* our interface, set LIH = -1 */ LIH = path_set_laddr(api_filtp); /* (signals: from API) */ mapp->rsvp_hop = (RSVP_HOP *) objp; hop_if_create(pkt->rsvp_phop,&GET_IF(api_num),LIH); objp = Next_Object(objp); New_Object(mapp->rsvp_timev, TIME_VALUES, TIME_VALUES_CTYPE); pkt->rsvp_R = api_refresh_t; #if defined LABEL1 if( recp->api_flags & RAPI_LSP_SESSION) { New_Object(sdscp->rsvp_stempl, SENDER_TEMPLATE, SENDER_TEMPLATE_lspv4); } else { New_Object(sdscp->rsvp_stempl, SENDER_TEMPLATE, SENDER_TEMPLATE_ipv4); } #endif sdscp->rsvp_stempl = (SENDER_TEMPLATE *) objp; Move_filter_api2d(api_filtp, sdscp->rsvp_stempl, FALSE); objp = Next_Object(objp); New_VObject(sdscp->rsvp_stspec, SENDER_TSPEC, SENDER_TSPEC_CTYPE, size_api2d(api_tspecp->len)); Move_tspec_api2d(api_tspecp, sdscp->rsvp_stspec); /* If sender gave us initial adspec, put it into Path message. * Otherwise, call Traffic Control interface to create minimal * adspec, and put that into message. */ if (api_adspecp) { New_VObject(sdscp->rsvp_adspec, ADSPEC, ADSPEC_INTSERV, size_api2d(api_adspecp->len)); Move_adspec_api2d(api_adspecp, sdscp->rsvp_adspec); } else { New_VObject(sdscp->rsvp_adspec, ADSPEC, ADSPEC_INTSERV, (DFLT_ADSPEC_LEN)); New_Adspec(sdscp->rsvp_adspec); } /* Finish up common header. * Note: no checksum for API packet (per byte order field) */ pkt->pkt_data->rsvp_cksum = 0; pkt->pkt_data->rsvp_length = pkt->pkt_len = (char *)objp - (char *) pkt->pkt_data; pkt->pkt_data->rsvp_snd_TTL = (req->rq_ttl)? req->rq_ttl+1: RSVP_TTL_MAX; /* If local sender address was bad, generate an error upcall * and return 0 => free the packet buffer */ if (LIH < 0) { rsvp_path_err(-1, RSVP_Err_API_ERROR, RAPI_ERR_BADSEND, pkt); return(0); } /* * If the DstPort in the SESSION object was zero * but SrcPort in SENDER_TEMPLATE was non-zero, * upcall with "Conflicting Src Port" error and free packet. */ if (session_get_port(pkt->rsvp_sess) == 0 && filterspec_port(STempl_of(SenderDesc_of(pkt))) != 0) { rsvp_path_err(-1, RSVP_Err_API_ERROR, RAPI_ERR_BADSPORT, pkt); return(0); } return(1); } /* Process rapi_status request. */ int api_status(rsvp_req *req) { Session *destp; api_rec *apip; int i; net_addr dest; net_addr_assign_api_addr(&dest,&req->rq_dest,1); if (!IsAddrAPI(&dest)) { /* Specific destination -- * Find the dest (session) record */ destp = locate_api_session(req,0); if (!destp) { destp = locate_api_session(req,RAPI_GPI_SESSION); #if defined LABEL if (!destp) { destp = locate_api_session(req,RAPI_LSP_SESSION); } #endif if (!destp) return(-1); } api_dest_status(destp, req); return(0); } /* Else status of all destinations for this user process */ for (i=0, apip= api_table; i < API_TABLE_SIZE; i++, apip++) { if (apip->api_fd == 0) break; if (apip->api_pid != req->rq_pid) break; destp = locate_api_session(req, (apip->api_flags)); if (destp) api_dest_status(destp, req); } return(0); } int api_dest_status(Session *dest, rsvp_req *req) { #ifdef ISI_TEST if (req->rq_flags & RAPI_STAT_PATH) { api_PATH_EVENT_upcall1(dest, UPCALL_MODE_STAT, ALL_SID); /* ?? XXX */ } if (req->rq_flags & RAPI_STAT_RESV) { /*** Need to call api_RESV_EVENT_upcall for all RSBs api_RESV_EVENT_upcall_stat(dest, rp); ***/ } #endif /* ISI_TEST */ return(0); } /* * api_PATH_EVENT_upcall(): Notify local API clients of (remote) * Path state. Also, if there is an active reservation request * from API, refresh it immediately. */ void api_PATH_EVENT_upcall(Session *destp) { api_PATH_EVENT_upcall1(destp, UPCALL_MODE_PATH, ALL_SID); } /* * Special case of PATH EVENT upcall: new API session has just * registered; deliver any pending path state to it immediately. * */ void api_PATH_EVENT_init(Session *destp, int sid) { api_PATH_EVENT_upcall1(destp, UPCALL_MODE_IFANY, sid); } void api_PATH_EVENT_upcall1(Session *destp, int mode, int sid) { char *resp_buf; rsvp_resp *resp; API_TSpec *tspecp; API_FilterSpec *filtp; API_Adspec *adsp; PSB *sp; int resp_len; /* Make first pass over PSBs to compute length of required * response message, and then malloc a buffer of that length. */ resp_len = sizeof(rsvp_resp); for (sp = destp->d_PSB_list; sp != NULL; sp = sp->ps_next) { if (mode != UPCALL_MODE_STAT && IsHopAPI(&sp->ps_phop)) continue; resp_len += sizeof(rapi_filter_t) + size_d2api(Object_Size(sp->ps_tspec)); if (sp->ps_adspec) resp_len += size_d2api(Object_Size(sp->ps_adspec)); } /* If there were no matches and if mode calls for suppression * of null responses, return now. */ if (resp_len == sizeof(rsvp_resp) && mode != UPCALL_MODE_PATH) return; if (!(resp_buf = malloc(resp_len))) { Log_Mem_Full("API Resp"); return; } memset(resp = (rsvp_resp *)resp_buf, 0, resp_len); resp->resp_type = (mode == UPCALL_MODE_STAT)? RAPI_PATH_STATUS: RAPI_PATH_EVENT; resp_session_assign(resp,destp->d_session); /* * Second pass over PSBs to insert sender tspecs and templates */ filtp = (API_FilterSpec *) resp->resp_flows; for (sp = destp->d_PSB_list; sp != NULL; sp = sp->ps_next) { if (mode != UPCALL_MODE_STAT && IsHopAPI(&sp->ps_phop)) continue; tspecp = (API_TSpec *) Move_filter_d2api(sp->ps_templ, filtp); /* Move TSpec or empty object */ filtp = (API_FilterSpec *) Move_tspec_d2api(sp->ps_tspec, tspecp); resp->resp_nflwd++; } /* * Third pass over PSBs to insert adspec list */ adsp = (API_Adspec *) filtp; for (sp = destp->d_PSB_list; sp != NULL; sp = sp->ps_next) { if (mode != UPCALL_MODE_STAT && IsHopAPI(&sp->ps_phop)) continue; adsp = (API_Adspec *) Move_adspec_d2api(sp->ps_adspec, adsp); } upcall_to_appl(resp, (char *) adsp - resp_buf, NULL, sid); /* * If notifying of PATH state and there was a * pending Resv from API, retry Resv immediately. */ if (mode == UPCALL_MODE_PATH) { for(sid = 0; sid < API_TABLE_SIZE; sid++) { api_rec *recp = &api_table[sid]; if (resp->resp_nflwd && recp->api_r_packet.pkt_data) rsvp_pkt_process(&recp->api_r_packet, NULL, api_num); } } free(resp_buf); } /* * api_PATH_ERR_upcall: Pass Path Error message across API to all * application(s) that match it. */ void api_PATH_ERR_upcall(struct packet *pkt) { char resp_buf[MAX_PKT]; rsvp_resp *resp = (rsvp_resp *) resp_buf; API_FilterSpec *api_filtp = (API_FilterSpec *) &resp->resp_flows; API_TSpec *api_tspecp; SenderDesc *sdscp = SenderDesc_of(pkt); FORCE_HOST_ORDER(pkt); memset(resp, 0, MAX_PKT); /* Excessive... */ resp->resp_type = RAPI_PATH_ERROR; api_ERR_upcall_common(resp, pkt); assert(pkt->rsvp_nflwd <= 1); if (pkt->rsvp_nflwd < 1) return; resp->resp_nflwd = 1; api_tspecp = (API_TSpec *) Move_filter_d2api(sdscp->rsvp_stempl, api_filtp); api_filtp = (API_FilterSpec *) Move_tspec_d2api(sdscp->rsvp_stspec, api_tspecp); upcall_to_appl(resp, (char *)api_filtp - resp_buf, sdscp->rsvp_stempl, ALL_SID); } void api_RESV_EVENT_upcall(Session *destp, RSB *rp) { api_RESV_EVENT_upcall1(destp, rp, 0); } void api_RESV_EVENT_upcall_stat(Session *destp, RSB *rp) { api_RESV_EVENT_upcall1(destp, rp, 1); } /* * api_RESV_EVENT_upcall1() [Inner routine] * * Make RESV_EVENT upcall to application for specific RSB. * If is_stat is non-zero, use STATUS type in response msg. */ void api_RESV_EVENT_upcall1(Session *destp, RSB *rp, int is_stat) { char resp_buf[MAX_PKT]; rsvp_resp *resp = (rsvp_resp *) resp_buf; API_Flowspec *api_specp; API_FilterSpec *api_filtp; int i; memset(resp, 0, MAX_PKT); resp->resp_type = (is_stat)? RAPI_RESV_STATUS: RAPI_RESV_EVENT; resp_session_assign(resp,destp->d_session); /* Map style into external style id */ switch (rp->rs_style) { case STYLE_WF: resp->resp_style = RAPI_RSTYLE_WILDCARD; break; case STYLE_FF: resp->resp_style = RAPI_RSTYLE_FIXED; break; case STYLE_SE: resp->resp_style = RAPI_RSTYLE_SE; break; default: assert(0); } api_filtp = (API_FilterSpec *) resp->resp_flows; if (rp->rs_spec == NULL) { resp->resp_nflwd = 0; upcall_to_appl(resp, (char *)api_filtp-resp_buf,NULL,ALL_SID); return; } /* After rq_policy in API response comes pair: * Style=WF: * Style=FF: * Style=SE: * Note that only one flowspec is passed per upcall; one FF * style Resv may produce multiple upcalls. Furthermore, only * the matching filter spec is passed for SE. But if state * has been torn down, make empty upcall. */ resp->resp_nflwd = 1; if (resp->resp_style == RAPI_RSTYLE_WILDCARD) { api_specp = (API_Flowspec *) Move_filter_d2api(NULL, api_filtp); api_filtp = (API_FilterSpec *) Move_spec_d2api(rp->rs_spec, api_specp); upcall_to_appl(resp, (char *) api_filtp-resp_buf,NULL,ALL_SID); return; } for (i = 0; i < rp->rs_fcount; i++) { api_specp = (API_Flowspec *) Move_filter_d2api(rp->rs_Filtp(i), api_filtp); api_filtp = (API_FilterSpec *) Move_spec_d2api(rp->rs_spec, api_specp); upcall_to_appl(resp, (char *) api_filtp - resp_buf, rp->rs_Filtp(i), ALL_SID); } } /* api_RESV_ERR_upcall: Send reservation error or confirmation to * all applications matching session. */ void api_RESV_ERR_upcall(struct packet *pkt) { char resp_buf[MAX_PKT]; rsvp_resp *resp = (rsvp_resp *) resp_buf; int i; API_FilterSpec *api_filtp = (API_FilterSpec *) &resp->resp_flows; API_Flowspec *api_specp; FORCE_HOST_ORDER(pkt); memset(resp, 0, MAX_PKT); /* Excessive... */ resp->resp_type = (errorspec_get_errcode(pkt->rsvp_errs) == RSVP_Err_NONE)? RAPI_RESV_CONFIRM: RAPI_RESV_ERROR; api_ERR_upcall_common(resp, pkt); /* Map style into external style id */ switch (Style(pkt)) { case STYLE_WF: resp->resp_style = RAPI_RSTYLE_WILDCARD; break; case STYLE_FF: resp->resp_style = RAPI_RSTYLE_FIXED; break; case STYLE_SE: resp->resp_style = RAPI_RSTYLE_SE; break; default: assert(0); } resp->resp_nflwd = pkt->rsvp_nflwd; for (i = 0; i < pkt->rsvp_nflwd; i++) { FlowDesc *flwdp = FlowDesc_of(pkt, i); api_specp = (API_Flowspec *) Move_filter_d2api(flwdp->rsvp_filtp, api_filtp); api_filtp = (API_FilterSpec *) Move_spec_d2api(flwdp->rsvp_specp, api_specp); } upcall_to_appl(resp, (char *) api_filtp - resp_buf, NULL, ALL_SID); } void api_ERR_upcall_common(rsvp_resp *resp, struct packet *pkt) { SESSION *session = pkt->rsvp_sess; ERROR_SPEC *errorspec = pkt->rsvp_errs; if (Obj_Class(session) != class_SESSION) return; if (Obj_Class(errorspec) != class_ERROR_SPEC) return; resp_session_assign(resp, session); switch(Obj_CType(session)) { case ctype_SESSION_ipv4: case ctype_SESSION_ipv4GPI: case ctype_SESSION_lsp_tunv4: if (Obj_CType(errorspec) != ctype_ERROR_SPEC_ipv4) return; resp->resp_errcode = errorspec->errspec4_code; resp->resp_errval = errorspec->errspec4_value; resp->resp_errflags = errorspec->errspec4_flags; NET_SOCKADDR_IPv4( (struct sockaddr_in *) &resp->resp_errnode, errorspec->errspec4_enode); return; #ifdef USE_IPV6 case ctype_SESSION_ipv6: case ctype_SESSION_ipv6GPI: if (Obj_CType(errorspec) != ctype_ERROR_SPEC_ipv6) return; resp->resp_errcode = errorspec->errspec6_code; resp->resp_errval = errorspec->errspec6_value; resp->resp_errflags = errorspec->errspec6_flags; NET_SOCKADDR_IPv6( (struct sockaddr_in6 *) &resp->resp_errnode, errorspec->errspec6_enode); return; #endif /* USE_IPV6 */ default: return; } } static int resp_session_assign(rsvp_resp *resp,SESSION *session) { if (Obj_Class(session) != class_SESSION) return(FALSE); resp->resp_flags = 0; switch(Obj_CType(session)) { case ctype_SESSION_ipv4GPI: resp->resp_flags |= RAPI_GPI_SESSION; case ctype_SESSION_ipv4: resp->resp_dest.type = htons(API_ADDR_TYPE_IPv4); resp->resp_dest.port = session->sess4_port; memcpy(&resp->resp_dest.u.addr_ipv4, &session->sess4_addr, sizeof(resp->resp_dest.u.addr_ipv4)); resp->resp_protid = session->sess4_prot; return(TRUE); #ifdef USE_IPV6 case ctype_SESSION_ipv6GPI: resp->resp_flags |= RAPI_GPI_SESSION; case ctype_SESSION_ipv6: resp->resp_dest.type = htons(API_ADDR_TYPE_IPv6); resp->resp_dest.port = session->sess6_port; memcpy(&resp->resp_dest.u.addr_ipv6, &session->sess6_addr, sizeof(resp->resp_dest.u.addr_ipv6)); resp->resp_protid = session->sess6_prot; return(TRUE); #endif /* USE_IPV6 */ case ctype_SESSION_lsp_tunv4: resp->resp_flags |= RAPI_LSP_SESSION; resp->resp_dest.type = htons(API_ADDR_TYPE_IPv4); resp->resp_dest.port = session->sesslsp_tunid; memcpy(&resp->resp_dest.u.addr_ipv4, &session->sesslsp_addr, sizeof(resp->resp_dest.u.addr_ipv4)); resp->resp_protid = 0; /* No protocol no */ return(TRUE); default: return(FALSE); } } /* Vector of direction flags for each event type. */ static int DIR_per_EVENT[] = {0, 0, /* 1- Path event: OK even if dir not set */ API_DIR_SEND, /* 2- Resv event */ API_DIR_SEND, /* 3- Path error event */ API_DIR_RECV, /* 4- Resv error event */ API_DIR_RECV, /* 5- Confirmation event */ 0, 0, 0, 0, /* 9- Path status */ API_DIR_SEND /* 10- Resv status */ }; /* Given response message, pass it to specified API session. If * sid = -1 (ALL_SID), pass it to all API sessions with matching * session and direction, and for FILTER_SPEC *filtp matching sender * if filtp is not NULL. Otherwise, pass to specific sid. * */ static void upcall_to_appl(rsvp_resp *resp, int len, FILTER_SPEC *filtp, int sid) { api_rec *recp; net_addr dest; resp->resp_version = VERSION_API; if (sid >= 0) { upcall_to_sid(resp, len, sid); return; } net_addr_assign_api_addr(&dest,&resp->resp_dest,1); for(sid = 0; sid < API_TABLE_SIZE; sid++) { recp = &api_table[sid]; if (recp->api_fd == 0) continue; if (DIR_per_EVENT[resp->resp_type] && (recp->api_flags & DIR_per_EVENT[resp->resp_type]) == 0) continue; if (filtp) { if (!recp->api_p_packet.pkt_data) continue; else if (!match_filter(filtp, (SenderDesc_of(&recp->api_p_packet))->rsvp_stempl)) continue; } if (net_addr_equal(&dest, &recp->api_dest) && (resp->resp_protid == recp->api_protid)) upcall_to_sid(resp, len, sid); } } /* Given response message and length, send as upcall to specified * API session (inner routine of upcall_to_appl()) */ void upcall_to_sid(rsvp_resp *resp, int len, int sid) { api_rec *recp = &api_table[sid]; resp->resp_a_sid = recp->api_a_sid; /* Client's SID */ if (IsDebug(DEBUG_ALL)) { static char *Event_Names[] = { "", "Path Evt", "Resv Evt", "Perr Evt", "Rerr Evt", "RConfirm", "??6 Ev", "??7 Ev", "??8 Ev", "Pstat Ev", "Rstat Ev"}; net_addr dest; net_addr_assign_api_addr(&dest,&resp->resp_dest,1); log_api_event(LOGEV_API_upcall, Event_Names[resp->resp_type], &dest, resp->resp_protid, "> API pid=%d Asid=%d\n", recp->api_pid, recp->api_a_sid); } if (NetByteOrderResp(sid)) { char *newbuf = malloc(len); if (!newbuf) return; memcpy(newbuf, (char *)resp, len); hton_api_resp((rsvp_resp *)newbuf, len); send_to_api(sid, (rsvp_resp *)newbuf, len); free(newbuf); } else send_to_api(sid, resp, len); } /* * Write message 'resp' of length 'len' bytes across API to application * with local session id 'sid'. * */ void send_to_api(int sid, rsvp_resp *resp, int len) { struct iovec iov[2]; int nlen = len; if (l_debug >= LOG_HEXD && len > 0) { hexf(stderr, (char *) resp, len); } if (NetByteOrderResp(sid)) HTON32(nlen); iov[0].iov_base = (char *) (&nlen); iov[0].iov_len = sizeof(int); iov[1].iov_base = (char *) resp; iov[1].iov_len = len; if (writev(api_table[sid].api_fd, iov, 2) == -1) { log(LOG_ERR, errno, "NBIO write error\n"); } } int api_refresh_delay(int sid) { api_rec *recp = &api_table[sid]; if (recp->api_p_packet.pkt_data) return ((&recp->api_p_packet)->rsvp_R); else if (recp->api_r_packet.pkt_data) return ((&recp->api_r_packet)->rsvp_R); else return (0); } Session * locate_api_session(rsvp_req *req, int gpi) { SESSION Session_obj; net_addr dest; net_addr_assign_api_addr(&dest,&req->rq_dest,1); session_create(&Session_obj,&dest, (req->rq_protid)?req->rq_protid:RSVP_DFLT_PROTID,0,gpi); return(locate_session(&Session_obj)); } void log_api_event(int evtype, char *type, net_addr *adrp, int protid, const char *format, int pid, int asid) { SESSION Session_obj; session_create(&Session_obj,adrp,protid,0,FALSE); log_event(evtype, type, &Session_obj, format, pid, asid); } static void print_api_request(rsvp_req *req, int len, int sid) { api_rec *recp = &api_table[sid]; API_FilterSpec *api_filtp; API_TSpec *api_tspecp; API_Flowspec *api_specp; char buff1[80], buff2[80]; int i; char *flgstr; net_addr dest; if (len==0 || req->rq_type == API_CLOSE) { log_api_event(LOGEV_API_close, "", &recp->api_dest, recp->api_protid, "api_pid, recp->api_a_sid); return; } net_addr_assign_api_addr(&dest,&req->rq_dest,1); switch (req->rq_type) { case API2_REGISTER: flgstr = cnv_flags("SRCIG??L", req->rq_flags); /* Flags: * S: Sender * R: Receiver * C: Confirmation request on rapi_reserve call * I: Intserv format for upcalls * G: GPI format */ log_api_event(LOGEV_API_regi, flgstr, &dest, req->rq_protid, "rq_pid, req->rq_a_sid); if (IsDebug(DEBUG_EVENTS)&& req->rq_nflwd) { api_filtp = (API_FilterSpec *) After_APIObj(req->rq_policy); api_tspecp = (API_TSpec *) After_APIObj(api_filtp); rapi_fmt_filtspec(api_filtp, buff1, 80); rapi_fmt_tspec(api_tspecp, buff2, 80); log(LOG_DEBUG, 0, " Register sender: %s %s\n", buff1, buff2); } break; case API2_RESV: log_api_event(LOGEV_API_resv, style_names[req->rq_style], &dest, req->rq_protid, "rq_pid, req->rq_a_sid); if (IsDebug(DEBUG_EVENTS)) { log(LOG_DEBUG, 0, " Reserve StyleID= %d\n", req->rq_style); api_filtp = (API_FilterSpec *) After_APIObj(req->rq_policy); for (i = 0; i < req->rq_nflwd; i++) { api_specp = (API_Flowspec *) After_APIObj(api_filtp); rapi_fmt_filtspec(api_filtp, buff1, 80); buff2[0] = '\0'; if (api_specp->form != RAPI_EMPTY_OTYPE) rapi_fmt_flowspec(api_specp, buff2, 80); api_filtp = (API_FilterSpec *) After_APIObj(api_specp); log(LOG_DEBUG, 0, " %s %s\n", buff1, buff2); } } break; default: break; } } /* Define a set of object reformatting routines: * * Move_XXXX_api2d: copy object of type XXXX, repackaging it * from the [r]api framing of daemon's object framing. * * Move_XXXX_d2api: copy object of type XXXX, repackaging it * from the daemon object framing to [r]api framing. */ int Move_spec_api2d(rapi_flowspec_t * api_specp, FLOWSPEC * d_specp) { int size; /* XXX should validity-check type and length */ Obj_Length(d_specp) = size = size_api2d(api_specp->len); memcpy(Obj_data(d_specp), RAPIObj_data(api_specp), size - sizeof(Object_header)); return(0); } /* In rsvpd -> API direction, send flowspec, Tspec, or Adspec in * int-serv format but with RAPI framing. This common routine * does the necessary reframing. */ void Reframe_d2api(Object_header *d_specp, rapi_hdr_t * api_specp, int type) { int size; if (!d_specp) { api_specp->len = sizeof(rapi_hdr_t); api_specp->form = RAPI_EMPTY_OTYPE; /* Empty entry */ } else { api_specp->len = size = size_d2api(Obj_Length(d_specp)); api_specp->form = type; memcpy(RAPIObj_data(api_specp), Obj_data(d_specp), size - sizeof(rapi_hdr_t)); } } char * Move_spec_d2api(FLOWSPEC * d_specp, rapi_flowspec_t * api_specp) { Reframe_d2api((Object_header *) d_specp, (rapi_hdr_t *) api_specp, RAPI_FLOWSTYPE_Intserv); return(After_APIObj(api_specp)); } int Move_tspec_api2d(rapi_tspec_t * api_tspecp, SENDER_TSPEC * d_tspecp) { /* XXX should validity-check type and length */ Move_spec_api2d((rapi_flowspec_t *)api_tspecp, (FLOWSPEC *)d_tspecp); return(0); } char * Move_tspec_d2api(SENDER_TSPEC * d_tspecp, rapi_tspec_t * api_tspecp) { Reframe_d2api((Object_header *) d_tspecp, (rapi_hdr_t *) api_tspecp, RAPI_TSPECTYPE_Intserv); return(After_APIObj(api_tspecp)); } int Move_adspec_api2d(rapi_adspec_t * api_adspecp, ADSPEC * d_adspecp) { /* XXX should validity-check type and length */ Move_spec_api2d((rapi_flowspec_t *)api_adspecp, (FLOWSPEC *)d_adspecp); return(0); } char * Move_adspec_d2api(ADSPEC * d_adspecp, rapi_adspec_t * api_adspecp) { Reframe_d2api((Object_header *) d_adspecp, (rapi_hdr_t *) api_adspecp, RAPI_ADSTYPE_Intserv); return(After_APIObj(api_adspecp)); } int Move_filter_api2d(rapi_filter_t * api_filtp, FILTER_SPEC * d_filtp,int filt) { switch (api_filtp->form) { case RAPI_FILTERFORM_BASE: if (filt) { Init_Object(d_filtp,FILTER_SPEC, FILTER_SPEC_ipv4); } else { Init_Object(d_filtp,SENDER_TEMPLATE, SENDER_TEMPLATE_ipv4); } d_filtp->filt4_srcaddr.s_addr = api_filtp->rapi_filtbase4_addr.s_addr; d_filtp->filt4_srcport = api_filtp->rapi_filtbase4_port; break; case RAPI_FILTERFORM_GPI: if (filt) { Init_Object(d_filtp,FILTER_SPEC, FILTER_SPEC_ipv4GPI); } else { Init_Object(d_filtp,SENDER_TEMPLATE, SENDER_TEMPLATE_ipv4GPI); } d_filtp->filtgpi4_srcaddr.s_addr = api_filtp->rapi_filtgpi4_addr.s_addr; d_filtp->filtgpi4_srcgpi = api_filtp->rapi_filtgpi4_gpi; break; #ifdef USE_IPV6 case RAPI_FILTERFORM_BASE6: if (filt) { Init_Object(d_filtp,FILTER_SPEC, FILTER_SPEC_ipv6); } else { Init_Object(d_filtp,SENDER_TEMPLATE, SENDER_TEMPLATE_ipv6); } d_filtp->filt6_srcaddr = api_filtp->rapi_filtbase6_addr; d_filtp->filt6_srcport = api_filtp->rapi_filtbase6_port; break; case RAPI_FILTERFORM_GPI6: if (filt) { Init_Object(d_filtp,FILTER_SPEC, FILTER_SPEC_ipv6GPI); } else { Init_Object(d_filtp,SENDER_TEMPLATE, SENDER_TEMPLATE_ipv6GPI); } d_filtp->filtgpi6_srcaddr = api_filtp->rapi_filtgpi6_addr; d_filtp->filtgpi6_srcgpi = api_filtp->rapi_filtgpi6_gpi; break; #endif /* USE_IPV6 */ case RAPI_FILTERFORM_LSPv4: if (filt) { Init_Object(d_filtp,FILTER_SPEC, FILTER_SPEC_lsp_tunv4); } else { Init_Object(d_filtp,SENDER_TEMPLATE, SENDER_TEMPLATE_lspv4); } d_filtp->filtlsp4_saddr.s_addr = api_filtp->rapi_filtlspv4_addr.s_addr; d_filtp->filtlsp4_zero = api_filtp->rapi_filtlspv4_zero; d_filtp->filtlsp4_id = api_filtp->rapi_filtlspv4_lspid; break; default: log(LOG_ERR, 0, "API: Bad filterspec type %d\n", api_filtp->form); break; } return(0); } int path_set_laddr(rapi_filter_t * api_filtp) { net_addr addr; switch (api_filtp->form) { case RAPI_FILTERFORM_BASE: if (IN_ARE_ADDR_EQUAL(&api_filtp->rapi_filtbase4_addr, &inaddr_any)) api_filtp->rapi_filtbase4_addr = NET_GET_ADDR_IPv4(&Get_local_addr); NET_SET_ADDR_IPv4(&addr,api_filtp->rapi_filtbase4_addr); return map_if_addr(&addr); case RAPI_FILTERFORM_GPI: if (IN_ARE_ADDR_EQUAL(&api_filtp->rapi_filtgpi4_addr, &inaddr_any)) api_filtp->rapi_filtgpi4_addr = NET_GET_ADDR_IPv4(&Get_local_addr); NET_SET_ADDR_IPv4(&addr,api_filtp->rapi_filtgpi4_addr); return map_if_addr(&addr); #ifdef USE_IPV6 case RAPI_FILTERFORM_BASE6: if (IN6_ARE_ADDR_EQUAL(&api_filtp->rapi_filtbase6_addr, &in6addr_any)) api_filtp->rapi_filtbase6_addr = NET_GET_ADDR_IPv6(&Get_local_addr6); NET_SET_ADDR_IPv6(&addr,api_filtp->rapi_filtbase6_addr); return map_if_addr(&addr); #endif /* USE_IPV6 */ case RAPI_FILTERFORM_LSPv4: if (IN_ARE_ADDR_EQUAL(&api_filtp->rapi_filtlspv4_addr, &inaddr_any)) api_filtp->rapi_filtlspv4_addr = NET_GET_ADDR_IPv4(&Get_local_addr); NET_SET_ADDR_IPv4(&addr,api_filtp->rapi_filtlspv4_addr); return map_if_addr(&addr); default: /* Error noted later */ break; } return(-1); } char * Move_filter_d2api(FILTER_SPEC * d_filtp, rapi_filter_t * api_filtp) { if (!d_filtp) { api_filtp->len = sizeof(rapi_hdr_t); api_filtp->form = RAPI_EMPTY_OTYPE; /* Empty entry */ return (After_APIObj(api_filtp)); } switch (Obj_CType(d_filtp)) { case ctype_FILTER_SPEC_ipv4: api_filtp->form = RAPI_FILTERFORM_BASE; NET_SOCKADDR_UDP_IPv4( &api_filtp->rapi_filt4, d_filtp->filt4_srcaddr, d_filtp->filt4_srcport); api_filtp->len = sizeof(rapi_hdr_t)+sizeof(rapi_filter_base_t); break; case ctype_FILTER_SPEC_ipv4GPI: api_filtp->form = RAPI_FILTERFORM_GPI; api_filtp->rapi_filtgpi4_addr.s_addr = d_filtp->filtgpi4_srcaddr.s_addr; api_filtp->rapi_filtgpi4_gpi = d_filtp->filtgpi4_srcgpi; api_filtp->len = sizeof(rapi_hdr_t) + sizeof(rapi_filter_gpi_t); break; #ifdef USE_IPV6 case ctype_FILTER_SPEC_ipv6: api_filtp->form = RAPI_FILTERFORM_BASE6; NET_SOCKADDR_UDP_IPv6( &api_filtp->rapi_filt6, d_filtp->filt6_srcaddr, d_filtp->filt6_srcport); api_filtp->len = sizeof(rapi_hdr_t)+sizeof(rapi_filter_base6_t); break; case ctype_FILTER_SPEC_ipv6GPI: api_filtp->form = RAPI_FILTERFORM_GPI6; api_filtp->rapi_filtgpi6_addr = d_filtp->filtgpi6_srcaddr; api_filtp->rapi_filtgpi6_gpi = d_filtp->filtgpi6_srcgpi; api_filtp->len = sizeof(rapi_hdr_t)+sizeof(rapi_filter_gpi6_t); break; #endif /* USE_IPV6 */ case ctype_FILTER_SPEC_lsp_tunv4: api_filtp->form = RAPI_FILTERFORM_LSPv4; api_filtp->rapi_filtlspv4_addr.s_addr = d_filtp->filtlsp4_saddr.s_addr; api_filtp->rapi_filtlspv4_zero = d_filtp->filtlsp4_zero; api_filtp->rapi_filtlspv4_lspid = d_filtp->filtlsp4_id; api_filtp->len = sizeof(rapi_hdr_t)+sizeof(rapi_filter_lspv4_t); break; default: /* Something is wrong with filter spec. Pass null (but * not empty) one. Maybe someone will notice... * But really: should validity check filter spec before * reach here! */ api_filtp->form = RAPI_FILTERFORM_BASE; NET_SOCKADDR_UDP_IPv4(&api_filtp->rapi_filt4, inaddr_any,hton16(0)); api_filtp->len = sizeof(rapi_hdr_t)+sizeof(rapi_filter_base_t); break; } return (After_APIObj(api_filtp)); } /* * ntoh_api_request(): API request from net to host byte order * */ void ntoh_api_request(rsvp_req *req, int len) { #if BYTE_ORDER == LITTLE_ENDIAN int i; rapi_flowspec_t *api_specp; rapi_filter_t *api_filtp; NTOH32(req->rq_a_sid); NTOH32(req->rq_pid); NTOH16(req->rq_nflwd); NTOH_RAPIhdr(req->rq_policy); api_filtp = (API_FilterSpec *) After_APIObj(req->rq_policy); for (i = 0; i < req->rq_nflwd; i++) { NTOH_RAPIhdr(api_filtp); api_specp = (API_Flowspec *) After_APIObj(api_filtp); NTOH_RAPIhdr(api_specp); ntoh_rapi_flowspec(&api_specp->specbody_IS); api_filtp = (API_FilterSpec *) After_APIObj(api_specp); } if (i == 1 && (char *)api_filtp < (char *)req + len) { NTOH_RAPIhdr(api_filtp); ntoh_rapi_adspec(&((API_Adspec *)api_filtp)->adspecbody_IS); } #endif /* LITTLE_ENDIAN */ } /* * hton_api_resp(): API response from host to net byte order * */ void hton_api_resp(rsvp_resp *resp, int len) { #if BYTE_ORDER == LITTLE_ENDIAN int i; rapi_flowspec_t *api_specp; rapi_filter_t *api_filtp; rapi_adspec_t *api_adspec, *next_adspec; HTON32(resp->resp_a_sid); HTON32(resp->resp_style); HTON16(resp->resp_errval); api_filtp = (API_FilterSpec *) resp->resp_flows; for (i = 0; i < resp->resp_nflwd; i++) { api_specp = (API_Flowspec *) After_APIObj(api_filtp); HTON_RAPIhdr(api_filtp); api_filtp = (API_FilterSpec *) After_APIObj(api_specp); hton_rapi_flowspec(&api_specp->specbody_IS); HTON_RAPIhdr(api_specp); } if ((char *)api_filtp - (char *) resp < len) { /* There is a list of adspecs too */ api_adspec = (API_Adspec *) api_filtp; for (i = 0; i < resp->resp_nflwd; i++) { hton_rapi_adspec(&api_adspec->adspecbody_IS); next_adspec = (API_Adspec *) After_APIObj(api_adspec); HTON_RAPIhdr(api_adspec); api_adspec = next_adspec; } } HTON16(resp->resp_nflwd); resp->resp_flags |= API_NET_BO; #endif /* LITTLE_ENDIAN */ } int net_addr_assign_api_addr(net_addr *addr,const api_addr *x,int udp) { struct in_addr a4; #ifdef USE_IPV6 struct in6_addr a6; #endif /* USE_IPV6 */ switch (ntohs(x->type)) { case API_ADDR_TYPE_IPv4: memcpy(&a4,x->u.addr_ipv4,sizeof(x->u.addr_ipv4)); if (udp) { NET_SET_ADDR3_UDP_IPv4(addr,a4,x->port); } else { NET_SET_ADDR_IPv4(addr,a4); } return(TRUE); #ifdef USE_IPV6 case API_ADDR_TYPE_IPv6: memcpy(&a6,x->u.addr_ipv6,sizeof(x->u.addr_ipv6)); if (udp) { NET_SET_ADDR3_UDP_IPv6(addr,a6,x->port); } else { NET_SET_ADDR_IPv6(addr,a6); } return(TRUE); #endif /* USE_IPV6 */ default: return(FALSE); } }